mirror of
https://github.com/OCA/rma.git
synced 2025-02-16 17:11:47 +02:00
Merge pull request #86 from cyrilgdn/9.0-crm_claim_rma
crm_claim_rma: migration V9
This commit is contained in:
90
crm_claim_rma/README.rst
Normal file
90
crm_claim_rma/README.rst
Normal file
@@ -0,0 +1,90 @@
|
||||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
|
||||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||
:alt: License: AGPL-3
|
||||
|
||||
====================================================
|
||||
Management of Return Merchandise Authorization (RMA)
|
||||
====================================================
|
||||
|
||||
This module aims to improve the Claims by adding a way to manage the
|
||||
product returns. It allows you to create and manage picking from a
|
||||
claim. It also introduces a new object: the claim lines to better
|
||||
handle that problematic. One Claim can have several lines that
|
||||
concern the return of differents products. It's for every of them
|
||||
that you'll be able to check the warranty (still running or not).
|
||||
|
||||
It mainly contains the following features:
|
||||
|
||||
* product returns (one by one, mass return by invoice)
|
||||
* warranty control & return address (based on invoice date and product form)
|
||||
* product picking in / out
|
||||
* product refund
|
||||
* access to related customer data (orders, invoices, refunds, picking
|
||||
in/out) from a claim
|
||||
* use the OpenERP chatter within team like in opportunity (reply to refer to
|
||||
the team, not a person)
|
||||
|
||||
Using this module makes the logistic flow of return this way:
|
||||
|
||||
* Returning product goes into Stock or Supplier location with a incoming
|
||||
shipment (depending on the settings of the supplier info in the
|
||||
product form)
|
||||
* You can make a delivery from the RMA to send a new product to the Customer
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- New field priority in claim line
|
||||
- Calculate priority of claim line depending of today date and claim date
|
||||
- Grouping by priority in claim line
|
||||
|
||||
|
||||
For further information, please visit:
|
||||
|
||||
* https://www.odoo.com/forum/help-1
|
||||
|
||||
Known issues / Roadmap
|
||||
======================
|
||||
|
||||
* Currently, the warranty duration used is the one configured on the
|
||||
products today, not the one which was configured when the product
|
||||
has been sold.
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/rma/issues>`_.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us smashing it by providing a detailed and welcomed feedback
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Contributors:
|
||||
-------------
|
||||
|
||||
* Emmanuel Samyn <esamyn@gmail.com>
|
||||
* Sébastien Beau <sebastien.beau@akretion.com.br>
|
||||
* Benoît Guillot <benoit.guillot@akretion.com.br>
|
||||
* Joel Grand-Guillaume <joel.grandguillaume@camptocamp.com>
|
||||
* Guewen Baconnier <guewen.baconnier@camptocamp.com>
|
||||
* Yannick Vaucher <yannick.vaucher@camptocamp.com>
|
||||
* Javier Carrasco <javier.carrasco@eezee-it.com>
|
||||
* Yanina Aular <yanina.aular@vauxoo.com>
|
||||
* Osval Reyes <osval@vauxoo.com>
|
||||
* Cyril Gaudin <cyril.gaudin@camptocamp.com>
|
||||
|
||||
Maintainer
|
||||
----------
|
||||
|
||||
.. image:: https://odoo-community.org/logo.png
|
||||
:alt: Odoo Community Association
|
||||
:target: https://odoo-community.org
|
||||
|
||||
This module is maintained by the OCA.
|
||||
|
||||
OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||
mission is to support the collaborative development of Odoo features and
|
||||
promote its widespread use.
|
||||
|
||||
To contribute to this module, please visit http://odoo-community.org.
|
||||
@@ -1,26 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright 2015 Eezee-It
|
||||
# Copyright 2013 Camptocamp
|
||||
# Copyright 2009-2013 Akretion,
|
||||
# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau,
|
||||
# Joel Grand-Guillaume
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from . import models
|
||||
from . import wizards
|
||||
|
||||
@@ -1,104 +1,44 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright 2015 Eezee-It
|
||||
# Copyright 2013 Camptocamp
|
||||
# Copyright 2009-2013 Akretion,
|
||||
# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau,
|
||||
# Benoît Guillot, Joel Grand-Guillaume
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# © 2015 Vauxoo
|
||||
# © 2015 Eezee-It
|
||||
# © 2009-2013 Akretion
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
{
|
||||
'name': 'RMA Claim (Product Return Management)',
|
||||
'version': '8.0.1.1.0',
|
||||
'version': '9.0.1.0.0',
|
||||
'category': 'Generic Modules/CRM & SRM',
|
||||
'description': """
|
||||
Management of Return Merchandise Authorization (RMA)
|
||||
====================================================
|
||||
|
||||
This module aims to improve the Claims by adding a way to manage the
|
||||
product returns. It allows you to create and manage picking from a
|
||||
claim. It also introduces a new object: the claim lines to better
|
||||
handle that problematic. One Claim can have several lines that
|
||||
concern the return of differents products. It's for every of them
|
||||
that you'll be able to check the warranty (still running or not).
|
||||
|
||||
It mainly contains the following features:
|
||||
|
||||
* product returns (one by one, mass return by invoice)
|
||||
* warranty control & return address (based on invoice date and product form)
|
||||
* product picking in / out
|
||||
* product refund
|
||||
* access to related customer data (orders, invoices, refunds, picking
|
||||
in/out) from a claim
|
||||
* use the OpenERP chatter within team like in opportunity (reply to refer to
|
||||
the team, not a person)
|
||||
|
||||
Using this module makes the logistic flow of return this way:
|
||||
|
||||
* Returning product goes into Stock or Supplier location with a incoming
|
||||
shipment (depending on the settings of the supplier info in the
|
||||
product form)
|
||||
* You can make a delivery from the RMA to send a new product to the Customer
|
||||
|
||||
.. warning:: Currently, the warranty duration used is the one configured on the
|
||||
products today, not the one which was configured when the product
|
||||
has been sold.
|
||||
|
||||
Contributors:
|
||||
-------------
|
||||
|
||||
* Emmanuel Samyn <esamyn@gmail.com>
|
||||
* Sébastien Beau <sebastien.beau@akretion.com.br>
|
||||
* Benoît Guillot <benoit.guillot@akretion.com.br>
|
||||
* Joel Grand-Guillaume <joel.grandguillaume@camptocamp.com>
|
||||
* Guewen Baconnier <guewen.baconnier@camptocamp.com>
|
||||
* Yannick Vaucher <yannick.vaucher@camptocamp.com>
|
||||
* Javier Carrasco <javier.carrasco@eezee-it.com>
|
||||
|
||||
""",
|
||||
'author': "Akretion, Camptocamp, Eezee-it, MONK Software, "
|
||||
'author': "Akretion, Camptocamp, Eezee-it, MONK Software, Vauxoo, "
|
||||
"Odoo Community Association (OCA)",
|
||||
'website': 'http://www.akretion.com, http://www.camptocamp.com, '
|
||||
'http://www.eezee-it.com, http://www.wearemonk.com',
|
||||
'http://www.eezee-it.com, http://www.wearemonk.com, '
|
||||
'http://www.vauxoo.com',
|
||||
'license': 'AGPL-3',
|
||||
'depends': [
|
||||
'purchase',
|
||||
'sale',
|
||||
'sales_team',
|
||||
'stock',
|
||||
'crm_claim',
|
||||
'crm_claim_code',
|
||||
'crm_claim_type',
|
||||
'crm_claim_rma_code',
|
||||
'crm_rma_location',
|
||||
'product_warranty',
|
||||
],
|
||||
'data': [
|
||||
'wizards/claim_make_picking.xml',
|
||||
'views/crm_claim_rma.xml',
|
||||
'data/ir_sequence_type.xml',
|
||||
'data/crm_team.xml',
|
||||
'data/crm_claim_category.xml',
|
||||
'views/account_invoice.xml',
|
||||
'wizards/claim_make_picking.xml',
|
||||
'views/crm_claim.xml',
|
||||
"views/claim_line.xml",
|
||||
'views/res_partner.xml',
|
||||
'data/crm_claim_rma.xml',
|
||||
'views/stock_view.xml',
|
||||
'security/ir.model.access.csv',
|
||||
],
|
||||
'test': ['test/test_invoice_refund.yml'],
|
||||
'images': [
|
||||
'images/product_return.png',
|
||||
'images/claim.png',
|
||||
'images/return_line.png',
|
||||
'images/exchange.png',
|
||||
'demo': [],
|
||||
'test': [
|
||||
'test/test_invoice_refund.yml'
|
||||
],
|
||||
'installable': False,
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
}
|
||||
|
||||
62
crm_claim_rma/data/crm_claim_category.xml
Normal file
62
crm_claim_rma/data/crm_claim_category.xml
Normal file
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo noupdate="1">
|
||||
<record id="categ_claim10" model="crm.claim.category">
|
||||
<field name="name">No Inventory</field>
|
||||
<field name="team_id" ref="team_after_sales_service"/>
|
||||
</record>
|
||||
|
||||
<record id="categ_claim11" model="crm.claim.category">
|
||||
<field name="name">Customer Return</field>
|
||||
<field name="team_id" ref="team_after_sales_service"/>
|
||||
</record>
|
||||
|
||||
<record id="categ_claim12" model="crm.claim.category">
|
||||
<field name="name">Buyer Cancelled</field>
|
||||
<field name="team_id" ref="team_after_sales_service"/>
|
||||
</record>
|
||||
|
||||
<record id="categ_claim13" model="crm.claim.category">
|
||||
<field name="name">General Adjustement</field>
|
||||
<field name="team_id" ref="team_after_sales_service"/>
|
||||
</record>
|
||||
|
||||
<record id="categ_claim14" model="crm.claim.category">
|
||||
<field name="name">Could Not Ship</field>
|
||||
<field name="team_id" ref="team_after_sales_service"/>
|
||||
</record>
|
||||
|
||||
<record id="categ_claim15" model="crm.claim.category">
|
||||
<field name="name">Different Item</field>
|
||||
<field name="team_id" ref="team_after_sales_service"/>
|
||||
</record>
|
||||
|
||||
<record id="categ_claim16" model="crm.claim.category">
|
||||
<field name="name">Merchandise Not Received</field>
|
||||
<field name="team_id" ref="team_after_sales_service"/>
|
||||
</record>
|
||||
|
||||
<record id="categ_claim17" model="crm.claim.category">
|
||||
<field name="name">Merchandise Not As Described</field>
|
||||
<field name="team_id" ref="team_after_sales_service"/>
|
||||
</record>
|
||||
|
||||
<record id="categ_claim18" model="crm.claim.category">
|
||||
<field name="name">Pricing Error</field>
|
||||
<field name="team_id" ref="team_after_sales_service"/>
|
||||
</record>
|
||||
|
||||
<record id="categ_claim19" model="crm.claim.category">
|
||||
<field name="name">Shipping Address Undeliverable</field>
|
||||
<field name="team_id" ref="team_after_sales_service"/>
|
||||
</record>
|
||||
|
||||
<record id="categ_claim20" model="crm.claim.category">
|
||||
<field name="name">Delivered Late by Carrier</field>
|
||||
<field name="team_id" ref="team_after_sales_service"/>
|
||||
</record>
|
||||
|
||||
<record id="categ_claim21" model="crm.claim.category">
|
||||
<field name="name">Missed Fulfilment Promise</field>
|
||||
<field name="team_id" ref="team_after_sales_service"/>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -1,103 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
<!-- Claims Sequence n° -->
|
||||
<record id="seq_type_claim" model="ir.sequence.type">
|
||||
<field name="name">CRM Claim</field>
|
||||
<field name="code">crm.claim.rma</field>
|
||||
</record>
|
||||
|
||||
<record id="seq_claim" model="ir.sequence">
|
||||
<field name="name">CRM Claim</field>
|
||||
<field name="code">crm.claim.rma</field>
|
||||
<field eval="5" name="padding"/>
|
||||
<field name="prefix">RMA-%(year)s/</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
Claim sections
|
||||
-->
|
||||
|
||||
<record model="crm.case.section" id="section_after_sales_service">
|
||||
<field name="name">After Sales Service</field>
|
||||
<field name="code">ASV</field>
|
||||
<field name="parent_id" ref="sales_team.section_sales_department"/>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
Claim categories
|
||||
-->
|
||||
|
||||
<record model="crm.case.categ" id="categ_claim10">
|
||||
<field name="name">No Inventory</field>
|
||||
<field name="section_id" ref="section_after_sales_service"/>
|
||||
<field name="object_id" search="[('model','=','crm.claim')]" model="ir.model"/>
|
||||
</record>
|
||||
|
||||
<record model="crm.case.categ" id="categ_claim11">
|
||||
<field name="name">Customer Return</field>
|
||||
<field name="section_id" ref="section_after_sales_service"/>
|
||||
<field name="object_id" search="[('model','=','crm.claim')]" model="ir.model"/>
|
||||
</record>
|
||||
|
||||
<record model="crm.case.categ" id="categ_claim12">
|
||||
<field name="name">Buyer Cancelled</field>
|
||||
<field name="section_id" ref="section_after_sales_service"/>
|
||||
<field name="object_id" search="[('model','=','crm.claim')]" model="ir.model"/>
|
||||
</record>
|
||||
|
||||
<record model="crm.case.categ" id="categ_claim13">
|
||||
<field name="name">General Adjustement</field>
|
||||
<field name="section_id" ref="section_after_sales_service"/>
|
||||
<field name="object_id" search="[('model','=','crm.claim')]" model="ir.model"/>
|
||||
</record>
|
||||
|
||||
<record model="crm.case.categ" id="categ_claim14">
|
||||
<field name="name">Could Not Ship</field>
|
||||
<field name="section_id" ref="section_after_sales_service"/>
|
||||
<field name="object_id" search="[('model','=','crm.claim')]" model="ir.model"/>
|
||||
</record>
|
||||
|
||||
<record model="crm.case.categ" id="categ_claim15">
|
||||
<field name="name">Different Item</field>
|
||||
<field name="section_id" ref="section_after_sales_service"/>
|
||||
<field name="object_id" search="[('model','=','crm.claim')]" model="ir.model"/>
|
||||
</record>
|
||||
|
||||
<record model="crm.case.categ" id="categ_claim16">
|
||||
<field name="name">Merchandise Not Received</field>
|
||||
<field name="section_id" ref="section_after_sales_service"/>
|
||||
<field name="object_id" search="[('model','=','crm.claim')]" model="ir.model"/>
|
||||
</record>
|
||||
|
||||
<record model="crm.case.categ" id="categ_claim17">
|
||||
<field name="name">Merchandise Not As Described</field>
|
||||
<field name="section_id" ref="section_after_sales_service"/>
|
||||
<field name="object_id" search="[('model','=','crm.claim')]" model="ir.model"/>
|
||||
</record>
|
||||
|
||||
<record model="crm.case.categ" id="categ_claim18">
|
||||
<field name="name">Pricing Error</field>
|
||||
<field name="section_id" ref="section_after_sales_service"/>
|
||||
<field name="object_id" search="[('model','=','crm.claim')]" model="ir.model"/>
|
||||
</record>
|
||||
|
||||
<record model="crm.case.categ" id="categ_claim19">
|
||||
<field name="name">Shipping Address Undeliverable</field>
|
||||
<field name="section_id" ref="section_after_sales_service"/>
|
||||
<field name="object_id" search="[('model','=','crm.claim')]" model="ir.model"/>
|
||||
</record>
|
||||
|
||||
<record model="crm.case.categ" id="categ_claim20">
|
||||
<field name="name">Delivered Late by Carrier</field>
|
||||
<field name="section_id" ref="section_after_sales_service"/>
|
||||
<field name="object_id" search="[('model','=','crm.claim')]" model="ir.model"/>
|
||||
</record>
|
||||
|
||||
<record model="crm.case.categ" id="categ_claim21">
|
||||
<field name="name">Missed Fulfilment Promise</field>
|
||||
<field name="section_id" ref="section_after_sales_service"/>
|
||||
<field name="object_id" search="[('model','=','crm.claim')]" model="ir.model"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
7
crm_claim_rma/data/crm_team.xml
Normal file
7
crm_claim_rma/data/crm_team.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo noupdate="1">
|
||||
<record id="team_after_sales_service" model="crm.team">
|
||||
<field name="name">After Sales Service</field>
|
||||
<field name="code">ASV</field>
|
||||
</record>
|
||||
</odoo>
|
||||
9
crm_claim_rma/data/ir_sequence_type.xml
Normal file
9
crm_claim_rma/data/ir_sequence_type.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo noupdate="1">
|
||||
<record id="seq_claim" model="ir.sequence">
|
||||
<field name="name">CRM Claim</field>
|
||||
<field name="code">crm.claim.rma</field>
|
||||
<field eval="5" name="padding"/>
|
||||
<field name="prefix">RMA-%(year)s/</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -75,7 +75,7 @@ msgid "Company"
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_claim_rma
|
||||
#: selection:claim.line,claim_origine:0
|
||||
#: selection:claim.line,claim_origin:0
|
||||
msgid "Order cancellation"
|
||||
msgstr ""
|
||||
|
||||
@@ -130,7 +130,7 @@ msgstr ""
|
||||
|
||||
#. module: crm_claim_rma
|
||||
#: view:claim.line:0
|
||||
msgid "Compute Waranty"
|
||||
msgid "Compute Warranty"
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_claim_rma
|
||||
@@ -211,7 +211,7 @@ msgid "To set the last state / substate change"
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_claim_rma
|
||||
#: selection:claim.line,claim_origine:0
|
||||
#: selection:claim.line,claim_origin:0
|
||||
msgid "Not specified"
|
||||
msgstr ""
|
||||
|
||||
@@ -252,7 +252,7 @@ msgid "Warehouse"
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_claim_rma
|
||||
#: help:claim.line,claim_origine:0
|
||||
#: help:claim.line,claim_origin:0
|
||||
msgid "To describe the line product problem"
|
||||
msgstr ""
|
||||
|
||||
@@ -267,7 +267,7 @@ msgid "More"
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_claim_rma
|
||||
#: selection:claim.line,claim_origine:0
|
||||
#: selection:claim.line,claim_origin:0
|
||||
msgid "Legal retractation"
|
||||
msgstr ""
|
||||
|
||||
@@ -286,8 +286,8 @@ msgid "The warranty limit is computed as: invoice date + warranty defined on sel
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_claim_rma
|
||||
#: field:claim.line,claim_origine:0
|
||||
#: model:ir.model.fields,field_description:crm_claim_rma.field_claim_line_claim_origine
|
||||
#: field:claim.line,claim_origin:0
|
||||
#: model:ir.model.fields,field_description:crm_claim_rma.field_claim_line_claim_origin
|
||||
msgid "Claim Subject"
|
||||
msgstr ""
|
||||
|
||||
@@ -366,12 +366,12 @@ msgid "Quotations and Sales"
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_claim_rma
|
||||
#: selection:claim.line,claim_origine:0
|
||||
#: selection:claim.line,claim_origin:0
|
||||
msgid "Lost during transport"
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_claim_rma
|
||||
#: selection:claim.line,claim_origine:0
|
||||
#: selection:claim.line,claim_origin:0
|
||||
msgid "Shipping error"
|
||||
msgstr ""
|
||||
|
||||
@@ -563,13 +563,19 @@ msgid "Unit sale price of the product. Auto filled if retrun done by invoice sel
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_claim_rma
|
||||
#: code:addons/crm_claim_rma/crm_claim_rma.py:313
|
||||
#: code:addons/crm_claim_rma/crm_claim_rma.py:473
|
||||
#, python-format
|
||||
msgid "Please set product and invoice."
|
||||
msgid "Please set invoice first"
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_claim_rma
|
||||
#: selection:claim.line,claim_origine:0
|
||||
#: code:addons/crm_claim_rma/crm_claim_rma.py:470
|
||||
#, python-format
|
||||
msgid "Please set product first"
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_claim_rma
|
||||
#: selection:claim.line,claim_origin:0
|
||||
msgid "Damaged delivered product"
|
||||
msgstr ""
|
||||
|
||||
@@ -691,7 +697,7 @@ msgid "Merchandise Not As Described"
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_claim_rma
|
||||
#: selection:claim.line,claim_origine:0
|
||||
#: selection:claim.line,claim_origin:0
|
||||
msgid "Exchange request"
|
||||
msgstr ""
|
||||
|
||||
@@ -717,7 +723,7 @@ msgid "Current"
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_claim_rma
|
||||
#: selection:claim.line,claim_origine:0
|
||||
#: selection:claim.line,claim_origin:0
|
||||
#: selection:crm.claim,claim_type:0
|
||||
msgid "Other"
|
||||
msgstr ""
|
||||
@@ -889,3 +895,17 @@ msgstr ""
|
||||
msgid "The product has no supplier configured."
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_claim_rma
|
||||
#: help:claim.line,number:0
|
||||
msgid "Claim Line Identification Number"
|
||||
msgstr "Número de idetifiación de la línea de reclamo"
|
||||
|
||||
#. module: crm_claim_rma
|
||||
#: field:crm.claim,rma_number:0
|
||||
msgid "RMA Number"
|
||||
msgstr "Número RMA"
|
||||
|
||||
#. module: crm_claim_rma
|
||||
#: help:crm.claim,rma_number:0
|
||||
msgid "RMA Number provided by supplier"
|
||||
msgstr "Número RMA asignado por el proveedor"
|
||||
|
||||
1050
crm_claim_rma/i18n/de.po
Normal file
1050
crm_claim_rma/i18n/de.po
Normal file
File diff suppressed because it is too large
Load Diff
1049
crm_claim_rma/i18n/en.po
Normal file
1049
crm_claim_rma/i18n/en.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
16
crm_claim_rma/i18n/es_MX.po
Normal file
16
crm_claim_rma/i18n/es_MX.po
Normal file
@@ -0,0 +1,16 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * crm_claim_rma
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 8.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-07-17 18:30+0000\n"
|
||||
"PO-Revision-Date: 2015-07-17 18:30+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
16
crm_claim_rma/i18n/es_PA.po
Normal file
16
crm_claim_rma/i18n/es_PA.po
Normal file
@@ -0,0 +1,16 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * crm_claim_rma
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 8.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-07-17 18:30+0000\n"
|
||||
"PO-Revision-Date: 2015-07-17 18:30+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
16
crm_claim_rma/i18n/es_VE.po
Normal file
16
crm_claim_rma/i18n/es_VE.po
Normal file
@@ -0,0 +1,16 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * crm_claim_rma
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 8.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-07-17 18:30+0000\n"
|
||||
"PO-Revision-Date: 2015-07-17 18:30+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1049
crm_claim_rma/i18n/ro.po
Normal file
1049
crm_claim_rma/i18n/ro.po
Normal file
File diff suppressed because it is too large
Load Diff
1050
crm_claim_rma/i18n/sl.po
Normal file
1050
crm_claim_rma/i18n/sl.po
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,12 @@
|
||||
from . import crm_claim_rma
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import account_invoice
|
||||
from . import stock
|
||||
from . import account_invoice_line
|
||||
from . import claim_line
|
||||
from . import crm_claim
|
||||
from . import invoice_no_date
|
||||
from . import product_no_supplier
|
||||
from . import procurement_group
|
||||
from . import stock_move
|
||||
from . import stock_picking
|
||||
from . import substate_substate
|
||||
|
||||
@@ -1,42 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright 2015 Eezee-It, MONK Software
|
||||
# Copyright 2013 Camptocamp
|
||||
# Copyright 2009-2013 Akretion,
|
||||
# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau,
|
||||
# Benoît Guillot, Joel Grand-Guillaume, Leonardo Donelli
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# © 2015 Eezee-It, MONK Software, Vauxoo
|
||||
# © 2013 Camptocamp
|
||||
# © 2009-2013 Akretion,
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api, exceptions
|
||||
from openerp.tools.translate import _
|
||||
from openerp import _, api, exceptions, fields, models
|
||||
|
||||
|
||||
class AccountInvoice(models.Model):
|
||||
|
||||
_inherit = "account.invoice"
|
||||
|
||||
claim_id = fields.Many2one('crm.claim', string='Claim')
|
||||
|
||||
@api.model
|
||||
def _refund_cleanup_lines(self, lines):
|
||||
"""
|
||||
Override when from claim to update the quantity and link to the
|
||||
""" Override when from claim to update the quantity and link to the
|
||||
claim line.
|
||||
"""
|
||||
|
||||
# check if is an invoice_line and we are from a claim
|
||||
if not (self.env.context.get('claim_line_ids') and lines and
|
||||
lines[0]._name == 'account.invoice.line'):
|
||||
@@ -59,44 +40,27 @@ class AccountInvoice(models.Model):
|
||||
elif column_type not in ('many2many', 'one2many'):
|
||||
clean_line[field_name] = inv_line[field_name]
|
||||
elif field_name == 'invoice_line_tax_id':
|
||||
|
||||
tax_ids = inv_line[field_name].ids
|
||||
clean_line[field_name] = [(6, 0, tax_ids)]
|
||||
clean_line['quantity'] = claim_line.product_returned_quantity
|
||||
clean_line['claim_line_id'] = [claim_line.id]
|
||||
|
||||
new_lines.append(clean_line)
|
||||
if not new_lines:
|
||||
# TODO use custom states to show button of this wizard or
|
||||
# not instead of raise an error
|
||||
raise exceptions.Warning(
|
||||
_('A refund has already been created for this claim !'))
|
||||
|
||||
raise exceptions.UserError(
|
||||
_('A refund has already been created for this claim !')
|
||||
)
|
||||
return [(0, 0, l) for l in new_lines]
|
||||
|
||||
@api.model
|
||||
def _prepare_refund(self, invoice, date=None, period_id=None,
|
||||
description=None, journal_id=None):
|
||||
result = super(AccountInvoice, self)._prepare_refund(
|
||||
invoice, date=date, period_id=period_id, description=description,
|
||||
journal_id=journal_id)
|
||||
def _prepare_refund(self, *args, **kwargs):
|
||||
result = super(AccountInvoice, self)._prepare_refund(*args, **kwargs)
|
||||
|
||||
if self.env.context.get('claim_id'):
|
||||
result['claim_id'] = self.env.context['claim_id']
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class AccountInvoiceLine(models.Model):
|
||||
_inherit = "account.invoice.line"
|
||||
|
||||
@api.model
|
||||
@api.returns('self', lambda value: value.id)
|
||||
def create(self, vals):
|
||||
claim_line_id = vals.get('claim_line_id')
|
||||
if claim_line_id:
|
||||
del vals['claim_line_id']
|
||||
|
||||
line = super(AccountInvoiceLine, self).create(vals)
|
||||
if claim_line_id:
|
||||
claim_line = self.env['claim.line'].browse(claim_line_id)
|
||||
claim_line.refund_line_id = line.id
|
||||
|
||||
return line
|
||||
|
||||
25
crm_claim_rma/models/account_invoice_line.py
Normal file
25
crm_claim_rma/models/account_invoice_line.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Vauxoo
|
||||
# © 2013 Camptocamp
|
||||
# © 2009-2013 Akretion,
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import api, models
|
||||
|
||||
|
||||
class AccountInvoiceLine(models.Model):
|
||||
|
||||
_inherit = "account.invoice.line"
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
claim_line_id = vals.get('claim_line_id')
|
||||
if claim_line_id:
|
||||
del vals['claim_line_id']
|
||||
|
||||
line = super(AccountInvoiceLine, self).create(vals)
|
||||
if claim_line_id:
|
||||
claim_line = self.env['claim.line'].browse(claim_line_id)
|
||||
claim_line.refund_line_id = line.id
|
||||
|
||||
return line
|
||||
408
crm_claim_rma/models/claim_line.py
Normal file
408
crm_claim_rma/models/claim_line.py
Normal file
@@ -0,0 +1,408 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Vauxoo
|
||||
# © 2013 Camptocamp
|
||||
# © 2009-2013 Akretion,
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import calendar
|
||||
import math
|
||||
from datetime import datetime
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from openerp import _, api, exceptions, fields, models
|
||||
from openerp.tools import (DEFAULT_SERVER_DATE_FORMAT,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
|
||||
from .invoice_no_date import InvoiceNoDate
|
||||
from .product_no_supplier import ProductNoSupplier
|
||||
|
||||
|
||||
class ClaimLine(models.Model):
|
||||
|
||||
_name = "claim.line"
|
||||
|
||||
_inherit = 'mail.thread'
|
||||
_description = "List of product to return"
|
||||
_rec_name = "display_name"
|
||||
|
||||
SUBJECT_LIST = [('none', 'Not specified'),
|
||||
('legal', 'Legal retractation'),
|
||||
('cancellation', 'Order cancellation'),
|
||||
('damaged', 'Damaged delivered product'),
|
||||
('error', 'Shipping error'),
|
||||
('exchange', 'Exchange request'),
|
||||
('lost', 'Lost during transport'),
|
||||
('perfect_conditions',
|
||||
'Perfect Conditions'),
|
||||
('imperfection', 'Imperfection'),
|
||||
('physical_damage_client',
|
||||
'Physical Damage by Client'),
|
||||
('physical_damage_company',
|
||||
'Physical Damage by Company'),
|
||||
('other', 'Other')]
|
||||
WARRANT_COMMENT = [
|
||||
('valid', _("Valid")),
|
||||
('expired', _("Expired")),
|
||||
('not_define', _("Not Defined"))]
|
||||
|
||||
number = fields.Char(
|
||||
readonly=True,
|
||||
default='/',
|
||||
help='Claim Line Identification Number')
|
||||
company_id = fields.Many2one(
|
||||
'res.company', string='Company', readonly=False,
|
||||
change_default=True,
|
||||
default=lambda self: self.env['res.company']._company_default_get(
|
||||
'claim.line'))
|
||||
date = fields.Date('Claim Line Date',
|
||||
select=True,
|
||||
default=fields.date.today())
|
||||
name = fields.Char('Description', default='none', required=True,
|
||||
help="More precise description of the problem")
|
||||
priority = fields.Selection([('0_not_define', 'Not Define'),
|
||||
('1_normal', 'Normal'),
|
||||
('2_high', 'High'),
|
||||
('3_very_high', 'Very High')],
|
||||
'Priority', default='0_not_define',
|
||||
compute='_compute_priority',
|
||||
store=True,
|
||||
readonly=False,
|
||||
help="Priority attention of claim line")
|
||||
claim_diagnosis = fields.\
|
||||
Selection([('damaged', 'Product Damaged'),
|
||||
('repaired', 'Product Repaired'),
|
||||
('good', 'Product in good condition'),
|
||||
('hidden', 'Product with hidden physical damage'),
|
||||
],
|
||||
help="To describe the line product diagnosis")
|
||||
claim_origin = fields.Selection(SUBJECT_LIST, 'Claim Subject',
|
||||
required=True, help="To describe the "
|
||||
"line product problem")
|
||||
product_id = fields.Many2one('product.product', string='Product',
|
||||
help="Returned product")
|
||||
product_returned_quantity = \
|
||||
fields.Float('Quantity', digits=(12, 2),
|
||||
help="Quantity of product returned")
|
||||
unit_sale_price = fields.Float(digits=(12, 2),
|
||||
help="Unit sale price of the product. "
|
||||
"Auto filled if retrun done "
|
||||
"by invoice selection. Be careful "
|
||||
"and check the automatic "
|
||||
"value as don't take into account "
|
||||
"previous refunds, invoice "
|
||||
"discount, can be for 0 if product "
|
||||
"for free,...")
|
||||
return_value = fields.Float(compute='_compute_line_total_amount',
|
||||
string='Total return',
|
||||
help="Quantity returned * Unit sold price",)
|
||||
prodlot_id = fields.Many2one('stock.production.lot',
|
||||
string='Serial/Lot number',
|
||||
help="The serial/lot of "
|
||||
"the returned product")
|
||||
applicable_guarantee = fields.Selection([('us', 'Company'),
|
||||
('supplier', 'Supplier'),
|
||||
('brand', 'Brand manufacturer')],
|
||||
'Warranty type')
|
||||
guarantee_limit = fields.Date('Warranty limit', readonly=True,
|
||||
help="The warranty limit is "
|
||||
"computed as: invoice date + warranty "
|
||||
"defined on selected product.")
|
||||
warning = fields.Selection(WARRANT_COMMENT,
|
||||
'Warranty', readonly=True,
|
||||
help="If warranty has expired")
|
||||
display_name = fields.Char('Name', compute='_get_display_name')
|
||||
|
||||
@api.model
|
||||
def get_warranty_return_partner(self):
|
||||
return self.env['product.supplierinfo']._columns[
|
||||
'warranty_return_partner'
|
||||
].selection
|
||||
|
||||
warranty_type = fields.Selection(
|
||||
get_warranty_return_partner, readonly=True,
|
||||
help="Who is in charge of the warranty return treatment towards "
|
||||
"the end customer. Company will use the current company "
|
||||
"delivery or default address and so on for supplier and brand "
|
||||
"manufacturer. Does not necessarily mean that the warranty "
|
||||
"to be applied is the one of the return partner (ie: can be "
|
||||
"returned to the company and be under the brand warranty")
|
||||
warranty_return_partner = \
|
||||
fields.Many2one('res.partner', string='Warranty Address',
|
||||
help="Where the customer has to "
|
||||
"send back the product(s)")
|
||||
claim_id = fields.Many2one('crm.claim', string='Related claim',
|
||||
ondelete='cascade',
|
||||
help="To link to the case.claim object")
|
||||
state = fields.Selection([('draft', 'Draft'), ('refused', 'Refused'),
|
||||
('confirmed', 'Confirmed, waiting for product'),
|
||||
('in_to_control', 'Received, to control'),
|
||||
('in_to_treate', 'Controlled, to treate'),
|
||||
('treated', 'Treated')],
|
||||
string='State', default='draft')
|
||||
substate_id = fields.Many2one('substate.substate', string='Sub state',
|
||||
help="Select a sub state to precise the "
|
||||
"standard state. Example 1: "
|
||||
"state = refused; substate could "
|
||||
"be warranty over, not in "
|
||||
"warranty, no problem,... . "
|
||||
"Example 2: state = to treate; "
|
||||
"substate could be to refund, to "
|
||||
"exchange, to repair,...")
|
||||
last_state_change = fields.Date(string='Last change', help="To set the"
|
||||
"last state / substate change")
|
||||
invoice_line_id = fields.Many2one('account.invoice.line',
|
||||
string='Invoice Line',
|
||||
help='The invoice line related'
|
||||
' to the returned product')
|
||||
refund_line_id = fields.Many2one('account.invoice.line',
|
||||
string='Refund Line',
|
||||
help='The refund line related'
|
||||
' to the returned product')
|
||||
move_in_id = fields.Many2one('stock.move',
|
||||
string='Move Line from picking in',
|
||||
help='The move line related'
|
||||
' to the returned product')
|
||||
move_out_id = fields.Many2one('stock.move',
|
||||
string='Move Line from picking out',
|
||||
help='The move line related'
|
||||
' to the returned product')
|
||||
location_dest_id = fields.Many2one('stock.location',
|
||||
string='Return Stock Location',
|
||||
help='The return stock location'
|
||||
' of the returned product')
|
||||
claim_type = fields.Many2one(related='claim_id.claim_type',
|
||||
string="Claim Line Type",
|
||||
store=True, help="Claim classification")
|
||||
invoice_date = fields.Datetime(related='invoice_line_id.invoice_id.'
|
||||
'create_date',
|
||||
help="Date of Claim Invoice")
|
||||
|
||||
# Method to calculate total amount of the line : qty*UP
|
||||
@api.multi
|
||||
def _compute_line_total_amount(self):
|
||||
for line in self:
|
||||
line.return_value = (line.unit_sale_price *
|
||||
line.product_returned_quantity)
|
||||
|
||||
@api.multi
|
||||
def copy(self, default=None):
|
||||
self.ensure_one()
|
||||
default = default or {}
|
||||
std_default = {
|
||||
'move_in_id': False,
|
||||
'move_out_id': False,
|
||||
'refund_line_id': False,
|
||||
}
|
||||
std_default.update(default)
|
||||
return super(ClaimLine, self).copy(default=std_default)
|
||||
|
||||
@api.depends('invoice_date', 'date')
|
||||
def _compute_priority(self):
|
||||
"""
|
||||
To determine the priority of claim line
|
||||
"""
|
||||
for line_id in self:
|
||||
if line_id.invoice_date:
|
||||
days = fields.datetime.strptime(line_id.date, '%Y-%m-%d') - \
|
||||
fields.datetime.strptime(line_id.invoice_date,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
if days.days <= 1:
|
||||
line_id.priority = '3_very_high'
|
||||
elif days.days <= 7:
|
||||
line_id.priority = '2_high'
|
||||
else:
|
||||
line_id.priority = '1_normal'
|
||||
|
||||
def _get_subject(self, num):
|
||||
if num > 0 and num <= len(self.SUBJECT_LIST):
|
||||
return self.SUBJECT_LIST[num - 1][0]
|
||||
else:
|
||||
return self.SUBJECT_LIST[0][0]
|
||||
|
||||
@staticmethod
|
||||
def warranty_limit(start, warranty_duration):
|
||||
""" Take a duration in float, return the duration in relativedelta
|
||||
|
||||
``relative_delta(months=...)`` only accepts integers.
|
||||
We have to extract the decimal part, and then, extend the delta with
|
||||
days.
|
||||
|
||||
"""
|
||||
decimal_part, months = math.modf(warranty_duration)
|
||||
months = int(months)
|
||||
# If we have a decimal part, we add the number them as days to
|
||||
# the limit. We need to get the month to know the number of
|
||||
# days.
|
||||
delta = relativedelta(months=months)
|
||||
monthday = start + delta
|
||||
__, days_month = calendar.monthrange(monthday.year, monthday.month)
|
||||
# ignore the rest of the days (hours) since we expect a date
|
||||
days = int(days_month * decimal_part)
|
||||
return start + relativedelta(months=months, days=days)
|
||||
|
||||
def _warranty_limit_values(self, invoice, claim_type, product, claim_date):
|
||||
if not (invoice and claim_type and product and claim_date):
|
||||
return {'guarantee_limit': False, 'warning': False}
|
||||
|
||||
invoice_date = invoice.create_date
|
||||
if not invoice_date:
|
||||
raise InvoiceNoDate
|
||||
|
||||
warning = 'not_define'
|
||||
invoice_date = datetime.strptime(invoice_date,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
|
||||
if isinstance(claim_type, self.env['crm.claim.type'].__class__):
|
||||
claim_type = claim_type.id
|
||||
|
||||
if claim_type == self.env.ref('crm_claim_type.'
|
||||
'crm_claim_type_supplier').id:
|
||||
try:
|
||||
warranty_duration = product.seller_ids[0].warranty_duration
|
||||
except IndexError:
|
||||
raise ProductNoSupplier
|
||||
else:
|
||||
warranty_duration = product.warranty
|
||||
|
||||
limit = self.warranty_limit(invoice_date, warranty_duration)
|
||||
if warranty_duration > 0:
|
||||
claim_date = datetime.strptime(claim_date,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
if limit < claim_date:
|
||||
warning = 'expired'
|
||||
else:
|
||||
warning = 'valid'
|
||||
|
||||
return {'guarantee_limit': limit.strftime(DEFAULT_SERVER_DATE_FORMAT),
|
||||
'warning': warning}
|
||||
|
||||
def set_warranty_limit(self):
|
||||
self.ensure_one()
|
||||
|
||||
claim = self.claim_id
|
||||
invoice_id = self.invoice_line_id and self.invoice_line_id.invoice_id \
|
||||
or claim.invoice_id
|
||||
try:
|
||||
values = self._warranty_limit_values(
|
||||
invoice_id, claim.claim_type,
|
||||
self.product_id, claim.date)
|
||||
except InvoiceNoDate:
|
||||
raise exceptions.UserError(
|
||||
_('Cannot find any date for invoice. '
|
||||
'Must be a validated invoice.')
|
||||
)
|
||||
except ProductNoSupplier:
|
||||
raise exceptions.UserError(
|
||||
_('The product has no supplier configured.')
|
||||
)
|
||||
|
||||
self.write(values)
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def auto_set_warranty(self):
|
||||
""" Set warranty automatically
|
||||
if the user has not himself pressed on 'Calculate warranty state'
|
||||
button, it sets warranty for him"""
|
||||
for line in self:
|
||||
if not line.warning:
|
||||
line.set_warranty()
|
||||
return True
|
||||
|
||||
@api.returns('stock.location')
|
||||
def get_destination_location(self, product_id, warehouse_id):
|
||||
""" Compute and return the destination location to take
|
||||
for a return. Always take 'Supplier' one when return type different
|
||||
from company.
|
||||
"""
|
||||
location_dest_id = warehouse_id.lot_stock_id
|
||||
|
||||
if product_id.seller_ids:
|
||||
seller = product_id.seller_ids[0]
|
||||
if seller.warranty_return_partner != 'company' \
|
||||
and seller.name and \
|
||||
seller.name.property_stock_supplier:
|
||||
location_dest_id = seller.name.property_stock_supplier
|
||||
|
||||
return location_dest_id
|
||||
|
||||
def _warranty_return_address_values(self, product, company, warehouse):
|
||||
""" Return the partner to be used as return destination and
|
||||
the destination stock location of the line in case of return.
|
||||
|
||||
We can have various cases here:
|
||||
- company or other: return to company partner or
|
||||
crm_return_address_id if specified
|
||||
- supplier: return to the supplier address
|
||||
"""
|
||||
if not (product and company and warehouse):
|
||||
return {
|
||||
'warranty_return_partner': False,
|
||||
'warranty_type': False,
|
||||
'location_dest_id': False
|
||||
}
|
||||
sellers = product.seller_ids
|
||||
if sellers:
|
||||
seller = sellers[0]
|
||||
return_address_id = seller.warranty_return_address.id
|
||||
return_type = seller.warranty_return_partner
|
||||
else:
|
||||
# when no supplier is configured, returns to the company
|
||||
return_address = (company.crm_return_address_id or
|
||||
company.partner_id)
|
||||
return_address_id = return_address.id
|
||||
return_type = 'company'
|
||||
location_dest = self.get_destination_location(product, warehouse)
|
||||
return {
|
||||
'warranty_return_partner': return_address_id,
|
||||
'warranty_type': return_type,
|
||||
'location_dest_id': location_dest.id
|
||||
}
|
||||
|
||||
def set_warranty_return_address(self):
|
||||
self.ensure_one()
|
||||
claim = self.claim_id
|
||||
values = self._warranty_return_address_values(
|
||||
self.product_id, claim.company_id, claim.warehouse_id)
|
||||
self.write(values)
|
||||
return True
|
||||
|
||||
@api.multi
|
||||
def set_warranty(self):
|
||||
""" Calculate warranty limit and address
|
||||
"""
|
||||
for line_id in self:
|
||||
if not line_id.product_id:
|
||||
raise exceptions.UserError(_('Please set product first'))
|
||||
|
||||
if not line_id.invoice_line_id:
|
||||
raise exceptions.UserError(_('Please set invoice first'))
|
||||
|
||||
line_id.set_warranty_limit()
|
||||
line_id.set_warranty_return_address()
|
||||
|
||||
@api.model
|
||||
def _get_sequence_number(self):
|
||||
""" Return the value of the sequence for the number field in the
|
||||
claim.line model.
|
||||
"""
|
||||
return self.env['ir.sequence'].next_by_code('claim.line')
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
"""Return write the identify number once the claim line is create.
|
||||
"""
|
||||
vals = vals or {}
|
||||
|
||||
if ('number' not in vals) or (vals.get('number', False) == '/'):
|
||||
vals['number'] = self._get_sequence_number()
|
||||
|
||||
res = super(ClaimLine, self).create(vals)
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
def _get_display_name(self):
|
||||
for line_id in self:
|
||||
line_id.display_name = "%s - %s" % (
|
||||
line_id.claim_id.code, line_id.name)
|
||||
217
crm_claim_rma/models/crm_claim.py
Normal file
217
crm_claim_rma/models/crm_claim.py
Normal file
@@ -0,0 +1,217 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Eezee-It, MONK Software, Vauxoo
|
||||
# © 2013 Camptocamp
|
||||
# © 2009-2013 Akretion,
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import _, api, exceptions, fields, models
|
||||
|
||||
from .invoice_no_date import InvoiceNoDate
|
||||
from .product_no_supplier import ProductNoSupplier
|
||||
|
||||
|
||||
class CrmClaim(models.Model):
|
||||
_inherit = 'crm.claim'
|
||||
|
||||
def _get_default_warehouse(self):
|
||||
company_id = self.env.user.company_id.id
|
||||
wh_obj = self.env['stock.warehouse']
|
||||
wh = wh_obj.search([('company_id', '=', company_id)], limit=1)
|
||||
if not wh:
|
||||
raise exceptions.UserError(
|
||||
_('There is no warehouse for the current user\'s company.')
|
||||
)
|
||||
return wh
|
||||
|
||||
def _get_picking_ids(self):
|
||||
""" Search all stock_picking associated with this claim.
|
||||
|
||||
Either directly with claim_id in stock_picking or through a
|
||||
procurement_group.
|
||||
"""
|
||||
picking_model = self.env['stock.picking']
|
||||
for claim in self:
|
||||
claim.picking_ids = picking_model.search([
|
||||
'|',
|
||||
('claim_id', '=', claim.id),
|
||||
('group_id.claim_id', '=', claim.id)
|
||||
])
|
||||
|
||||
@api.multi
|
||||
def name_get(self):
|
||||
res = []
|
||||
for claim in self:
|
||||
code = claim.code and str(claim.code) or ''
|
||||
res.append((claim.id, '[' + code + '] ' + claim.name))
|
||||
return res
|
||||
|
||||
company_id = fields.Many2one(change_default=True,
|
||||
default=lambda self:
|
||||
self.env['res.company']._company_default_get(
|
||||
'crm.claim'))
|
||||
|
||||
claim_line_ids = fields.One2many('claim.line', 'claim_id',
|
||||
string='Return lines')
|
||||
planned_revenue = fields.Float('Expected revenue')
|
||||
planned_cost = fields.Float('Expected cost')
|
||||
real_revenue = fields.Float()
|
||||
real_cost = fields.Float()
|
||||
invoice_ids = fields.One2many('account.invoice', 'claim_id', 'Refunds',
|
||||
copy=False)
|
||||
picking_ids = fields.One2many('stock.picking',
|
||||
compute=_get_picking_ids,
|
||||
string='RMA',
|
||||
copy=False)
|
||||
invoice_id = fields.Many2one('account.invoice', string='Invoice',
|
||||
help='Related original Cusotmer invoice')
|
||||
pick = fields.Boolean('Pick the product in the store')
|
||||
delivery_address_id = fields.Many2one('res.partner',
|
||||
string='Partner delivery address',
|
||||
help="This address will be used to "
|
||||
"deliver repaired or replacement "
|
||||
"products.")
|
||||
sequence = fields.Integer(default=lambda *args: 1)
|
||||
warehouse_id = fields.Many2one('stock.warehouse', string='Warehouse',
|
||||
required=True,
|
||||
default=_get_default_warehouse)
|
||||
rma_number = fields.Char(size=128, help='RMA Number provided by supplier')
|
||||
|
||||
@api.model
|
||||
def _get_claim_type_default(self):
|
||||
return self.env.ref('crm_claim_type.crm_claim_type_customer')
|
||||
|
||||
claim_type = \
|
||||
fields.Many2one(default=_get_claim_type_default,
|
||||
help="Claim classification",
|
||||
required=True)
|
||||
|
||||
@api.onchange('invoice_id', 'warehouse_id', 'claim_type', 'date')
|
||||
def _onchange_invoice_warehouse_type_date(self):
|
||||
context = self.env.context
|
||||
claim_line = self.env['claim.line']
|
||||
if not self.warehouse_id:
|
||||
self.warehouse_id = self._get_default_warehouse()
|
||||
claim_type = self.claim_type
|
||||
claim_date = self.date
|
||||
warehouse = self.warehouse_id
|
||||
company = self.company_id
|
||||
create_lines = context.get('create_lines')
|
||||
|
||||
def warranty_values(invoice, product):
|
||||
values = {}
|
||||
try:
|
||||
warranty = claim_line._warranty_limit_values(
|
||||
invoice, claim_type, product, claim_date)
|
||||
except (InvoiceNoDate, ProductNoSupplier):
|
||||
# we don't mind at this point if the warranty can't be
|
||||
# computed and we don't want to block the user
|
||||
values.update({'guarantee_limit': False, 'warning': False})
|
||||
else:
|
||||
values.update(warranty)
|
||||
|
||||
warranty_address = claim_line._warranty_return_address_values(
|
||||
product, company, warehouse)
|
||||
values.update(warranty_address)
|
||||
return values
|
||||
|
||||
if create_lines: # happens when the invoice is changed
|
||||
claim_lines = []
|
||||
invoices_lines = self.invoice_id.invoice_line_ids.filtered(
|
||||
lambda line: line.product_id.type in ('consu', 'product')
|
||||
)
|
||||
for invoice_line in invoices_lines:
|
||||
location_dest = claim_line.get_destination_location(
|
||||
invoice_line.product_id, warehouse)
|
||||
line = {
|
||||
'name': invoice_line.name,
|
||||
'claim_origin': "none",
|
||||
'invoice_line_id': invoice_line.id,
|
||||
'product_id': invoice_line.product_id.id,
|
||||
'product_returned_quantity': invoice_line.quantity,
|
||||
'unit_sale_price': invoice_line.price_unit,
|
||||
'location_dest_id': location_dest.id,
|
||||
'state': 'draft',
|
||||
}
|
||||
line.update(warranty_values(invoice_line.invoice_id,
|
||||
invoice_line.product_id))
|
||||
claim_lines.append((0, 0, line))
|
||||
|
||||
value = self._convert_to_cache(
|
||||
{'claim_line_ids': claim_lines}, validate=False)
|
||||
self.update(value)
|
||||
|
||||
if self.invoice_id:
|
||||
self.delivery_address_id = self.invoice_id.partner_id.id
|
||||
|
||||
@api.model
|
||||
def message_get_reply_to(self, res_ids, default=None):
|
||||
""" Override to get the reply_to of the parent project.
|
||||
"""
|
||||
results = dict.fromkeys(res_ids, default or False)
|
||||
if res_ids:
|
||||
claims = self.browse(res_ids)
|
||||
results.update({
|
||||
claim.id: self.env['crm.team'].message_get_reply_to(
|
||||
[claim.team_id], default
|
||||
)[claim.team_id] for claim in claims if claim.team_id
|
||||
})
|
||||
|
||||
return results
|
||||
|
||||
@api.multi
|
||||
def message_get_suggested_recipients(self):
|
||||
recipients = super(CrmClaim, self).message_get_suggested_recipients()
|
||||
try:
|
||||
for claim in self:
|
||||
if claim.partner_id:
|
||||
claim._message_add_suggested_recipient(
|
||||
recipients,
|
||||
partner=claim.partner_id,
|
||||
reason=_('Customer')
|
||||
)
|
||||
elif claim.email_from:
|
||||
claim._message_add_suggested_recipient(
|
||||
recipients,
|
||||
email=claim.email_from,
|
||||
reason=_('Customer Email')
|
||||
)
|
||||
except exceptions.AccessError:
|
||||
# no read access rights -> just ignore suggested recipients
|
||||
# because this imply modifying followers
|
||||
pass
|
||||
return recipients
|
||||
|
||||
def _get_sequence_number(self, code_id):
|
||||
claim_type_code = self.env['crm.claim.type'].\
|
||||
browse(code_id).ir_sequence_id.code
|
||||
sequence = self.env['ir.sequence']
|
||||
|
||||
return claim_type_code and sequence.next_by_code(
|
||||
claim_type_code
|
||||
) or '/'
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
values = values or {}
|
||||
if 'code' not in values or not values.get('code') \
|
||||
or values.get('code') == '/':
|
||||
|
||||
claim_type = values.get('claim_type')
|
||||
if not claim_type:
|
||||
claim_type = self._get_claim_type_default().id
|
||||
|
||||
values['code'] = self._get_sequence_number(claim_type)
|
||||
|
||||
return super(CrmClaim, self).create(values)
|
||||
|
||||
@api.multi
|
||||
def copy(self, default=None):
|
||||
self.ensure_one()
|
||||
|
||||
default = default or {}
|
||||
std_default = {
|
||||
'code': '/'
|
||||
}
|
||||
|
||||
std_default.update(default)
|
||||
return super(CrmClaim, self).copy(default=std_default)
|
||||
@@ -1,527 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright 2015 Eezee-It, MONK Software
|
||||
# Copyright 2013 Camptocamp
|
||||
# Copyright 2009-2013 Akretion,
|
||||
# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau,
|
||||
# Benoît Guillot, Joel Grand-Guillaume, Leonardo Donelli
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
import math
|
||||
import calendar
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from openerp import models, fields, api, exceptions
|
||||
from openerp.tools.misc import (DEFAULT_SERVER_DATE_FORMAT,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
class InvoiceNoDate(Exception):
|
||||
""" Raised when a warranty cannot be computed for a claim line
|
||||
because the invoice has no date. """
|
||||
|
||||
|
||||
class ProductNoSupplier(Exception):
|
||||
""" Raised when a warranty cannot be computed for a claim line
|
||||
because the product has no supplier. """
|
||||
|
||||
|
||||
class SubstateSubstate(models.Model):
|
||||
""" To precise a state (state=refused; substates= reason 1, 2,...) """
|
||||
_name = "substate.substate"
|
||||
_description = "substate that precise a given state"
|
||||
|
||||
name = fields.Char(string='Sub state', required=True)
|
||||
substate_descr = fields.Text(
|
||||
string='Description',
|
||||
help="To give more information about the sub state")
|
||||
|
||||
|
||||
class ClaimLine(models.Model):
|
||||
"""
|
||||
Class to handle a product return line (corresponding to one invoice line)
|
||||
"""
|
||||
_name = "claim.line"
|
||||
_description = "List of product to return"
|
||||
|
||||
# Comment written in a claim.line to know about the warranty status
|
||||
WARRANT_COMMENT = {
|
||||
'valid': "Valid",
|
||||
'expired': "Expired",
|
||||
'not_define': "Not Defined"}
|
||||
|
||||
# Method to calculate total amount of the line : qty*UP
|
||||
@api.one
|
||||
def _line_total_amount(self):
|
||||
self.return_value = (self.unit_sale_price *
|
||||
self.product_returned_quantity)
|
||||
|
||||
def get_warranty_return_partner(self):
|
||||
return self.env['product.supplierinfo'].get_warranty_return_partner()
|
||||
|
||||
name = fields.Char(string='Description', required=True, default=None)
|
||||
claim_origine = fields.Selection(
|
||||
[('none', 'Not specified'),
|
||||
('legal', 'Legal retractation'),
|
||||
('cancellation', 'Order cancellation'),
|
||||
('damaged', 'Damaged delivered product'),
|
||||
('error', 'Shipping error'),
|
||||
('exchange', 'Exchange request'),
|
||||
('lost', 'Lost during transport'),
|
||||
('other', 'Other')
|
||||
],
|
||||
string='Claim Subject', required=True,
|
||||
help="To describe the line product problem")
|
||||
claim_descr = fields.Text(
|
||||
string='Claim description',
|
||||
help="More precise description of the problem")
|
||||
product_id = fields.Many2one(
|
||||
'product.product', string='Product', help="Returned product")
|
||||
product_returned_quantity = fields.Float(
|
||||
string='Quantity', digits=(12, 2), help="Quantity of product returned")
|
||||
unit_sale_price = fields.Float(
|
||||
string='Unit sale price', digits=(12, 2),
|
||||
help="Unit sale price of the product. Auto filled if retrun done "
|
||||
"by invoice selection. Be careful and check the automatic "
|
||||
"value as don't take into account previous refunds, invoice "
|
||||
"discount, can be for 0 if product for free,...")
|
||||
return_value = fields.Float(
|
||||
string='Total return', compute='_line_total_amount',
|
||||
help="Quantity returned * Unit sold price",)
|
||||
prodlot_id = fields.Many2one(
|
||||
'stock.production.lot',
|
||||
string='Serial/Lot n°', help="The serial/lot of the returned product")
|
||||
applicable_guarantee = fields.Selection(
|
||||
[('us', 'Company'),
|
||||
('supplier', 'Supplier'),
|
||||
('brand', 'Brand manufacturer')],
|
||||
string='Warranty type')
|
||||
guarantee_limit = fields.Date(
|
||||
string='Warranty limit',
|
||||
readonly=True,
|
||||
help="The warranty limit is computed as: invoice date + warranty "
|
||||
"defined on selected product.")
|
||||
warning = fields.Char(
|
||||
string='Warranty',
|
||||
readonly=True,
|
||||
help="If warranty has expired")
|
||||
warranty_type = fields.Selection(
|
||||
get_warranty_return_partner,
|
||||
string='Warranty type',
|
||||
readonly=True,
|
||||
help="Who is in charge of the warranty return treatment towards "
|
||||
"the end customer. Company will use the current company "
|
||||
"delivery or default address and so on for supplier and brand"
|
||||
" manufacturer. Does not necessarily mean that the warranty "
|
||||
"to be applied is the one of the return partner (ie: can be "
|
||||
"returned to the company and be under the brand warranty")
|
||||
warranty_return_partner = fields.Many2one(
|
||||
'res.partner',
|
||||
string='Warranty Address',
|
||||
help="Where the customer has to send back the product(s)")
|
||||
claim_id = fields.Many2one(
|
||||
'crm.claim',
|
||||
string='Related claim',
|
||||
help="To link to the case.claim object")
|
||||
state = fields.Selection(
|
||||
[('draft', 'Draft'),
|
||||
('refused', 'Refused'),
|
||||
('confirmed', 'Confirmed, waiting for product'),
|
||||
('in_to_control', 'Received, to control'),
|
||||
('in_to_treate', 'Controlled, to treate'),
|
||||
('treated', 'Treated')],
|
||||
string='State',
|
||||
default="draft")
|
||||
substate_id = fields.Many2one(
|
||||
'substate.substate',
|
||||
string='Sub state',
|
||||
help="Select a sub state to precise the standard state. Example 1:"
|
||||
" state = refused; substate could be warranty over, not in "
|
||||
"warranty, no problem,... . Example 2: state = to treate; "
|
||||
"substate could be to refund, to exchange, to repair,...")
|
||||
last_state_change = fields.Date(
|
||||
string='Last change',
|
||||
help="To set the last state / substate change")
|
||||
invoice_line_id = fields.Many2one(
|
||||
'account.invoice.line',
|
||||
string='Invoice Line',
|
||||
help='The invoice line related to the returned product')
|
||||
refund_line_id = fields.Many2one(
|
||||
'account.invoice.line',
|
||||
string='Refund Line',
|
||||
copy=False,
|
||||
help='The refund line related to the returned product')
|
||||
move_in_id = fields.Many2one(
|
||||
'stock.move',
|
||||
string='Move Line from picking in',
|
||||
copy=False,
|
||||
help='The move line related to the returned product')
|
||||
move_out_id = fields.Many2one(
|
||||
'stock.move',
|
||||
string='Move Line from picking out',
|
||||
copy=False,
|
||||
help='The move line related to the returned product')
|
||||
location_dest_id = fields.Many2one(
|
||||
'stock.location',
|
||||
string='Return Stock Location',
|
||||
help='The return stock location of the returned product')
|
||||
|
||||
@staticmethod
|
||||
def warranty_limit(start, warranty_duration):
|
||||
""" Take a duration in float, return the duration in relativedelta
|
||||
|
||||
``relative_delta(months=...)`` only accepts integers.
|
||||
We have to extract the decimal part, and then, extend the delta with
|
||||
days.
|
||||
"""
|
||||
decimal_part, months = math.modf(warranty_duration)
|
||||
months = int(months)
|
||||
# If we have a decimal part, we add the number them as days to
|
||||
# the limit. We need to get the month to know the number of
|
||||
# days.
|
||||
delta = relativedelta(months=months)
|
||||
monthday = start + delta
|
||||
__, days_month = calendar.monthrange(monthday.year, monthday.month)
|
||||
# ignore the rest of the days (hours) since we expect a date
|
||||
days = int(days_month * decimal_part)
|
||||
return start + relativedelta(months=months, days=days)
|
||||
|
||||
def _warranty_limit_values(self, invoice, claim_type, product, claim_date):
|
||||
if not (invoice and claim_type and product and claim_date):
|
||||
return {'guarantee_limit': False, 'warning': False}
|
||||
|
||||
date_invoice = invoice.date_invoice
|
||||
if not date_invoice:
|
||||
raise InvoiceNoDate
|
||||
|
||||
warning = 'not_define'
|
||||
date_invoice = datetime.strptime(date_invoice,
|
||||
DEFAULT_SERVER_DATE_FORMAT)
|
||||
|
||||
if isinstance(claim_type, self.env['crm.claim.type'].__class__):
|
||||
claim_type = claim_type.id
|
||||
|
||||
if claim_type == self.env.ref('crm_claim_type.'
|
||||
'crm_claim_type_supplier').id:
|
||||
try:
|
||||
warranty_duration = product.seller_ids[0].warranty_duration
|
||||
except IndexError:
|
||||
raise ProductNoSupplier
|
||||
else:
|
||||
warranty_duration = product.warranty
|
||||
|
||||
limit = self.warranty_limit(date_invoice, warranty_duration)
|
||||
if warranty_duration > 0:
|
||||
claim_date = datetime.strptime(claim_date,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
if limit < claim_date:
|
||||
warning = 'expired'
|
||||
else:
|
||||
warning = 'valid'
|
||||
|
||||
return {'guarantee_limit': limit.strftime(DEFAULT_SERVER_DATE_FORMAT),
|
||||
'warning': warning}
|
||||
|
||||
def set_warranty_limit(self):
|
||||
self.ensure_one()
|
||||
claim = self.claim_id
|
||||
try:
|
||||
values = self._warranty_limit_values(
|
||||
claim.invoice_id, claim.claim_type,
|
||||
self.product_id, claim.date)
|
||||
except InvoiceNoDate:
|
||||
raise exceptions.Warning(
|
||||
_('Error'), _('Cannot find any date for invoice. '
|
||||
'Must be a validated invoice.'))
|
||||
except ProductNoSupplier:
|
||||
raise exceptions.Warning(
|
||||
_('Error'), _('The product has no supplier configured.'))
|
||||
|
||||
self.write(values)
|
||||
return True
|
||||
|
||||
@api.multi
|
||||
def auto_set_warranty(self):
|
||||
""" Set warranty automatically
|
||||
if the user has not himself pressed on 'Calculate warranty state'
|
||||
button, it sets warranty for him"""
|
||||
for line in self:
|
||||
if not line.warning:
|
||||
line.set_warranty()
|
||||
return True
|
||||
|
||||
@api.returns('stock.location')
|
||||
def get_destination_location(self, product, warehouse):
|
||||
"""
|
||||
Compute and return the destination location to take
|
||||
for a return. Always take 'Supplier' one when return type different
|
||||
from company.
|
||||
"""
|
||||
if isinstance(warehouse, int):
|
||||
location_dest_id = self.env['stock.warehouse']\
|
||||
.browse(warehouse).lot_stock_id
|
||||
else:
|
||||
location_dest_id = warehouse.lot_stock_id
|
||||
|
||||
if isinstance(product, int):
|
||||
product = self.env['product.product']\
|
||||
.browse(product)
|
||||
try:
|
||||
seller = product.seller_ids[0]
|
||||
if seller.warranty_return_partner != 'company':
|
||||
location_dest_id = seller.name.property_stock_supplier
|
||||
finally:
|
||||
return location_dest_id
|
||||
|
||||
@api.onchange('product_id', 'invoice_line_id')
|
||||
def _onchange_product_invoice_line(self):
|
||||
product = self.product_id
|
||||
invoice_line = self.invoice_line_id
|
||||
context = self.env.context
|
||||
|
||||
claim = context.get('claim_id')
|
||||
company_id = context.get('company_id')
|
||||
warehouse_id = context.get('warehouse_id')
|
||||
claim_type = context.get('claim_type')
|
||||
claim_date = context.get('claim_date')
|
||||
|
||||
# claim_exists = not isinstance(claim.id, NewId)
|
||||
if not claim and not (company_id and warehouse_id and
|
||||
claim_type and claim_date):
|
||||
# if we have a claim_id, we get the info from there,
|
||||
# otherwise we get it from the args (on creation typically)
|
||||
return False
|
||||
if not (product and invoice_line):
|
||||
return False
|
||||
|
||||
invoice = invoice_line.invoice_id
|
||||
claim_line_model = self.env['claim.line']
|
||||
|
||||
if claim:
|
||||
claim = self.env['crm.claim'].browse(claim)
|
||||
company = claim.company_id
|
||||
warehouse = claim.warehouse_id
|
||||
claim_type = claim.claim_type
|
||||
claim_date = claim.date
|
||||
else:
|
||||
warehouse_obj = self.env['stock.warehouse']
|
||||
company_obj = self.env['res.company']
|
||||
company = company_obj.browse(company_id)
|
||||
warehouse = warehouse_obj.browse(warehouse_id)
|
||||
|
||||
values = {}
|
||||
try:
|
||||
warranty = claim_line_model._warranty_limit_values(
|
||||
invoice, claim_type, product, claim_date)
|
||||
except (InvoiceNoDate, ProductNoSupplier):
|
||||
# we don't mind at this point if the warranty can't be
|
||||
# computed and we don't want to block the user
|
||||
values.update({'guarantee_limit': False, 'warning': False})
|
||||
else:
|
||||
values.update(warranty)
|
||||
warranty_address = claim_line_model._warranty_return_address_values(
|
||||
product, company, warehouse)
|
||||
values.update(warranty_address)
|
||||
self.update(values)
|
||||
|
||||
def _warranty_return_address_values(self, product, company, warehouse):
|
||||
"""
|
||||
Return the partner to be used as return destination and
|
||||
the destination stock location of the line in case of return.
|
||||
|
||||
We can have various cases here:
|
||||
- company or other: return to company partner or
|
||||
crm_return_address_id if specified
|
||||
- supplier: return to the supplier address
|
||||
"""
|
||||
if not (product and company and warehouse):
|
||||
return {
|
||||
'warranty_return_partner': False,
|
||||
'warranty_type': False,
|
||||
'location_dest_id': False
|
||||
}
|
||||
sellers = product.seller_ids
|
||||
if sellers:
|
||||
seller = sellers[0]
|
||||
return_address_id = seller.warranty_return_address.id
|
||||
return_type = seller.warranty_return_partner
|
||||
else:
|
||||
# when no supplier is configured, returns to the company
|
||||
return_address = (company.crm_return_address_id or
|
||||
company.partner_id)
|
||||
return_address_id = return_address.id
|
||||
return_type = 'company'
|
||||
location_dest = self.get_destination_location(product, warehouse)
|
||||
return {
|
||||
'warranty_return_partner': return_address_id,
|
||||
'warranty_type': return_type,
|
||||
'location_dest_id': location_dest.id
|
||||
}
|
||||
|
||||
def set_warranty_return_address(self):
|
||||
self.ensure_one()
|
||||
claim = self.claim_id
|
||||
values = self._warranty_return_address_values(
|
||||
self.product_id, claim.company_id, claim.warehouse_id)
|
||||
self.write(values)
|
||||
return True
|
||||
|
||||
@api.one
|
||||
def set_warranty(self):
|
||||
""" Calculate warranty limit and address """
|
||||
if not (self.product_id and self.invoice_line_id):
|
||||
raise exceptions.Warning(
|
||||
_('Error'), _('Please set product and invoice.'))
|
||||
self.set_warranty_limit()
|
||||
self.set_warranty_return_address()
|
||||
|
||||
|
||||
# TODO add the option to split the claim_line in order to manage the same
|
||||
# product separately
|
||||
class CrmClaim(models.Model):
|
||||
_inherit = 'crm.claim'
|
||||
|
||||
def _get_default_warehouse(self):
|
||||
company_id = self.env.user.company_id.id
|
||||
wh_obj = self.env['stock.warehouse']
|
||||
wh = wh_obj.search([('company_id', '=', company_id)], limit=1)
|
||||
if not wh:
|
||||
raise exceptions.Warning(
|
||||
_('There is no warehouse for the current user\'s company.'))
|
||||
return wh
|
||||
|
||||
@api.one
|
||||
def name_get(self):
|
||||
return (self.id, u'[{}] {}'.format(self.code or '', self.name))
|
||||
|
||||
claim_line_ids = fields.One2many('claim.line', 'claim_id',
|
||||
string='Claim lines')
|
||||
planned_revenue = fields.Float(string='Expected revenue')
|
||||
planned_cost = fields.Float(string='Expected cost')
|
||||
real_revenue = fields.Float(string='Real revenue')
|
||||
real_cost = fields.Float(string='Real cost')
|
||||
invoice_ids = fields.One2many('account.invoice', 'claim_id',
|
||||
string='Refunds',
|
||||
copy=False)
|
||||
picking_ids = fields.One2many('stock.picking', 'claim_id',
|
||||
string='RMA',
|
||||
copy=False)
|
||||
invoice_id = fields.Many2one(
|
||||
'account.invoice',
|
||||
string='Invoice',
|
||||
help='Related original Customer invoice')
|
||||
delivery_address_id = fields.Many2one(
|
||||
'res.partner',
|
||||
string='Partner delivery address',
|
||||
help="This address will be used to deliver repaired or replacement"
|
||||
"products.")
|
||||
warehouse_id = fields.Many2one(
|
||||
'stock.warehouse',
|
||||
string='Warehouse',
|
||||
default=_get_default_warehouse,
|
||||
required=True)
|
||||
|
||||
@api.onchange('invoice_id', 'warehouse_id', 'claim_type', 'date')
|
||||
def _onchange_invoice_warehouse_type_date(self):
|
||||
context = self.env.context
|
||||
claim_line_obj = self.env['claim.line']
|
||||
invoice_lines = self.invoice_id.invoice_line
|
||||
claim_lines = []
|
||||
if not self.warehouse_id:
|
||||
self.warehouse_id = self._get_default_warehouse()
|
||||
|
||||
claim_type = self.claim_type
|
||||
claim_date = self.date
|
||||
warehouse = self.warehouse_id
|
||||
company = self.company_id
|
||||
create_lines = context.get('create_lines')
|
||||
|
||||
def warranty_values(invoice, product):
|
||||
values = {}
|
||||
try:
|
||||
warranty = claim_line_obj._warranty_limit_values(
|
||||
invoice, claim_type, product, claim_date)
|
||||
except (InvoiceNoDate, ProductNoSupplier):
|
||||
# we don't mind at this point if the warranty can't be
|
||||
# computed and we don't want to block the user
|
||||
values.update({'guarantee_limit': False, 'warning': False})
|
||||
else:
|
||||
values.update(warranty)
|
||||
|
||||
warranty_address = claim_line_obj._warranty_return_address_values(
|
||||
product, company, warehouse)
|
||||
values.update(warranty_address)
|
||||
return values
|
||||
|
||||
if create_lines: # happens when the invoice is changed
|
||||
for invoice_line in invoice_lines:
|
||||
location_dest = claim_line_obj.get_destination_location(
|
||||
invoice_line.product_id, warehouse)
|
||||
line = {
|
||||
'name': invoice_line.name,
|
||||
'claim_origine': "none",
|
||||
'invoice_line_id': invoice_line.id,
|
||||
'product_id': invoice_line.product_id.id,
|
||||
'product_returned_quantity': invoice_line.quantity,
|
||||
'unit_sale_price': invoice_line.price_unit,
|
||||
'location_dest_id': location_dest.id,
|
||||
'state': 'draft',
|
||||
}
|
||||
line.update(warranty_values(invoice_line.invoice_id,
|
||||
invoice_line.product_id))
|
||||
claim_lines.append((0, 0, line))
|
||||
|
||||
value = self._convert_to_cache(
|
||||
{'claim_line_ids': claim_lines}, validate=False)
|
||||
self.update(value)
|
||||
|
||||
if self.invoice_id:
|
||||
self.delivery_address_id = self.invoice_id.partner_id.id
|
||||
|
||||
@api.multi
|
||||
def message_get_reply_to(self):
|
||||
""" Override to get the reply_to of the parent project. """
|
||||
result = {}
|
||||
for claim in self.sudo():
|
||||
section = claim.section_id
|
||||
if section:
|
||||
section_reply_to = section.message_get_reply_to()
|
||||
result[claim.id] = section_reply_to[section.id]
|
||||
else:
|
||||
result[claim.id] = False
|
||||
return result
|
||||
|
||||
@api.multi
|
||||
def message_get_suggested_recipients(self):
|
||||
recipients = super(CrmClaim, self).message_get_suggested_recipients()
|
||||
try:
|
||||
for claim in self:
|
||||
if claim.partner_id:
|
||||
self._message_add_suggested_recipient(
|
||||
recipients, claim,
|
||||
partner=claim.partner_id, reason=_('Customer'))
|
||||
elif claim.email_from:
|
||||
self._message_add_suggested_recipient(
|
||||
recipients, claim,
|
||||
email=claim.email_from, reason=_('Customer Email'))
|
||||
except exceptions.AccessError:
|
||||
# no read access rights -> just ignore suggested recipients
|
||||
# because this imply modifying followers
|
||||
pass
|
||||
return recipients
|
||||
11
crm_claim_rma/models/invoice_no_date.py
Normal file
11
crm_claim_rma/models/invoice_no_date.py
Normal file
@@ -0,0 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Eezee-It, MONK Software, Vauxoo
|
||||
# © 2013 Camptocamp
|
||||
# © 2009-2013 Akretion,
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
|
||||
class InvoiceNoDate(Exception):
|
||||
""" Raised when a warranty cannot be computed for a claim line
|
||||
because the invoice has no date.
|
||||
"""
|
||||
11
crm_claim_rma/models/procurement_group.py
Normal file
11
crm_claim_rma/models/procurement_group.py
Normal file
@@ -0,0 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2016 Cyril Gaudin (Camptocamp)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import fields, models
|
||||
|
||||
|
||||
class ProcurementGroup(models.Model):
|
||||
_inherit = 'procurement.group'
|
||||
|
||||
claim_id = fields.Many2one('crm.claim', 'Claim')
|
||||
12
crm_claim_rma/models/product_no_supplier.py
Normal file
12
crm_claim_rma/models/product_no_supplier.py
Normal file
@@ -0,0 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Vauxoo
|
||||
# © 2015 Eezee-It, MONK Software
|
||||
# © 2013 Camptocamp
|
||||
# © 2009-2013 Akretion,
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
|
||||
class ProductNoSupplier(Exception):
|
||||
""" Raised when a warranty cannot be computed for a claim line
|
||||
because the product has no supplier.
|
||||
"""
|
||||
@@ -1,58 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright 2015 Eezee-It, MONK Software
|
||||
# Copyright 2013 Camptocamp
|
||||
# Copyright 2009-2013 Akretion,
|
||||
# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau,
|
||||
# Benoît Guillot, Joel Grand-Guillaume, Leonardo Donelli
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp import models, fields, api
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
_inherit = "stock.picking"
|
||||
|
||||
claim_id = fields.Many2one('crm.claim', string='Claim')
|
||||
|
||||
@api.model
|
||||
@api.returns('self', lambda value: value.id)
|
||||
def create(self, vals):
|
||||
if ('name' not in vals) or (vals.get('name') == '/'):
|
||||
vals['name'] = self.env['ir.sequence'].get(self._name)
|
||||
return super(StockPicking, self).create(vals)
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
_inherit = "stock.move"
|
||||
|
||||
@api.model
|
||||
@api.returns('self', lambda value: value.id)
|
||||
def create(self, vals):
|
||||
"""
|
||||
In case of a wrong picking out, We need to create a new stock_move in a
|
||||
picking already open.
|
||||
To avoid having to confirm the stock_move, we override the create and
|
||||
confirm it at the creation only for this case.
|
||||
"""
|
||||
move = super(StockMove, self).create(vals)
|
||||
if vals.get('picking_id'):
|
||||
picking = self.env['stock.picking'].browse(vals['picking_id'])
|
||||
if picking.claim_id and picking.picking_type_id.code == 'incoming':
|
||||
move.write({'state': 'confirmed'})
|
||||
return move
|
||||
27
crm_claim_rma/models/stock_move.py
Normal file
27
crm_claim_rma/models/stock_move.py
Normal file
@@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Eezee-It, MONK Software, Vauxoo
|
||||
# © 2013 Camptocamp
|
||||
# © 2009-2013 Akretion,
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import api, models
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
|
||||
_name = 'stock.move'
|
||||
_inherit = ['stock.move', 'mail.thread']
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
""" In case of a wrong picking out,
|
||||
We need to create a new stock_move in a picking already open.
|
||||
To avoid having to confirm the stock_move, we override the create and
|
||||
confirm it at the creation only for this case.
|
||||
"""
|
||||
move = super(StockMove, self).create(vals)
|
||||
if vals.get('picking_id'):
|
||||
picking = self.env['stock.picking'].browse(vals['picking_id'])
|
||||
if picking.claim_id and picking.picking_type_id.code == 'incoming':
|
||||
move.write({'state': 'confirmed'})
|
||||
return move
|
||||
14
crm_claim_rma/models/stock_picking.py
Normal file
14
crm_claim_rma/models/stock_picking.py
Normal file
@@ -0,0 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Eezee-It, MONK Software, Vauxoo
|
||||
# © 2013 Camptocamp
|
||||
# © 2009-2013 Akretion,
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import fields, models
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
|
||||
_inherit = "stock.picking"
|
||||
|
||||
claim_id = fields.Many2one('crm.claim', 'Claim')
|
||||
20
crm_claim_rma/models/substate_substate.py
Normal file
20
crm_claim_rma/models/substate_substate.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Eezee-It, MONK Software, Vauxoo
|
||||
# © 2013 Camptocamp
|
||||
# © 2009-2013 Akretion,
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import fields, models
|
||||
|
||||
|
||||
class SubstateSubstate(models.Model):
|
||||
""" To precise a state (state=refused; substates= reason 1, 2,...)
|
||||
"""
|
||||
|
||||
_name = "substate.substate"
|
||||
_description = "substate that precise a given state"
|
||||
|
||||
name = fields.Char('Sub state', required=True)
|
||||
substate_descr = fields.Text('Description',
|
||||
help="To give more "
|
||||
"information about the sub state")
|
||||
@@ -1,7 +1,7 @@
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"access_substate_user","substate.substate.user","model_substate_substate","base.group_sale_salesman_all_leads","True","True","True",
|
||||
"access_claim_line_user","claim.line.user","model_claim_line","base.group_sale_salesman_all_leads","True","True","True",
|
||||
"access_substate_manager","substate.substate.manager","model_substate_substate","base.group_sale_manager","True","True","True","True"
|
||||
"access_claim_line_manager","claim.line.manager","model_claim_line","base.group_sale_manager","True","True","True","True"
|
||||
"access_substate_user","substate.substate.user","model_substate_substate","base.group_sale_salesman","True","True","True",
|
||||
"access_claim_line_user","claim.line.user","model_claim_line","base.group_sale_salesman","True","True","True",
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_substate_user_all_leads,substate.substate.user,model_substate_substate,base.group_sale_salesman_all_leads,1,1,1,0
|
||||
access_claim_line_user_all_leads,claim.line.user,model_claim_line,base.group_sale_salesman_all_leads,1,1,1,0
|
||||
access_substate_manager,substate.substate.manager,model_substate_substate,base.group_sale_manager,1,1,1,1
|
||||
access_claim_line_manager,claim.line.manager,model_claim_line,base.group_sale_manager,1,1,1,1
|
||||
access_substate_user,substate.substate.user,model_substate_substate,base.group_sale_salesman,1,1,1,0
|
||||
access_claim_line_user,claim.line.user,model_claim_line,base.group_sale_salesman,1,1,1,0
|
||||
|
||||
|
@@ -3,12 +3,11 @@
|
||||
-
|
||||
I create a customer invoice
|
||||
-
|
||||
!record {model: account.invoice, id: account_invoice_claim_refund, view: account.invoice_form}:
|
||||
payment_term: account.account_payment_term_advance
|
||||
journal_id: account.sales_journal
|
||||
!record {model: account.invoice, id: account_invoice_claim_refund}:
|
||||
payment_term_id: account.account_payment_term_advance
|
||||
partner_id: base.res_partner_3
|
||||
name: 'Test Customer Invoice'
|
||||
invoice_line:
|
||||
invoice_line_ids:
|
||||
- product_id: product.product_product_5
|
||||
quantity: 10.0
|
||||
- product_id: product.product_product_4
|
||||
@@ -54,4 +53,3 @@
|
||||
refund_lines = self.pool.get('account.invoice.line').browse(cr, uid, refund_line_ids)
|
||||
assert ref('product.product_product_4') in [refund_lines[0].product_id.id, refund_lines[1].product_id.id], "First line is checked"
|
||||
assert ref('product.product_product_5') in [refund_lines[0].product_id.id, refund_lines[1].product_id.id], "Second line is checked"
|
||||
|
||||
|
||||
@@ -1,21 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Author: Yannick Vaucher
|
||||
# Copyright 2014 Camptocamp SA
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from . import test_claim
|
||||
from . import test_picking_creation
|
||||
|
||||
32
crm_claim_rma/tests/test_claim.py
Normal file
32
crm_claim_rma/tests/test_claim.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2016 Cyril Gaudin (Camptocamp)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp.tests import TransactionCase
|
||||
|
||||
|
||||
class TestClaim(TransactionCase):
|
||||
|
||||
def test_create__no_claim_type(self):
|
||||
# Just test the case when claim_type is not in values and default value
|
||||
# is not yet filled by BaseModel.create as we override this method
|
||||
# and our code need claim_type to generate code
|
||||
claim = self.env['crm.claim'].create({'name': 'Test claim'})
|
||||
|
||||
self.assertEqual(
|
||||
self.env.ref('crm_claim_type.crm_claim_type_customer'),
|
||||
claim.claim_type,
|
||||
)
|
||||
self.assertIsNotNone(claim.code)
|
||||
self.assertTrue(claim.code.startswith('RMA-C/'))
|
||||
|
||||
def test_create__with_claim_type(self):
|
||||
supplier_type = self.env.ref('crm_claim_type.crm_claim_type_supplier')
|
||||
claim = self.env['crm.claim'].create({
|
||||
'name': 'Test claim',
|
||||
'claim_type': supplier_type.id,
|
||||
})
|
||||
|
||||
self.assertEqual(supplier_type, claim.claim_type)
|
||||
self.assertIsNotNone(claim.code)
|
||||
self.assertTrue(claim.code.startswith('RMA-V/'))
|
||||
@@ -1,25 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Author: Yannick Vaucher
|
||||
# Yanina Aular
|
||||
# Copyright 2015 Vauxoo
|
||||
# Copyright 2014 Camptocamp SA
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# © 2015 Vauxoo
|
||||
# © 2014 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp.tests import common
|
||||
|
||||
|
||||
@@ -31,21 +14,41 @@ class TestPickingCreation(common.TransactionCase):
|
||||
super(TestPickingCreation, self).setUp()
|
||||
|
||||
self.wizard_make_picking = self.env['claim_make_picking.wizard']
|
||||
self.stockpicking = self.env['stock.picking']
|
||||
claim = self.env['crm.claim']
|
||||
|
||||
self.product_id = self.env.ref('product.product_product_4')
|
||||
|
||||
self.partner_id = self.env.ref('base.res_partner_12')
|
||||
|
||||
self.customer_location_id = self.env.ref(
|
||||
'stock.stock_location_customers')
|
||||
'stock.stock_location_customers'
|
||||
)
|
||||
|
||||
sale_order_agrolait_demo = self.env.ref('sale.sale_order_1')
|
||||
self.assertTrue(sale_order_agrolait_demo.invoice_ids,
|
||||
"The Order Sale of Agrolait not have Invoice")
|
||||
invoice_agrolait = sale_order_agrolait_demo.invoice_ids[0]
|
||||
invoice_agrolait.\
|
||||
signal_workflow('invoice_open')
|
||||
uom_unit = self.env.ref('product.product_uom_unit')
|
||||
self.sale_order = self.env['sale.order'].create({
|
||||
'state': 'done',
|
||||
'partner_id': self.env.ref('base.res_partner_2').id,
|
||||
'partner_invoice_id': self.env.ref('base.res_partner_2').id,
|
||||
'partner_shipping_id': self.env.ref('base.res_partner_2').id,
|
||||
'pricelist_id': self.env.ref('product.list0').id,
|
||||
'order_line': [
|
||||
(0, False, {
|
||||
'name': product.name,
|
||||
'product_id': product.id,
|
||||
'product_uom_qty': qty,
|
||||
'qty_delivered': qty,
|
||||
'product_uom': uom_unit.id,
|
||||
'price_unit': product.list_price
|
||||
|
||||
}) for product, qty in [
|
||||
(self.env.ref('product.product_product_25'), 3),
|
||||
(self.env.ref('product.product_product_30'), 5),
|
||||
(self.env.ref('product.product_product_33'), 2),
|
||||
]
|
||||
]
|
||||
})
|
||||
invoice_id = self.sale_order.action_invoice_create()[0]
|
||||
self.invoice = self.env['account.invoice'].browse(invoice_id)
|
||||
|
||||
# Create the claim with a claim line
|
||||
self.claim_id = claim.create(
|
||||
@@ -56,7 +59,7 @@ class TestPickingCreation(common.TransactionCase):
|
||||
'crm_claim_type_customer').id,
|
||||
'delivery_address_id': self.partner_id.id,
|
||||
'partner_id': self.env.ref('base.res_partner_2').id,
|
||||
'invoice_id': invoice_agrolait.id,
|
||||
'invoice_id': invoice_id,
|
||||
})
|
||||
self.claim_id.with_context({'create_lines': True}).\
|
||||
_onchange_invoice_warehouse_type_date()
|
||||
@@ -85,10 +88,11 @@ class TestPickingCreation(common.TransactionCase):
|
||||
"Incorrect destination location")
|
||||
|
||||
def test_01_new_delivery(self):
|
||||
"""Test wizard creates a correct picking for a new delivery
|
||||
|
||||
"""Test wizard creates and runs a procurement for a new delivery
|
||||
"""
|
||||
|
||||
group_model = self.env['procurement.group']
|
||||
|
||||
wizardchangeproductqty = self.env['stock.change.product.qty']
|
||||
wizard_chg_qty = wizardchangeproductqty.with_context({
|
||||
'active_id': self.product_id.id,
|
||||
@@ -99,6 +103,9 @@ class TestPickingCreation(common.TransactionCase):
|
||||
|
||||
wizard_chg_qty.change_product_qty()
|
||||
|
||||
self.assertEqual(0, group_model.search_count([
|
||||
('claim_id', '=', self.claim_id.id)
|
||||
]))
|
||||
wizard = self.wizard_make_picking.with_context({
|
||||
'active_id': self.claim_id.id,
|
||||
'partner_id': self.partner_id.id,
|
||||
@@ -107,29 +114,36 @@ class TestPickingCreation(common.TransactionCase):
|
||||
}).create({})
|
||||
wizard.action_create_picking()
|
||||
|
||||
procurement_group = group_model.search([
|
||||
('claim_id', '=', self.claim_id.id)
|
||||
])
|
||||
self.assertEqual(1, len(procurement_group))
|
||||
|
||||
self.assertEquals(len(self.claim_id.picking_ids), 1,
|
||||
"Incorrect number of pickings created")
|
||||
picking = self.claim_id.picking_ids[0]
|
||||
|
||||
self.assertEquals(picking.location_id, self.warehouse_id.lot_stock_id,
|
||||
# Should have 1 procurement by product:
|
||||
# One on Customer location and one on output
|
||||
self.assertEqual(3, len(procurement_group.procurement_ids))
|
||||
|
||||
# And 2 pickings
|
||||
self.assertEqual(1, len(self.claim_id.picking_ids))
|
||||
|
||||
self.assertEquals(self.warehouse_id.lot_stock_id,
|
||||
self.claim_id.picking_ids.location_id,
|
||||
"Incorrect source location")
|
||||
self.assertEquals(picking.location_dest_id, self.customer_location_id,
|
||||
self.assertEquals(self.customer_location_id,
|
||||
self.claim_id.picking_ids.location_dest_id,
|
||||
"Incorrect destination location")
|
||||
|
||||
def test_02_new_product_return(self):
|
||||
"""Test wizard creates a correct picking for product return
|
||||
|
||||
"""
|
||||
company = self.env.ref('base.main_company')
|
||||
warehouse_obj = self.env['stock.warehouse']
|
||||
warehouse_rec = \
|
||||
warehouse_obj.search([('company_id',
|
||||
'=', company.id)])[0]
|
||||
wizard = self.wizard_make_picking.with_context({
|
||||
'active_id': self.claim_id.id,
|
||||
'partner_id': self.partner_id.id,
|
||||
'warehouse_id': self.warehouse_id.id,
|
||||
'picking_type': warehouse_rec.in_type_id.id,
|
||||
'picking_type': 'in',
|
||||
}).create({})
|
||||
wizard.action_create_picking()
|
||||
|
||||
@@ -143,13 +157,54 @@ class TestPickingCreation(common.TransactionCase):
|
||||
self.warehouse_id.lot_stock_id,
|
||||
"Incorrect destination location")
|
||||
|
||||
def test_copy(self):
|
||||
new_claim = self.claim_id.copy()
|
||||
self.assertNotEqual(new_claim.code, self.claim_id.code)
|
||||
def test_03_invoice_refund(self):
|
||||
claim_id = self.env['crm.claim'].browse(
|
||||
self.ref('crm_claim.crm_claim_6')
|
||||
)
|
||||
self.invoice.confirm_paid()
|
||||
claim_id.write({
|
||||
'invoice_id': self.invoice.id
|
||||
})
|
||||
claim_id.with_context({'create_lines': True}).\
|
||||
_onchange_invoice_warehouse_type_date()
|
||||
|
||||
def test_mail_thread_recipient(self):
|
||||
recipients = self.claim_id.message_get_suggested_recipients()
|
||||
recipients = recipients[self.claim_id.id]
|
||||
recipient_ids = [r[0] for r in recipients]
|
||||
self.assertEqual(recipient_ids,
|
||||
[self.claim_id.partner_id.id])
|
||||
invoice_refund_wizard_id = self.env['account.invoice.refund'].\
|
||||
with_context({
|
||||
# Test that invoice_ids is correctly passed as active_ids
|
||||
'invoice_ids': [claim_id.invoice_id.id],
|
||||
'claim_line_ids':
|
||||
[[4, cl.id, False] for cl in claim_id.claim_line_ids],
|
||||
'description': "Testing Invoice Refund for Claim",
|
||||
}).create({})
|
||||
|
||||
self.assertEqual(
|
||||
"Testing Invoice Refund for Claim",
|
||||
invoice_refund_wizard_id.description
|
||||
)
|
||||
|
||||
res = invoice_refund_wizard_id.invoice_refund()
|
||||
|
||||
self.assertTrue(res)
|
||||
self.assertEquals(res['res_model'], 'account.invoice')
|
||||
self.assertEqual(2, len(res['domain']))
|
||||
|
||||
# Second leaf is ('id', 'in', [created_invoice_id])
|
||||
self.assertEqual(('id', 'in'), res['domain'][1][:2])
|
||||
self.assertEqual(1, len(res['domain'][1][2]))
|
||||
|
||||
refund_invoice = self.env['account.invoice'].browse(
|
||||
res['domain'][1][2]
|
||||
)
|
||||
self.assertEqual('out_refund', refund_invoice.type)
|
||||
|
||||
def test_04_display_name(self):
|
||||
"""
|
||||
It tests that display_name for each line has a message for it
|
||||
"""
|
||||
claim_line_ids = self.env['crm.claim'].browse(
|
||||
self.ref('crm_claim.crm_claim_6')
|
||||
)[0].claim_line_ids
|
||||
|
||||
all_values = sum([bool(line_id.display_name)
|
||||
for line_id in claim_line_ids])
|
||||
self.assertEquals(len(claim_line_ids), all_values)
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<!-- INHERITED VIEW FOR THE OBJECT : account_invoice -->
|
||||
<odoo>
|
||||
<!-- INHERITED VIEW FOR THE OBJECT : account_invoice -->
|
||||
|
||||
<record id="invoice_form" model="ir.ui.view">
|
||||
<field name="name">crm_claim_rma.invoice_form</field>
|
||||
<field name="model">account.invoice</field>
|
||||
<field name="inherit_id" ref="account.invoice_form" />
|
||||
<field eval="16" name="priority"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<xpath expr="/form/sheet/notebook/page[@string='Other Info']/group/group/field[@name='origin']" position="after">
|
||||
<field name="claim_id" attrs="{'invisible':[('type','!=','out_refund')]}"/>
|
||||
</xpath>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
<record id="invoice_form" model="ir.ui.view">
|
||||
<field name="name">crm_claim_rma.invoice_form</field>
|
||||
<field name="model">account.invoice</field>
|
||||
<field name="inherit_id" ref="account.invoice_form"/>
|
||||
<field eval="16" name="priority"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<field name='origin' position="after">
|
||||
<field name="claim_id" attrs="{'invisible':[('type','!=','out_refund')]}"/>
|
||||
</field>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
199
crm_claim_rma/views/claim_line.xml
Normal file
199
crm_claim_rma/views/claim_line.xml
Normal file
@@ -0,0 +1,199 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<record id="view_crm_claim_lines_filter" model="ir.ui.view">
|
||||
<field name="name">CRM - Claims Search</field>
|
||||
<field name="model">claim.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Claims">
|
||||
<filter icon="terp-check" string="Current" name="current"
|
||||
domain="[('state','in',('draft', 'refused', 'treated'))]"
|
||||
separator="1" help="Draft and Open Claims"/>
|
||||
<filter icon="terp-camera_test"
|
||||
string="In Progress"
|
||||
domain="[('state','in',('confirmed','in_to_control','in_to_treate'))]"
|
||||
separator="1" help="In Progress Claims"/>
|
||||
<separator orientation="vertical"/>
|
||||
<field name="number"/>
|
||||
<field name="state" select='1'/>
|
||||
<field name="substate_id" select='1'/>
|
||||
<field name="name" select='1'/>
|
||||
<field name="warning" select='1'/>
|
||||
<field name="invoice_line_id" select='1' readonly='1'/>
|
||||
<field name="product_id" select='1'/>
|
||||
<field name="prodlot_id" select='1'/>
|
||||
<field name="move_in_id"/>
|
||||
<newline/>
|
||||
<group expand="0" string="More">
|
||||
<field name="last_state_change" select='1'/>
|
||||
<field name="guarantee_limit" select='1'/>
|
||||
<field name="return_value" select='1'/>
|
||||
<field name="name" select='1'/>
|
||||
</group>
|
||||
<newline/>
|
||||
<group expand="0" string="Group By...">
|
||||
<filter string="Invoice" icon="terp-dolar"
|
||||
domain="[]" help="Invoice"
|
||||
context="{'group_by':'invoice_id'}"/>
|
||||
|
||||
<filter string="Product" icon="terp-product"
|
||||
domain="[]" help="Product"
|
||||
context="{'group_by':'product_id'}"/>
|
||||
<separator orientation="vertical"/>
|
||||
|
||||
<filter string="Substate" icon="terp-stage"
|
||||
domain="[]" context="{'group_by':'substate_id'}"/>
|
||||
|
||||
<filter string="Claim n°" icon="terp-emblem-documents"
|
||||
domain="[]" context="{'group_by':'claim_id'}"/>
|
||||
|
||||
<filter string="Priority"
|
||||
name="group_by_priority"
|
||||
domain="[]"
|
||||
context="{'group_by':'priority'}"
|
||||
help="Priority"/>
|
||||
|
||||
<filter string="State"
|
||||
name="group_by_state"
|
||||
domain="[]"
|
||||
context="{'group_by':'state'}"
|
||||
help="Grouping by state"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="crm_claim_line_tree_view">
|
||||
<field name="name">CRM - Claims Tree</field>
|
||||
<field name="model">claim.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Claim lines">
|
||||
<field name="claim_id" invisible="1"/>
|
||||
<field name="number"/>
|
||||
<field name="state"/>
|
||||
<field name="substate_id"/>
|
||||
<field name="product_id"/>
|
||||
<field name="name"/>
|
||||
<field name="prodlot_id"/>
|
||||
<field name="warning"/>
|
||||
<field name="warranty_type"/>
|
||||
<field name="warranty_return_partner"/>
|
||||
<button name="set_warranty" string="Compute Warranty" type="object" icon="gtk-justify-fill"/>
|
||||
<field name="product_returned_quantity"/>
|
||||
<field name="claim_origin"/>
|
||||
<field name="claim_diagnosis"/>
|
||||
<field name="refund_line_id"/>
|
||||
<field name="move_in_id"/>
|
||||
<field name="move_out_id"/>
|
||||
<field name="priority"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="crm_claim_line_form_view">
|
||||
<field name="name">CRM - Claim product return line Form</field>
|
||||
<field name="model">claim.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Claim Line" version="7.0">
|
||||
<header>
|
||||
<button name="set_warranty" string="Calculate warranty state" type="object" class="oe_highlight"/>
|
||||
<field name="state"
|
||||
widget="statusbar"/>
|
||||
</header>
|
||||
<sheet string="Claims">
|
||||
<div class="oe_title" colspan="4">
|
||||
<group>
|
||||
<h1>
|
||||
<field name="number" class="oe_inline"/>
|
||||
</h1>
|
||||
</group>
|
||||
</div>
|
||||
<separator string="Problem" colspan="4"/>
|
||||
<group col="6" colspan="4">
|
||||
<field name="name" colspan="6"/>
|
||||
<field name="product_id" readonly="1" colspan="6"/>
|
||||
<field name="prodlot_id" colspan="6"/>
|
||||
<field name="claim_origin" colspan="6"/>
|
||||
<field name="claim_diagnosis" colspan="6"/>
|
||||
<field name="priority" colspan="6"/>
|
||||
<field name="product_returned_quantity" invisible="1"/>
|
||||
<field name="unit_sale_price"/>
|
||||
<field name="return_value"/>
|
||||
</group>
|
||||
<group>
|
||||
<group string="Warranty">
|
||||
<field name="guarantee_limit" readonly="1"/>
|
||||
<field name="warning" readonly="1"/>
|
||||
<field name="warranty_type" readonly="1"/>
|
||||
<field name="warranty_return_partner"/>
|
||||
</group>
|
||||
<group string="Linked Document">
|
||||
<field name="claim_id" readonly="1"/>
|
||||
<field name="invoice_line_id" readonly="1"/>
|
||||
<field name="refund_line_id" readonly="1"/>
|
||||
<field name="move_in_id" readonly="1"/>
|
||||
<field name="move_out_id" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<separator string="State" colspan="4"/>
|
||||
<group col="6" colspan="4">
|
||||
<field name="substate_id" widget='selection'/>
|
||||
<field name="last_state_change"/>
|
||||
</group>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
A second slightly modified form view to be used for the claim_line_ids
|
||||
field in the crm.claim form view. Defining it here instead of directly
|
||||
inside the field allows us to write only the changes and reference it
|
||||
-->
|
||||
<record id="crm_claim_line_view_form_embedded" model="ir.ui.view">
|
||||
<field name="name">Claim line form view to be used inside claim tree</field>
|
||||
<field name="mode">primary</field>
|
||||
<field name="model">claim.line</field>
|
||||
<field name="priority" eval="30"/>
|
||||
<field name="inherit_id" ref="crm_claim_line_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="claim_id" position="attributes">
|
||||
<attribute name="readonly">1</attribute>
|
||||
</field>
|
||||
<field name="product_id" position="attributes">
|
||||
<attribute name="context">{'claim_id': parent.id, 'company_id': parent.company_id, 'warehouse_id':
|
||||
parent.warehouse_id, 'claim_type': parent.claim_type, 'claim_date': parent.date}
|
||||
</attribute>
|
||||
</field>
|
||||
<field name="invoice_line_id" position="attributes">
|
||||
<attribute name="context">{'claim_id': parent.id, 'company_id': parent.company_id, 'warehouse_id':
|
||||
parent.warehouse_id, 'claim_type': parent.claim_type, 'claim_date': parent.date}
|
||||
</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Claim lines action -->
|
||||
<record model="ir.actions.act_window" id="act_crm_case_claim_lines">
|
||||
<field name="name">Claim lines</field>
|
||||
<field name="res_model">claim.line</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="crm_claim_line_tree_view"/>
|
||||
<field name="search_view_id" ref="view_crm_claim_lines_filter"/>
|
||||
<field name="context">{'search_default_group_by_priority': True,
|
||||
'search_default_group_by_state': True}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Menu -->
|
||||
<menuitem
|
||||
name="Claim lines"
|
||||
id="menu_crm_case_claims_claim_lines"
|
||||
parent="base.menu_aftersale"
|
||||
action="act_crm_case_claim_lines"
|
||||
sequence="2"/>
|
||||
</odoo>
|
||||
291
crm_claim_rma/views/crm_claim.xml
Normal file
291
crm_claim_rma/views/crm_claim.xml
Normal file
@@ -0,0 +1,291 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<!-- CLAIM VIEWS -->
|
||||
<record model="ir.ui.view" id="crm_case_claims_tree_view">
|
||||
<field name="name">CRM - Claims Tree</field>
|
||||
<field name="model">crm.claim</field>
|
||||
<field name="inherit_id" ref="crm_claim.crm_case_claims_tree_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="stage_id" position="after">
|
||||
<field name="team_id"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<!-- Crm claim Search view -->
|
||||
<record id="view_crm_case_claims_filter" model="ir.ui.view">
|
||||
<field name="name">CRM - Claims Search</field>
|
||||
<field name="model">crm.claim</field>
|
||||
<field name="inherit_id" ref="crm_claim.view_crm_case_claims_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="/search/group/filter[position()=2]" position="after">
|
||||
<filter string="Sales Team" icon="terp-stock_symbol-selection"
|
||||
domain="[]"
|
||||
context="{'group_by':'team_id'}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Right side link to orders -->
|
||||
<act_window
|
||||
id="act_crm_claim_rma_sale_orders"
|
||||
name="Quotations and Sales"
|
||||
res_model="sale.order"
|
||||
src_model="crm.claim"/>
|
||||
|
||||
<act_window
|
||||
id="act_crm_claim_rma_purchase_orders"
|
||||
name="Purchases"
|
||||
res_model="purchase.order"
|
||||
src_model="crm.claim"/>
|
||||
|
||||
<act_window
|
||||
domain="[('type', 'in', ('in_invoice', 'out_invoice'))]"
|
||||
id="act_crm_claim_rma_invoice"
|
||||
name="Invoices"
|
||||
res_model="account.invoice"
|
||||
src_model="crm.claim"/>
|
||||
|
||||
<act_window
|
||||
id="act_crm_claim_rma_refunds"
|
||||
name="Refunds"
|
||||
res_model="account.invoice"
|
||||
src_model="crm.claim"
|
||||
domain="[('type', 'in', ('in_refund', 'out_refund'))]"/>
|
||||
|
||||
<act_window
|
||||
id="act_crm_claim_rma_picking_in"
|
||||
name="Incoming Shipment and Returns"
|
||||
res_model="stock.picking"
|
||||
src_model="crm.claim"/>
|
||||
|
||||
|
||||
<record model="ir.ui.view" id="crm_claim_rma_form_view">
|
||||
<field name="name">CRM - Claim product return Form</field>
|
||||
<field name="model">crm.claim</field>
|
||||
<field name="inherit_id" ref="crm_claim.crm_case_claims_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<!-- Header/workflow Buttons -->
|
||||
<xpath expr="//field[@name='stage_id']" position="before">
|
||||
<button name="%(action_claim_picking_in)d"
|
||||
string="New Products Return"
|
||||
class="oe_inline"
|
||||
type="action" target="new"
|
||||
context="{'warehouse_id': warehouse_id,
|
||||
'partner_id': partner_id}"/>
|
||||
|
||||
<button name="%(action_claim_picking_out)d"
|
||||
class="oe_inline"
|
||||
string="New Delivery"
|
||||
type="action" target="new"
|
||||
context="{'warehouse_id': warehouse_id,
|
||||
'partner_id': partner_id}"/>
|
||||
|
||||
<button name="%(account.action_account_invoice_refund)d"
|
||||
class="oe_inline"
|
||||
type='action' string='New Refund'
|
||||
context="{
|
||||
'invoice_ids': [invoice_id],
|
||||
'claim_line_ids': claim_line_ids,
|
||||
'description': name,
|
||||
'claim_id': id,
|
||||
}"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='team_id']/parent::group" position="replace">
|
||||
<group colspan="4" col="4" groups="base.group_user">
|
||||
<field name="warehouse_id"/>
|
||||
<field name="date"/>
|
||||
<field name="user_id"
|
||||
context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'base.group_sale_salesman_all_leads']}"/>
|
||||
<field name="priority" widget="priority"/>
|
||||
<field name="date_deadline"/>
|
||||
<field name="team_id"/>
|
||||
</group>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//field[@name='partner_id']" position="attributes">
|
||||
<attribute name="required">1</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='partner_phone']" position="attributes">
|
||||
<attribute name="required">1</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='email_from']" position="attributes">
|
||||
<attribute name="required">1</attribute>
|
||||
</xpath>
|
||||
|
||||
<!-- Smart buttons -->
|
||||
<xpath expr="//field[@name='name']/parent::group" position="before">
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button class="oe_stat_button"
|
||||
name="%(act_crm_claim_rma_sale_orders)d"
|
||||
type="action"
|
||||
icon="fa-strikethrough"
|
||||
string="Sales"
|
||||
attrs="{'invisible': ['|',('partner_id','=', False)]}"
|
||||
context="{'search_default_partner_id': [partner_id], 'search_default_user_id':False}"/>
|
||||
<button class="oe_stat_button"
|
||||
name="%(act_crm_claim_rma_purchase_orders)d"
|
||||
type="action"
|
||||
icon="fa-shopping-cart"
|
||||
string="Purchases"
|
||||
attrs="{'invisible': ['|',('partner_id','=', False)]}"
|
||||
context="{'search_default_partner_id': [partner_id],
|
||||
'search_default_user_id':False}"/>
|
||||
|
||||
<button class="oe_stat_button"
|
||||
name="%(act_crm_claim_rma_invoice)d"
|
||||
type="action"
|
||||
string="Invoices"
|
||||
icon="fa-pencil-square"
|
||||
attrs="{'invisible': ['|',('partner_id','=', False)]}"
|
||||
context="{'search_default_partner_id': [partner_id], 'group_by':'type', 'search_default_user_id':False}"/>
|
||||
|
||||
<button class="oe_stat_button"
|
||||
name="%(act_crm_claim_rma_refunds)d"
|
||||
type="action"
|
||||
string="Refunds"
|
||||
icon="fa-file-text"
|
||||
attrs="{'invisible': ['|',('partner_id','=', False), ('claim_type','in', ['customer','other'])]}"
|
||||
context="{'search_default_partner_id': [partner_id], 'group_by':'type', 'search_default_user_id':False}"/>
|
||||
|
||||
<button class="oe_stat_button"
|
||||
icon="fa-reply"
|
||||
name="%(act_crm_claim_rma_picking_in)d"
|
||||
type="action"
|
||||
string="Returns"
|
||||
attrs="{'invisible': ['|',('partner_id','=', False), ('claim_type','in', ['supplier','other'])]}"
|
||||
context="{'search_default_claim_id': active_id, 'search_default_user_id':False}"/>
|
||||
</div>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='name']/parent::group" position="replace">
|
||||
<div class="oe_title oe_left">
|
||||
<h1>
|
||||
<field name="code"/>
|
||||
</h1>
|
||||
<div class="oe_edit_only">
|
||||
<label for="name"/>
|
||||
</div>
|
||||
<h1>
|
||||
<small>
|
||||
<field name="name"/>
|
||||
</small>
|
||||
</h1>
|
||||
</div>
|
||||
</xpath>
|
||||
|
||||
<field name="email_from" position="after">
|
||||
<field name="pick" string="Pick the product in the store"/>
|
||||
<field name="delivery_address_id"
|
||||
string="Partner delivery address"
|
||||
domain="[('id','child_of',partner_id)]"
|
||||
attrs="{'invisible': ['|',('pick','=', True)],
|
||||
'required': [('pick','=', False)]}"
|
||||
context="{'tree_view_ref': 'crm_claim_rma.view_partner_contact_tree',
|
||||
'search_default_parent_id': partner_id}"/>
|
||||
<field name="invoice_id"
|
||||
domain="['|',('commercial_partner_id','=',partner_id),('partner_id','=',partner_id)]"
|
||||
context="{'create_lines': True}"/>
|
||||
</field>
|
||||
|
||||
<xpath expr="//field[@name='email_from']/parent::group" position="after">
|
||||
<div name="serial">
|
||||
<!-- Place for mass return button from crm_rma_lot_mass_return -->
|
||||
</div>
|
||||
<separator colspan="2" string="Product Returns"/>
|
||||
<field name="claim_line_ids">
|
||||
<tree string="Returned lines" create="false">
|
||||
<field name="claim_id" invisible="1"/>
|
||||
<field name="state"/>
|
||||
<field name="product_id"/>
|
||||
<field name="name"/>
|
||||
<field name="prodlot_id"/>
|
||||
<field name="invoice_line_id" invisible="True"/>
|
||||
<field name="warning"/>
|
||||
<field name="warranty_type"/>
|
||||
<button name="set_warranty" string="Compute Warranty"
|
||||
type="object" icon="gtk-justify-fill"/>
|
||||
<field name="product_returned_quantity"/>
|
||||
<field name="claim_origin"/>
|
||||
<field name="claim_diagnosis"/>
|
||||
<field name="location_dest_id" invisible="True"/>
|
||||
</tree>
|
||||
</field>
|
||||
</xpath>
|
||||
|
||||
<!-- New tabs for products return and generated documents -->
|
||||
<xpath expr="//field[@name='email_from']/ancestor::page" position="after">
|
||||
<page string="Generated Documents">
|
||||
<separator colspan="2" string="Refunds"/>
|
||||
<field name="invoice_ids" colspan="4" readonly="1"/>
|
||||
<separator colspan="2" string="Receptions / Deliveries"/>
|
||||
<field name="picking_ids" colspan="4" readonly="1"/>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record model="ir.actions.act_window" id="crm_claim.crm_claim_category_claim0">
|
||||
<field name="context">{"search_default_user_id":uid, "stage_type":'claim'}</field>
|
||||
</record>
|
||||
|
||||
<!-- substates action -->
|
||||
<record id="act_crm_claim_substates" model="ir.actions.act_window">
|
||||
<field name="name">Claim line substates</field>
|
||||
<field name="res_model">substate.substate</field>
|
||||
<field name="view_type">form</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
name="Claim line substates"
|
||||
id="menu_crm_case_claims_claim_line_substates"
|
||||
parent="crm_claim.menu_config_claim"
|
||||
action="act_crm_claim_substates"
|
||||
sequence="2"/>
|
||||
|
||||
<!-- Update account invoice !-->
|
||||
<record id="crm_claim_rma_form" model="ir.ui.view">
|
||||
<field name="name">CRM Claim RMA</field>
|
||||
<field name="model">crm.claim</field>
|
||||
<field name="inherit_id" ref="crm_claim.crm_case_claims_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<xpath expr="//field[@name='date_deadline']" position="after">
|
||||
<field name="rma_number"/>
|
||||
</xpath>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="search_crm_claim_rma_number" model="ir.ui.view">
|
||||
<field name="name">CRM - Claims Search</field>
|
||||
<field name="model">crm.claim</field>
|
||||
<field name="inherit_id" ref="crm_claim.view_crm_case_claims_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='name']" position="after">
|
||||
<field name="rma_number"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="tree_crm_claim_rma_number" model="ir.ui.view">
|
||||
<field name="name">CRM - Claims Tree</field>
|
||||
<field name="model">crm.claim</field>
|
||||
<field name="inherit_id" ref="crm_claim.crm_case_claims_tree_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='name']" position="after">
|
||||
<field name="rma_number"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="crm_case_claims_form_view">
|
||||
<field name="name">CRM - Claims Form</field>
|
||||
<field name="model">crm.claim</field>
|
||||
<field name="inherit_id" ref="crm_claim_type.crm_case_claims_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='claim_type']" position="attributes">
|
||||
<attribute name="context">{'create_lines': False}</attribute>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -1,409 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<!-- Claim line views -->
|
||||
<!-- SEARCH -->
|
||||
<record id="view_crm_claim_lines_filter" model="ir.ui.view">
|
||||
<field name="name">CRM - Claims Search</field>
|
||||
<field name="model">claim.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Claims">
|
||||
<filter icon="terp-check" string="Current" name="current"
|
||||
domain="[('state','in',('draft', 'refused', 'treated'))]"
|
||||
separator="1" help="Draft and Open Claims" />
|
||||
<filter icon="terp-camera_test"
|
||||
string="In Progress"
|
||||
domain="[('state','in',('confirmed','in_to_control','in_to_treate'))]"
|
||||
separator="1" help="In Progress Claims"/>
|
||||
<separator orientation="vertical"/>
|
||||
<field name="state" select='1'/>
|
||||
<field name="substate_id" select='1'/>
|
||||
<field name="name" select='1'/>
|
||||
<field name="warning" select='1'/>
|
||||
<field name="invoice_line_id" select='1'/>
|
||||
<field name="product_id" select='1'/>
|
||||
<field name="prodlot_id" select='1'/>
|
||||
<newline/>
|
||||
<group expand="0" string="More">
|
||||
<field name="last_state_change" select='1'/>
|
||||
<field name="guarantee_limit" select='1'/>
|
||||
<field name="return_value" select='1'/>
|
||||
<field name="name" select='1'/>
|
||||
</group>
|
||||
<newline/>
|
||||
<group expand="0" string="Group By...">
|
||||
<filter string="Invoice" icon="terp-dolar"
|
||||
domain="[]" help="Invoice"
|
||||
context="{'group_by':'invoice_id'}"/>
|
||||
<filter string="Product" icon="terp-product"
|
||||
domain="[]" help="Product"
|
||||
context="{'group_by':'product_id'}"/>
|
||||
<separator orientation="vertical"/>
|
||||
<filter string="Substate" icon="terp-stage"
|
||||
domain="[]" context="{'group_by':'substate_id'}"/>
|
||||
<filter string="Claim n°" icon="terp-emblem-documents"
|
||||
domain="[]" context="{'group_by':'claim_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- TREE -->
|
||||
<record model="ir.ui.view" id="crm_claim_line_tree_view">
|
||||
<field name="name">CRM - Claims Tree</field>
|
||||
<field name="model">claim.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Claim lines">
|
||||
<field name="claim_id" invisible="1"/>
|
||||
<field name="state"/>
|
||||
<field name="substate_id"/>
|
||||
<field name="product_id"/>
|
||||
<field name="name"/>
|
||||
<field name="prodlot_id"/>
|
||||
<field name="warning"/>
|
||||
<field name="warranty_type"/>
|
||||
<field name="warranty_return_partner"/>
|
||||
<button name="set_warranty" string="Compute Waranty" type="object" icon="gtk-justify-fill"/>
|
||||
<field name="product_returned_quantity"/>
|
||||
<field name="claim_origine"/>
|
||||
<field name="refund_line_id"/>
|
||||
<field name="move_in_id"/>
|
||||
<field name="move_out_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- FORM -->
|
||||
<record model="ir.ui.view" id="crm_claim_line_form_view">
|
||||
<field name="name">CRM - Claim product return line Form</field>
|
||||
<field name="model">claim.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Claim Line" version="7.0">
|
||||
<header>
|
||||
<button name="set_warranty" string="Calculate warranty state" type="object" class="oe_highlight"/>
|
||||
</header>
|
||||
<sheet string="Claims">
|
||||
<div class="oe_title">
|
||||
<group>
|
||||
<label for="name" class="oe_edit_only"/>
|
||||
<h1><field name="name"/></h1>
|
||||
</group>
|
||||
</div>
|
||||
<group>
|
||||
<group string="Returned good">
|
||||
<field name="product_returned_quantity"/>
|
||||
<field name="product_id" />
|
||||
<field name="prodlot_id"/>
|
||||
<field name="unit_sale_price"/>
|
||||
<field name="return_value"/>
|
||||
</group>
|
||||
<group string="Linked Document">
|
||||
<field name="claim_id"/>
|
||||
<field name="invoice_line_id"/>
|
||||
<field name="refund_line_id"/>
|
||||
<field name="move_in_id"/>
|
||||
<field name="move_out_id"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group string="Problem">
|
||||
<field name="claim_origine" nolabel="1" colspan="4"/>
|
||||
<field name="claim_descr" nolabel="1" colspan="4"/>
|
||||
</group>
|
||||
<group string="Warranty">
|
||||
<field name="guarantee_limit"/>
|
||||
<field name="warning"/>
|
||||
<field name="warranty_return_partner"/>
|
||||
<field name="warranty_type"/>
|
||||
</group>
|
||||
</group>
|
||||
<separator string="State" colspan="4"/>
|
||||
<group col="6" colspan="4">
|
||||
<field name="state"/>
|
||||
<field name="substate_id" widget='selection'/>
|
||||
<field name="last_state_change"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
A second slightly modified form view to be used for the claim_line_ids
|
||||
field in the crm.claim form view. Defining it here instead of directly
|
||||
inside the field allows us to write only the changes and reference it
|
||||
-->
|
||||
<record id="crm_claim_line_view_form_embedded" model="ir.ui.view">
|
||||
<field name="name">Claim line form view to be used inside claim tree</field>
|
||||
<field name="mode">primary</field>
|
||||
<field name="model">claim.line</field>
|
||||
<field name="priority" eval="30"/>
|
||||
<field name="inherit_id" ref="crm_claim_line_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="claim_id" position="attributes">
|
||||
<attribute name="readonly">1</attribute>
|
||||
</field>
|
||||
<field name="product_id" position="attributes">
|
||||
<attribute name="context">{'claim_id': parent.id, 'company_id': parent.company_id, 'warehouse_id': parent.warehouse_id, 'claim_type': parent.claim_type, 'claim_date': parent.date}</attribute>
|
||||
</field>
|
||||
<field name="invoice_line_id" position="attributes">
|
||||
<attribute name="context">{'claim_id': parent.id, 'company_id': parent.company_id, 'warehouse_id': parent.warehouse_id, 'claim_type': parent.claim_type, 'claim_date': parent.date}</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- CLAIM VIEWS -->
|
||||
<record model="ir.ui.view" id="crm_case_claims_tree_view">
|
||||
<field name="name">CRM - Claims Tree</field>
|
||||
<field name="model">crm.claim</field>
|
||||
<field name="inherit_id" ref="crm_claim.crm_case_claims_tree_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="stage_id" position="after">
|
||||
<field name="section_id"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Crm claim Search view -->
|
||||
<record id="view_crm_case_claims_filter" model="ir.ui.view">
|
||||
<field name="name">CRM - Claims Search</field>
|
||||
<field name="model">crm.claim</field>
|
||||
<field name="inherit_id" ref="crm_claim.view_crm_case_claims_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<filter string="Stage" icon="terp-stage" domain="[]" context="{'group_by':'stage_id'}" position="before">
|
||||
<filter string="Sales Team" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'section_id'}"/>
|
||||
</filter>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Right side link to orders -->
|
||||
<act_window
|
||||
id="act_crm_claim_rma_sale_orders"
|
||||
name="Quotations and Sales"
|
||||
res_model="sale.order"
|
||||
src_model="crm.claim"/>
|
||||
<!-- Right side link to invoices -->
|
||||
<act_window
|
||||
domain="[('type', '=', 'out_invoice')]"
|
||||
id="act_crm_claim_rma_invoice_out"
|
||||
name="Customer Invoices"
|
||||
res_model="account.invoice"
|
||||
src_model="crm.claim"/>
|
||||
<!-- Right side link to invoices -->
|
||||
<act_window
|
||||
domain="[('type', '=', 'in_invoice')]"
|
||||
id="act_crm_claim_rma_invoice_in"
|
||||
name="Supplier Invoices"
|
||||
res_model="account.invoice"
|
||||
src_model="crm.claim"/>
|
||||
<!-- Right side link to refunds -->
|
||||
<act_window
|
||||
domain="[('type', '=', 'out_refund')]"
|
||||
id="act_crm_claim_rma_refunds_out"
|
||||
name="Customer Refunds"
|
||||
res_model="account.invoice"
|
||||
src_model="crm.claim"/>
|
||||
<!-- Right side link to refunds -->
|
||||
<act_window
|
||||
domain="[('type', '=', 'in_refund')]"
|
||||
id="act_crm_claim_rma_refunds_in"
|
||||
name="Supplier Refunds"
|
||||
res_model="account.invoice"
|
||||
src_model="crm.claim"/>
|
||||
<!-- Right side link to picking in -->
|
||||
<act_window
|
||||
domain="[('picking_type_id.code', '=', 'incoming')]"
|
||||
id="act_crm_claim_rma_picking_in"
|
||||
name="Incoming Shipment and Returns"
|
||||
res_model="stock.picking"
|
||||
src_model="crm.claim"/>
|
||||
<!-- Right side link to picking out -->
|
||||
<act_window
|
||||
domain="[('picking_type_id.code', '=', 'outgoing')]"
|
||||
id="act_crm_claim_rma_picking_out"
|
||||
name="Deliveries"
|
||||
res_model="stock.picking"
|
||||
src_model="crm.claim"/>
|
||||
|
||||
<record model="ir.actions.act_window" id="crm_claim.crm_case_categ_claim0">
|
||||
<field name="context">{"search_default_user_id":uid, "stage_type":'claim'}</field>
|
||||
</record>
|
||||
|
||||
<!-- Claim lines action -->
|
||||
<record model="ir.actions.act_window" id="act_crm_case_claim_lines">
|
||||
<field name="name">Claim lines</field>
|
||||
<field name="res_model">claim.line</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="crm_claim_line_tree_view"/>
|
||||
<field name="search_view_id" ref="view_crm_claim_lines_filter"/>
|
||||
</record>
|
||||
|
||||
<!-- substates action -->
|
||||
<record id="act_crm_claim_substates" model="ir.actions.act_window">
|
||||
<field name="name">Claim line substates</field>
|
||||
<field name="res_model">substate.substate</field>
|
||||
<field name="view_type">form</field>
|
||||
</record>
|
||||
|
||||
<!-- Menu -->
|
||||
<menuitem
|
||||
name="Claim lines"
|
||||
id="menu_crm_case_claims_claim_lines"
|
||||
parent="base.menu_aftersale"
|
||||
action="act_crm_case_claim_lines"
|
||||
sequence="2"/>
|
||||
<menuitem
|
||||
name="Claim line substates"
|
||||
id="menu_crm_case_claims_claim_line_substates"
|
||||
parent="crm_claim.menu_config_claim"
|
||||
action="act_crm_claim_substates"
|
||||
sequence="2"/>
|
||||
|
||||
<record model="ir.ui.view" id="crm_case_claims_form_view">
|
||||
<field name="name">CRM - Claims Form</field>
|
||||
<field name="model">crm.claim</field>
|
||||
<field name="inherit_id" ref="crm_claim_type.crm_case_claims_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='claim_type']" position="attributes">
|
||||
<attribute name="context">{'create_lines': False}</attribute>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="crm_claim_rma_form_view">
|
||||
<field name="name">CRM - Claims Form</field>
|
||||
<field name="model">crm.claim</field>
|
||||
<field name="inherit_id" ref="crm_claim.crm_case_claims_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<!-- Header/workflow Buttons -->
|
||||
<field name="stage_id" position="before">
|
||||
<button
|
||||
name="%(action_claim_picking_in)d"
|
||||
type="action" string="New Products Return"
|
||||
attrs="{'invisible': [('partner_id','=', False)]}"
|
||||
context="{'warehouse_id': warehouse_id, 'partner_id': partner_id}"/>
|
||||
<button
|
||||
name="%(action_claim_picking_out)d"
|
||||
type="action"
|
||||
string="New Delivery"
|
||||
attrs="{'invisible': [('partner_id','=', False)]}"
|
||||
context="{'warehouse_id': warehouse_id, 'partner_id': partner_id}"/>
|
||||
<button
|
||||
name="%(account.action_account_invoice_refund)d"
|
||||
type='action'
|
||||
string='New Refund'
|
||||
attrs="{'invisible': [('invoice_id','=', False)]}"
|
||||
context="{'invoice_ids': [invoice_id], 'claim_line_ids': claim_line_ids, 'description': name, 'claim_id': id}"/>
|
||||
</field>
|
||||
<field name="date_deadline" position="after">
|
||||
<field name="warehouse_id" context="{'create_lines': False}"/>
|
||||
</field>
|
||||
<field name="date" position="replace"/>
|
||||
<field name="user_id" position="before">
|
||||
<field name="date" context="{'create_lines': False}"/>
|
||||
</field>
|
||||
<!-- Smart buttons -->
|
||||
<xpath expr="//sheet[@string='Claims']/group[1]" position="after">
|
||||
<div class="oe_right oe_button_box" style="width: 300px;" name="buttons">
|
||||
<button name="%(act_crm_claim_rma_sale_orders)d" type="action"
|
||||
string="Quotation/Sales"
|
||||
icon="fa-strikethrough"
|
||||
class="oe_stat_button"
|
||||
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in',
|
||||
[%(crm_claim_type.crm_claim_type_supplier)d,%(crm_claim_type.crm_claim_type_other)d])]}"
|
||||
context="{'search_default_partner_id': [partner_id],'search_default_user_id':False}"/>
|
||||
|
||||
<button name="%(act_crm_claim_rma_invoice_out)d" type="action"
|
||||
string="Invoices"
|
||||
icon="fa-pencil-square-o"
|
||||
class="oe_stat_button"
|
||||
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in',
|
||||
[%(crm_claim_type.crm_claim_type_supplier)d,%(crm_claim_type.crm_claim_type_other)d])]}"
|
||||
context="{'search_default_partner_id': [partner_id],'search_default_user_id':False}"/>
|
||||
|
||||
<button name="%(act_crm_claim_rma_refunds_out)d" type="action"
|
||||
string="Refunds"
|
||||
icon="fa-file-text-o"
|
||||
class="oe_stat_button"
|
||||
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in',
|
||||
[%(crm_claim_type.crm_claim_type_supplier)d,%(crm_claim_type.crm_claim_type_other)d])]}"
|
||||
context="{'search_default_partner_id': [partner_id],'search_default_user_id':False}"/>
|
||||
|
||||
<button name="%(act_crm_claim_rma_invoice_in)d" type="action"
|
||||
string="Invoices"
|
||||
icon="fa-pencil-square-o"
|
||||
class="oe_stat_button"
|
||||
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in',
|
||||
[%(crm_claim_type.crm_claim_type_customer)d,%(crm_claim_type.crm_claim_type_other)d])]}"
|
||||
context="{'search_default_partner_id': [partner_id],'search_default_user_id':False}"/>
|
||||
|
||||
<button name="%(act_crm_claim_rma_refunds_in)d" type="action"
|
||||
string="Refunds"
|
||||
icon="fa-file-text-o"
|
||||
class="oe_stat_button"
|
||||
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in',
|
||||
[%(crm_claim_type.crm_claim_type_customer)d,%(crm_claim_type.crm_claim_type_other)d])]}"
|
||||
context="{'search_default_partner_id': [partner_id],'search_default_user_id':False}"/>
|
||||
|
||||
<button name="%(act_crm_claim_rma_picking_in)d" type="action"
|
||||
string="Products"
|
||||
icon="fa-reply"
|
||||
class="oe_stat_button"
|
||||
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in',
|
||||
[%(crm_claim_type.crm_claim_type_customer)d,%(crm_claim_type.crm_claim_type_other)d])]}"
|
||||
context="{'search_default_claim_id': active_id,'search_default_user_id':False}"/>
|
||||
|
||||
<button name="%(act_crm_claim_rma_picking_out)d" type="action"
|
||||
string="Deliveries"
|
||||
icon="fa-truck"
|
||||
class="oe_stat_button"
|
||||
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in',
|
||||
[%(crm_claim_type.crm_claim_type_supplier)d,%(crm_claim_type.crm_claim_type_other)d])]}"
|
||||
context="{'search_default_partner_id': [partner_id],'search_default_user_id':False}"/>
|
||||
</div>
|
||||
</xpath>
|
||||
<xpath expr="//sheet[@string='Claims']/group[1]" position="replace">
|
||||
<div class="oe_title oe_left">
|
||||
<h1><field name="code"/></h1>
|
||||
<div class="oe_edit_only">
|
||||
<label for="name"/>
|
||||
</div>
|
||||
<h1><small><field name="name"/></small></h1>
|
||||
</div>
|
||||
</xpath>
|
||||
<!-- Remove domain and widget attributes -->
|
||||
<field name="categ_id" widget="selection" position="replace">
|
||||
<field name="categ_id"/>
|
||||
</field>
|
||||
<!-- New tabs for products return and generated documents -->
|
||||
<page string="Follow Up" position="before">
|
||||
<page string="Product Return">
|
||||
<group name="Product Return">
|
||||
<separator string="Product Return" colspan="4"/>
|
||||
<group>
|
||||
<field name="company_id" invisible="1"/>
|
||||
<field name="invoice_id" domain="['|',('commercial_partner_id','=',partner_id),('partner_id','=',partner_id)]" context="{'create_lines': True}"/>
|
||||
<field name="delivery_address_id" context="{'tree_view_ref': 'crm_claim_rma.view_partner_contact_tree', 'search_default_parent_id': partner_id}"/>
|
||||
</group>
|
||||
<div name="serial">
|
||||
<!-- Place for mass return button from crm_rma_lot_mass_return -->
|
||||
</div>
|
||||
<field
|
||||
name="claim_line_ids"
|
||||
nolabel="1"
|
||||
context="{'default_claim_id': active_id, 'form_view_ref': 'crm_claim_rma.crm_claim_line_view_form_embedded'}"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Generated Documents">
|
||||
<separator colspan="2" string="Refunds"/>
|
||||
<field name="invoice_ids" colspan="4" readonly="1"/>
|
||||
<separator colspan="2" string="Receptions / Deliveries"/>
|
||||
<field name="picking_ids" colspan="4" readonly="1"/>
|
||||
</page>
|
||||
</page>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,24 +1,22 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<!-- Address list with details to help shipping address selection -->
|
||||
<record id="view_partner_contact_tree" model="ir.ui.view">
|
||||
<field name="name">res.partner.contact.tree</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Contacts">
|
||||
<field name="name"/>
|
||||
<field name="function" invisible="1"/>
|
||||
<field name="street"/>
|
||||
<field name="zip"/>
|
||||
<field name="city"/>
|
||||
<field name="email"/>
|
||||
<field name="user_id" invisible="1"/>
|
||||
<field name="is_company" invisible="1"/>
|
||||
<field name="country_id"/>
|
||||
<field name="parent_id" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
<field name="name">res.partner.contact.tree</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Contacts">
|
||||
<field name="name"/>
|
||||
<field name="function" invisible="True"/>
|
||||
<field name="street"/>
|
||||
<field name="zip"/>
|
||||
<field name="city"/>
|
||||
<field name="email"/>
|
||||
<field name="user_id" invisible="True"/>
|
||||
<field name="is_company" invisible="True"/>
|
||||
<field name="country_id"/>
|
||||
<field name="parent_id" invisible="True"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
38
crm_claim_rma/views/stock_view.xml
Normal file
38
crm_claim_rma/views/stock_view.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- INHERITED VIEW FOR THE OBJECT : stock_picking -->
|
||||
<record id="picking_in_form" model="ir.ui.view">
|
||||
<field name="name">crm_claim_rma.picking_in_form</field>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='move_type']" position="after">
|
||||
<field name="claim_id"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<record id="stock_move_mail_thread" model="ir.ui.view">
|
||||
<field name="name">stock_move_mail_thread</field>
|
||||
<field name="model">stock.move</field>
|
||||
<field name="inherit_id" ref="stock.view_move_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//sheet" position="after">
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<!-- SEARCH -->
|
||||
<record id="view_picking_internal_search_claim_id" model="ir.ui.view">
|
||||
<field name="name">stock.picking.internal.search</field>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_internal_search"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//search" position="inside">
|
||||
<field name="claim_id" help="Moves created from claims"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -1,26 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright 2015 Eezee-It
|
||||
# Copyright 2013 Camptocamp
|
||||
# Copyright 2009-2013 Akretion,
|
||||
# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau,
|
||||
# Benoît Guillot, Joel Grand-Guillaume
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from . import claim_make_picking
|
||||
from . import account_invoice_refund
|
||||
|
||||
@@ -1,28 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright 2015 Eezee-It, MONK Software
|
||||
# Copyright 2013 Camptocamp
|
||||
# Copyright 2009-2013 Akretion,
|
||||
# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau,
|
||||
# Benoît Guillot, Joel Grand-Guillaume, Leonardo Donelli
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# © 2015 Vauxoo
|
||||
# © 2015 Eezee-It, MONK Software
|
||||
# © 2013 Camptocamp
|
||||
# © 2009-2013 Akretion,
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api
|
||||
from openerp import api, fields, models
|
||||
|
||||
|
||||
class AccountInvoiceRefund(models.TransientModel):
|
||||
@@ -33,8 +16,9 @@ class AccountInvoiceRefund(models.TransientModel):
|
||||
|
||||
description = fields.Char(default=_default_description)
|
||||
|
||||
@api.one
|
||||
@api.multi
|
||||
def compute_refund(self, mode='refund'):
|
||||
self.ensure_one()
|
||||
invoice_ids = self.env.context.get('invoice_ids', [])
|
||||
if invoice_ids:
|
||||
self = self.with_context(active_ids=invoice_ids)
|
||||
|
||||
@@ -1,26 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright 2015 Eezee-It, MONK Software
|
||||
# Copyright 2013 Camptocamp
|
||||
# Copyright 2009-2013 Akretion,
|
||||
# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau,
|
||||
# Benoît Guillot, Joel Grand-Guillaume, Leonardo Donelli
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# © 2015 Eezee-It, MONK Software
|
||||
# © 2013 Camptocamp
|
||||
# © 2009-2013 Akretion,
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import time
|
||||
|
||||
from openerp import models, fields, exceptions, api, _
|
||||
@@ -33,8 +16,7 @@ class ClaimMakePicking(models.TransientModel):
|
||||
|
||||
@api.returns('stock.location')
|
||||
def _get_common_dest_location_from_line(self, lines):
|
||||
"""
|
||||
If all the lines have the same destination location return that,
|
||||
""" If all the lines have the same destination location return that,
|
||||
else return an empty recordset
|
||||
"""
|
||||
dests = lines.mapped('location_dest_id')
|
||||
@@ -43,8 +25,7 @@ class ClaimMakePicking(models.TransientModel):
|
||||
|
||||
@api.returns('res.partner')
|
||||
def _get_common_partner_from_line(self, lines):
|
||||
"""
|
||||
If all the lines have the same warranty return partner return that,
|
||||
""" If all the lines have the same warranty return partner return that,
|
||||
else return an empty recordset
|
||||
"""
|
||||
partners = lines.mapped('warranty_return_partner')
|
||||
@@ -55,13 +36,8 @@ class ClaimMakePicking(models.TransientModel):
|
||||
def _default_claim_line_source_location_id(self):
|
||||
picking_type = self.env.context.get('picking_type')
|
||||
partner_id = self.env.context.get('partner_id')
|
||||
warehouse_id = self.env.context.get('warehouse_id')
|
||||
|
||||
if picking_type == 'out' and warehouse_id:
|
||||
return self.env['stock.warehouse'].browse(
|
||||
warehouse_id).lot_stock_id
|
||||
|
||||
if partner_id:
|
||||
if picking_type == 'in' and partner_id:
|
||||
partner = self.env['res.partner'].browse(partner_id)
|
||||
return partner.property_stock_customer
|
||||
|
||||
@@ -78,11 +54,6 @@ class ClaimMakePicking(models.TransientModel):
|
||||
picking_type = self.env.context.get('picking_type')
|
||||
partner_id = self.env.context.get('partner_id')
|
||||
|
||||
if isinstance(picking_type, int):
|
||||
picking_obj = self.env['stock.picking.type']
|
||||
return picking_obj.browse(picking_type)\
|
||||
.default_location_dest_id
|
||||
|
||||
if picking_type == 'out' and partner_id:
|
||||
return self.env['res.partner'].browse(
|
||||
partner_id).property_stock_customer
|
||||
@@ -100,35 +71,28 @@ class ClaimMakePicking(models.TransientModel):
|
||||
# TODO use custom states to show buttons of this wizard or not instead
|
||||
# of raise an error
|
||||
picking_type = self.env.context.get('picking_type')
|
||||
if isinstance(picking_type, int):
|
||||
picking_obj = self.env['stock.picking.type']
|
||||
if picking_obj.\
|
||||
browse(picking_type).\
|
||||
code == 'incoming':
|
||||
picking_type = 'in'
|
||||
else:
|
||||
picking_type = 'out'
|
||||
|
||||
move_field = ('move_in_id'
|
||||
if picking_type == 'in'
|
||||
else 'move_out_id')
|
||||
move_field = 'move_in_id' if picking_type == 'in' else 'move_out_id'
|
||||
domain = [('claim_id', '=', self.env.context['active_id'])]
|
||||
lines = self.env['claim.line'].\
|
||||
search(domain)
|
||||
if lines:
|
||||
domain = domain + [
|
||||
'|', (move_field, '=', False),
|
||||
(move_field+'.state', '=', 'cancel')
|
||||
]
|
||||
domain = domain + ['|', (move_field, '=', False),
|
||||
(move_field + '.state', '=', 'cancel')]
|
||||
lines = lines.search(domain)
|
||||
if not lines:
|
||||
raise exceptions.Warning(
|
||||
_('Error'),
|
||||
_('A picking has already been created for this claim.'))
|
||||
raise exceptions.UserError(
|
||||
_('A picking has already been created for this claim.')
|
||||
)
|
||||
return lines
|
||||
|
||||
delivery_warehouse_id = fields.Many2one(
|
||||
'stock.warehouse', string='Source Warehouse',
|
||||
default=lambda self: self.env.context.get('warehouse_id'),
|
||||
help="Warehouse where to take the replacement products for customers.",
|
||||
)
|
||||
|
||||
claim_line_source_location_id = fields.Many2one(
|
||||
'stock.location', string='Source Location', required=True,
|
||||
'stock.location', string='Source Location',
|
||||
default=_default_claim_line_source_location_id,
|
||||
help="Location where the returned products are from.")
|
||||
|
||||
@@ -159,7 +123,6 @@ class ClaimMakePicking(models.TransientModel):
|
||||
'state': 'draft',
|
||||
'date': time.strftime(DT_FORMAT),
|
||||
'partner_id': partner_id,
|
||||
'invoice_state': "none",
|
||||
'company_id': claim.company_id.id,
|
||||
'location_id': self.claim_line_source_location_id.id,
|
||||
'location_dest_id': self.claim_line_dest_location_id.id,
|
||||
@@ -186,34 +149,17 @@ class ClaimMakePicking(models.TransientModel):
|
||||
'note': self._get_picking_note(),
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def action_create_picking(self):
|
||||
|
||||
context = self._context
|
||||
picking_type = self.env.context.get('picking_type')
|
||||
if isinstance(picking_type, int):
|
||||
picking_obj = self.env['stock.picking.type']
|
||||
picking_type_rec = picking_obj.browse(picking_type)
|
||||
if picking_type_rec.code == 'incoming':
|
||||
picking_type = 'in'
|
||||
elif picking_type_rec.code == 'outgoing':
|
||||
picking_type = 'out'
|
||||
else:
|
||||
picking_type = 'int'
|
||||
|
||||
warehouse_obj = self.env['stock.warehouse']
|
||||
warehouse_rec = warehouse_obj.browse(context.get('warehouse_id'))
|
||||
if picking_type == 'out':
|
||||
picking_type = warehouse_rec.out_type_id
|
||||
write_field = 'move_out_id'
|
||||
elif picking_type == 'in':
|
||||
def _create_picking(self, claim, picking_type):
|
||||
warehouse_rec = self.env['stock.warehouse'].browse(
|
||||
self.env.context.get('warehouse_id')
|
||||
)
|
||||
if picking_type == 'in':
|
||||
picking_type = warehouse_rec.in_type_id
|
||||
write_field = 'move_in_id'
|
||||
else:
|
||||
picking_type = warehouse_rec.int_type_id
|
||||
write_field = 'move_out_id'
|
||||
|
||||
claim = self.env['crm.claim'].browse(self.env.context['active_id'])
|
||||
partner_id = claim.delivery_address_id.id
|
||||
claim_lines = self.claim_line_ids
|
||||
|
||||
@@ -224,21 +170,21 @@ class ClaimMakePicking(models.TransientModel):
|
||||
common_dest_location = self._get_common_dest_location_from_line(
|
||||
claim_lines)
|
||||
if not common_dest_location:
|
||||
raise Warning(
|
||||
_('Error'),
|
||||
raise exceptions.UserError(
|
||||
_('A product return cannot be created for various '
|
||||
'destination locations, please choose line with a '
|
||||
'same destination location.'))
|
||||
'same destination location.')
|
||||
)
|
||||
|
||||
claim_lines.auto_set_warranty()
|
||||
common_dest_partner = self._get_common_partner_from_line(
|
||||
claim_lines)
|
||||
if not common_dest_partner:
|
||||
raise exceptions.Warning(
|
||||
_('Error'),
|
||||
raise exceptions.UserError(
|
||||
_('A product return cannot be created for various '
|
||||
'destination addresses, please choose line with a '
|
||||
'same address.'))
|
||||
'same address.')
|
||||
)
|
||||
partner_id = common_dest_partner.id
|
||||
|
||||
# create picking
|
||||
@@ -258,10 +204,9 @@ class ClaimMakePicking(models.TransientModel):
|
||||
domain = ("[('picking_type_id', '=', %s), ('partner_id', '=', %s)]" %
|
||||
(picking_type.id, partner_id))
|
||||
|
||||
view_obj = self.env['ir.ui.view']
|
||||
view_id = view_obj.search([('model', '=', 'stock.picking'),
|
||||
('type', '=', 'form'),
|
||||
])[0]
|
||||
view_id = self.env['ir.ui.view'].search(
|
||||
[('model', '=', 'stock.picking'),
|
||||
('type', '=', 'form')])[0]
|
||||
return {
|
||||
'name': self._get_picking_name(),
|
||||
'view_type': 'form',
|
||||
@@ -273,6 +218,44 @@ class ClaimMakePicking(models.TransientModel):
|
||||
'type': 'ir.actions.act_window',
|
||||
}
|
||||
|
||||
def _create_procurement(self, claim):
|
||||
""" Create a procurement order for each line in this claim and put
|
||||
all procurements in a procurement group linked to this claim.
|
||||
|
||||
:type claim: crm_claim
|
||||
"""
|
||||
group = self.env['procurement.group'].create({
|
||||
'name': claim.code,
|
||||
'claim_id': claim.id,
|
||||
'move_type': 'direct',
|
||||
})
|
||||
|
||||
for line in self.claim_line_ids:
|
||||
procurement = self.env['procurement.order'].create({
|
||||
'name': line.product_id.name_template,
|
||||
'group_id': group.id,
|
||||
'origin': claim.code,
|
||||
'warehouse_id': self.delivery_warehouse_id.id,
|
||||
'date_planned': time.strftime(DT_FORMAT),
|
||||
'product_id': line.product_id.id,
|
||||
'product_qty': line.product_returned_quantity,
|
||||
'product_uom': line.product_id.product_tmpl_id.uom_id.id,
|
||||
'location_id': self.claim_line_dest_location_id.id,
|
||||
'company_id': claim.company_id.id,
|
||||
})
|
||||
procurement.run()
|
||||
|
||||
@api.multi
|
||||
def action_create_picking(self):
|
||||
claim = self.env['crm.claim'].browse(self.env.context['active_id'])
|
||||
picking_type = self.env.context.get('picking_type')
|
||||
|
||||
if picking_type == 'out':
|
||||
return self._create_procurement(claim)
|
||||
|
||||
else:
|
||||
return self._create_picking(claim, picking_type)
|
||||
|
||||
@api.multi
|
||||
def action_cancel(self):
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
@@ -5,54 +5,54 @@
|
||||
Copyright (C) 2011 Akretion Benoît GUILLOT <benoit.guillot@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_claim_picking" model="ir.ui.view">
|
||||
<field name="name">claim_picking</field>
|
||||
<field name="model">claim_make_picking.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Select exchange lines to add in picking" version="7.0">
|
||||
<group name="locations" string="Locations">
|
||||
<field name="claim_line_source_location_id"/>
|
||||
<field name="claim_line_dest_location_id"/>
|
||||
</group>
|
||||
<separator string="Select lines for picking"/>
|
||||
<field name="claim_line_ids" nolabel="1"/>
|
||||
<footer>
|
||||
<button
|
||||
<odoo>
|
||||
<record id="view_claim_picking" model="ir.ui.view">
|
||||
<field name="name">claim_picking</field>
|
||||
<field name="model">claim_make_picking.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Select exchange lines to add in picking">
|
||||
<group name="locations" string="Locations">
|
||||
<field name="delivery_warehouse_id" invisible="context.get('picking_type') != 'out'"
|
||||
required="context.get('picking_type') == 'out'"/>
|
||||
<field name="claim_line_source_location_id" invisible="context.get('picking_type') == 'out'"
|
||||
required="context.get('picking_type') != 'out'"/>
|
||||
<field name="claim_line_dest_location_id"/>
|
||||
</group>
|
||||
<separator string="Select lines for picking"/>
|
||||
<field name="claim_line_ids" nolabel="1"/>
|
||||
<footer>
|
||||
<button
|
||||
string="Create picking"
|
||||
name="action_create_picking" type="object"
|
||||
class="oe_highlight"/>
|
||||
or
|
||||
<button name="action_cancel"
|
||||
string="Cancel" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
or
|
||||
<button name="action_cancel"
|
||||
string="Cancel" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_claim_picking_in" model="ir.actions.act_window">
|
||||
<field name="name">Return Products</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">claim_make_picking.wizard</field>
|
||||
<field name="src_model">crm.claim</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="context">{'picking_type': 'in','product_return': True}</field>
|
||||
</record>
|
||||
<record id="action_claim_picking_in" model="ir.actions.act_window">
|
||||
<field name="name">Return Products</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">claim_make_picking.wizard</field>
|
||||
<field name="src_model">crm.claim</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="context">{'picking_type': 'in','product_return': True}</field>
|
||||
</record>
|
||||
|
||||
<record id="action_claim_picking_out" model="ir.actions.act_window">
|
||||
<field name="name">Create Outgoing Shipments</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">claim_make_picking.wizard</field>
|
||||
<field name="src_model">crm.claim</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="context">{'picking_type': 'out'}</field>
|
||||
</record>
|
||||
<record id="action_claim_picking_out" model="ir.actions.act_window">
|
||||
<field name="name">Create Outgoing Shipments</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">claim_make_picking.wizard</field>
|
||||
<field name="src_model">crm.claim</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="context">{'picking_type': 'out'}</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
Reference in New Issue
Block a user