From a73d6957197002b1230cd502b4930d3a620ec10d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Vall=C3=A9s=20Fuster?= Date: Tue, 12 Mar 2024 17:17:40 +0100 Subject: [PATCH] [MIG] rma: migration to 17.0 [IMP] rma: test fixes --- rma/README.rst | 171 ++ rma/__init__.py | 5 + rma/__manifest__.py | 39 + rma/data/rma_operation.xml | 45 + rma/data/rma_sequence.xml | 42 + rma/data/stock_data.xml | 206 ++ rma/demo/stock_demo.xml | 115 ++ rma/i18n/es.po | 1785 +++++++++++++++++ rma/i18n/rma.pot | 1779 ++++++++++++++++ rma/models/__init__.py | 12 + rma/models/procurement_group.py | 37 + rma/models/product.py | 22 + rma/models/product_category.py | 30 + rma/models/res_company.py | 14 + rma/models/res_config_settings.py | 22 + rma/models/res_partner.py | 27 + rma/models/rma_operation.py | 96 + rma/models/rma_order.py | 322 +++ rma/models/rma_order_line.py | 807 ++++++++ rma/models/stock_move.py | 107 + rma/models/stock_rule.py | 40 + rma/models/stock_warehouse.py | 270 +++ rma/pyproject.toml | 3 + rma/readme/CONFIGURE.rst | 41 + rma/readme/CONTRIBUTORS.rst | 8 + rma/readme/DESCRIPTION.rst | 18 + rma/readme/ROADMAP.rst | 6 + rma/readme/USAGE.rst | 12 + rma/report/report_deliveryslip.xml | 57 + rma/report/rma_report.xml | 24 + rma/report/rma_report_templates.xml | 268 +++ rma/security/ir.model.access.csv | 25 + rma/security/rma.xml | 93 + rma/static/description/icon.png | Bin 0 -> 4261 bytes rma/tests/__init__.py | 4 + rma/tests/test_rma.py | 1089 ++++++++++ rma/views/product_view.xml | 54 + rma/views/res_config_settings_views.xml | 74 + rma/views/res_partner_view.xml | 28 + rma/views/rma_menu.xml | 148 ++ rma/views/rma_operation_view.xml | 89 + rma/views/rma_order_line_view.xml | 547 +++++ rma/views/rma_order_view.xml | 327 +++ rma/views/stock_view.xml | 26 + rma/views/stock_warehouse.xml | 22 + rma/wizards/__init__.py | 4 + rma/wizards/rma_add_serial.py | 157 ++ rma/wizards/rma_add_serial_views.xml | 102 + rma/wizards/rma_add_stock_move.py | 199 ++ rma/wizards/rma_add_stock_move_view.xml | 188 ++ rma/wizards/rma_make_picking.py | 290 +++ rma/wizards/rma_make_picking_view.xml | 137 ++ .../rma_order_line_make_supplier_rma.py | 202 ++ .../rma_order_line_make_supplier_rma_view.xml | 77 + 54 files changed, 10312 insertions(+) create mode 100644 rma/README.rst create mode 100644 rma/__init__.py create mode 100644 rma/__manifest__.py create mode 100644 rma/data/rma_operation.xml create mode 100644 rma/data/rma_sequence.xml create mode 100644 rma/data/stock_data.xml create mode 100644 rma/demo/stock_demo.xml create mode 100644 rma/i18n/es.po create mode 100644 rma/i18n/rma.pot create mode 100644 rma/models/__init__.py create mode 100644 rma/models/procurement_group.py create mode 100644 rma/models/product.py create mode 100644 rma/models/product_category.py create mode 100644 rma/models/res_company.py create mode 100644 rma/models/res_config_settings.py create mode 100644 rma/models/res_partner.py create mode 100644 rma/models/rma_operation.py create mode 100644 rma/models/rma_order.py create mode 100644 rma/models/rma_order_line.py create mode 100644 rma/models/stock_move.py create mode 100644 rma/models/stock_rule.py create mode 100644 rma/models/stock_warehouse.py create mode 100644 rma/pyproject.toml create mode 100644 rma/readme/CONFIGURE.rst create mode 100644 rma/readme/CONTRIBUTORS.rst create mode 100644 rma/readme/DESCRIPTION.rst create mode 100644 rma/readme/ROADMAP.rst create mode 100644 rma/readme/USAGE.rst create mode 100644 rma/report/report_deliveryslip.xml create mode 100644 rma/report/rma_report.xml create mode 100644 rma/report/rma_report_templates.xml create mode 100644 rma/security/ir.model.access.csv create mode 100644 rma/security/rma.xml create mode 100644 rma/static/description/icon.png create mode 100644 rma/tests/__init__.py create mode 100644 rma/tests/test_rma.py create mode 100644 rma/views/product_view.xml create mode 100644 rma/views/res_config_settings_views.xml create mode 100644 rma/views/res_partner_view.xml create mode 100644 rma/views/rma_menu.xml create mode 100644 rma/views/rma_operation_view.xml create mode 100644 rma/views/rma_order_line_view.xml create mode 100644 rma/views/rma_order_view.xml create mode 100644 rma/views/stock_view.xml create mode 100644 rma/views/stock_warehouse.xml create mode 100644 rma/wizards/__init__.py create mode 100644 rma/wizards/rma_add_serial.py create mode 100644 rma/wizards/rma_add_serial_views.xml create mode 100644 rma/wizards/rma_add_stock_move.py create mode 100644 rma/wizards/rma_add_stock_move_view.xml create mode 100644 rma/wizards/rma_make_picking.py create mode 100644 rma/wizards/rma_make_picking_view.xml create mode 100644 rma/wizards/rma_order_line_make_supplier_rma.py create mode 100644 rma/wizards/rma_order_line_make_supplier_rma_view.xml diff --git a/rma/README.rst b/rma/README.rst new file mode 100644 index 00000000..65f83cb7 --- /dev/null +++ b/rma/README.rst @@ -0,0 +1,171 @@ +====================================== +RMA (Return Merchandise Authorization) +====================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:320013d460e1f02cfc3ff65322457095d8a01aa5d18f2e850b3c7174c16b9bdd + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2F-lightgray.png?logo=github + :target: https://github.com/OCA//tree/17.0/rma + :alt: OCA/ +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/-17-0/-17-0-rma + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +A Return Merchandise Authorization (RMA), is a part of the process of +returning a product in order to receive a refund, replacement, or repair +during the product's warranty period. + +The purchaser of the product must contact the manufacturer (or distributor +or retailer) to obtain authorization to return the product. + +The resulting RMA number must be displayed on or included in the returned +product's packaging. + +The issuance of an RMA is a key gatekeeping moment in the reverse logistics +cycle, providing the vendor with a final opportunity to diagnose and correct +the customer's problem with the product (such as improper installation or +configuration) before the customer permanently relinquishes ownership +of the product to the manufacturer, commonly referred to as a return. + +As returns are costly for the vendor and inconvenient for the customer, +any return that can be prevented benefits both parties. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +Security +-------- + +Go to Settings > Users and assign the appropiate permissions to users. +Different security groups grant distinct levels of access to the RMA features. + +* Users in group "RMA Customer User" or "RMA Supplier User" can access to, + create and process RMA's associated to customers or suppliers respectively. + +* Users in group "RMA Manager" can access to, create, approve and process RMA's + associated to both customers and suppliers. + +RMA Approval Policy +------------------- + +There are two RMA approval policies in product catogories: + +* One step: Always auto-approve RMAs that only contain products within + categories with this policy. +* Two steps: A RMA order containing a product within a category with this + policy will request the RMA manager approval. + +In order to change the approval policy of a product category follow the next +steps: + +#. Go to *Inventory > Configuration > Products > Product Categories*. +#. Select one and change the field *RMA Approval Policy* to your convenience. + +Other Settings +-------------- + +#. Go to RMA > Configuration > Settings > Return Merchandising + Authorization and select the option "Display 3 fields on rma: partner, + invoice address, delivery address" if needed. +#. Go to RMA > Configuration > Warehouse management > Warehouses and add + a default RMA location and RMA picking type for customers and suppliers RMA + picking type. In case the warehouse is configured to use routes, you need to + create at least one route per rma type with at least two push rules (one for + inbound another for outbound) it's very important to select the type of + operation supplier if we are moving in the company and customer if we are + moving out of the company. + +Usage +===== + +RMA are accessible though Inventory menu. There's four menus, divided by type. +Users can access to the list of RMA or RMA lines. + +Create an RMA: + +#. Select a partner. Enter RMA lines associated to an existing picking, or + manually. +#. Request approval and approve. +#. Click on RMA Lines button. +#. Click on more and select an option: "Receive products", "Create Delivery + Order". +#. Go back to the RMA. Set the RMA to done if not further action is required. + +Known issues / Roadmap +====================== + +* Picking operations report in customer RMA dropshipping case is showing + "Vendor Address" while it should be "Customer Address". +* Dropshipping always counted as a delivery on the smart buttons. +* Uninstall hook. +* Constraints instead of required fields on rma.order.line. +* Rename type field on rma.order and rma.order.line + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* ForgeFlow + +Contributors +~~~~~~~~~~~~ + +* Jordi Ballester Alomar +* Aaron Henriquez +* Lois Rilo +* Bhavesh Odedra +* Akim Juillerat +* Alexandre Fayolle +* Chafique Delli +* Héctor Villarreal + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +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. + +This module is part of the `OCA/ `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/rma/__init__.py b/rma/__init__.py new file mode 100644 index 00000000..79030e0e --- /dev/null +++ b/rma/__init__.py @@ -0,0 +1,5 @@ +# Copyright (C) 2017-20 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from . import models +from . import wizards diff --git a/rma/__manifest__.py b/rma/__manifest__.py new file mode 100644 index 00000000..b1aad662 --- /dev/null +++ b/rma/__manifest__.py @@ -0,0 +1,39 @@ +# Copyright (C) 2017-20 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +{ + "name": "RMA (Return Merchandise Authorization)", + "version": "17.0.1.0.0", + "license": "LGPL-3", + "category": "RMA", + "summary": "Introduces the return merchandise authorization (RMA) process in odoo", + "author": "ForgeFlow", + "website": "https://github.com/OCA/", + "depends": ["stock", "mail", "web"], + "demo": ["demo/stock_demo.xml"], + "data": [ + "security/rma.xml", + "security/ir.model.access.csv", + "data/rma_sequence.xml", + "data/stock_data.xml", + "data/rma_operation.xml", + "report/rma_report.xml", + "report/rma_report_templates.xml", + "views/rma_order_view.xml", + "views/rma_operation_view.xml", + "views/rma_order_line_view.xml", + "views/stock_view.xml", + "views/stock_warehouse.xml", + "views/product_view.xml", + "views/res_partner_view.xml", + "views/res_config_settings_views.xml", + "views/rma_menu.xml", + "wizards/rma_make_picking_view.xml", + "wizards/rma_add_stock_move_view.xml", + "wizards/rma_order_line_make_supplier_rma_view.xml", + "report/report_deliveryslip.xml", + "wizards/rma_add_serial_views.xml", + ], + "installable": True, + "application": True, +} diff --git a/rma/data/rma_operation.xml b/rma/data/rma_operation.xml new file mode 100644 index 00000000..92e3fec0 --- /dev/null +++ b/rma/data/rma_operation.xml @@ -0,0 +1,45 @@ + + + + Replace After Receive + RPL-C + ordered + received + customer + + + + + + Replace + RPL-S + ordered + ordered + supplier + + + + + + Dropship - Deliver to vendor + DS-RPL-C + ordered + no + customer + + + + + + + Dropship - Deliver to customer + DS-RPL-S + no + ordered + supplier + + + + + + diff --git a/rma/data/rma_sequence.xml b/rma/data/rma_sequence.xml new file mode 100644 index 00000000..db71c5ca --- /dev/null +++ b/rma/data/rma_sequence.xml @@ -0,0 +1,42 @@ + + + + Customer RMA sequence + rma.order.customer + 5 + RMAG/%(year)s/ + + + + + + Supplier RMA sequence + rma.order.supplier + 5 + RTVG/%(year)s/ + + + + + + + Customer RMA Line sequence + rma.order.line.customer + 5 + RMA/%(year)s/ + + + + + + + Supplier RMA Line sequence + rma.order.line.supplier + 5 + RTV/%(year)s/ + + + + + + diff --git a/rma/data/stock_data.xml b/rma/data/stock_data.xml new file mode 100644 index 00000000..d8dfe694 --- /dev/null +++ b/rma/data/stock_data.xml @@ -0,0 +1,206 @@ + + + + WH RMA + internal + + + + + DOC + RCO + 5 + + + + + INC + RCI + 5 + + + + + DOS + RSO + 5 + + + + + INS + RSI + 5 + + + + + DSS + DSS + 5 + + + + + RMA → Customer + + RMA → Customer + + + + outgoing + + + + Customer → RMA + + Customer → RMA + + + + incoming + + + + RMA -> Supplier + + RMA -> Supplier + + + + outgoing + + + + Supplier -> RMA + + Supplier -> RMA + + + + incoming + + + + Customer -> Supplier + + Customer -> Supplier + + + + incoming + + + + Supplier -> Customer + + Supplier -> Customer + + + + incoming + + + + + + + + + + + + RMA Customer + + 10 + + + + + + + + RMA Supplier + + 10 + + + + + + + + RMA Dropship + + 10 + + + + + + + + Customer → RMA + pull + + + + make_to_stock + + + + + + RMA → Customer + pull + + + + make_to_stock + + + + + + RMA → Supplier + pull + + + + make_to_stock + + + + + + Supplier → RMA + pull + + + + make_to_stock + + + + + + Customer → Supplier + pull + + + make_to_stock + + + + + + Supplier → Customer + pull + + + make_to_stock + + + + + diff --git a/rma/demo/stock_demo.xml b/rma/demo/stock_demo.xml new file mode 100644 index 00000000..a7554c01 --- /dev/null +++ b/rma/demo/stock_demo.xml @@ -0,0 +1,115 @@ + + + + + + RMA Customer Sequence out + RMA/CUST/OUT + 5 + + + + + RMA Customer Sequence in + RMA/CUST/IN + 5 + + + + + RMA Supplier Sequence out + RMA/SUPP/OUT + 5 + + + + + RMA Supplier Sequence in + RMA/SUPP/IN + 5 + + + + + RMA Dropship + RMA/DS + 5 + + + + + + Customer -> Supplier + + + + + incoming + + + + Supplier -> Customer + + + + + incoming + + + + + RMA Customer + 10 + + + + + + + + RMA Supplier + 10 + + + + + + + + RMA Dropship + 10 + + + + + + + + + Customer → Supplier + pull + + + + make_to_stock + + + + + + Supplier → Customer + pull + + + + make_to_stock + + + + + + + + + + diff --git a/rma/i18n/es.po b/rma/i18n/es.po new file mode 100644 index 00000000..29e59b71 --- /dev/null +++ b/rma/i18n/es.po @@ -0,0 +1,1785 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * rma +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-11-07 07:37+0000\n" +"PO-Revision-Date: 2022-11-07 07:37+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" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__out_shipment_count +msgid "# of Deliveries" +msgstr "# de entregas" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__out_shipment_count +msgid "# of Outgoing Shipments" +msgstr "# de envíos salientes" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__line_count +msgid "# of RMA lines" +msgstr "# de líneas RMA" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__rma_line_count +msgid "# of RMA lines associated" +msgstr "# de líneas RMA asociadas" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__in_shipment_count +#: model:ir.model.fields,field_description:rma.field_rma_order_line__in_shipment_count +msgid "# of Shipments" +msgstr "# de envíos" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__supplier_line_count +msgid "# of Supplier RMAs" +msgstr "# de RMA de proveedores" + +#. module: rma +#: model:ir.actions.report,print_report_name:rma.rma_order_line_report +msgid "('RMA - %s' % (object.name))" +msgstr "('RMA - %s' % (object.name)" + +#. module: rma +#: model:ir.actions.report,print_report_name:rma.rma_order_report +msgid "('RMA Group - %s' % (object.name))" +msgstr "('Grupo RMA - %s' % (object.name)" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Contact Person:" +msgstr "Persona de contacto:" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Date Ordered:" +msgstr "Fecha de pedido:" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Operation:" +msgstr "Operación:" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Origin Reference:" +msgstr "Referencia de origen:" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_delivery_document +msgid "RMA" +msgstr "RMA" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +msgid "Reference:" +msgstr "Referencia:" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Shipping address:" +msgstr "Dirección de envío:" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_needaction +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_needaction +msgid "Action Needed" +msgstr "Acción necesaria" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__active +msgid "Active" +msgstr "Activo" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_button_supplier_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer_form +msgid "Add From Stock Move" +msgstr "Añadir desde movimiento de existencias" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_customer_form +msgid "Add Lot/Serial Numbers" +msgstr "Agregar números de lote/serie" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_button_supplier_form +msgid "Add Lot/Serial numbers" +msgstr "Agregar números de lote/serie" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_add_serial_wiz_supplier +msgid "Add from Lot/Serial Number" +msgstr "Agregar desde números de lote/serie" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_add_serial_wiz_customer +msgid "Add from Lot/Serial Numbers" +msgstr "Agregar desde números de lote/serie" + +#. module: rma +#: code:addons/rma/wizards/rma_add_stock_move.py:0 +#: model:ir.actions.act_window,name:rma.action_rma_add_stock_move_customer +#: model:ir.actions.act_window,name:rma.action_rma_add_stock_move_supplier +#, python-format +msgid "Add from Stock Move" +msgstr "Añadir desde movimiento de existencias" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order_line__name +#: model:ir.model.fields,help:rma.field_rma_order_line_make_supplier_rma_item__name +msgid "Add here the supplier RMA #. Otherwise an internal code is assigned." +msgstr "Agregue aquí el número de RMA del proveedor. De lo contrario, se asigna un código interno." + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__comment +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +msgid "Additional Information" +msgstr "Información Adicional" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__customer_address_id +#: model:ir.model.fields,help:rma.field_rma_order_line__customer_address_id +msgid "Address of the customer in case of Supplier RMA operation dropship." +msgstr "Dirección del cliente en caso de operación Dropship de RMA de Proveedor." + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__supplier_address_id +#: model:ir.model.fields,help:rma.field_rma_order_line__supplier_address_id +msgid "Address of the supplier in case of Customer RMA operation dropship." +msgstr "Dirección del proveedor en caso de operación de envío directo de RMA del Cliente." + +#. module: rma +#: model:res.groups,name:rma.group_rma_delivery_invoice_address +msgid "Addresses in RMA" +msgstr "Direcciones en RMA" + +#. module: rma +#: code:addons/rma/models/rma_order.py:0 +#, python-format +msgid "All grouped RMA's should have same partner." +msgstr "Todos los RMA agrupados deben tener el mismo socio." + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Approve" +msgstr "Aprobada" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_order__state__approved +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__state__approved +msgid "Approved" +msgstr "Aprobada" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.rma_operation_form +msgid "Archived" +msgstr "Archivado" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__assigned_to +#: model:ir.model.fields,field_description:rma.field_rma_order_line__assigned_to +msgid "Assigned To" +msgstr "Asignado a" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_attachment_count +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_attachment_count +msgid "Attachment Count" +msgstr "Recuento de archivos adjuntos" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Back to Approved" +msgstr "Volver a Aprovado" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Back to Draft" +msgstr "Volver al borrador" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_operation__receipt_policy__delivered +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__receipt_policy__delivered +msgid "Based on Delivered Quantities" +msgstr "Basado en las cantidades entregadas" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_operation__delivery_policy__ordered +#: model:ir.model.fields.selection,name:rma.selection__rma_operation__receipt_policy__ordered +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__delivery_policy__ordered +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__receipt_policy__ordered +msgid "Based on Ordered Quantities" +msgstr "Basado en las cantidades pedidas" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_operation__delivery_policy__received +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__delivery_policy__received +msgid "Based on Received Quantities" +msgstr "Basado en las cantidades recibidas" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_supplier +#: model_terms:ir.ui.view,arch_db:rma.view_rma_order_line_make_supplier_rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_picking +#: model_terms:ir.ui.view,arch_db:rma.view_rma_picking_out +msgid "Cancel" +msgstr "Cancelar" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__code +msgid "Code" +msgstr "Código" + +#. module: rma +#: model:ir.model,name:rma.model_res_company +msgid "Companies" +msgstr "Compañías" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__company_id +#: model:ir.model.fields,field_description:rma.field_rma_order__company_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__company_id +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Company" +msgstr "Compañía" + +#. module: rma +#: model:ir.model,name:rma.model_res_config_settings +msgid "Config Settings" +msgstr "Ajustes de configuración" + +#. module: rma +#: model:ir.ui.menu,name:rma.menu_rma_config +msgid "Configuration" +msgstr "Configuración" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_supplier +#: model_terms:ir.ui.view,arch_db:rma.view_rma_picking +#: model_terms:ir.ui.view,arch_db:rma.view_rma_picking_out +msgid "Confirm" +msgstr "Confirmar" + +#. module: rma +#: model:ir.model,name:rma.model_res_partner +#: model_terms:ir.ui.view,arch_db:rma.view_rma_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_form +msgid "Contact" +msgstr "Contacto" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_picking_out +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_button_form +msgid "Create Delivery" +msgstr "Crear entrega" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_picking_in +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_button_form +msgid "Create Incoming Shipment" +msgstr "Crear envío entrante" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_order_line_make_supplier_rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_supplier_rma_button_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_order_line_make_supplier_rma +msgid "Create Supplier RMA" +msgstr "Crear RMA del proveedor" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_order_line_make_supplier_rma +msgid "Create/Update Supplier RMA" +msgstr "Crear/Actualizar RMA de proveedor" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__create_uid +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__create_uid +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard__create_uid +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__create_uid +#: model:ir.model.fields,field_description:rma.field_rma_operation__create_uid +#: model:ir.model.fields,field_description:rma.field_rma_order__create_uid +#: model:ir.model.fields,field_description:rma.field_rma_order_line__create_uid +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__create_uid +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__create_date +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__create_date +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard__create_date +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__create_date +#: model:ir.model.fields,field_description:rma.field_rma_operation__create_date +#: model:ir.model.fields,field_description:rma.field_rma_order__create_date +#: model:ir.model.fields,field_description:rma.field_rma_order_line__create_date +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__create_date +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__create_date +msgid "Created on" +msgstr "Creado en" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__currency_id +msgid "Currency" +msgstr "Moneda" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_operation__type__customer +#: model:ir.model.fields.selection,name:rma.selection__rma_order__type__customer +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__type__customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_tree +msgid "Customer" +msgstr "Cliente" + +#. module: rma +#: model:stock.picking.type,name:rma.picking_type_rma_dropship_return +msgid "Customer -> Supplier" +msgstr "Cliente -> Proveedor" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__customer_address_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__customer_address_id +msgid "Customer Address" +msgstr "Dirección del cliente" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_operation_customer +#: model:ir.ui.menu,name:rma.menu_rma_operation_customer +msgid "Customer Operations" +msgstr "Operaciones del cliente" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_customer_lines +#: model:ir.ui.menu,name:rma.menu_customer_rma +#: model:ir.ui.menu,name:rma.menu_rma_line_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_supplier_form +msgid "Customer RMA" +msgstr "RMA del cliente" + +#. module: rma +#: code:addons/rma/models/stock_warehouse.py:0 +#, python-format +msgid "Customer RMA Deliveries" +msgstr "Entregas RMA del cliente" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_customer +#: model:ir.ui.menu,name:rma.menu_rma_act_customer +msgid "Customer RMA Group" +msgstr "Grupo RMa del cliente" + +#. module: rma +#: code:addons/rma/models/stock_warehouse.py:0 +#, python-format +msgid "Customer RMA Receipts" +msgstr "Recibos RMA del cliente" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__customer_rma_id +msgid "Customer RMA line" +msgstr "Línea RMA del cliente" + +#. module: rma +#: model:stock.picking.type,name:rma.picking_type_rma_cust_in +#: model:stock.rule,name:rma.rule_rma_customer_in_pull +msgid "Customer → RMA" +msgstr "Cliente → RMA" + +#. module: rma +#: model:stock.rule,name:rma.rule_rma_dropship_return +msgid "Customer → Supplier" +msgstr "Cliente → Proveedor" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Customer:" +msgstr "Cliente:" + +#. module: rma +#: model:ir.ui.menu,name:rma.rma_res_partner_menu_customer +msgid "Customers" +msgstr "Clientes" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +msgid "Date" +msgstr "Fecha" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_product_category__rma_customer_operation_id +#: model:ir.model.fields,field_description:rma.field_product_product__rma_customer_operation_id +#: model:ir.model.fields,field_description:rma.field_product_template__rma_customer_operation_id +msgid "Default RMA Customer Operation" +msgstr "Operación de cliente RMA predeterminada" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_product_category__rma_supplier_operation_id +#: model:ir.model.fields,field_description:rma.field_product_product__rma_supplier_operation_id +#: model:ir.model.fields,field_description:rma.field_product_template__rma_supplier_operation_id +msgid "Default RMA Supplier Operation" +msgstr "Operación de proveedor de RMA predeterminada" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__partner_shipping_id +msgid "Deliver To" +msgstr "Entregar a" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_form +msgid "Deliveries" +msgstr "Entregas" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__delivery_policy +#: model:ir.model.fields,field_description:rma.field_rma_order_line__delivery_policy +msgid "Delivery Policy" +msgstr "Entregas" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__name +#: model:ir.model.fields,field_description:rma.field_rma_order_line__description +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +#: model_terms:ir.ui.view,arch_db:rma.rma_operation_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Description" +msgstr "Descripción" + +#. module: rma +#: model:ir.model.fields,help:rma.field_res_company__group_rma_delivery_address +#: model:ir.model.fields,help:rma.field_res_config_settings__group_rma_delivery_address +msgid "Display 3 fields on rma: partner, invoice address, delivery address" +msgstr "Mostrar 3 campos en rma: socio, dirección de facturación, dirección de entrega" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.res_config_settings_view_form +msgid "Display 3 fields on rma: partner, invoice address, delivery address." +msgstr "Mostrar 3 campos en rma: socio, dirección de facturación, dirección de entrega." + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__display_name +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__display_name +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard__display_name +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__display_name +#: model:ir.model.fields,field_description:rma.field_rma_operation__display_name +#: model:ir.model.fields,field_description:rma.field_rma_order__display_name +#: model:ir.model.fields,field_description:rma.field_rma_order_line__display_name +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__display_name +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__display_name +msgid "Display Name" +msgstr "Nombre para mostrar" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_order__state__done +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__state__done +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Done" +msgstr "Hecho" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_order__state__draft +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__state__draft +msgid "Draft" +msgstr "Borrador" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.res_config_settings_view_form +msgid "Enable RMA invoicing" +msgstr "Habilitar facturación RMA" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order_line__product_tracking +msgid "Ensure the traceability of a storable product in your warehouse." +msgstr "Asegure la trazabilidad de un producto almacenable en su almacén." + +#. module: rma +#: code:addons/rma/wizards/rma_order_line_make_supplier_rma.py:0 +#, python-format +msgid "Enter a positive quantity." +msgstr "Introduzca una cantidad positiva." + +#. module: rma +#: code:addons/rma/wizards/rma_order_line_make_supplier_rma.py:0 +#, python-format +msgid "Enter a supplier." +msgstr "Introduce un proveedor." + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_order_line_make_supplier_rma +msgid "Existing Supplier RMA to update:" +msgstr "Proveedor existente RMA para actualizar:" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_follower_ids +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_follower_ids +msgid "Followers" +msgstr "Seguidor" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_partner_ids +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_partner_ids +msgid "Followers (Partners)" +msgstr "Seguidores (Socios)" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "General" +msgstr "General" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order_line__sequence +msgid "Gives the sequence of this line when displaying the rma." +msgstr "Da la secuencia de esta línea al mostrar el rma." + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_filter +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "Group By" +msgstr "Agrupar por" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__name +msgid "Group Number" +msgstr "Número de grupo" + +#. module: rma +#: model:ir.model.fields,help:rma.field_res_company__group_rma_lines +#: model:ir.model.fields,help:rma.field_res_config_settings__group_rma_lines +#: model_terms:ir.ui.view,arch_db:rma.res_config_settings_view_form +msgid "Group RMA lines in one RMA group" +msgstr "Agrupar líneas de RMA en un grupo de RMA" + +#. module: rma +#: code:addons/rma/models/rma_order.py:0 +#: code:addons/rma/models/rma_order_line.py:0 +#, python-format +msgid "Group partner and RMA's partner must be the same." +msgstr "El socio del grupo y el socio de RMA deben ser el mismo." + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__has_message +#: model:ir.model.fields,field_description:rma.field_rma_order_line__has_message +msgid "Has Message" +msgstr "Tiene mensaje" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__id +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__id +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard__id +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__id +#: model:ir.model.fields,field_description:rma.field_rma_operation__id +#: model:ir.model.fields,field_description:rma.field_rma_order__id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__id +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__id +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__id +msgid "ID" +msgstr "Identidad" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__message_needaction +#: model:ir.model.fields,help:rma.field_rma_order__message_unread +#: model:ir.model.fields,help:rma.field_rma_order_line__message_needaction +#: model:ir.model.fields,help:rma.field_rma_order_line__message_unread +msgid "If checked, new messages require your attention." +msgstr "Si está marcado, los nuevos mensajes requieren su atención." + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__message_has_error +#: model:ir.model.fields,help:rma.field_rma_order__message_has_sms_error +#: model:ir.model.fields,help:rma.field_rma_order_line__message_has_error +#: model:ir.model.fields,help:rma.field_rma_order_line__message_has_sms_error +msgid "If checked, some messages have a delivery error." +msgstr "Si está marcada, algunos mensajes tienen un error de entrega." + +#. module: rma +#: model:ir.model.fields,help:rma.field_stock_warehouse__rma_in_this_wh +msgid "" +"If set, it will create RMA location, picking types and routes for this " +"warehouse." +msgstr "Si se configura, creará una ubicación de RMA, tipos de selección y rutas para este " +"almacén." + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.rma_operation_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_form +msgid "Inbound" +msgstr "Entrante" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__in_route_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__in_route_id +msgid "Inbound Route" +msgstr "Ruta entrante" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__in_warehouse_id +#: model:ir.model.fields,field_description:rma.field_rma_order__in_warehouse_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__in_warehouse_id +msgid "Inbound Warehouse" +msgstr "Almacén de entrada" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__qty_incoming +msgid "Incoming Qty" +msgstr "Cantidad entrante" + +#. module: rma +#: model:ir.model,name:rma.model_stock_location_route +msgid "Inventory Routes" +msgstr "Rutas de inventario" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_is_follower +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_is_follower +msgid "Is Follower" +msgstr "Es seguidor" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard__item_ids +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__item_ids +msgid "Items" +msgstr "Elementos" + +#. module: rma +#: model:ir.model,name:rma.model_rma_make_picking_wizard_item +msgid "Items to receive" +msgstr "Artiulos para recibir" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz____last_update +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move____last_update +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard____last_update +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item____last_update +#: model:ir.model.fields,field_description:rma.field_rma_operation____last_update +#: model:ir.model.fields,field_description:rma.field_rma_order____last_update +#: model:ir.model.fields,field_description:rma.field_rma_order_line____last_update +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma____last_update +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item____last_update +msgid "Last Modified on" +msgstr "Última modificación el" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__write_uid +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__write_uid +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard__write_uid +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__write_uid +#: model:ir.model.fields,field_description:rma.field_rma_operation__write_uid +#: model:ir.model.fields,field_description:rma.field_rma_order__write_uid +#: model:ir.model.fields,field_description:rma.field_rma_order_line__write_uid +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__write_uid +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__write_uid +msgid "Last Updated by" +msgstr "Última actualización por" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__write_date +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__write_date +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard__write_date +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__write_date +#: model:ir.model.fields,field_description:rma.field_rma_operation__write_date +#: model:ir.model.fields,field_description:rma.field_rma_order__write_date +#: model:ir.model.fields,field_description:rma.field_rma_order_line__write_date +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__write_date +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__write_date +msgid "Last Updated on" +msgstr "Última actualización en" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__lot_id +msgid "Lot/Serial Number" +msgstr "Número de lote/serie" + +#. module: rma +#: code:addons/rma/wizards/rma_add_serial.py:0 +#, python-format +msgid "Lot/Serial Number %s already added." +msgstr "Número de lote/serie %s ya agregado." + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__lot_domain_ids +msgid "Lots Domain" +msgstr "Lotes Dominio" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__lot_ids +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__lot_ids +msgid "Lots/Serials selected" +msgstr "Lotes/Serie seleccionados" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_main_attachment_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_main_attachment_id +msgid "Main Attachment" +msgstr "Archivo adjunto principal" + +#. module: rma +#: model:ir.ui.menu,name:rma.menu_rma_rma_control +msgid "Master Data" +msgstr "Master Data" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_has_error +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_has_error +msgid "Message Delivery error" +msgstr "Error de entrega de mensajes" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_ids +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_ids +msgid "Messages" +msgstr "Mensajes" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "My RMAs" +msgstr "Mis RMA" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_order_line_make_supplier_rma +msgid "New RMA details:" +msgstr "Nuevos detalles de RMA:" + +#. module: rma +#: code:addons/rma/wizards/rma_make_picking.py:0 +#, python-format +msgid "No deliveries needed for this operation" +msgstr "No se necesitan entregas para esta operación" + +#. module: rma +#: code:addons/rma/wizards/rma_make_picking.py:0 +#, python-format +msgid "No quantity to transfer on %(arg1)s shipment of product %(arg2)s." +msgstr "No hay cantidad para transferir en %a envío de productos." + +#. module: rma +#: code:addons/rma/wizards/rma_make_picking.py:0 +#, python-format +msgid "No route specified" +msgstr "Sin ruta especificada" + +#. module: rma +#: code:addons/rma/models/procurement_group.py:0 +#, python-format +msgid "" +"No rule found for this product %(product)s and location %(location)s that is" +" valid for RMA operations." +msgstr "No se encontró ninguna regla para este producto %(product)s y" +" ubicación %(location)s que sea válida para operaciones de RMA." + +#. module: rma +#: code:addons/rma/wizards/rma_make_picking.py:0 +#, python-format +msgid "No shipments needed for this operation" +msgstr "No se necesitan envíos para esta operación" + +#. module: rma +#: code:addons/rma/wizards/rma_make_picking.py:0 +#, python-format +msgid "No warehouse specified" +msgstr "No se especifica almacén" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_operation__delivery_policy__no +#: model:ir.model.fields.selection,name:rma.selection__rma_operation__receipt_policy__no +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__delivery_policy__no +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__receipt_policy__no +msgid "Not required" +msgstr "No requerido" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_needaction_counter +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_needaction_counter +msgid "Number of Actions" +msgstr "Número de acciones" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_has_error_counter +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_has_error_counter +msgid "Number of errors" +msgstr "Número de errores" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__message_needaction_counter +#: model:ir.model.fields,help:rma.field_rma_order_line__message_needaction_counter +msgid "Number of messages which requires an action" +msgstr "Número de mensajes que requieren una acción" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__message_has_error_counter +#: model:ir.model.fields,help:rma.field_rma_order_line__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "Número de mensajes con error de entrega" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__message_unread_counter +#: model:ir.model.fields,help:rma.field_rma_order_line__message_unread_counter +msgid "Number of unread messages" +msgstr "Número de mensajes no leídos" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__product_category__rma_approval_policy__one_step +msgid "One step" +msgstr "Un paso" + +#. module: rma +#: code:addons/rma/wizards/rma_make_picking.py:0 +#, python-format +msgid "Only RMA lines from the same partner can be processed at the same time" +msgstr "Solo las líneas RMA del mismo socio se pueden procesar al mismo tiempo" + +#. module: rma +#: code:addons/rma/wizards/rma_order_line_make_supplier_rma.py:0 +#, python-format +msgid "" +"Only RMA lines from the same supplier can be processed at the same time" +msgstr "Solo las líneas RMA del mismo proveedor se pueden procesar al mismo tiempo" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__operation_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__operation_id +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "Operation" +msgstr "Operación" + +#. module: rma +#: model:ir.model.fields,help:rma.field_product_category__rma_approval_policy +#: model:ir.model.fields,help:rma.field_product_product__rma_approval_policy +#: model:ir.model.fields,help:rma.field_product_template__rma_approval_policy +msgid "" +"Options: \n" +" * One step: Always auto-approve RMAs that only contain products within categories with this policy.\n" +"* Two steps: A RMA containing a product within a category with this policy will request the RMA manager approval." +msgstr "Opciones: \n" +"* Un paso: Siempre apruebe automáticamente las RMA que solo contengan productos dentro de categorías con esta política.\n" +"* Dos pasos: una RMA que contenga un producto dentro de una categoría con esta política solicitará la aprobación del administrador de RMA" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__date_rma +msgid "Order Date" +msgstr "Fecha de orden" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Origin" +msgstr "Origen" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__reference_move_id +msgid "Originating Stock Move" +msgstr "Movimiento de existencias de origen" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Other Info" +msgstr "Otra información" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.rma_operation_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_form +msgid "Outbound" +msgstr "Saliente" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__out_route_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__out_route_id +msgid "Outbound Route" +msgstr "Ruta de salida" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__out_warehouse_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__out_warehouse_id +msgid "Outbound Warehouse" +msgstr "Almacén de salida" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__qty_outgoing +msgid "Outgoing Qty" +msgstr "Cantidad saliente" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__partner_id +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__partner_id +#: model:ir.model.fields,field_description:rma.field_rma_order__partner_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__partner_id +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_filter +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "Partner" +msgstr "Socio" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__reference +msgid "Partner Reference" +msgstr "Referencia de socios" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__delivery_address_id +msgid "Partner delivery address" +msgstr "Dirección de entrega del socio" + +#. module: rma +#: model:ir.ui.menu,name:rma.menu_rma_config_partners +msgid "Partners" +msgstr "Socios" + +#. module: rma +#: code:addons/rma/wizards/rma_add_serial.py:0 +#: code:addons/rma/wizards/rma_add_stock_move.py:0 +#: code:addons/rma/wizards/rma_order_line_make_supplier_rma.py:0 +#, python-format +msgid "Please define a warehouse with a default RMA location" +msgstr "Defina un almacén con una ubicación RMA predeterminada" + +#. module: rma +#: code:addons/rma/models/rma_order_line.py:0 +#, python-format +msgid "Please define a warehouse with a default RMA location." +msgstr "Defina un almacén con una ubicación RMA predeterminada." + +#. module: rma +#: code:addons/rma/wizards/rma_add_serial.py:0 +#: code:addons/rma/wizards/rma_add_stock_move.py:0 +#: code:addons/rma/wizards/rma_order_line_make_supplier_rma.py:0 +#, python-format +msgid "Please define an RMA route" +msgstr "Defina una ruta RMA" + +#. module: rma +#: code:addons/rma/models/rma_order_line.py:0 +#, python-format +msgid "Please define an RMA route." +msgstr "Defina una ruta RMA." + +#. module: rma +#: code:addons/rma/wizards/rma_add_serial.py:0 +#: code:addons/rma/wizards/rma_add_stock_move.py:0 +#, python-format +msgid "Please define an operation first" +msgstr "Por favor, defina una operación primero" + +#. module: rma +#: code:addons/rma/models/rma_order_line.py:0 +#, python-format +msgid "Please define an operation first." +msgstr "Por favor, defina una operación primero." + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.rma_operation_form +msgid "Policies" +msgstr "Políticas" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__price_unit +msgid "Price Unit" +msgstr "Precio unitario" + +#. module: rma +#: model:ir.model,name:rma.model_procurement_group +msgid "Procurement Group" +msgstr "Grupo de Adquisiciones" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__product_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__product_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__product_id +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "Product" +msgstr "Producto" + +#. module: rma +#: code:addons/rma/models/rma_order_line.py:0 +#, python-format +msgid "" +"Product %s has serial tracking configuration, quantity to receive should be " +"1" +msgstr "El producto %s tiene una configuración de seguimiento en serie, la cantidad a recibir debe ser " +"1" + +#. module: rma +#: model:ir.model,name:rma.model_product_category +msgid "Product Category" +msgstr "Categoria de producto" + +#. module: rma +#: model:ir.model,name:rma.model_product_template +msgid "Product Template" +msgstr "Plantilla de producto" + +#. module: rma +#: model:ir.ui.menu,name:rma.rma_product_product_menu +msgid "Product Variants" +msgstr "Variantes del producto" + +#. module: rma +#: model:ir.ui.menu,name:rma.menu_rma_config_stock +msgid "Products" +msgstr "Productos" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__qty_delivered +msgid "Qty Delivered" +msgstr "Cantidad entregada" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__qty_received +msgid "Qty Received" +msgstr "Cantidad recibida" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__qty_to_deliver +msgid "Qty To Deliver" +msgstr "Cantidad a entregar" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__qty_to_receive +msgid "Qty To Receive" +msgstr "Cantidad a recibir" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__qty_in_supplier_rma +msgid "Qty in Supplier RMA" +msgstr "Cantidad en proveedor RMA" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__qty_to_supplier_rma +msgid "Qty to send to Supplier RMA" +msgstr "Cantidad para enviar al proveedor RMA" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Quantities" +msgstr "Cantidades" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__product_qty +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Quantity" +msgstr "Cantidad" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__product_qty +msgid "Quantity Ordered" +msgstr "Cantidad ordenada" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__qty_to_deliver +msgid "Quantity To Deliver" +msgstr "Cantidad a entregar" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__qty_to_receive +msgid "Quantity to Receive" +msgstr "Cantidad a recibir" + +#. module: rma +#: model:ir.actions.report,name:rma.rma_order_line_report +#: model:ir.model,name:rma.model_rma_order_line +#: model:ir.model.fields,field_description:rma.field_procurement_group__rma_id +#: model:ir.module.category,name:rma.module_category_rma +#: model:ir.ui.menu,name:rma.menu_rma_root +#: model_terms:ir.ui.view,arch_db:rma.res_config_settings_view_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_form +msgid "RMA" +msgstr "RMA" + +#. module: rma +#: code:addons/rma/wizards/rma_make_picking.py:0 +#, python-format +msgid "RMA %s is not approved" +msgstr "RMA %s no está aprobado" + +#. module: rma +#: model:stock.picking.type,name:rma.picking_type_rma_sup_out +msgid "RMA -> Supplier" +msgstr "RMA -> Proveedor" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_product_category__rma_approval_policy +#: model:ir.model.fields,field_description:rma.field_product_product__rma_approval_policy +#: model:ir.model.fields,field_description:rma.field_product_template__rma_approval_policy +msgid "RMA Approval Policy" +msgstr "Política de aprobación de RMA" + +#. module: rma +#: model:stock.location.route,name:rma.route_rma_customer +msgid "RMA Customer" +msgstr "Cliente RMA" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_customer_in_pull_id +msgid "RMA Customer In Rule" +msgstr "Cliente RMA en regla" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_customer_out_pull_id +msgid "RMA Customer Out Rule" +msgstr "Regla de salida del cliente de RMA" + +#. module: rma +#: model:res.groups,name:rma.group_rma_customer_user +msgid "RMA Customer User" +msgstr "Usuario del cliente de RMA" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_cust_in_type_id +msgid "RMA Customer in Type" +msgstr "Cliente RMA en tipo" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_cust_out_type_id +msgid "RMA Customer out Type" +msgstr "Tipo de salida de cliente RMA" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_filter +msgid "RMA Date" +msgstr "Fecha RMA" + +#. module: rma +#: model:stock.location.route,name:rma.route_rma_dropship +msgid "RMA Dropship" +msgstr "Entrega directa de RMA" + +#. module: rma +#: model:ir.actions.report,name:rma.rma_order_report +#: model:ir.model,name:rma.model_rma_order +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__rma_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__rma_id +msgid "RMA Group" +msgstr "Grupo RMA" + +#. module: rma +#: model:res.groups,name:rma.group_rma_groups +msgid "RMA Groups" +msgstr "Grupos RMA" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__line_id +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "RMA Line" +msgstr "Línea RMA" + +#. module: rma +#: model:ir.model,name:rma.model_rma_order_line_make_supplier_rma +msgid "RMA Line Make Supplier RMA" +msgstr "RMA Línea Marca Proveedor RMA" + +#. module: rma +#: model:ir.model,name:rma.model_rma_order_line_make_supplier_rma_item +msgid "RMA Line Make Supplier RMA Item" +msgstr "Línea RMA Marca Proveedor Artículo RMA" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_form +msgid "RMA Lines" +msgstr "Líneas RMA" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__lot_rma_id +msgid "RMA Location" +msgstr "Ubicación RMA" + +#. module: rma +#: model:res.groups,name:rma.group_rma_manager +msgid "RMA Manager" +msgstr "Gerente de RMA" + +#. module: rma +#: model:ir.model,name:rma.model_rma_operation +msgid "RMA Operation" +msgstr "Operación RMA" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.rma_operation_form +msgid "RMA Operations" +msgstr "Operaciones RMA" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__rma_id +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__rma_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__rma_id +msgid "RMA Order" +msgstr "Pedido RMA" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.stock_location_route_form_view_inherit_rma_stock +msgid "RMA Order Lines" +msgstr "Líneas de pedido RMA" + +#. module: rma +#: model:stock.location.route,name:rma.route_rma_supplier +msgid "RMA Supplier" +msgstr "Proveedor RMA" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_supplier_in_pull_id +msgid "RMA Supplier In Rule" +msgstr "Proveedor RMA en regla" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_supplier_out_pull_id +msgid "RMA Supplier Out Rule" +msgstr "Regla de salida del proveedor de RMA" + +#. module: rma +#: model:res.groups,name:rma.group_rma_supplier_user +msgid "RMA Supplier User" +msgstr "Usuario proveedor RMA" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_sup_in_type_id +msgid "RMA Supplier in Type" +msgstr "Proveedor RMA en Tipo" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_sup_out_type_id +msgid "RMA Supplier out Type" +msgstr "Tipo de salida del proveedor de RMA" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_res_company__group_rma_delivery_address +#: model:ir.model.fields,field_description:rma.field_res_config_settings__group_rma_delivery_address +msgid "RMA addresses" +msgstr "Direcciones RMA" + +#. module: rma +#: code:addons/rma/models/rma_order_line.py:0 +#, python-format +msgid "RMA customer and originating stock move customer doesn't match." +msgstr "El cliente de RMA y el cliente de movimiento de existencias de origen no coincid" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_in_this_wh +msgid "RMA in this Warehouse" +msgstr "RMA en este Almacén" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_res_config_settings__module_rma_account +msgid "RMA invoicing" +msgstr "Facturación RMA" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_procurement_group__rma_line_id +#: model:ir.model.fields,field_description:rma.field_stock_move__rma_line_id +msgid "RMA line" +msgstr "Línea RMA" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__rma_line_ids +#: model:ir.model.fields,field_description:rma.field_rma_order__rma_line_ids +msgid "RMA lines" +msgstr "Líneas RMA" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__line_id +msgid "RMA order Line" +msgstr "Línea de pedido RMA" + +#. module: rma +#: model:stock.picking.type,name:rma.picking_type_rma_cust_out +#: model:stock.rule,name:rma.rule_rma_customer_out_pull +msgid "RMA → Customer" +msgstr "RMA → Cliente" + +#. module: rma +#: model:stock.rule,name:rma.rule_rma_supplier_out_pull +msgid "RMA → Supplier" +msgstr "RMA → Proveedor" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_res_partner__rma_line_ids +#: model:ir.model.fields,field_description:rma.field_res_users__rma_line_ids +#: model_terms:ir.ui.view,arch_db:rma.view_partner_form +msgid "RMAs" +msgstr "RMAs" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__receipt_policy +#: model:ir.model.fields,field_description:rma.field_rma_order_line__receipt_policy +msgid "Receipt Policy" +msgstr "Política de recibos" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__name +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__name +msgid "Reference" +msgstr "Referencia" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order_line__origin +msgid "Reference of the document that produced this rma." +msgstr "Referencia del documento que produjo esta rma." + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_form +msgid "Rel. RMA Lines" +msgstr "Rel. Líneas RMA" + +#. module: rma +#: model:ir.actions.server,name:rma.action_request_approve_rma_order_line +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Request Approval" +msgstr "Pedir aprobación" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__requested_by +#: model:ir.model.fields,field_description:rma.field_rma_order_line__requested_by +msgid "Requested By" +msgstr "Solicitado por" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.res_config_settings_view_form +msgid "Return Merchandise Authorization" +msgstr "Autorización de devolución de mercancía" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__product_qty +msgid "Return Qty" +msgstr "Cantidad de devolución" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_res_partner__rma_line_count +#: model:ir.model.fields,field_description:rma.field_res_users__rma_line_count +msgid "Rma Line Count" +msgstr "Recuento de líneas Rma" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Routes" +msgstr "Rutas" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_has_sms_error +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_has_sms_error +msgid "SMS Delivery error" +msgstr "Error de entrega de SMS" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_filter +msgid "Search RMA" +msgstr "Buscar RMA" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "Search RMA line" +msgstr "Buscar línea RMA" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_customer +msgid "Select Lot/Serial Numbers to add" +msgstr "Seleccionar números de lote/serie para agregar" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_supplier +msgid "Select Move" +msgstr "Seleccione Mover" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_supplier +msgid "Select Stock Moves to add" +msgstr "Seleccione Movimientos de existencias para agregar" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +msgid "Select all" +msgstr "Seleccionar todo" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_picking +#: model_terms:ir.ui.view,arch_db:rma.view_rma_picking_out +msgid "Select lines for picking" +msgstr "Seleccionar líneas para recoger" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_location_route__rma_selectable +msgid "Selectable on RMA Lines" +msgstr "Seleccionable en líneas RMA" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +msgid "Selected Lot/Serial Numbers" +msgstr "Números de lote/serie seleccionados" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__location_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__location_id +msgid "Send To This Company Location" +msgstr "Enviar a la ubicación de esta empresa" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__sequence +msgid "Sequence" +msgstr "Secuencia" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_config_settings +#: model:ir.ui.menu,name:rma.menu_rma_global_settings +msgid "Settings" +msgstr "Ajustes" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_form +msgid "Shipments" +msgstr "Envíos" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_customer +msgid "Shipping Address" +msgstr "Dirección de Envío" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__show_lot_filter +msgid "Show lot filter?" +msgstr "¿Mostrar filtro de lotes?" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__origin +msgid "Source Document" +msgstr "Documento fuente" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__state +#: model:ir.model.fields,field_description:rma.field_rma_order_line__state +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "State" +msgstr "Estado" + +#. module: rma +#: model:ir.model,name:rma.model_stock_move +msgid "Stock Move" +msgstr "Movimiento de existencias" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__move_ids +#: model:ir.model.fields,field_description:rma.field_rma_order_line__move_ids +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Stock Moves" +msgstr "Movimientos de existencias" + +#. module: rma +#: model:ir.model,name:rma.model_stock_rule +msgid "Stock Rule" +msgstr "Regla de existencias" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__partner_id +#: model:ir.model.fields.selection,name:rma.selection__rma_operation__type__supplier +#: model:ir.model.fields.selection,name:rma.selection__rma_order__type__supplier +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__type__supplier +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_supplier +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_supplier +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_supplier_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_tree +msgid "Supplier" +msgstr "Proveedor" + +#. module: rma +#: model:stock.picking.type,name:rma.picking_type_rma_dropship +msgid "Supplier -> Customer" +msgstr "Proveedor -> Cliente" + +#. module: rma +#: model:stock.picking.type,name:rma.picking_type_rma_sup_in +msgid "Supplier -> RMA" +msgstr "Proveedor -> RMA" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__supplier_address_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__supplier_address_id +msgid "Supplier Address" +msgstr "Dirección del proveedor" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_operation_supplier +#: model:ir.ui.menu,name:rma.menu_rma_operation_supplier +msgid "Supplier Operations" +msgstr "Operaciones de proveedores" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_supplier_lines +#: model:ir.ui.menu,name:rma.menu_rma_line_supplier +#: model:ir.ui.menu,name:rma.menu_supplier_rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Supplier RMA" +msgstr "Proveedor RMA" + +#. module: rma +#: code:addons/rma/models/stock_warehouse.py:0 +#, python-format +msgid "Supplier RMA Deliveries" +msgstr "Entregas RMA del proveedor" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_supplier +#: model:ir.ui.menu,name:rma.menu_rma_act_supplier +msgid "Supplier RMA Group" +msgstr "Proveedor Grupo RMA" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__supplier_rma_id +msgid "Supplier RMA Order Group" +msgstr "Grupo de pedido de RMA del proveedor" + +#. module: rma +#: code:addons/rma/models/stock_warehouse.py:0 +#, python-format +msgid "Supplier RMA Receipts" +msgstr "Recibos de RMA del proveedor" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__supplier_rma_line_ids +msgid "Supplier Rma Line" +msgstr "Proveedor Línea Rma" + +#. module: rma +#: model:stock.rule,name:rma.rule_rma_dropship +msgid "Supplier → Customer" +msgstr "Proveedor → Cliente" + +#. module: rma +#: model:stock.rule,name:rma.rule_rma_supplier_in_pull +msgid "Supplier → RMA" +msgstr "Proveedor → RMA" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Supplier:" +msgstr "Proveedor:" + +#. module: rma +#: model:ir.ui.menu,name:rma.rma_res_partner_menu_suppliers +msgid "Suppliers" +msgstr "Proveedores" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Term and conditions" +msgstr "Términos y Condiciones" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__conditions +msgid "Terms and conditions" +msgstr "Términos y condiciones" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +msgid "" +"The creation of the RMA Lines will be separated according to the lots or " +"serials selected" +msgstr "La creación de las Líneas RMA se separará según los lotes o " +"series seleccionadas" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__customer_to_supplier +#: model:ir.model.fields,field_description:rma.field_rma_order__customer_to_supplier +#: model:ir.model.fields,field_description:rma.field_rma_order_line__customer_to_supplier +msgid "The customer will send to the supplier" +msgstr "El cliente enviará al proveedor" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__reference +msgid "The partner reference of this RMA order." +msgstr "La referencia del socio de este pedido de RMA." + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__supplier_to_customer +#: model:ir.model.fields,field_description:rma.field_rma_order__supplier_to_customer +#: model:ir.model.fields,field_description:rma.field_rma_order_line__supplier_to_customer +msgid "The supplier will send to the customer" +msgstr "El proveedor enviará al cliente" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order_line__delivery_address_id +msgid "This address will be used to deliver repaired or replacement products." +msgstr "Esta dirección se utilizará para entregar productos reparados o de reemplazo." + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_order__state__to_approve +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__state__to_approve +msgid "To Approve" +msgstr "Aprobar" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "To Deliver" +msgstr "Para entregar" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "To Receive" +msgstr "Para recibir" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "To Send to Supplier RMA" +msgstr "Para enviar al proveedor RMA" + +#. module: rma +#: code:addons/rma/models/rma_order_line.py:0 +#, python-format +msgid "To manage lots use RMA groups." +msgstr "Para gestionar lotes utilice grupos RMA." + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__product_tracking +msgid "Tracking" +msgstr "Seguimiento" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__product_category__rma_approval_policy__two_step +msgid "Two steps" +msgstr "Dos pasos" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__type +#: model:ir.model.fields,field_description:rma.field_rma_order_line__type +msgid "Type" +msgstr "Tipo" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__under_warranty +msgid "Under Warranty?" +msgstr "Bajo garantía?" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Unit Price" +msgstr "Precio unitario" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__uom_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__uom_id +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +msgid "Unit of Measure" +msgstr "Unidad de medida" + +#. module: rma +#: code:addons/rma/wizards/rma_make_picking.py:0 +#, python-format +msgid "Unknown delivery address" +msgstr "Dirección de entrega desconocida" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_unread +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_unread +msgid "Unread Messages" +msgstr "Mensajes no leídos" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_unread_counter +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_unread_counter +msgid "Unread Messages Counter" +msgstr "Contador de mensajes no leídos" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__uom_id +msgid "UoM" +msgstr "UdM" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_res_company__group_rma_lines +#: model:ir.model.fields,field_description:rma.field_res_config_settings__group_rma_lines +msgid "Use RMA groups" +msgstr "Usar grupos de RMA" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__type +msgid "Used in RMA of this type" +msgstr "Usado en RMA de este tipo" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "VAT:" +msgstr "NIF:" + +#. module: rma +#: model:ir.model,name:rma.model_stock_warehouse +#: model:ir.ui.menu,name:rma.menu_rma_config_warehouse +msgid "Warehouse" +msgstr "Almacén" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__website_message_ids +#: model:ir.model.fields,field_description:rma.field_rma_order_line__website_message_ids +msgid "Website Messages" +msgstr "Mensajes del sitio web" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__website_message_ids +#: model:ir.model.fields,help:rma.field_rma_order_line__website_message_ids +msgid "Website communication history" +msgstr "Historial de comunicación del sitio web" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__wiz_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__wiz_id +msgid "Wizard" +msgstr "Asistente" + +#. module: rma +#: model:ir.model,name:rma.model_rma_add_serial_wiz +msgid "Wizard to add rma lines from Serial/Lot numbers" +msgstr "Asistente para agregar líneas rma desde números de serie/lote" + +#. module: rma +#: model:ir.model,name:rma.model_rma_add_stock_move +msgid "Wizard to add rma lines from pickings" +msgstr "Asistente para agregar líneas rma desde recolectas" + +#. module: rma +#: model:ir.model,name:rma.model_rma_make_picking_wizard +msgid "Wizard to create pickings from rma lines" +msgstr "Asistente para crear pickings a partir de líneas rma" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_supplier +#: model_terms:ir.ui.view,arch_db:rma.view_rma_picking +#: model_terms:ir.ui.view,arch_db:rma.view_rma_picking_out +msgid "or" +msgstr "o" diff --git a/rma/i18n/rma.pot b/rma/i18n/rma.pot new file mode 100644 index 00000000..bf387868 --- /dev/null +++ b/rma/i18n/rma.pot @@ -0,0 +1,1779 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * rma +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-11-07 07:37+0000\n" +"PO-Revision-Date: 2022-11-07 07:37+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" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__out_shipment_count +msgid "# of Deliveries" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__out_shipment_count +msgid "# of Outgoing Shipments" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__line_count +msgid "# of RMA lines" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__rma_line_count +msgid "# of RMA lines associated" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__in_shipment_count +#: model:ir.model.fields,field_description:rma.field_rma_order_line__in_shipment_count +msgid "# of Shipments" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__supplier_line_count +msgid "# of Supplier RMAs" +msgstr "" + +#. module: rma +#: model:ir.actions.report,print_report_name:rma.rma_order_line_report +msgid "('RMA - %s' % (object.name))" +msgstr "" + +#. module: rma +#: model:ir.actions.report,print_report_name:rma.rma_order_report +msgid "('RMA Group - %s' % (object.name))" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Contact Person:" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Date Ordered:" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Operation:" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Origin Reference:" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_delivery_document +msgid "RMA" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +msgid "Reference:" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Shipping address:" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_needaction +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__active +msgid "Active" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_button_supplier_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer_form +msgid "Add From Stock Move" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_customer_form +msgid "Add Lot/Serial Numbers" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_button_supplier_form +msgid "Add Lot/Serial numbers" +msgstr "" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_add_serial_wiz_supplier +msgid "Add from Lot/Serial Number" +msgstr "" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_add_serial_wiz_customer +msgid "Add from Lot/Serial Numbers" +msgstr "" + +#. module: rma +#: code:addons/rma/wizards/rma_add_stock_move.py:0 +#: model:ir.actions.act_window,name:rma.action_rma_add_stock_move_customer +#: model:ir.actions.act_window,name:rma.action_rma_add_stock_move_supplier +#, python-format +msgid "Add from Stock Move" +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order_line__name +#: model:ir.model.fields,help:rma.field_rma_order_line_make_supplier_rma_item__name +msgid "Add here the supplier RMA #. Otherwise an internal code is assigned." +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__comment +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +msgid "Additional Information" +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__customer_address_id +#: model:ir.model.fields,help:rma.field_rma_order_line__customer_address_id +msgid "Address of the customer in case of Supplier RMA operation dropship." +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__supplier_address_id +#: model:ir.model.fields,help:rma.field_rma_order_line__supplier_address_id +msgid "Address of the supplier in case of Customer RMA operation dropship." +msgstr "" + +#. module: rma +#: model:res.groups,name:rma.group_rma_delivery_invoice_address +msgid "Addresses in RMA" +msgstr "" + +#. module: rma +#: code:addons/rma/models/rma_order.py:0 +#, python-format +msgid "All grouped RMA's should have same partner." +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Approve" +msgstr "" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_order__state__approved +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__state__approved +msgid "Approved" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.rma_operation_form +msgid "Archived" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__assigned_to +#: model:ir.model.fields,field_description:rma.field_rma_order_line__assigned_to +msgid "Assigned To" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_attachment_count +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Back to Approved" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Back to Draft" +msgstr "" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_operation__receipt_policy__delivered +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__receipt_policy__delivered +msgid "Based on Delivered Quantities" +msgstr "" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_operation__delivery_policy__ordered +#: model:ir.model.fields.selection,name:rma.selection__rma_operation__receipt_policy__ordered +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__delivery_policy__ordered +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__receipt_policy__ordered +msgid "Based on Ordered Quantities" +msgstr "" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_operation__delivery_policy__received +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__delivery_policy__received +msgid "Based on Received Quantities" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_supplier +#: model_terms:ir.ui.view,arch_db:rma.view_rma_order_line_make_supplier_rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_picking +#: model_terms:ir.ui.view,arch_db:rma.view_rma_picking_out +msgid "Cancel" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__code +msgid "Code" +msgstr "" + +#. module: rma +#: model:ir.model,name:rma.model_res_company +msgid "Companies" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__company_id +#: model:ir.model.fields,field_description:rma.field_rma_order__company_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__company_id +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Company" +msgstr "" + +#. module: rma +#: model:ir.model,name:rma.model_res_config_settings +msgid "Config Settings" +msgstr "" + +#. module: rma +#: model:ir.ui.menu,name:rma.menu_rma_config +msgid "Configuration" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_supplier +#: model_terms:ir.ui.view,arch_db:rma.view_rma_picking +#: model_terms:ir.ui.view,arch_db:rma.view_rma_picking_out +msgid "Confirm" +msgstr "" + +#. module: rma +#: model:ir.model,name:rma.model_res_partner +#: model_terms:ir.ui.view,arch_db:rma.view_rma_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_form +msgid "Contact" +msgstr "" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_picking_out +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_button_form +msgid "Create Delivery" +msgstr "" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_picking_in +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_button_form +msgid "Create Incoming Shipment" +msgstr "" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_order_line_make_supplier_rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_supplier_rma_button_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_order_line_make_supplier_rma +msgid "Create Supplier RMA" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_order_line_make_supplier_rma +msgid "Create/Update Supplier RMA" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__create_uid +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__create_uid +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard__create_uid +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__create_uid +#: model:ir.model.fields,field_description:rma.field_rma_operation__create_uid +#: model:ir.model.fields,field_description:rma.field_rma_order__create_uid +#: model:ir.model.fields,field_description:rma.field_rma_order_line__create_uid +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__create_uid +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__create_uid +msgid "Created by" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__create_date +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__create_date +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard__create_date +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__create_date +#: model:ir.model.fields,field_description:rma.field_rma_operation__create_date +#: model:ir.model.fields,field_description:rma.field_rma_order__create_date +#: model:ir.model.fields,field_description:rma.field_rma_order_line__create_date +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__create_date +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__create_date +msgid "Created on" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__currency_id +msgid "Currency" +msgstr "" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_operation__type__customer +#: model:ir.model.fields.selection,name:rma.selection__rma_order__type__customer +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__type__customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_tree +msgid "Customer" +msgstr "" + +#. module: rma +#: model:stock.picking.type,name:rma.picking_type_rma_dropship_return +msgid "Customer -> Supplier" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__customer_address_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__customer_address_id +msgid "Customer Address" +msgstr "" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_operation_customer +#: model:ir.ui.menu,name:rma.menu_rma_operation_customer +msgid "Customer Operations" +msgstr "" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_customer_lines +#: model:ir.ui.menu,name:rma.menu_customer_rma +#: model:ir.ui.menu,name:rma.menu_rma_line_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_supplier_form +msgid "Customer RMA" +msgstr "" + +#. module: rma +#: code:addons/rma/models/stock_warehouse.py:0 +#, python-format +msgid "Customer RMA Deliveries" +msgstr "" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_customer +#: model:ir.ui.menu,name:rma.menu_rma_act_customer +msgid "Customer RMA Group" +msgstr "" + +#. module: rma +#: code:addons/rma/models/stock_warehouse.py:0 +#, python-format +msgid "Customer RMA Receipts" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__customer_rma_id +msgid "Customer RMA line" +msgstr "" + +#. module: rma +#: model:stock.picking.type,name:rma.picking_type_rma_cust_in +#: model:stock.rule,name:rma.rule_rma_customer_in_pull +msgid "Customer → RMA" +msgstr "" + +#. module: rma +#: model:stock.rule,name:rma.rule_rma_dropship_return +msgid "Customer → Supplier" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Customer:" +msgstr "" + +#. module: rma +#: model:ir.ui.menu,name:rma.rma_res_partner_menu_customer +msgid "Customers" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +msgid "Date" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_product_category__rma_customer_operation_id +#: model:ir.model.fields,field_description:rma.field_product_product__rma_customer_operation_id +#: model:ir.model.fields,field_description:rma.field_product_template__rma_customer_operation_id +msgid "Default RMA Customer Operation" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_product_category__rma_supplier_operation_id +#: model:ir.model.fields,field_description:rma.field_product_product__rma_supplier_operation_id +#: model:ir.model.fields,field_description:rma.field_product_template__rma_supplier_operation_id +msgid "Default RMA Supplier Operation" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__partner_shipping_id +msgid "Deliver To" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_form +msgid "Deliveries" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__delivery_policy +#: model:ir.model.fields,field_description:rma.field_rma_order_line__delivery_policy +msgid "Delivery Policy" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__name +#: model:ir.model.fields,field_description:rma.field_rma_order_line__description +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +#: model_terms:ir.ui.view,arch_db:rma.rma_operation_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Description" +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_res_company__group_rma_delivery_address +#: model:ir.model.fields,help:rma.field_res_config_settings__group_rma_delivery_address +msgid "Display 3 fields on rma: partner, invoice address, delivery address" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.res_config_settings_view_form +msgid "Display 3 fields on rma: partner, invoice address, delivery address." +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__display_name +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__display_name +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard__display_name +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__display_name +#: model:ir.model.fields,field_description:rma.field_rma_operation__display_name +#: model:ir.model.fields,field_description:rma.field_rma_order__display_name +#: model:ir.model.fields,field_description:rma.field_rma_order_line__display_name +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__display_name +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__display_name +msgid "Display Name" +msgstr "" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_order__state__done +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__state__done +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Done" +msgstr "" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_order__state__draft +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__state__draft +msgid "Draft" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.res_config_settings_view_form +msgid "Enable RMA invoicing" +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order_line__product_tracking +msgid "Ensure the traceability of a storable product in your warehouse." +msgstr "" + +#. module: rma +#: code:addons/rma/wizards/rma_order_line_make_supplier_rma.py:0 +#, python-format +msgid "Enter a positive quantity." +msgstr "" + +#. module: rma +#: code:addons/rma/wizards/rma_order_line_make_supplier_rma.py:0 +#, python-format +msgid "Enter a supplier." +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_order_line_make_supplier_rma +msgid "Existing Supplier RMA to update:" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_follower_ids +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_partner_ids +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "General" +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order_line__sequence +msgid "Gives the sequence of this line when displaying the rma." +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_filter +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "Group By" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__name +msgid "Group Number" +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_res_company__group_rma_lines +#: model:ir.model.fields,help:rma.field_res_config_settings__group_rma_lines +#: model_terms:ir.ui.view,arch_db:rma.res_config_settings_view_form +msgid "Group RMA lines in one RMA group" +msgstr "" + +#. module: rma +#: code:addons/rma/models/rma_order.py:0 +#: code:addons/rma/models/rma_order_line.py:0 +#, python-format +msgid "Group partner and RMA's partner must be the same." +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__has_message +#: model:ir.model.fields,field_description:rma.field_rma_order_line__has_message +msgid "Has Message" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__id +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__id +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard__id +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__id +#: model:ir.model.fields,field_description:rma.field_rma_operation__id +#: model:ir.model.fields,field_description:rma.field_rma_order__id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__id +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__id +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__id +msgid "ID" +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__message_needaction +#: model:ir.model.fields,help:rma.field_rma_order__message_unread +#: model:ir.model.fields,help:rma.field_rma_order_line__message_needaction +#: model:ir.model.fields,help:rma.field_rma_order_line__message_unread +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__message_has_error +#: model:ir.model.fields,help:rma.field_rma_order__message_has_sms_error +#: model:ir.model.fields,help:rma.field_rma_order_line__message_has_error +#: model:ir.model.fields,help:rma.field_rma_order_line__message_has_sms_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_stock_warehouse__rma_in_this_wh +msgid "" +"If set, it will create RMA location, picking types and routes for this " +"warehouse." +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.rma_operation_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_form +msgid "Inbound" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__in_route_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__in_route_id +msgid "Inbound Route" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__in_warehouse_id +#: model:ir.model.fields,field_description:rma.field_rma_order__in_warehouse_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__in_warehouse_id +msgid "Inbound Warehouse" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__qty_incoming +msgid "Incoming Qty" +msgstr "" + +#. module: rma +#: model:ir.model,name:rma.model_stock_location_route +msgid "Inventory Routes" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_is_follower +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard__item_ids +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__item_ids +msgid "Items" +msgstr "" + +#. module: rma +#: model:ir.model,name:rma.model_rma_make_picking_wizard_item +msgid "Items to receive" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz____last_update +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move____last_update +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard____last_update +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item____last_update +#: model:ir.model.fields,field_description:rma.field_rma_operation____last_update +#: model:ir.model.fields,field_description:rma.field_rma_order____last_update +#: model:ir.model.fields,field_description:rma.field_rma_order_line____last_update +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma____last_update +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item____last_update +msgid "Last Modified on" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__write_uid +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__write_uid +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard__write_uid +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__write_uid +#: model:ir.model.fields,field_description:rma.field_rma_operation__write_uid +#: model:ir.model.fields,field_description:rma.field_rma_order__write_uid +#: model:ir.model.fields,field_description:rma.field_rma_order_line__write_uid +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__write_uid +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__write_date +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__write_date +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard__write_date +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__write_date +#: model:ir.model.fields,field_description:rma.field_rma_operation__write_date +#: model:ir.model.fields,field_description:rma.field_rma_order__write_date +#: model:ir.model.fields,field_description:rma.field_rma_order_line__write_date +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__write_date +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__write_date +msgid "Last Updated on" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__lot_id +msgid "Lot/Serial Number" +msgstr "" + +#. module: rma +#: code:addons/rma/wizards/rma_add_serial.py:0 +#, python-format +msgid "Lot/Serial Number %s already added." +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__lot_domain_ids +msgid "Lots Domain" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__lot_ids +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__lot_ids +msgid "Lots/Serials selected" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_main_attachment_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_main_attachment_id +msgid "Main Attachment" +msgstr "" + +#. module: rma +#: model:ir.ui.menu,name:rma.menu_rma_rma_control +msgid "Master Data" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_has_error +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_ids +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_ids +msgid "Messages" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "My RMAs" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_order_line_make_supplier_rma +msgid "New RMA details:" +msgstr "" + +#. module: rma +#: code:addons/rma/wizards/rma_make_picking.py:0 +#, python-format +msgid "No deliveries needed for this operation" +msgstr "" + +#. module: rma +#: code:addons/rma/wizards/rma_make_picking.py:0 +#, python-format +msgid "No quantity to transfer on %(arg1)s shipment of product %(arg2)s." +msgstr "" + +#. module: rma +#: code:addons/rma/wizards/rma_make_picking.py:0 +#, python-format +msgid "No route specified" +msgstr "" + +#. module: rma +#: code:addons/rma/models/procurement_group.py:0 +#, python-format +msgid "" +"No rule found for this product %(product)s and location %(location)s that is" +" valid for RMA operations." +msgstr "" + +#. module: rma +#: code:addons/rma/wizards/rma_make_picking.py:0 +#, python-format +msgid "No shipments needed for this operation" +msgstr "" + +#. module: rma +#: code:addons/rma/wizards/rma_make_picking.py:0 +#, python-format +msgid "No warehouse specified" +msgstr "" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_operation__delivery_policy__no +#: model:ir.model.fields.selection,name:rma.selection__rma_operation__receipt_policy__no +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__delivery_policy__no +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__receipt_policy__no +msgid "Not required" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_needaction_counter +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_has_error_counter +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_has_error_counter +msgid "Number of errors" +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__message_needaction_counter +#: model:ir.model.fields,help:rma.field_rma_order_line__message_needaction_counter +msgid "Number of messages which requires an action" +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__message_has_error_counter +#: model:ir.model.fields,help:rma.field_rma_order_line__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__message_unread_counter +#: model:ir.model.fields,help:rma.field_rma_order_line__message_unread_counter +msgid "Number of unread messages" +msgstr "" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__product_category__rma_approval_policy__one_step +msgid "One step" +msgstr "" + +#. module: rma +#: code:addons/rma/wizards/rma_make_picking.py:0 +#, python-format +msgid "Only RMA lines from the same partner can be processed at the same time" +msgstr "" + +#. module: rma +#: code:addons/rma/wizards/rma_order_line_make_supplier_rma.py:0 +#, python-format +msgid "" +"Only RMA lines from the same supplier can be processed at the same time" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__operation_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__operation_id +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "Operation" +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_product_category__rma_approval_policy +#: model:ir.model.fields,help:rma.field_product_product__rma_approval_policy +#: model:ir.model.fields,help:rma.field_product_template__rma_approval_policy +msgid "" +"Options: \n" +" * One step: Always auto-approve RMAs that only contain products within categories with this policy.\n" +"* Two steps: A RMA containing a product within a category with this policy will request the RMA manager approval." +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__date_rma +msgid "Order Date" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Origin" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__reference_move_id +msgid "Originating Stock Move" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Other Info" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.rma_operation_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_form +msgid "Outbound" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__out_route_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__out_route_id +msgid "Outbound Route" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__out_warehouse_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__out_warehouse_id +msgid "Outbound Warehouse" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__qty_outgoing +msgid "Outgoing Qty" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__partner_id +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__partner_id +#: model:ir.model.fields,field_description:rma.field_rma_order__partner_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__partner_id +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_filter +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "Partner" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__reference +msgid "Partner Reference" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__delivery_address_id +msgid "Partner delivery address" +msgstr "" + +#. module: rma +#: model:ir.ui.menu,name:rma.menu_rma_config_partners +msgid "Partners" +msgstr "" + +#. module: rma +#: code:addons/rma/wizards/rma_add_serial.py:0 +#: code:addons/rma/wizards/rma_add_stock_move.py:0 +#: code:addons/rma/wizards/rma_order_line_make_supplier_rma.py:0 +#, python-format +msgid "Please define a warehouse with a default RMA location" +msgstr "" + +#. module: rma +#: code:addons/rma/models/rma_order_line.py:0 +#, python-format +msgid "Please define a warehouse with a default RMA location." +msgstr "" + +#. module: rma +#: code:addons/rma/wizards/rma_add_serial.py:0 +#: code:addons/rma/wizards/rma_add_stock_move.py:0 +#: code:addons/rma/wizards/rma_order_line_make_supplier_rma.py:0 +#, python-format +msgid "Please define an RMA route" +msgstr "" + +#. module: rma +#: code:addons/rma/models/rma_order_line.py:0 +#, python-format +msgid "Please define an RMA route." +msgstr "" + +#. module: rma +#: code:addons/rma/wizards/rma_add_serial.py:0 +#: code:addons/rma/wizards/rma_add_stock_move.py:0 +#, python-format +msgid "Please define an operation first" +msgstr "" + +#. module: rma +#: code:addons/rma/models/rma_order_line.py:0 +#, python-format +msgid "Please define an operation first." +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.rma_operation_form +msgid "Policies" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__price_unit +msgid "Price Unit" +msgstr "" + +#. module: rma +#: model:ir.model,name:rma.model_procurement_group +msgid "Procurement Group" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__product_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__product_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__product_id +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "Product" +msgstr "" + +#. module: rma +#: code:addons/rma/models/rma_order_line.py:0 +#, python-format +msgid "" +"Product %s has serial tracking configuration, quantity to receive should be " +"1" +msgstr "" + +#. module: rma +#: model:ir.model,name:rma.model_product_category +msgid "Product Category" +msgstr "" + +#. module: rma +#: model:ir.model,name:rma.model_product_template +msgid "Product Template" +msgstr "" + +#. module: rma +#: model:ir.ui.menu,name:rma.rma_product_product_menu +msgid "Product Variants" +msgstr "" + +#. module: rma +#: model:ir.ui.menu,name:rma.menu_rma_config_stock +msgid "Products" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__qty_delivered +msgid "Qty Delivered" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__qty_received +msgid "Qty Received" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__qty_to_deliver +msgid "Qty To Deliver" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__qty_to_receive +msgid "Qty To Receive" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__qty_in_supplier_rma +msgid "Qty in Supplier RMA" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__qty_to_supplier_rma +msgid "Qty to send to Supplier RMA" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Quantities" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__product_qty +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Quantity" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__product_qty +msgid "Quantity Ordered" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__qty_to_deliver +msgid "Quantity To Deliver" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__qty_to_receive +msgid "Quantity to Receive" +msgstr "" + +#. module: rma +#: model:ir.actions.report,name:rma.rma_order_line_report +#: model:ir.model,name:rma.model_rma_order_line +#: model:ir.model.fields,field_description:rma.field_procurement_group__rma_id +#: model:ir.module.category,name:rma.module_category_rma +#: model:ir.ui.menu,name:rma.menu_rma_root +#: model_terms:ir.ui.view,arch_db:rma.res_config_settings_view_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_form +msgid "RMA" +msgstr "" + +#. module: rma +#: code:addons/rma/wizards/rma_make_picking.py:0 +#, python-format +msgid "RMA %s is not approved" +msgstr "" + +#. module: rma +#: model:stock.picking.type,name:rma.picking_type_rma_sup_out +msgid "RMA -> Supplier" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_product_category__rma_approval_policy +#: model:ir.model.fields,field_description:rma.field_product_product__rma_approval_policy +#: model:ir.model.fields,field_description:rma.field_product_template__rma_approval_policy +msgid "RMA Approval Policy" +msgstr "" + +#. module: rma +#: model:stock.location.route,name:rma.route_rma_customer +msgid "RMA Customer" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_customer_in_pull_id +msgid "RMA Customer In Rule" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_customer_out_pull_id +msgid "RMA Customer Out Rule" +msgstr "" + +#. module: rma +#: model:res.groups,name:rma.group_rma_customer_user +msgid "RMA Customer User" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_cust_in_type_id +msgid "RMA Customer in Type" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_cust_out_type_id +msgid "RMA Customer out Type" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_filter +msgid "RMA Date" +msgstr "" + +#. module: rma +#: model:stock.location.route,name:rma.route_rma_dropship +msgid "RMA Dropship" +msgstr "" + +#. module: rma +#: model:ir.actions.report,name:rma.rma_order_report +#: model:ir.model,name:rma.model_rma_order +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__rma_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__rma_id +msgid "RMA Group" +msgstr "" + +#. module: rma +#: model:res.groups,name:rma.group_rma_groups +msgid "RMA Groups" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__line_id +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "RMA Line" +msgstr "" + +#. module: rma +#: model:ir.model,name:rma.model_rma_order_line_make_supplier_rma +msgid "RMA Line Make Supplier RMA" +msgstr "" + +#. module: rma +#: model:ir.model,name:rma.model_rma_order_line_make_supplier_rma_item +msgid "RMA Line Make Supplier RMA Item" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_form +msgid "RMA Lines" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__lot_rma_id +msgid "RMA Location" +msgstr "" + +#. module: rma +#: model:res.groups,name:rma.group_rma_manager +msgid "RMA Manager" +msgstr "" + +#. module: rma +#: model:ir.model,name:rma.model_rma_operation +msgid "RMA Operation" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.rma_operation_form +msgid "RMA Operations" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_serial_wiz__rma_id +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__rma_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__rma_id +msgid "RMA Order" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.stock_location_route_form_view_inherit_rma_stock +msgid "RMA Order Lines" +msgstr "" + +#. module: rma +#: model:stock.location.route,name:rma.route_rma_supplier +msgid "RMA Supplier" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_supplier_in_pull_id +msgid "RMA Supplier In Rule" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_supplier_out_pull_id +msgid "RMA Supplier Out Rule" +msgstr "" + +#. module: rma +#: model:res.groups,name:rma.group_rma_supplier_user +msgid "RMA Supplier User" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_sup_in_type_id +msgid "RMA Supplier in Type" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_sup_out_type_id +msgid "RMA Supplier out Type" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_res_company__group_rma_delivery_address +#: model:ir.model.fields,field_description:rma.field_res_config_settings__group_rma_delivery_address +msgid "RMA addresses" +msgstr "" + +#. module: rma +#: code:addons/rma/models/rma_order_line.py:0 +#, python-format +msgid "RMA customer and originating stock move customer doesn't match." +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_in_this_wh +msgid "RMA in this Warehouse" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_res_config_settings__module_rma_account +msgid "RMA invoicing" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_procurement_group__rma_line_id +#: model:ir.model.fields,field_description:rma.field_stock_move__rma_line_id +msgid "RMA line" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__rma_line_ids +#: model:ir.model.fields,field_description:rma.field_rma_order__rma_line_ids +msgid "RMA lines" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__line_id +msgid "RMA order Line" +msgstr "" + +#. module: rma +#: model:stock.picking.type,name:rma.picking_type_rma_cust_out +#: model:stock.rule,name:rma.rule_rma_customer_out_pull +msgid "RMA → Customer" +msgstr "" + +#. module: rma +#: model:stock.rule,name:rma.rule_rma_supplier_out_pull +msgid "RMA → Supplier" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_res_partner__rma_line_ids +#: model:ir.model.fields,field_description:rma.field_res_users__rma_line_ids +#: model_terms:ir.ui.view,arch_db:rma.view_partner_form +msgid "RMAs" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__receipt_policy +#: model:ir.model.fields,field_description:rma.field_rma_order_line__receipt_policy +msgid "Receipt Policy" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__name +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__name +msgid "Reference" +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order_line__origin +msgid "Reference of the document that produced this rma." +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_form +msgid "Rel. RMA Lines" +msgstr "" + +#. module: rma +#: model:ir.actions.server,name:rma.action_request_approve_rma_order_line +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Request Approval" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__requested_by +#: model:ir.model.fields,field_description:rma.field_rma_order_line__requested_by +msgid "Requested By" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.res_config_settings_view_form +msgid "Return Merchandise Authorization" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__product_qty +msgid "Return Qty" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_res_partner__rma_line_count +#: model:ir.model.fields,field_description:rma.field_res_users__rma_line_count +msgid "Rma Line Count" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Routes" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_has_sms_error +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_has_sms_error +msgid "SMS Delivery error" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_filter +msgid "Search RMA" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "Search RMA line" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_customer +msgid "Select Lot/Serial Numbers to add" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_supplier +msgid "Select Move" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_supplier +msgid "Select Stock Moves to add" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +msgid "Select all" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_picking +#: model_terms:ir.ui.view,arch_db:rma.view_rma_picking_out +msgid "Select lines for picking" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_stock_location_route__rma_selectable +msgid "Selectable on RMA Lines" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +msgid "Selected Lot/Serial Numbers" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__location_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__location_id +msgid "Send To This Company Location" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__sequence +msgid "Sequence" +msgstr "" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_config_settings +#: model:ir.ui.menu,name:rma.menu_rma_global_settings +msgid "Settings" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_form +msgid "Shipments" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_customer +msgid "Shipping Address" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__show_lot_filter +msgid "Show lot filter?" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__origin +msgid "Source Document" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__state +#: model:ir.model.fields,field_description:rma.field_rma_order_line__state +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "State" +msgstr "" + +#. module: rma +#: model:ir.model,name:rma.model_stock_move +msgid "Stock Move" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_add_stock_move__move_ids +#: model:ir.model.fields,field_description:rma.field_rma_order_line__move_ids +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Stock Moves" +msgstr "" + +#. module: rma +#: model:ir.model,name:rma.model_stock_rule +msgid "Stock Rule" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__partner_id +#: model:ir.model.fields.selection,name:rma.selection__rma_operation__type__supplier +#: model:ir.model.fields.selection,name:rma.selection__rma_order__type__supplier +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__type__supplier +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_supplier +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_supplier +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_supplier_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_form +#: model_terms:ir.ui.view,arch_db:rma.view_rma_supplier_tree +msgid "Supplier" +msgstr "" + +#. module: rma +#: model:stock.picking.type,name:rma.picking_type_rma_dropship +msgid "Supplier -> Customer" +msgstr "" + +#. module: rma +#: model:stock.picking.type,name:rma.picking_type_rma_sup_in +msgid "Supplier -> RMA" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__supplier_address_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__supplier_address_id +msgid "Supplier Address" +msgstr "" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_operation_supplier +#: model:ir.ui.menu,name:rma.menu_rma_operation_supplier +msgid "Supplier Operations" +msgstr "" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_supplier_lines +#: model:ir.ui.menu,name:rma.menu_rma_line_supplier +#: model:ir.ui.menu,name:rma.menu_supplier_rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_line_form +msgid "Supplier RMA" +msgstr "" + +#. module: rma +#: code:addons/rma/models/stock_warehouse.py:0 +#, python-format +msgid "Supplier RMA Deliveries" +msgstr "" + +#. module: rma +#: model:ir.actions.act_window,name:rma.action_rma_supplier +#: model:ir.ui.menu,name:rma.menu_rma_act_supplier +msgid "Supplier RMA Group" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma__supplier_rma_id +msgid "Supplier RMA Order Group" +msgstr "" + +#. module: rma +#: code:addons/rma/models/stock_warehouse.py:0 +#, python-format +msgid "Supplier RMA Receipts" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__supplier_rma_line_ids +msgid "Supplier Rma Line" +msgstr "" + +#. module: rma +#: model:stock.rule,name:rma.rule_rma_dropship +msgid "Supplier → Customer" +msgstr "" + +#. module: rma +#: model:stock.rule,name:rma.rule_rma_supplier_in_pull +msgid "Supplier → RMA" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Supplier:" +msgstr "" + +#. module: rma +#: model:ir.ui.menu,name:rma.rma_res_partner_menu_suppliers +msgid "Suppliers" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Term and conditions" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__conditions +msgid "Terms and conditions" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +msgid "" +"The creation of the RMA Lines will be separated according to the lots or " +"serials selected" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__customer_to_supplier +#: model:ir.model.fields,field_description:rma.field_rma_order__customer_to_supplier +#: model:ir.model.fields,field_description:rma.field_rma_order_line__customer_to_supplier +msgid "The customer will send to the supplier" +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__reference +msgid "The partner reference of this RMA order." +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__supplier_to_customer +#: model:ir.model.fields,field_description:rma.field_rma_order__supplier_to_customer +#: model:ir.model.fields,field_description:rma.field_rma_order_line__supplier_to_customer +msgid "The supplier will send to the customer" +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order_line__delivery_address_id +msgid "This address will be used to deliver repaired or replacement products." +msgstr "" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__rma_order__state__to_approve +#: model:ir.model.fields.selection,name:rma.selection__rma_order_line__state__to_approve +msgid "To Approve" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "To Deliver" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "To Receive" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_rma_line_filter +msgid "To Send to Supplier RMA" +msgstr "" + +#. module: rma +#: code:addons/rma/models/rma_order_line.py:0 +#, python-format +msgid "To manage lots use RMA groups." +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__product_tracking +msgid "Tracking" +msgstr "" + +#. module: rma +#: model:ir.model.fields.selection,name:rma.selection__product_category__rma_approval_policy__two_step +msgid "Two steps" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__type +#: model:ir.model.fields,field_description:rma.field_rma_order_line__type +msgid "Type" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line__under_warranty +msgid "Under Warranty?" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "Unit Price" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__uom_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line__uom_id +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +msgid "Unit of Measure" +msgstr "" + +#. module: rma +#: code:addons/rma/wizards/rma_make_picking.py:0 +#, python-format +msgid "Unknown delivery address" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_unread +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_unread +msgid "Unread Messages" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__message_unread_counter +#: model:ir.model.fields,field_description:rma.field_rma_order_line__message_unread_counter +msgid "Unread Messages Counter" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__uom_id +msgid "UoM" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_res_company__group_rma_lines +#: model:ir.model.fields,field_description:rma.field_res_config_settings__group_rma_lines +msgid "Use RMA groups" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_operation__type +msgid "Used in RMA of this type" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_document +#: model_terms:ir.ui.view,arch_db:rma.report_rma_order_line_document +msgid "VAT:" +msgstr "" + +#. module: rma +#: model:ir.model,name:rma.model_stock_warehouse +#: model:ir.ui.menu,name:rma.menu_rma_config_warehouse +msgid "Warehouse" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_order__website_message_ids +#: model:ir.model.fields,field_description:rma.field_rma_order_line__website_message_ids +msgid "Website Messages" +msgstr "" + +#. module: rma +#: model:ir.model.fields,help:rma.field_rma_order__website_message_ids +#: model:ir.model.fields,help:rma.field_rma_order_line__website_message_ids +msgid "Website communication history" +msgstr "" + +#. module: rma +#: model:ir.model.fields,field_description:rma.field_rma_make_picking_wizard_item__wiz_id +#: model:ir.model.fields,field_description:rma.field_rma_order_line_make_supplier_rma_item__wiz_id +msgid "Wizard" +msgstr "" + +#. module: rma +#: model:ir.model,name:rma.model_rma_add_serial_wiz +msgid "Wizard to add rma lines from Serial/Lot numbers" +msgstr "" + +#. module: rma +#: model:ir.model,name:rma.model_rma_add_stock_move +msgid "Wizard to add rma lines from pickings" +msgstr "" + +#. module: rma +#: model:ir.model,name:rma.model_rma_make_picking_wizard +msgid "Wizard to create pickings from rma lines" +msgstr "" + +#. module: rma +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_serial_wiz_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_customer +#: model_terms:ir.ui.view,arch_db:rma.view_rma_add_stock_move_supplier +#: model_terms:ir.ui.view,arch_db:rma.view_rma_picking +#: model_terms:ir.ui.view,arch_db:rma.view_rma_picking_out +msgid "or" +msgstr "" diff --git a/rma/models/__init__.py b/rma/models/__init__.py new file mode 100644 index 00000000..612e4aaa --- /dev/null +++ b/rma/models/__init__.py @@ -0,0 +1,12 @@ +from . import rma_order +from . import rma_order_line +from . import rma_operation +from . import stock_move +from . import stock_warehouse +from . import product +from . import product_category +from . import procurement_group +from . import stock_rule +from . import res_partner +from . import res_company +from . import res_config_settings diff --git a/rma/models/procurement_group.py b/rma/models/procurement_group.py new file mode 100644 index 00000000..8fe4b1a5 --- /dev/null +++ b/rma/models/procurement_group.py @@ -0,0 +1,37 @@ +# Copyright (C) 2017-22 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class ProcurementGroup(models.Model): + _inherit = "procurement.group" + + rma_id = fields.Many2one( + comodel_name="rma.order", string="RMA", ondelete="set null" + ) + rma_line_id = fields.Many2one( + comodel_name="rma.order.line", string="RMA line", ondelete="set null" + ) + + @api.model + def _get_rule(self, product_id, location_id, values): + """Ensure that the selected rule is valid for RMAs""" + res = super()._get_rule(product_id, location_id, values) + rma_route_check = self.env.context.get("rma_route_check") + if rma_route_check: + if res and not res.route_id.rma_selectable: + raise ValidationError( + _( + "No rule found for this product %(product)s and " + "location %(location)s that is valid for RMA operations." + ) + % { + "product": product_id.default_code or product_id.name, + "location": location_id.complete_name, + } + ) + # Don't enforce check on any chained moves + rma_route_check.clear() + return res diff --git a/rma/models/product.py b/rma/models/product.py new file mode 100644 index 00000000..c4055c5b --- /dev/null +++ b/rma/models/product.py @@ -0,0 +1,22 @@ +# Copyright (C) 2017-20 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import fields, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + rma_customer_operation_id = fields.Many2one( + company_dependent=True, + comodel_name="rma.operation", + string="Default RMA Customer Operation", + ) + rma_supplier_operation_id = fields.Many2one( + company_dependent=True, + comodel_name="rma.operation", + string="Default RMA Supplier Operation", + ) + rma_approval_policy = fields.Selection( + related="categ_id.rma_approval_policy", readonly=True + ) diff --git a/rma/models/product_category.py b/rma/models/product_category.py new file mode 100644 index 00000000..db832c2e --- /dev/null +++ b/rma/models/product_category.py @@ -0,0 +1,30 @@ +# Copyright 2017 ForgeFlow +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import fields, models + + +class ProductCategory(models.Model): + _inherit = "product.category" + + rma_approval_policy = fields.Selection( + selection=[("one_step", "One step"), ("two_step", "Two steps")], + string="RMA Approval Policy", + required=True, + default="one_step", + help="Options: \n " + "* One step: Always auto-approve RMAs that only contain " + "products within categories with this policy.\n" + "* Two steps: A RMA containing a product within a category with " + "this policy will request the RMA manager approval.", + ) + rma_customer_operation_id = fields.Many2one( + company_dependent=True, + comodel_name="rma.operation", + string="Default RMA Customer Operation", + ) + rma_supplier_operation_id = fields.Many2one( + company_dependent=True, + comodel_name="rma.operation", + string="Default RMA Supplier Operation", + ) diff --git a/rma/models/res_company.py b/rma/models/res_company.py new file mode 100644 index 00000000..1ed19e1d --- /dev/null +++ b/rma/models/res_company.py @@ -0,0 +1,14 @@ +from odoo import fields, models + + +class ResCompany(models.Model): + _inherit = "res.company" + + group_rma_delivery_address = fields.Boolean( + string="RMA addresses", + help="Display 3 fields on rma: partner, invoice address, delivery address", + ) + + group_rma_lines = fields.Boolean( + string="Use RMA groups", help="Group RMA lines in one RMA group" + ) diff --git a/rma/models/res_config_settings.py b/rma/models/res_config_settings.py new file mode 100644 index 00000000..53091e60 --- /dev/null +++ b/rma/models/res_config_settings.py @@ -0,0 +1,22 @@ +# Copyright (C) 2017-20 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + group_rma_delivery_address = fields.Boolean( + related="company_id.group_rma_delivery_address", + implied_group="rma.group_rma_delivery_invoice_address", + readonly=False, + ) + + group_rma_lines = fields.Boolean( + related="company_id.group_rma_lines", + readonly=False, + implied_group="rma.group_rma_groups", + ) + + module_rma_account = fields.Boolean(string="RMA invoicing") diff --git a/rma/models/res_partner.py b/rma/models/res_partner.py new file mode 100644 index 00000000..89c529ae --- /dev/null +++ b/rma/models/res_partner.py @@ -0,0 +1,27 @@ +# Copyright 2017-22 ForgeFlow +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class ResPartner(models.Model): + _inherit = "res.partner" + + def _compute_rma_line_count(self): + for rec in self: + rec.rma_line_count = len(rec.rma_line_ids) + + rma_line_ids = fields.One2many( + comodel_name="rma.order.line", string="RMAs", inverse_name="partner_id" + ) + rma_line_count = fields.Integer( + compute="_compute_rma_line_count", compute_sudo=True + ) + + def action_open_partner_rma(self): + action = self.env.ref("rma.action_rma_customer_lines") + result = action.sudo().read()[0] + result["context"] = {"search_default_partner_id": self.id} + result["domain"] = [] + result["display_name"] = "Partner RMAs" + return result diff --git a/rma/models/rma_operation.py b/rma/models/rma_operation.py new file mode 100644 index 00000000..bd3d0f16 --- /dev/null +++ b/rma/models/rma_operation.py @@ -0,0 +1,96 @@ +# Copyright 2017-18 ForgeFlow +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import api, fields, models + + +class RmaOperation(models.Model): + _name = "rma.operation" + _description = "RMA Operation" + + @api.model + def _default_warehouse_id(self): + company_id = self.env.user.company_id.id + warehouse = self.env["stock.warehouse"].search( + [("company_id", "=", company_id)], limit=1 + ) + return warehouse + + @api.model + def _default_customer_location_id(self): + return self.env.ref("stock.stock_location_customers") or False + + @api.model + def _default_supplier_location_id(self): + return self.env.ref("stock.stock_location_suppliers") or False + + @api.model + def _default_routes(self): + op_type = self.env.context.get("default_type") + if op_type == "customer": + return self.env.ref("rma.route_rma_customer") + elif op_type == "supplier": + return self.env.ref("rma.route_rma_supplier") + + name = fields.Char("Description", required=True) + code = fields.Char(required=True) + active = fields.Boolean(default=True) + receipt_policy = fields.Selection( + [ + ("no", "Not required"), + ("ordered", "Based on Ordered Quantities"), + ("delivered", "Based on Delivered Quantities"), + ], + default="no", + ) + delivery_policy = fields.Selection( + [ + ("no", "Not required"), + ("ordered", "Based on Ordered Quantities"), + ("received", "Based on Received Quantities"), + ], + default="no", + ) + in_route_id = fields.Many2one( + comodel_name="stock.route", + string="Inbound Route", + domain=[("rma_selectable", "=", True)], + default=lambda self: self._default_routes(), + ) + out_route_id = fields.Many2one( + comodel_name="stock.route", + string="Outbound Route", + domain=[("rma_selectable", "=", True)], + default=lambda self: self._default_routes(), + ) + customer_to_supplier = fields.Boolean( + string="The customer will send to the supplier" + ) + supplier_to_customer = fields.Boolean( + string="The supplier will send to the customer" + ) + in_warehouse_id = fields.Many2one( + comodel_name="stock.warehouse", + string="Inbound Warehouse", + default=lambda self: self._default_warehouse_id(), + ) + out_warehouse_id = fields.Many2one( + comodel_name="stock.warehouse", + string="Outbound Warehouse", + default=lambda self: self._default_warehouse_id(), + ) + location_id = fields.Many2one("stock.location", "Send To This Company Location") + type = fields.Selection( + [("customer", "Customer"), ("supplier", "Supplier")], + string="Used in RMA of this type", + required=True, + ) + rma_line_ids = fields.One2many( + comodel_name="rma.order.line", inverse_name="operation_id", string="RMA lines" + ) + company_id = fields.Many2one( + comodel_name="res.company", + string="Company", + required=True, + default=lambda self: self.env.user.company_id, + ) diff --git a/rma/models/rma_order.py b/rma/models/rma_order.py new file mode 100644 index 00000000..edd4d563 --- /dev/null +++ b/rma/models/rma_order.py @@ -0,0 +1,322 @@ +# Copyright (C) 2017-20 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from datetime import datetime + +from odoo import _, api, fields, models +from odoo.exceptions import UserError + + +class RmaOrder(models.Model): + _name = "rma.order" + _description = "RMA Group" + _inherit = ["mail.thread"] + _order = "id desc" + + @api.model + def _get_default_type(self): + if "supplier" in self.env.context: + return "supplier" + return "customer" + + def _compute_in_shipment_count(self): + for rec in self: + pickings = self.env["stock.picking"] + for line in rec.rma_line_ids: + pickings |= line._get_in_pickings() + rec.in_shipment_count = len(pickings) + + def _compute_out_shipment_count(self): + for rec in self: + pickings = self.env["stock.picking"] + for line in rec.rma_line_ids: + pickings |= line._get_out_pickings() + rec.out_shipment_count = len(pickings) + + def _compute_supplier_line_count(self): + self.supplier_line_count = len( + self.rma_line_ids.filtered(lambda r: r.supplier_rma_line_ids) + ) + + def _compute_line_count(self): + for rec in self: + rec.line_count = len(rec._get_valid_lines()) + + @api.depends("rma_line_ids", "rma_line_ids.state") + def _compute_state(self): + for rec in self: + rma_line_done = self.env["rma.order.line"].search_count( + [("id", "in", rec.rma_line_ids.ids), ("state", "=", "done")] + ) + rma_line_approved = self.env["rma.order.line"].search_count( + [("id", "in", rec.rma_line_ids.ids), ("state", "=", "approved")] + ) + rma_line_to_approve = self.env["rma.order.line"].search_count( + [("id", "in", rec.rma_line_ids.ids), ("state", "=", "to_approve")] + ) + if rma_line_done != 0: + state = "done" + elif rma_line_approved != 0: + state = "approved" + elif rma_line_to_approve != 0: + state = "to_approve" + else: + state = "draft" + rec.state = state + + @api.model + def _default_date_rma(self): + return datetime.now() + + @api.model + def _default_warehouse_id(self): + warehouse = self.env["stock.warehouse"].search( + [("company_id", "=", self.env.company.id)], limit=1 + ) + return warehouse + + name = fields.Char(string="Group Number", index=True, copy=False) + type = fields.Selection( + [("customer", "Customer"), ("supplier", "Supplier")], + required=True, + default=lambda self: self._get_default_type(), + readonly=True, + ) + reference = fields.Char( + string="Partner Reference", help="The partner reference of this RMA order." + ) + description = fields.Text() + comment = fields.Text("Additional Information") + date_rma = fields.Datetime( + compute="_compute_date_rma", + inverse="_inverse_date_rma", + string="Order Date", + index=True, + default=lambda self: self._default_date_rma(), + ) + partner_id = fields.Many2one( + comodel_name="res.partner", string="Partner", required=True + ) + rma_line_ids = fields.One2many("rma.order.line", "rma_id", string="RMA lines") + in_shipment_count = fields.Integer( + compute="_compute_in_shipment_count", string="# of Shipments" + ) + out_shipment_count = fields.Integer( + compute="_compute_out_shipment_count", string="# of Outgoing Shipments" + ) + line_count = fields.Integer(compute="_compute_line_count", string="# of RMA lines") + supplier_line_count = fields.Integer( + compute="_compute_supplier_line_count", string="# of Supplier RMAs" + ) + company_id = fields.Many2one( + "res.company", + string="Company", + required=True, + default=lambda self: self.env.company, + ) + assigned_to = fields.Many2one( + comodel_name="res.users", + tracking=True, + default=lambda self: self.env.uid, + ) + requested_by = fields.Many2one( + comodel_name="res.users", + tracking=True, + default=lambda self: self.env.uid, + ) + in_route_id = fields.Many2one( + "stock.route", + string="Inbound Route", + domain=[("rma_selectable", "=", True)], + ) + out_route_id = fields.Many2one( + "stock.route", + string="Outbound Route", + domain=[("rma_selectable", "=", True)], + ) + in_warehouse_id = fields.Many2one( + comodel_name="stock.warehouse", + string="Inbound Warehouse", + required=False, + default=_default_warehouse_id, + ) + out_warehouse_id = fields.Many2one( + comodel_name="stock.warehouse", + string="Outbound Warehouse", + required=False, + default=_default_warehouse_id, + ) + location_id = fields.Many2one( + comodel_name="stock.location", + string="Send To This Company Location", + ) + customer_to_supplier = fields.Boolean("The customer will send to the supplier") + supplier_to_customer = fields.Boolean("The supplier will send to the customer") + supplier_address_id = fields.Many2one( + comodel_name="res.partner", + string="Supplier Address", + help="Address of the supplier in case of Customer RMA operation " "dropship.", + ) + customer_address_id = fields.Many2one( + comodel_name="res.partner", + string="Customer Address", + help="Address of the customer in case of Supplier RMA operation " "dropship.", + ) + state = fields.Selection( + compute=_compute_state, + selection=[ + ("draft", "Draft"), + ("to_approve", "To Approve"), + ("approved", "Approved"), + ("done", "Done"), + ], + default="draft", + store=True, + ) + operation_default_id = fields.Many2one( + comodel_name="rma.operation", + required=False, + string="Default Operation Type", + ) + + @api.onchange( + "operation_default_id", + ) + def _onchange_operation(self): + if self.operation_default_id: + self.in_warehouse_id = self.operation_default_id.in_warehouse_id + self.out_warehouse_id = self.operation_default_id.out_warehouse_id + self.location_id = ( + self.operation_default_id.location_id or self.in_warehouse_id.lot_rma_id + ) + self.customer_to_supplier = self.operation_default_id.customer_to_supplier + self.supplier_to_customer = self.operation_default_id.supplier_to_customer + self.in_route_id = self.operation_default_id.in_route_id + self.out_route_id = self.operation_default_id.out_route_id + + @api.depends("rma_line_ids.date_rma") + def _compute_date_rma(self): + """If all order line have same date set date_rma. + If no lines, respect value given by the user. + """ + for rma in self: + if rma.rma_line_ids: + date_rma = rma.rma_line_ids[0].date_rma or False + for rma_line in rma.rma_line_ids: + if rma_line.date_rma != date_rma: + date_rma = False + break + rma.date_rma = date_rma + + def _inverse_date_rma(self): + """When set date_rma set date_rma on all order lines""" + for po in self: + if po.date_rma: + po.rma_line_ids.write({"date_rma": po.date_rma}) + + @api.constrains("partner_id", "rma_line_ids") + def _check_partner_id(self): + if self.rma_line_ids and self.partner_id != self.mapped( + "rma_line_ids.partner_id" + ): + raise UserError(_("Group partner and RMA's partner must be the same.")) + if len(self.mapped("rma_line_ids.partner_id")) > 1: + raise UserError(_("All grouped RMA's should have same partner.")) + + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + if self.env.context.get("supplier") or vals.get("type") == "supplier": + vals["name"] = self.env["ir.sequence"].next_by_code( + "rma.order.supplier" + ) + else: + vals["name"] = self.env["ir.sequence"].next_by_code( + "rma.order.customer" + ) + return super().create(vals_list) + + def _view_shipments(self, result, shipments): + # choose the view_mode accordingly + if len(shipments) > 1: + result["domain"] = [("id", "in", shipments.ids)] + elif len(shipments) == 1: + res = self.env.ref("stock.view_picking_form", False) + result["views"] = [(res and res.id or False, "form")] + result["res_id"] = shipments.ids[0] + return result + + def action_view_in_shipments(self): + action = self.env.ref("stock.action_picking_tree_all") + result = action.sudo().read()[0] + shipments = self.env["stock.picking"] + for line in self.rma_line_ids: + shipments |= line._get_in_pickings() + return self._view_shipments(result, shipments) + + def action_view_out_shipments(self): + action = self.env.ref("stock.action_picking_tree_all") + result = action.sudo().read()[0] + shipments = self.env["stock.picking"] + for line in self.rma_line_ids: + shipments |= line._get_out_pickings() + return self._view_shipments(result, shipments) + + def _get_valid_lines(self): + """:return: A recordset of rma lines.""" + self.ensure_one() + return self.rma_line_ids + + def action_view_lines(self): + if self.type == "customer": + action = self.env.ref("rma.action_rma_customer_lines") + res = self.env.ref("rma.view_rma_line_form", False) + else: + action = self.env.ref("rma.action_rma_supplier_lines") + res = self.env.ref("rma.view_rma_line_supplier_form", False) + result = action.sudo().read()[0] + lines = self._get_valid_lines() + # choose the view_mode accordingly + if len(lines.ids) != 1: + result["domain"] = [("id", "in", lines.ids)] + else: + result["views"] = [(res and res.id or False, "form")] + result["res_id"] = lines.id + result["context"] = {} + return result + + def action_view_supplier_lines(self): + action = self.env.ref("rma.action_rma_supplier_lines") + result = action.sudo().read()[0] + lines = self.rma_line_ids + for line_id in lines: + related_lines = [line.id for line in line_id.supplier_rma_line_ids] + # choose the view_mode accordingly + if len(related_lines) != 1: + result["domain"] = [("id", "in", related_lines)] + else: + res = self.env.ref("rma.view_rma_line_supplier_form", False) + result["views"] = [(res and res.id or False, "form")] + result["res_id"] = related_lines[0] + return result + + @api.onchange("in_warehouse_id") + def _onchange_in_warehouse_id(self): + if self.in_warehouse_id and self.rma_line_ids: + for rma_line in self.rma_line_ids: + rma_line.in_warehouse_id = self.in_warehouse_id.id + rma_line.location_id = self.in_warehouse_id.lot_rma_id.id + + @api.onchange("customer_to_supplier", "supplier_address_id") + def _onchange_customer_to_supplier(self): + if self.type == "customer" and self.rma_line_ids: + for rma_line in self.rma_line_ids: + rma_line.customer_to_supplier = self.customer_to_supplier + rma_line.supplier_address_id = self.supplier_address_id.id + + @api.onchange("supplier_to_customer", "customer_address_id") + def _onchange_supplier_to_customer(self): + if self.type == "supplier" and self.rma_line_ids: + for rma_line in self.rma_line_ids: + rma_line.supplier_to_customer = self.supplier_to_customer + rma_line.customer_address_id = self.customer_address_id.id diff --git a/rma/models/rma_order_line.py b/rma/models/rma_order_line.py new file mode 100644 index 00000000..be9c35c8 --- /dev/null +++ b/rma/models/rma_order_line.py @@ -0,0 +1,807 @@ +# Copyright (C) 2017-20 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +import operator + +from odoo import _, api, fields, models +from odoo.exceptions import UserError, ValidationError + +ops = {"=": operator.eq, "!=": operator.ne} + + +class RmaOrderLine(models.Model): + _name = "rma.order.line" + _description = "RMA" + _inherit = ["mail.thread"] + _order = "id desc" + + @api.model + def _get_default_type(self): + if "supplier" in self.env.context: + return "supplier" + return "customer" + + @api.model + def _default_warehouse_id(self): + rma_id = self.env.context.get("default_rma_id", False) + warehouse = self.env["stock.warehouse"] + if rma_id: + rma = self.env["rma.order"].browse(rma_id) + warehouse = self.env["stock.warehouse"].search( + [("company_id", "=", rma.company_id.id)], limit=1 + ) + return warehouse + + @api.model + def _default_location_id(self): + wh = self._default_warehouse_id() + return wh.lot_rma_id + + @api.onchange("partner_id") + def _onchange_delivery_address(self): + self.delivery_address_id = self.env["res.partner"].browse( + self.partner_id.address_get(["delivery"])["delivery"] + ) + + @api.model + def _get_in_pickings(self): + # We consider an in move one where the first origin is outside + # of the company and the final destination is outside. In case + # of 2 or 3 step pickings, we should categorize as in shipments + # even when they are technically internal transfers. + pickings = self.env["stock.picking"] + for move in self.move_ids: + first_usage = move._get_first_usage() + last_usage = move._get_last_usage() + if last_usage == "internal" and first_usage != "internal": + pickings |= move.picking_id + elif last_usage == "supplier" and first_usage == "customer": + pickings |= move.picking_id + return pickings + + @api.model + def _get_in_moves(self): + moves = self.env["stock.move"] + for move in self.move_ids: + first_usage = move._get_first_usage() + last_usage = move._get_last_usage() + if last_usage == "internal" and first_usage != "internal": + moves |= move + elif last_usage == "supplier" and first_usage == "customer": + moves |= move + return moves + + @api.model + def _get_out_pickings(self): + pickings = self.env["stock.picking"] + for move in self.move_ids: + first_usage = move._get_first_usage() + last_usage = move._get_last_usage() + if first_usage in ("internal", "production") and last_usage in ( + "customer", + "supplier", + ): + pickings |= move.picking_id + elif last_usage == "customer" and first_usage == "supplier": + pickings |= move.picking_id + return pickings + + def _compute_in_shipment_count(self): + for line in self: + pickings = line._get_in_pickings() + line.in_shipment_count = len(pickings) + + def _compute_out_shipment_count(self): + for line in self: + pickings = line._get_out_pickings() + line.out_shipment_count = len(pickings) + + def _get_rma_move_qty(self, states, direction="in"): + for rec in self: + product_obj = self.env["uom.uom"] + qty = 0.0 + if direction == "in": + moves = rec.move_ids.filtered( + lambda m: m.state in states + and ( + m.location_id.usage == "supplier" + or m.location_id.usage == "customer" + ) + and ( + m.location_dest_id.usage == "internal" + or m.location_dest_id.usage == "supplier" + ) + ) + elif direction == "out": + moves = rec.move_ids.filtered( + lambda m: m.state in states + and ( + m.location_dest_id.usage == "supplier" + or m.location_dest_id.usage == "customer" + ) + and ( + m.location_id.usage == "internal" + or m.location_id.usage == "supplier" + ) + ) + for move in moves: + # If the move is part of a chain don't count it + if direction == "out" and move.move_orig_ids: + continue + elif direction == "in" and move.move_dest_ids: + continue + qty += product_obj._compute_quantity(move.product_uom_qty, rec.uom_id) + return qty + + @api.depends( + "move_ids", + "move_ids.state", + "qty_received", + "receipt_policy", + "product_qty", + "type", + ) + def _compute_qty_to_receive(self): + for rec in self: + rec.qty_to_receive = 0.0 + if rec.receipt_policy == "ordered": + rec.qty_to_receive = rec.product_qty - rec.qty_received + elif rec.receipt_policy == "delivered": + rec.qty_to_receive = rec.qty_delivered - rec.qty_received + + @api.depends( + "move_ids", + "move_ids.state", + "delivery_policy", + "product_qty", + "type", + "qty_delivered", + "qty_received", + ) + def _compute_qty_to_deliver(self): + for rec in self: + rec.qty_to_deliver = 0.0 + if rec.delivery_policy == "ordered": + rec.qty_to_deliver = rec.product_qty - rec.qty_delivered + elif rec.delivery_policy == "received": + rec.qty_to_deliver = rec.qty_received - rec.qty_delivered + + @api.depends("move_ids", "move_ids.state", "type") + def _compute_qty_incoming(self): + for rec in self: + qty = rec._get_rma_move_qty( + ("draft", "confirmed", "assigned"), direction="in" + ) + rec.qty_incoming = qty + + @api.depends("move_ids", "move_ids.state", "type") + def _compute_qty_received(self): + for rec in self: + qty = rec._get_rma_move_qty("done", direction="in") + rec.qty_received = qty + + @api.depends("move_ids", "move_ids.state", "type") + def _compute_qty_outgoing(self): + for rec in self: + qty = rec._get_rma_move_qty( + ("draft", "confirmed", "assigned"), direction="out" + ) + rec.qty_outgoing = qty + + @api.depends("move_ids", "move_ids.state", "type") + def _compute_qty_delivered(self): + for rec in self: + qty = rec._get_rma_move_qty("done", direction="out") + rec.qty_delivered = qty + + @api.model + def _get_supplier_rma_qty(self): + return sum( + self.supplier_rma_line_ids.filtered(lambda r: r.state != "cancel").mapped( + "product_qty" + ) + ) + + @api.depends( + "customer_to_supplier", + "supplier_rma_line_ids", + "move_ids", + "move_ids.state", + "qty_received", + "receipt_policy", + "product_qty", + "type", + ) + def _compute_qty_supplier_rma(self): + for rec in self: + if rec.customer_to_supplier: + supplier_rma_qty = rec._get_supplier_rma_qty() + rec.qty_to_supplier_rma = rec.product_qty - supplier_rma_qty + rec.qty_in_supplier_rma = supplier_rma_qty + else: + rec.qty_to_supplier_rma = 0.0 + rec.qty_in_supplier_rma = 0.0 + + def _compute_rma_line_count(self): + for rec in self.filtered(lambda r: r.type == "customer"): + rec.rma_line_count = len(rec.supplier_rma_line_ids) + for rec in self.filtered(lambda r: r.type == "supplier"): + rec.rma_line_count = len(rec.customer_rma_id) + + @api.model + def _default_date_rma(self): + return fields.Datetime.now() + + delivery_address_id = fields.Many2one( + comodel_name="res.partner", + string="Partner delivery address", + help="This address will be used to deliver repaired or replacement " + "products.", + ) + rma_id = fields.Many2one( + comodel_name="rma.order", + string="RMA Group", + tracking=True, + readonly=True, + ) + name = fields.Char( + string="Reference", + required=True, + default="/", + help="Add here the supplier RMA #. Otherwise an internal code is" " assigned.", + copy=False, + ) + description = fields.Text() + conditions = fields.Html(string="Terms and conditions") + origin = fields.Char( + string="Source Document", + help="Reference of the document that produced this rma.", + ) + date_rma = fields.Datetime( + string="Order Date", index=True, default=lambda self: self._default_date_rma() + ) + state = fields.Selection( + selection=[ + ("draft", "Draft"), + ("to_approve", "To Approve"), + ("approved", "Approved"), + ("done", "Done"), + ("canceled", "Canceled"), + ], + default="draft", + tracking=True, + ) + operation_id = fields.Many2one( + comodel_name="rma.operation", + required=True, + readonly=False, + tracking=True, + ) + assigned_to = fields.Many2one( + comodel_name="res.users", + tracking=True, + default=lambda self: self.env.uid, + ) + requested_by = fields.Many2one( + comodel_name="res.users", + tracking=True, + default=lambda self: self.env.uid, + ) + partner_id = fields.Many2one( + comodel_name="res.partner", + required=True, + store=True, + tracking=True, + ) + sequence = fields.Integer( + default=10, help="Gives the sequence of this line when displaying the rma." + ) + product_id = fields.Many2one( + comodel_name="product.product", + ondelete="restrict", + required=True, + ) + product_tracking = fields.Selection(related="product_id.tracking") + lot_id = fields.Many2one( + comodel_name="stock.lot", + string="Lot/Serial Number", + ) + product_qty = fields.Float( + string="Return Qty", + copy=False, + default=1.0, + digits="Product Unit of Measure", + ) + uom_id = fields.Many2one( + comodel_name="uom.uom", + string="Unit of Measure", + required=True, + compute="_compute_uom_id", + precompute=True, + store=True, + ) + price_unit = fields.Monetary( + string="Unit cost", + help="Unit cost of the items under RMA", + ) + in_shipment_count = fields.Integer( + compute="_compute_in_shipment_count", string="# of Shipments" + ) + out_shipment_count = fields.Integer( + compute="_compute_out_shipment_count", string="# of Deliveries" + ) + move_ids = fields.One2many( + "stock.move", "rma_line_id", string="Stock Moves", readonly=True, copy=False + ) + reference_move_id = fields.Many2one( + comodel_name="stock.move", + string="Originating Stock Move", + copy=False, + ) + currency_id = fields.Many2one( + "res.currency", + default=lambda self: self.env.company.currency_id, + ) + company_id = fields.Many2one( + comodel_name="res.company", + required=True, + default=lambda self: self.env.company, + ) + type = fields.Selection( + selection=[("customer", "Customer"), ("supplier", "Supplier")], + required=True, + default=lambda self: self._get_default_type(), + readonly=True, + ) + customer_to_supplier = fields.Boolean( + "The customer will send to the supplier", + ) + supplier_to_customer = fields.Boolean( + "The supplier will send to the customer", + ) + receipt_policy = fields.Selection( + [ + ("no", "Not required"), + ("ordered", "Based on Ordered Quantities"), + ("delivered", "Based on Delivered Quantities"), + ], + required=True, + default="no", + readonly=False, + ) + delivery_policy = fields.Selection( + [ + ("no", "Not required"), + ("ordered", "Based on Ordered Quantities"), + ("received", "Based on Received Quantities"), + ], + required=True, + default="no", + readonly=False, + ondelete="cascade", + ) + in_route_id = fields.Many2one( + "stock.route", + string="Inbound Route", + required=True, + domain=[("rma_selectable", "=", True)], + compute="_compute_in_route_id", + precompute=True, + store=True, + ) + out_route_id = fields.Many2one( + "stock.route", + string="Outbound Route", + required=True, + domain=[("rma_selectable", "=", True)], + compute="_compute_out_route_id", + precompute=True, + store=True, + ) + in_warehouse_id = fields.Many2one( + comodel_name="stock.warehouse", + string="Inbound Warehouse", + required=True, + default=lambda self: self._default_warehouse_id(), + ) + out_warehouse_id = fields.Many2one( + comodel_name="stock.warehouse", + string="Outbound Warehouse", + required=True, + default=lambda self: self._default_warehouse_id(), + ) + location_id = fields.Many2one( + comodel_name="stock.location", + string="Send To This Company Location", + required=True, + default=lambda self: self._default_location_id(), + ) + customer_rma_id = fields.Many2one( + "rma.order.line", string="Customer RMA line", ondelete="cascade" + ) + supplier_rma_line_ids = fields.One2many("rma.order.line", "customer_rma_id") + rma_line_count = fields.Integer( + compute="_compute_rma_line_count", string="# of RMA lines associated" + ) + supplier_address_id = fields.Many2one( + comodel_name="res.partner", + string="Supplier Address", + help="Address of the supplier in case of Customer RMA operation " "dropship.", + ) + customer_address_id = fields.Many2one( + comodel_name="res.partner", + string="Customer Address", + help="Address of the customer in case of Supplier RMA operation " "dropship.", + ) + qty_to_receive = fields.Float( + digits="Product Unit of Measure", + compute="_compute_qty_to_receive", + store=True, + ) + qty_incoming = fields.Float( + string="Incoming Qty", + copy=False, + readonly=True, + digits="Product Unit of Measure", + compute="_compute_qty_incoming", + store=True, + ) + qty_received = fields.Float( + copy=False, + digits="Product Unit of Measure", + compute="_compute_qty_received", + store=True, + ) + qty_to_deliver = fields.Float( + copy=False, + digits="Product Unit of Measure", + readonly=True, + compute="_compute_qty_to_deliver", + store=True, + ) + qty_outgoing = fields.Float( + string="Outgoing Qty", + copy=False, + readonly=True, + digits="Product Unit of Measure", + compute="_compute_qty_outgoing", + store=True, + ) + qty_delivered = fields.Float( + copy=False, + digits="Product Unit of Measure", + readonly=True, + compute="_compute_qty_delivered", + store=True, + ) + qty_to_supplier_rma = fields.Float( + string="Qty to send to Supplier RMA", + digits="Product Unit of Measure", + readonly=True, + compute="_compute_qty_supplier_rma", + store=True, + ) + qty_in_supplier_rma = fields.Float( + string="Qty in Supplier RMA", + digits="Product Unit of Measure", + readonly=True, + compute="_compute_qty_supplier_rma", + store=True, + ) + under_warranty = fields.Boolean(string="Under Warranty?") + + def _prepare_rma_line_from_stock_move(self, sm, lot=False): + if not self.type: + self.type = self._get_default_type() + if self.type == "customer": + operation = ( + sm.product_id.rma_customer_operation_id + or sm.product_id.categ_id.rma_customer_operation_id + ) + else: + operation = ( + sm.product_id.rma_supplier_operation_id + or sm.product_id.categ_id.rma_supplier_operation_id + ) + + if not operation: + operation = self.env["rma.operation"].search( + [("type", "=", self.type)], limit=1 + ) + if not operation: + raise ValidationError(_("Please define an operation first.")) + + if not operation.in_route_id or not operation.out_route_id: + route = self.env["stock.route"].search( + [("rma_selectable", "=", True)], limit=1 + ) + if not route: + raise ValidationError(_("Please define an RMA route.")) + + if ( + not operation.in_warehouse_id + or not operation.out_warehouse_id + or not ( + operation.in_warehouse_id.lot_rma_id + or operation.out_warehouse_id.lot_rma_id + ) + ): + warehouse = self.env["stock.warehouse"].search( + [("company_id", "=", self.company_id.id), ("lot_rma_id", "!=", False)], + limit=1, + ) + if not warehouse: + raise ValidationError( + _("Please define a warehouse with a default RMA location.") + ) + + data = { + "product_id": sm.product_id.id, + "lot_id": lot and lot.id or False, + "origin": sm.picking_id.name or sm.name, + "uom_id": sm.product_uom.id, + "product_qty": sm.product_uom_qty, + "delivery_address_id": sm.picking_id.partner_id.id, + "operation_id": operation.id, + "receipt_policy": operation.receipt_policy, + "delivery_policy": operation.delivery_policy, + "in_warehouse_id": operation.in_warehouse_id.id or warehouse.id, + "out_warehouse_id": operation.out_warehouse_id.id or warehouse.id, + "in_route_id": operation.in_route_id.id or route.id, + "out_route_id": operation.out_route_id.id or route.id, + "location_id": ( + operation.location_id.id + or operation.in_warehouse_id.lot_rma_id.id + or operation.out_warehouse_id.lot_rma_id.id + or warehouse.lot_rma_id.id + ), + } + return data + + @api.onchange("reference_move_id") + def _onchange_reference_move_id(self): + self.ensure_one() + sm = self.reference_move_id + if not sm: + return + if sm.move_line_ids.lot_id: + if len(sm.move_line_ids.lot_id) > 1: + raise UserError(_("To manage lots use RMA groups.")) + else: + data = self._prepare_rma_line_from_stock_move( + sm, lot=sm.move_line_ids.lot_id[0] + ) + self.update(data) + else: + data = self._prepare_rma_line_from_stock_move(sm, lot=False) + self.update(data) + self._remove_other_data_origin("reference_move_id") + + @api.constrains("reference_move_id", "partner_id") + def _check_move_partner(self): + for rec in self: + if ( + rec.reference_move_id + and rec.reference_move_id.picking_id.partner_id != rec.partner_id + ): + raise ValidationError( + _( + "RMA customer and originating stock move customer " + "doesn't match." + ) + ) + + def _remove_other_data_origin(self, exception): + if not exception == "reference_move_id": + self.reference_move_id = False + return True + + def _check_lot_assigned(self): + for rec in self: + if rec.product_id.tracking == "serial" and rec.product_qty != 1: + raise ValidationError( + _( + "Product %s has serial tracking configuration, " + "quantity to receive should be 1" + ) + % (rec.product_id.display_name) + ) + + def action_rma_to_approve(self): + self._check_lot_assigned() + self.write({"state": "to_approve"}) + for rec in self: + if rec.product_id.rma_approval_policy == "one_step": + rec.action_rma_approve() + return True + + def action_rma_draft(self): + self.write({"state": "draft"}) + return True + + def action_rma_approve(self): + self.write({"state": "approved"}) + return True + + def action_rma_done(self): + self.write({"state": "done"}) + return True + + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + if not vals.get("name") or vals.get("name") == "/": + if self.env.context.get("supplier"): + vals["name"] = self.env["ir.sequence"].next_by_code( + "rma.order.line.supplier" + ) + else: + vals["name"] = self.env["ir.sequence"].next_by_code( + "rma.order.line.customer" + ) + return super().create(vals_list) + + def check_cancel(self): + for move in self.move_ids: + if move.state == "done": + raise UserError( + _("Unable to cancel %s as some receptions have already been done.") + % (self.name) + ) + + def action_rma_cancel(self): + for order in self: + order.check_cancel() + order.write({"state": "canceled"}) + order.move_ids._action_cancel() + shipments = order._get_in_pickings() + shipments |= order._get_out_pickings() + for ship in shipments: + ship.action_cancel() + return True + + def _get_price_unit(self): + """The price unit corresponds to the cost of that product""" + self.ensure_one() + if self.reference_move_id: + price_unit = self.reference_move_id.price_unit + else: + price_unit = self.product_id.with_company(self.company_id).standard_price + return price_unit + + @api.onchange("product_id") + def _onchange_product_id(self): + result = {} + if not self.product_id: + return result + self.uom_id = self.product_id.uom_id.id + if not self.type: + self.type = self._get_default_type() + self.price_unit = self._get_price_unit() + if self.type == "customer": + self.operation_id = ( + self.product_id.rma_customer_operation_id + or self.product_id.categ_id.rma_customer_operation_id + ) + else: + self.operation_id = ( + self.product_id.rma_supplier_operation_id + or self.product_id.categ_id.rma_supplier_operation_id + ) + if self.lot_id.product_id != self.product_id: + self.lot_id = False + return result + + @api.onchange("operation_id") + def _onchange_operation_id(self): + result = {} + if not self.operation_id: + return result + self.receipt_policy = self.operation_id.receipt_policy + self.delivery_policy = self.operation_id.delivery_policy + self.customer_to_supplier = ( + self.rma_id.customer_to_supplier or self.operation_id.customer_to_supplier + ) + self.supplier_to_customer = ( + self.rma_id.supplier_to_customer or self.operation_id.supplier_to_customer + ) + self.in_warehouse_id = ( + self.rma_id.in_warehouse_id or self.operation_id.in_warehouse_id + ) + self.out_warehouse_id = ( + self.rma_id.out_warehouse_id or self.operation_id.out_warehouse_id + ) + self.location_id = ( + self.rma_id.location_id + or self.operation_id.location_id + or self.in_warehouse_id.lot_rma_id + ) + self.in_route_id = self.rma_id.in_route_id or self.operation_id.in_route_id + self.out_route_id = self.rma_id.out_route_id or self.operation_id.out_route_id + return result + + @api.depends("operation_id") + def _compute_in_route_id(self): + for rec in self: + rec.in_route_id = rec.operation_id.in_route_id + + @api.depends("operation_id") + def _compute_out_route_id(self): + for rec in self: + rec.out_route_id = rec.operation_id.out_route_id + + @api.onchange("customer_to_supplier", "type") + def _onchange_receipt_policy(self): + if self.type == "supplier" and self.customer_to_supplier: + self.receipt_policy = "no" + elif self.type == "customer" and self.supplier_to_customer: + self.delivery_policy = "no" + + @api.onchange("lot_id") + def _onchange_lot_id(self): + product = self.lot_id.product_id + if product: + self.product_id = product + + @api.depends("product_id") + def _compute_uom_id(self): + for rec in self: + if rec.product_id: + rec.uom_id = rec.product_id.uom_id + + def action_view_in_shipments(self): + action = self.env.ref("stock.action_picking_tree_all") + result = action.sudo().read()[0] + shipments = self.env["stock.picking"] + for line in self: + shipments |= line._get_in_pickings() + # choose the view_mode accordingly + if len(shipments) != 1: + result["domain"] = "[('id', 'in', " + str(shipments.ids) + ")]" + elif len(shipments) == 1: + res = self.env.ref("stock.view_picking_form", False) + result["views"] = [(res and res.id or False, "form")] + result["res_id"] = shipments.ids[0] + return result + + def action_view_out_shipments(self): + action = self.env.ref("stock.action_picking_tree_all") + result = action.sudo().read()[0] + shipments = self.env["stock.picking"] + for line in self: + shipments |= line._get_out_pickings() + # choose the view_mode accordingly + if len(shipments) != 1: + result["domain"] = "[('id', 'in', " + str(shipments.ids) + ")]" + elif len(shipments) == 1: + res = self.env.ref("stock.view_picking_form", False) + result["views"] = [(res and res.id or False, "form")] + result["res_id"] = shipments.ids[0] + return result + + def action_view_rma_lines(self): + if self.type == "customer": + # from customer we link to supplier rma + action = self.env.ref("rma.action_rma_supplier_lines") + rma_lines = self.supplier_rma_line_ids.ids + res = self.env.ref("rma.view_rma_line_supplier_form", False) + else: + # from supplier we link to customer rma + action = self.env.ref("rma.action_rma_customer_lines") + rma_lines = self.customer_rma_id.ids + res = self.env.ref("rma.view_rma_line_form", False) + result = action.sudo().read()[0] + # choose the view_mode accordingly + if rma_lines and len(rma_lines) != 1: + result["domain"] = rma_lines.ids + elif len(rma_lines) == 1: + result["views"] = [(res and res.id or False, "form")] + result["res_id"] = rma_lines[0] + return result + + @api.constrains("partner_id", "rma_id") + def _check_partner_id(self): + if self.rma_id and self.partner_id != self.rma_id.partner_id: + raise ValidationError( + _("Group partner and RMA's partner must be the same.") + ) diff --git a/rma/models/stock_move.py b/rma/models/stock_move.py new file mode 100644 index 00000000..f3077f0b --- /dev/null +++ b/rma/models/stock_move.py @@ -0,0 +1,107 @@ +# Copyright (C) 2017-20 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import api, fields, models + + +class StockMove(models.Model): + _inherit = "stock.move" + + rma_line_id = fields.Many2one( + "rma.order.line", string="RMA line", ondelete="restrict" + ) + + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + if vals.get("group_id"): + group = self.env["procurement.group"].browse(vals["group_id"]) + if group.rma_line_id: + vals["rma_line_id"] = group.rma_line_id.id + return super().create(vals_list) + + def _action_assign(self, force_qty=False): + res = super()._action_assign(force_qty=force_qty) + for move in self: + if move.rma_line_id: + move.partner_id = move.rma_line_id.partner_id.id or False + return res + + @api.model + def _get_first_usage(self): + if self.move_orig_ids: + # We assume here that all origin moves come from the same place + return self.move_orig_ids[0]._get_first_usage() + else: + return self.location_id.usage + + @api.model + def _get_last_usage(self): + if self.move_dest_ids: + # We assume here that all origin moves come from the same place + return self.move_dest_ids[0]._get_last_usage() + else: + return self.location_dest_id.usage + + def _should_bypass_reservation(self, forced_location=False): + res = super()._should_bypass_reservation(forced_location=forced_location) + if self.env.context.get("force_no_bypass_reservation"): + return False + return res + + def _get_available_quantity( + self, + location_id, + lot_id=None, + package_id=None, + owner_id=None, + strict=False, + allow_negative=False, + ): + if ( + not lot_id + and self.rma_line_id.lot_id + and self.location_id.usage == "internal" + ): + # In supplier RMA deliveries we can only send the RMA lot/serial. + lot_id = self.rma_line_id.lot_id + return super()._get_available_quantity( + location_id, + lot_id=lot_id, + package_id=package_id, + owner_id=owner_id, + strict=strict, + allow_negative=allow_negative, + ) + + def _update_reserved_quantity( + self, + need, + location_id, + quant_ids=None, + lot_id=None, + package_id=None, + owner_id=None, + strict=True, + ): + if ( + not lot_id + and self.rma_line_id.lot_id + and self.location_id.usage == "internal" + ): + # In supplier RMA deliveries we can only send the RMA lot/serial. + lot_id = self.rma_line_id.lot_id + return super()._update_reserved_quantity( + need, + location_id, + quant_ids=quant_ids, + lot_id=lot_id, + package_id=package_id, + owner_id=owner_id, + strict=strict, + ) + + @api.model + def _prepare_merge_moves_distinct_fields(self): + res = super()._prepare_merge_moves_distinct_fields() + return res + ["rma_line_id"] diff --git a/rma/models/stock_rule.py b/rma/models/stock_rule.py new file mode 100644 index 00000000..acaf17f5 --- /dev/null +++ b/rma/models/stock_rule.py @@ -0,0 +1,40 @@ +# Copyright (C) 2017-22 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import models + + +class StockRule(models.Model): + _inherit = "stock.rule" + + def _get_stock_move_values( + self, + product_id, + product_qty, + product_uom, + location_id, + name, + origin, + company_id, + values, + ): + res = super()._get_stock_move_values( + product_id, + product_qty, + product_uom, + location_id, + name, + origin, + company_id, + values, + ) + if "rma_line_id" in values: + line = values.get("rma_line_id") + line = self.env["rma.order.line"].browse([line]) + res["rma_line_id"] = line.id + if line.delivery_address_id: + res["partner_id"] = line.delivery_address_id.id + elif line.rma_id.partner_id: + res["partner_id"] = line.rma_id.partner_id.id + res["price_unit"] = line._get_price_unit() + return res diff --git a/rma/models/stock_warehouse.py b/rma/models/stock_warehouse.py new file mode 100644 index 00000000..9feebe72 --- /dev/null +++ b/rma/models/stock_warehouse.py @@ -0,0 +1,270 @@ +# Copyright (C) 2017-20 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import _, fields, models + + +class StockWarehouse(models.Model): + _inherit = "stock.warehouse" + + lot_rma_id = fields.Many2one( + comodel_name="stock.location", string="RMA Location" + ) # not readonly to have the possibility to edit location and + # propagate to rma rules (add a auto-update when writing this field?) + rma_cust_out_type_id = fields.Many2one( + comodel_name="stock.picking.type", string="RMA Customer out Type", readonly=True + ) + rma_sup_out_type_id = fields.Many2one( + comodel_name="stock.picking.type", string="RMA Supplier out Type", readonly=True + ) + rma_cust_in_type_id = fields.Many2one( + comodel_name="stock.picking.type", string="RMA Customer in Type", readonly=True + ) + rma_sup_in_type_id = fields.Many2one( + comodel_name="stock.picking.type", string="RMA Supplier in Type", readonly=True + ) + rma_in_this_wh = fields.Boolean( + string="RMA in this Warehouse", + help="If set, it will create RMA location, picking types and routes " + "for this warehouse.", + ) + rma_customer_in_pull_id = fields.Many2one( + comodel_name="stock.rule", string="RMA Customer In Rule" + ) + rma_customer_out_pull_id = fields.Many2one( + comodel_name="stock.rule", string="RMA Customer Out Rule" + ) + rma_supplier_in_pull_id = fields.Many2one( + comodel_name="stock.rule", string="RMA Supplier In Rule" + ) + rma_supplier_out_pull_id = fields.Many2one( + comodel_name="stock.rule", string="RMA Supplier Out Rule" + ) + + def _get_rma_types(self): + return [ + self.rma_cust_out_type_id, + self.rma_sup_out_type_id, + self.rma_cust_in_type_id, + self.rma_sup_in_type_id, + ] + + def _rma_types_available(self): + self.ensure_one() + rma_types = self._get_rma_types() + for r_type in rma_types: + if not r_type: + return False + return True + + def write(self, vals): + if "rma_in_this_wh" in vals: + if vals.get("rma_in_this_wh"): + for wh in self: + # RMA location: + if not wh.lot_rma_id: + wh.lot_rma_id = self.env["stock.location"].create( + { + "name": "RMA", + "usage": "internal", + "location_id": wh.view_location_id.id, + "company_id": wh.company_id.id, + "return_location": True, + } + ) + # RMA types + if not wh._rma_types_available(): + wh._create_rma_picking_types() + else: + for r_type in wh._get_rma_types(): + if r_type: + r_type.active = True + # RMA rules: + wh._create_or_update_rma_pull() + else: + for wh in self: + for r_type in wh._get_rma_types(): + if r_type: + r_type.active = False + # Unlink rules: + self.mapped("rma_customer_in_pull_id").unlink() + self.mapped("rma_customer_out_pull_id").unlink() + self.mapped("rma_supplier_in_pull_id").unlink() + self.mapped("rma_supplier_out_pull_id").unlink() + return super().write(vals) + + def _create_rma_picking_types(self): + picking_type_obj = self.env["stock.picking.type"] + customer_loc, supplier_loc = self._get_partner_locations() + for wh in self: + other_pick_type = picking_type_obj.search( + [("warehouse_id", "=", wh.id)], order="sequence desc", limit=1 + ) + color = other_pick_type.color if other_pick_type else 0 + max_sequence = other_pick_type and other_pick_type.sequence or 0 + # create rma_cust_out_type_id: + rma_cust_out_type_id = picking_type_obj.create( + { + "name": _("Customer RMA Deliveries"), + "warehouse_id": wh.id, + "code": "outgoing", + "use_create_lots": True, + "use_existing_lots": False, + "sequence_id": self.env.ref("rma.seq_picking_type_rma_cust_out").id, + "default_location_src_id": wh.lot_rma_id.id, + "default_location_dest_id": customer_loc.id, + "sequence": max_sequence, + "color": color, + "sequence_code": "RMA → Customer", + } + ) + # create rma_sup_out_type_id: + rma_sup_out_type_id = picking_type_obj.create( + { + "name": _("Supplier RMA Deliveries"), + "warehouse_id": wh.id, + "code": "outgoing", + "use_create_lots": True, + "use_existing_lots": False, + "sequence_id": self.env.ref("rma.seq_picking_type_rma_sup_out").id, + "default_location_src_id": wh.lot_rma_id.id, + "default_location_dest_id": supplier_loc.id, + "sequence": max_sequence, + "color": color, + "sequence_code": "Customer → RMA", + } + ) + # create rma_cust_in_type_id: + rma_cust_in_type_id = picking_type_obj.create( + { + "name": _("Customer RMA Receipts"), + "warehouse_id": wh.id, + "code": "incoming", + "use_create_lots": True, + "use_existing_lots": False, + "sequence_id": self.env.ref("rma.seq_picking_type_rma_cust_in").id, + "default_location_src_id": customer_loc.id, + "default_location_dest_id": wh.lot_rma_id.id, + "sequence": max_sequence, + "color": color, + "sequence_code": "RMA -> Supplier", + } + ) + # create rma_sup_in_type_id: + rma_sup_in_type_id = picking_type_obj.create( + { + "name": _("Supplier RMA Receipts"), + "warehouse_id": wh.id, + "code": "incoming", + "use_create_lots": True, + "use_existing_lots": False, + "sequence_id": self.env.ref("rma.seq_picking_type_rma_sup_in").id, + "default_location_src_id": supplier_loc.id, + "default_location_dest_id": wh.lot_rma_id.id, + "sequence": max_sequence, + "color": color, + "sequence_code": "Supplier -> RMA", + } + ) + wh.write( + { + "rma_cust_out_type_id": rma_cust_out_type_id.id, + "rma_sup_out_type_id": rma_sup_out_type_id.id, + "rma_cust_in_type_id": rma_cust_in_type_id.id, + "rma_sup_in_type_id": rma_sup_in_type_id.id, + } + ) + return True + + def get_rma_rules_dict(self): + self.ensure_one() + rma_rules = dict() + customer_loc, supplier_loc = self._get_partner_locations() + rma_rules["rma_customer_in"] = { + "name": self._format_rulename(self, customer_loc, self.lot_rma_id.name), + "action": "pull", + "warehouse_id": self.id, + "company_id": self.company_id.id, + "location_src_id": customer_loc.id, + "location_dest_id": self.lot_rma_id.id, + "procure_method": "make_to_stock", + "route_id": self.env.ref("rma.route_rma_customer").id, + "picking_type_id": self.rma_cust_in_type_id.id, + "active": True, + } + rma_rules["rma_customer_out"] = { + "name": self._format_rulename(self, self.lot_rma_id, customer_loc.name), + "action": "pull", + "warehouse_id": self.id, + "company_id": self.company_id.id, + "location_src_id": self.lot_rma_id.id, + "location_dest_id": customer_loc.id, + "procure_method": "make_to_stock", + "route_id": self.env.ref("rma.route_rma_customer").id, + "picking_type_id": self.rma_cust_out_type_id.id, + "active": True, + } + rma_rules["rma_supplier_in"] = { + "name": self._format_rulename(self, supplier_loc, self.lot_rma_id.name), + "action": "pull", + "warehouse_id": self.id, + "company_id": self.company_id.id, + "location_src_id": supplier_loc.id, + "location_dest_id": self.lot_rma_id.id, + "procure_method": "make_to_stock", + "route_id": self.env.ref("rma.route_rma_supplier").id, + "picking_type_id": self.rma_sup_in_type_id.id, + "active": True, + } + rma_rules["rma_supplier_out"] = { + "name": self._format_rulename(self, self.lot_rma_id, supplier_loc.name), + "action": "pull", + "warehouse_id": self.id, + "company_id": self.company_id.id, + "location_src_id": self.lot_rma_id.id, + "location_dest_id": supplier_loc.id, + "procure_method": "make_to_stock", + "route_id": self.env.ref("rma.route_rma_supplier").id, + "picking_type_id": self.rma_sup_out_type_id.id, + "active": True, + } + return rma_rules + + def _create_or_update_rma_pull(self): + rule_obj = self.env["stock.rule"] + for wh in self: + rules_dict = wh.get_rma_rules_dict() + if wh.rma_customer_in_pull_id: + wh.rma_customer_in_pull_id.write(rules_dict["rma_customer_in"]) + else: + wh.rma_customer_in_pull_id = rule_obj.create( + rules_dict["rma_customer_in"] + ) + + if wh.rma_customer_out_pull_id: + wh.rma_customer_out_pull_id.write(rules_dict["rma_customer_out"]) + else: + wh.rma_customer_out_pull_id = rule_obj.create( + rules_dict["rma_customer_out"] + ) + + if wh.rma_supplier_in_pull_id: + wh.rma_supplier_in_pull_id.write(rules_dict["rma_supplier_in"]) + else: + wh.rma_supplier_in_pull_id = rule_obj.create( + rules_dict["rma_supplier_in"] + ) + + if wh.rma_supplier_out_pull_id: + wh.rma_supplier_out_pull_id.write(rules_dict["rma_supplier_out"]) + else: + wh.rma_supplier_out_pull_id = rule_obj.create( + rules_dict["rma_supplier_out"] + ) + return True + + +class StockLocationRoute(models.Model): + _inherit = "stock.route" + + rma_selectable = fields.Boolean(string="Selectable on RMA Lines") diff --git a/rma/pyproject.toml b/rma/pyproject.toml new file mode 100644 index 00000000..4231d0cc --- /dev/null +++ b/rma/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/rma/readme/CONFIGURE.rst b/rma/readme/CONFIGURE.rst new file mode 100644 index 00000000..740b1e14 --- /dev/null +++ b/rma/readme/CONFIGURE.rst @@ -0,0 +1,41 @@ +Security +-------- + +Go to Settings > Users and assign the appropiate permissions to users. +Different security groups grant distinct levels of access to the RMA features. + +* Users in group "RMA Customer User" or "RMA Supplier User" can access to, + create and process RMA's associated to customers or suppliers respectively. + +* Users in group "RMA Manager" can access to, create, approve and process RMA's + associated to both customers and suppliers. + +RMA Approval Policy +------------------- + +There are two RMA approval policies in product catogories: + +* One step: Always auto-approve RMAs that only contain products within + categories with this policy. +* Two steps: A RMA order containing a product within a category with this + policy will request the RMA manager approval. + +In order to change the approval policy of a product category follow the next +steps: + +#. Go to *Inventory > Configuration > Products > Product Categories*. +#. Select one and change the field *RMA Approval Policy* to your convenience. + +Other Settings +-------------- + +#. Go to RMA > Configuration > Settings > Return Merchandising + Authorization and select the option "Display 3 fields on rma: partner, + invoice address, delivery address" if needed. +#. Go to RMA > Configuration > Warehouse management > Warehouses and add + a default RMA location and RMA picking type for customers and suppliers RMA + picking type. In case the warehouse is configured to use routes, you need to + create at least one route per rma type with at least two push rules (one for + inbound another for outbound) it's very important to select the type of + operation supplier if we are moving in the company and customer if we are + moving out of the company. diff --git a/rma/readme/CONTRIBUTORS.rst b/rma/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..61bac6ba --- /dev/null +++ b/rma/readme/CONTRIBUTORS.rst @@ -0,0 +1,8 @@ +* Jordi Ballester Alomar +* Aaron Henriquez +* Lois Rilo +* Bhavesh Odedra +* Akim Juillerat +* Alexandre Fayolle +* Chafique Delli +* Héctor Villarreal diff --git a/rma/readme/DESCRIPTION.rst b/rma/readme/DESCRIPTION.rst new file mode 100644 index 00000000..6ca0172a --- /dev/null +++ b/rma/readme/DESCRIPTION.rst @@ -0,0 +1,18 @@ +A Return Merchandise Authorization (RMA), is a part of the process of +returning a product in order to receive a refund, replacement, or repair +during the product's warranty period. + +The purchaser of the product must contact the manufacturer (or distributor +or retailer) to obtain authorization to return the product. + +The resulting RMA number must be displayed on or included in the returned +product's packaging. + +The issuance of an RMA is a key gatekeeping moment in the reverse logistics +cycle, providing the vendor with a final opportunity to diagnose and correct +the customer's problem with the product (such as improper installation or +configuration) before the customer permanently relinquishes ownership +of the product to the manufacturer, commonly referred to as a return. + +As returns are costly for the vendor and inconvenient for the customer, +any return that can be prevented benefits both parties. diff --git a/rma/readme/ROADMAP.rst b/rma/readme/ROADMAP.rst new file mode 100644 index 00000000..ca6afe09 --- /dev/null +++ b/rma/readme/ROADMAP.rst @@ -0,0 +1,6 @@ +* Picking operations report in customer RMA dropshipping case is showing + "Vendor Address" while it should be "Customer Address". +* Dropshipping always counted as a delivery on the smart buttons. +* Uninstall hook. +* Constraints instead of required fields on rma.order.line. +* Rename type field on rma.order and rma.order.line diff --git a/rma/readme/USAGE.rst b/rma/readme/USAGE.rst new file mode 100644 index 00000000..b0ee9ff4 --- /dev/null +++ b/rma/readme/USAGE.rst @@ -0,0 +1,12 @@ +RMA are accessible though Inventory menu. There's four menus, divided by type. +Users can access to the list of RMA or RMA lines. + +Create an RMA: + +#. Select a partner. Enter RMA lines associated to an existing picking, or + manually. +#. Request approval and approve. +#. Click on RMA Lines button. +#. Click on more and select an option: "Receive products", "Create Delivery + Order". +#. Go back to the RMA. Set the RMA to done if not further action is required. diff --git a/rma/report/report_deliveryslip.xml b/rma/report/report_deliveryslip.xml new file mode 100644 index 00000000..d799380d --- /dev/null +++ b/rma/report/report_deliveryslip.xml @@ -0,0 +1,57 @@ + + + + + + + + + diff --git a/rma/report/rma_report.xml b/rma/report/rma_report.xml new file mode 100644 index 00000000..c5b9a811 --- /dev/null +++ b/rma/report/rma_report.xml @@ -0,0 +1,24 @@ + + + + + RMA + rma.order.line + qweb-pdf + rma.report_rma_order_line + rma.report_rma_order_line + ('RMA - %s' % (object.name)) + + report + + + RMA Group + rma.order + qweb-pdf + rma.report_rma_order + rma.report_rma_order + ('RMA Group - %s' % (object.name)) + + report + + diff --git a/rma/report/rma_report_templates.xml b/rma/report/rma_report_templates.xml new file mode 100644 index 00000000..a700b4d7 --- /dev/null +++ b/rma/report/rma_report_templates.xml @@ -0,0 +1,268 @@ + + + + + + + + + + + + diff --git a/rma/security/ir.model.access.csv b/rma/security/ir.model.access.csv new file mode 100644 index 00000000..3643627b --- /dev/null +++ b/rma/security/ir.model.access.csv @@ -0,0 +1,25 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_rma_user_customer,rma.order.customer.user,model_rma_order,group_rma_customer_user,1,1,1,1 +access_rma_user_supplier,rma.order.supplier.user,model_rma_order,group_rma_supplier_user,1,1,1,1 +access_rma_manager,rma.order.manager,model_rma_order,group_rma_manager,1,1,1,1 +access_rma_line_customer_user,rma.order.line.customer.user,model_rma_order_line,group_rma_customer_user,1,1,1,1 +access_rma_line_supplier_user,rma.order.line.customer.supplier,model_rma_order_line,group_rma_supplier_user,1,1,1,1 +access_rma_line_manager,rma.order.line,model_rma_order_line,group_rma_manager,1,1,1,1 +access_rma_operation_manager,access_rma_operation,model_rma_operation,group_rma_manager,1,1,1,1 +access_rma_operation_customer_user,access_rma_operation,model_rma_operation,group_rma_customer_user,1,0,0,0 +access_rma_operation_supplier_user,access_rma_operation,model_rma_operation,group_rma_supplier_user,1,0,0,0 +access_rma_order_line_user,access_rma_order_line,model_rma_order_line,base.group_user,1,0,0,0 +access_rma_picking_wizard,rma.order.manager,model_rma_make_picking_wizard,group_rma_manager,1,1,1,1 +access_rma_picking_wizard_customer,rma.order.manager,model_rma_make_picking_wizard,group_rma_customer_user,1,1,1,1 +access_rma_picking_wizard_supplier,rma.order.manager,model_rma_make_picking_wizard,group_rma_supplier_user,1,1,1,1 +access_rma_picking_wizard_item,rma.order.manager,model_rma_make_picking_wizard_item,group_rma_manager,1,1,1,1 +access_rma_picking_wizard_item_customer,rma.order.manager,model_rma_make_picking_wizard_item,group_rma_customer_user,1,1,1,1 +access_rma_picking_wizard_item_supplier,rma.order.manager,model_rma_make_picking_wizard_item,group_rma_supplier_user,1,1,1,1 +access_rma_order_line_make_supplier_rma_customer_user,rma.order.line.make.supplier.rma.customer.user,model_rma_order_line_make_supplier_rma,rma.group_rma_customer_user,1,1,1,1 +access_rma_order_line_make_supplier_rmasupplier_user,rma.order.line.make.supplier.rma.supplier.user,model_rma_order_line_make_supplier_rma,rma.group_rma_supplier_user,1,1,1,1 +access_rma_order_line_make_supplier_rma_customer_user_item,rma.order.line.make.supplier.rma.item.customer.user,model_rma_order_line_make_supplier_rma_item,rma.group_rma_customer_user,1,1,1,1 +access_rma_order_line_make_supplier_rmasupplier_user_item,rma.order.line.make.supplier.rma.item.supplier.user,model_rma_order_line_make_supplier_rma_item,rma.group_rma_supplier_user,1,1,1,1 +access_rma_add_stock_move_customer_user_item,rma.add.stock.move.customer.user,model_rma_add_stock_move,rma.group_rma_customer_user,1,1,1,1 +access_rma_add_stock_move_supplier_user_item,rma.add.stock.move.supplier.user,model_rma_add_stock_move,rma.group_rma_supplier_user,1,1,1,1 +access_rma_add_serial_wiz_customer,access_rma_add_serial_wiz_customer,model_rma_add_serial_wiz,rma.group_rma_customer_user,1,1,1,1 +access_rma_add_serial_wiz_supplier,access_rma_add_serial_wiz_supplier,model_rma_add_serial_wiz,rma.group_rma_supplier_user,1,1,1,1 diff --git a/rma/security/rma.xml b/rma/security/rma.xml new file mode 100644 index 00000000..af3e24aa --- /dev/null +++ b/rma/security/rma.xml @@ -0,0 +1,93 @@ + + + + + RMA + + 30 + + + + RMA Customer User + + + + + + RMA Supplier User + + + + + + RMA Manager + + + + + + + Addresses in RMA + + + + + + RMA Groups + + + + + + + + + + + + + rma order multi-company + + + ['|', ('company_id', '=', False), ('company_id', 'in', company_ids)] + + + rma order line multi-company + + + ['|', ('company_id', '=', False), ('company_id', 'in', company_ids)] + + + rma operation multi-company + + + ['|', ('company_id', '=', False), ('company_id', 'in', company_ids)] + + + diff --git a/rma/static/description/icon.png b/rma/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce758c20300c568fef329d9a5090c58bfeb29147 GIT binary patch literal 4261 zcmbuD1y>Z#*MJvMQdp2uLb_8BmTu`1kVd+@YblXN5NX&YL=a>N1u20gU3#Syq;pxi zbAkW*`v~tl=gfW1#64$b?##V2lc=YoNV^c^1SYUg0077=)Rh$sgCV=n5EBFAD})?j|3?-wG8|JrTXOE|s088~lka9ZUjr)5 z!oTQLdw94Zj2L!TDhz(yO8%`(tv0HjDw;QU*_}3{q*3Pf>`#ax{?^aqS$t1@1IW(C zmd_a%_>(>AW=<6JWy4LN9{{kZ z3P<&)KV@Def&q*Dz2)p8bm3b2oukq>3pCB#U^Q*b8%Cq{RI}<1lx+39bnfAqqhw%6lpg~4 z75&}Ra31FF&!_!P37mi`P{g<4ZdcKDIPvpx9$dgVA45k!PQ5*Y_96UV`7h-G;ob8? z_)$^UjJ?{+N=B|9#=^~hga{qiTmT9?aPG&e`naD1NoZA_cg`M>fn0g)Hg2_RWuHqH z=6QKFZss<*8U_b!Cx32A(+NkW>k6Iqt@qmtw}-p-ox^z}_?hR!R`*uDUeb>wTGBGP z_S*mKsGHmj)YS6+q0-kfu5osk-(NOI96B483VtKk-k^xM|8F{%qo~joTzj_tHI0{r zrq2kX=btb+t{HL+o8xUZsdx-O>)NHIa?<3jH2TsK+LH2M;-{YXVcP=AR#nS(ZiqL1 zV6C~q17W}mda}b+sH1IrJs2WZbca`=6Pbu;=*iio-Jd@fv2W=p?pdK?0G*kdnML==X9A>K7&?yL?!&L;o^ZKHD24MH$w zWsfzk;o$bzSG7pHMM1f5M-Dw4LjDrXITznEsj2F`uS{Y%Dv;<&whj}?`24Leagoe) z-5XxGmTj24<2}b1nFGs3_hrUfpSggdicm0||FUN5*s8wrN8i*3 z8Uw#oo?BXOZV98sq_igi#R_qFzGPAwRlG~OTXs7>*~$otK+YZ)iRBVP%$uHRV$Alk z2zN}ubvC$$hTIayp&5{Rrwhj(Rms_{Z=CerTo?zIZ5{voZ==Rb0BC zzrMLNUcuoQEsRfgb4z_XM=Y;%<|2RrW%N%kKqNvF(yR)5XT~*LwaDPm_%~T}aJ$i! zri!+RcQ6XH{QSE7@~Wna#-ks1r{(26sHM&R-q_;WyGWQ>DfQ#92p zjnS-m^qlx76N$uG*-X=o(Asq^{*)iOAg$agl(4A^LcTyq{>JUL zJz+~EYJEE;*-BGQnR05>^V8nt2+YLO;>RH4bw&cC7_Ae{Jn4K)JAMhQV&lMgSmhGb2{thp zRnt`1TT-)6TL>*8Nlqyj5{y4K{XCpBMM*JTb-~n`A@A3Ve?USY#&fGl5w|rJ*|Ejn zSQCO=`r2I@noqN1ISL(Jsug*<`ZsGRbQZhooi`p@>%`Y)e_K)PewxxHC$4PZq=hll zp_h%)65teWOe^2pTGxLac}18hIz`>*$wjf|k9v;u2IIqBANQ}jYZ*;`5f~ss_eHlC2bA4cH9I0$*HT|kverAXm`)Q zFXNG9BS&1*a}8eG4L-h1y|Yv;(JwW^N(UB+gyx6esxV!N&uV-U$!@6r1K4p>&k9J$*Sa zxIwhYq#Z~o^a4{nY6H7uev&tLQjkvfr$#Tgpr@>jp2$y7FE_`p2^_uhM%r+&{1T7e zOe&hK$Dg?5XufMWj7xxVV-AT4euC;KUdwje z4?IC|GUc8{GmE!0i19kwVZ#rec0{Vj5Xx*lINLe^H}~%>kaSlAZc|zv>Zyt_y1>I* zrF-n|eZ6ZA+PBa@641}gQPK&du9&(Xgw}{pRq!Vu=ms%0cYTid&Gzk%6|;bjND_d! zH2S&Py~53%m~HxW3ZizRF@7T%Pd+K}FbXMa5@%NJIGJfWLK`n8oCoPLKoMm>fR#r{ ztl$TbvPNujxk3N35c!TC-fVmaH~EmzjAB%OnXp`^b%H)sF`*ihaE9BFMMrbIBMVpC z$7AEh6*XTJD`Cs4>%{k=&CD4CkEPc`6h`NrsfMZK#2c!Xsw4N2i#|Jg-^wBB*@{P_ z`wvnGo^GBeFqsy=#H(8)T(plizZ*%S17FqLUdL`536!j~dLN&^9lS@)Ym<1v` zC~GE#9Lf*c9>IY$Ts5xnhi#G<8oZp%8aFE-P!0R`&JTmtuzQ zgovI)VnVOR<2;9`pDA0~A-As-%p=EBYsJ%BtqeTZ*Lop+UeChDh#(NC=;`Ni1ME36 zOCXEh*eA|~soC|O>jh5)srA@hXus$?b%RCf2C3&A*1s;c`#gH_AkY>AqX}rNjy%^^ zka|mg6F2eGa*PipJOFsdfTX!9j2zm^%FLm58|=VQ(E9Z#9NXL9=pMHqzvGZAvnu)_ zoP3`0c}0q&^=I-7i9yX|(|TKSsz0@6;D?$LL6R{HvtpZ*BdEvE zQ=#yOPh7b3TXQeEuugD(33Yddc}{xMVPLRFJ)aRIr|W+7+XQ=<#xmRK7k(rsBY;b* zf59T}QfP}M%6&q(+7i(@^2lhV#66KHG0#0CncEt#rlaK#t%mz+E8Tw?&*&KV`C2j& zJF3^dnr^YkoV$*EW;;$((VE#N&krFdLhKcql)O##oG0n8f* zrczRK&4ICUX`6jhLjjfkTgSw?m>o>mUX#ZzKDgt{p6^o0f#W=qyTJoxUY&fl13D^xa;Omym% zv{WD<1XV8@P+C50tJ5y4sPx!vJ&sHRT;T*TCx^>!IL7Z7AVOTmg`j8~ubLSRBo2^n zUbUbU|GX~vcd)i8N6v9qBlPVHl|?^z_Z+?c`QD26IDFuOweJ&Qjbake43A77)A?S& zqTRyrV1!O7IN+dE6@EXomy>MD2~a)T>e9%aB|2Or{Q;JN&Tm~HWDWK><*2tcI~+Hl zpU$e_4hpZp-}g|T%-avDU%^9=vS&1Ufm{ZDaB~lX(9^rpl+CWdGYZr8p6P1V7emcmF^OFH{Lr>%M&Gi6)a|gwRtWFX*lZ z#A8*HoqiE>biBUhkhxY!AxR0aPkS3S zJ8UJxC!D`bQ9jmg9GP71J1dM0*7Umbh>~8x<~-h=?##c_nK%tE8}{Xu{psh!fJ`hL zI`wT;?cOb)5)9Cl^qMn6Sa(6WvGJ<}D$?PpqZnTvGeTP|i(L`_A%!na)k# z1w|V*Zx8pE;5t^^NmXa1=WNYljXbi`Uvai3CgX%uv2EB3kOE#sS}OC^!(I?mKkSB| z%7V_EhS97J+vhzqjJa9tj7c`3A8_hp9K5{Bm|#|2-prKawq9PXZB2B>BHIvU+{3rN zwJr=jje*6=Bm%{b*y_rxy;frE0aZ3>|G~NzizpR42r!p6t@ux3*skGWua(#d2?&d7$l$;@%6ARI+%OMxvola*py z0A#gTDL=Uq(@(+_c&N~e_r4b%!$rcBXoa`~5E(hrPrvFZ!~Qz})L-Z**C<-Q`5!!| BS)2d> literal 0 HcmV?d00001 diff --git a/rma/tests/__init__.py b/rma/tests/__init__.py new file mode 100644 index 00000000..e485a52f --- /dev/null +++ b/rma/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright (C) 2017-20 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from . import test_rma diff --git a/rma/tests/test_rma.py b/rma/tests/test_rma.py new file mode 100644 index 00000000..261dbf49 --- /dev/null +++ b/rma/tests/test_rma.py @@ -0,0 +1,1089 @@ +# © 2017 ForgeFlow +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo.exceptions import UserError, ValidationError +from odoo.tests import Form, common + + +class TestRma(common.TransactionCase): + """Test the routes and the quantities""" + + @classmethod + def setUpClass(cls): + super().setUpClass() + # models + cls.rma_make_picking = cls.env["rma_make_picking.wizard"] + cls.make_supplier_rma = cls.env["rma.order.line.make.supplier.rma"] + cls.rma_add_stock_move = cls.env["rma_add_stock_move"] + cls.product_ctg_model = cls.env["product.category"] + cls.stockpicking = cls.env["stock.picking"] + cls.rma = cls.env["rma.order"] + cls.rma_line = cls.env["rma.order.line"] + cls.rma_op = cls.env["rma.operation"] + cls.product_product_model = cls.env["product.product"] + cls.res_users_model = cls.env["res.users"] + # References and records + cls.rma_cust_replace_op_id = cls.env.ref("rma.rma_operation_customer_replace") + cls.rma_sup_replace_op_id = cls.env.ref("rma.rma_operation_supplier_replace") + cls.rma_ds_replace_op_id = cls.env.ref("rma.rma_operation_ds_replace") + cls.category = cls._create_product_category( + "one_step", cls.rma_cust_replace_op_id, cls.rma_sup_replace_op_id + ) + cls.product_id = cls._create_product("PT0") + cls.product_1 = cls._create_product("PT1") + cls.product_2 = cls._create_product("PT2") + cls.product_3 = cls._create_product("PT3") + cls.uom_unit = cls.env.ref("uom.product_uom_unit") + cls.company = cls.env.company + cls.company.group_rma_delivery_address = True + cls.company.group_rma_lines = True + + cls.partner_id = cls.env.ref("base.res_partner_2") + cls.stock_location = cls.env.ref("stock.stock_location_stock") + cls.wh = cls.env.ref("stock.warehouse0") + cls.stock_rma_location = cls.wh.lot_rma_id + cls.customer_location = cls.env.ref("stock.stock_location_customers") + cls.supplier_location = cls.env.ref("stock.stock_location_suppliers") + cls.product_uom_id = cls.env.ref("uom.product_uom_unit") + cls.g_rma_customer_user = cls.env.ref("rma.group_rma_customer_user") + cls.g_rma_supplier_user = cls.env.ref("rma.group_rma_supplier_user") + cls.g_rma_manager = cls.env.ref("rma.group_rma_manager") + cls.g_stock_user = cls.env.ref("stock.group_stock_user") + cls.g_stock_manager = cls.env.ref("stock.group_stock_manager") + + cls.rma_basic_user = cls._create_user( + "rma worker", + [cls.g_stock_user, cls.g_rma_customer_user, cls.g_rma_supplier_user], + cls.company, + ) + cls.rma_manager_user = cls._create_user( + "rma manager", + [cls.g_stock_manager, cls.g_rma_manager], + cls.company, + ) + # Customer RMA: + products2move = [(cls.product_1, 3), (cls.product_2, 5), (cls.product_3, 2)] + cls.rma_customer_id = cls._create_rma_from_move( + products2move, "customer", cls.env.ref("base.res_partner_2"), dropship=False + ) + # Dropship: + cls.rma_droship_id = cls._create_rma_from_move( + products2move, + "customer", + cls.env.ref("base.res_partner_2"), + dropship=True, + supplier_address_id=cls.env.ref("base.res_partner_3"), + ) + # Supplier RMA: + cls.rma_supplier_id = cls._create_rma_from_move( + products2move, "supplier", cls.env.ref("base.res_partner_2"), dropship=False + ) + + @classmethod + def _create_user(cls, login, groups, company): + group_ids = [group.id for group in groups] + user = cls.res_users_model.create( + { + "name": login, + "login": login, + "email": "example@yourcompany.com", + "company_id": company.id, + "company_ids": [(4, company.id)], + "groups_id": [(6, 0, group_ids)], + } + ) + return user + + @classmethod + def _receive_rma(cls, rma_line_ids): + wizard = cls.rma_make_picking.with_context( + **{ + "active_ids": rma_line_ids.ids, + "active_model": "rma.order.line", + "picking_type": "incoming", + "active_id": 1, + } + ).create({}) + wizard._create_picking() + res = rma_line_ids.action_view_in_shipments() + picking = cls.env["stock.picking"].browse(res["res_id"]) + picking.action_assign() + for mv in picking.move_ids: + mv.quantity = mv.product_uom_qty + mv.picked = True + picking._action_done() + return picking + + @classmethod + def _deliver_rma(cls, rma_line_ids): + wizard = cls.rma_make_picking.with_context( + **{ + "active_ids": rma_line_ids.ids, + "active_model": "rma.order.line", + "picking_type": "outgoing", + "active_id": 1, + } + ).create({}) + wizard._create_picking() + res = rma_line_ids.action_view_out_shipments() + picking = cls.env["stock.picking"].browse(res["res_id"]) + picking.action_assign() + for mv in picking.move_ids: + mv.quantity = mv.product_uom_qty + mv.picked = True + picking._action_done() + return picking + + @classmethod + def _create_product_category( + cls, rma_approval_policy, rma_customer_operation_id, rma_supplier_operation_id + ): + return cls.product_ctg_model.create( + { + "name": "Test category", + "rma_approval_policy": rma_approval_policy, + "rma_customer_operation_id": rma_customer_operation_id.id, + "rma_supplier_operation_id": rma_supplier_operation_id.id, + } + ) + + @classmethod + def _create_product(cls, name): + return cls.product_product_model.create( + {"name": name, "categ_id": cls.category.id, "type": "product"} + ) + + @classmethod + def _create_picking(cls, partner, picking_type): + return cls.stockpicking.create( + { + "partner_id": partner.id, + "picking_type_id": picking_type.id, + "location_id": cls.stock_location.id, + "location_dest_id": cls.supplier_location.id, + } + ) + + @classmethod + def _do_picking(cls, picking): + """Do picking with only one move on the given date.""" + picking.action_confirm() + picking.action_assign() + for ml in picking.move_ids: + ml.filtered(lambda m: m.state != "waiting").quantity = ml.product_uom_qty + ml.filtered(lambda m: m.state != "waiting").picked = True + picking.button_validate() + + @classmethod + def _create_inventory(cls, product, qty, location): + """ + Creates inventory of a product on a specific location, this will be used + eventually to create a inventory at specific cost, that will be received in + a customer RMA or delivered in a supplier RMA + """ + inventory = ( + cls.env["stock.quant"] + .create( + { + "location_id": location.id, + "product_id": product.id, + "inventory_quantity": qty, + } + ) + .action_apply_inventory() + ) + return inventory + + @classmethod + def _get_picking_type(cls, wh, loc1, loc2): + picking_type = cls.env["stock.picking.type"].search( + [ + ("warehouse_id", "=", wh.id), + ("default_location_src_id", "=", loc1.id), + ("default_location_dest_id", "=", loc2.id), + ], + limit=1, + ) + if picking_type: + return picking_type + picking_type = cls.env["stock.picking.type"].create( + { + "name": loc1.name + " to " + loc2.name, + "sequence_code": loc1.name + " to " + loc2.name, + "code": "incoming", + "warehouse_id": wh.id, + "default_location_src_id": loc1.id, + "default_location_dest_id": loc2.id, + } + ) + return picking_type + + @classmethod + def _create_rma_from_move( + cls, products2move, r_type, partner, dropship, supplier_address_id=None + ): + moves = [] + if r_type == "customer": + picking_type = cls._get_picking_type( + cls.wh, cls.stock_location, cls.customer_location + ) + picking = cls._create_picking(partner, picking_type) + for item in products2move: + product = item[0] + product_qty = item[1] + cls._create_inventory(product, product_qty, cls.stock_location) + move_values = cls._prepare_move( + product, + product_qty, + cls.stock_location, + cls.customer_location, + picking, + ) + moves.append(cls.env["stock.move"].create(move_values)) + else: + picking_type = cls._get_picking_type( + cls.wh, cls.supplier_location, cls.stock_rma_location + ) + picking = cls._create_picking(partner, picking_type) + for item in products2move: + product = item[0] + product_qty = item[1] + cls._create_inventory(product, product_qty, cls.stock_location) + move_values = cls._prepare_move( + product, + product_qty, + cls.supplier_location, + cls.stock_rma_location, + picking, + ) + moves.append(cls.env["stock.move"].create(move_values)) + # Process the picking + cls._do_picking(picking) + # Create the RMA from the stock_move + rma_id = cls.rma.with_user(cls.rma_basic_user).create( + { + "reference": "0001", + "type": r_type, + "partner_id": partner.id, + "company_id": cls.env.ref("base.main_company").id, + } + ) + for move in moves: + if r_type == "customer": + wizard = cls.rma_add_stock_move.with_user(cls.rma_basic_user).new( + { + "move_ids": [(4, move.id)], + "rma_id": rma_id.id, + "partner_id": move.partner_id.id, + } + ) + wizard.with_context( + **{ + "move_ids": [(4, move.id)], + "reference_move_id": move.id, + "customer": True, + "active_ids": rma_id.id, + "partner_id": move.partner_id.id, + "active_model": "rma.order", + } + ).default_get([str(move.id), str(cls.partner_id.id)]) + data = ( + wizard.with_user(cls.rma_basic_user) + .with_context(customer=1) + ._prepare_rma_line_from_stock_move(move) + ) + + else: + wizard = cls.rma_add_stock_move.with_user(cls.rma_basic_user).new( + { + "move_ids": [(4, move.id)], + "rma_id": rma_id.id, + "partner_id": move.partner_id.id, + } + ) + wizard.with_context( + **{ + "move_ids": [(4, move.id)], + "reference_move_id": move.id, + "active_ids": rma_id.id, + "partner_id": move.partner_id.id, + "active_model": "rma.order", + } + ).default_get([str(move.id), str(cls.partner_id.id)]) + data = wizard.with_user( + cls.rma_basic_user + )._prepare_rma_line_from_stock_move(move) + data["type"] = "supplier" + if dropship: + data.update( + customer_to_supplier=dropship, + operation_id=cls.rma_ds_replace_op_id.id, + supplier_address_id=supplier_address_id.id, + ) + cls.line = cls.rma_line.with_user(cls.rma_basic_user).create(data) + cls.line._onchange_product_id() + cls.line._onchange_operation_id() + cls.line.action_rma_to_approve() + rma_id._get_default_type() + rma_id.action_view_in_shipments() + rma_id.action_view_out_shipments() + rma_id.action_view_lines() + rma_id.partner_id.action_open_partner_rma() + return rma_id + + @classmethod + def _prepare_move(cls, product, qty, src, dest, picking_in): + location_id = src.id + + return { + "name": product.name, + "partner_id": picking_in.partner_id.id, + "origin": picking_in.name, + "company_id": picking_in.picking_type_id.warehouse_id.company_id.id, + "product_id": product.id, + "product_uom": product.uom_id.id, + "state": "draft", + "product_uom_qty": qty, + "location_id": location_id, + "location_dest_id": dest.id, + "picking_id": picking_in.id, + "price_unit": product.standard_price, + } + + def _check_equal_quantity(self, qty1, qty2, msg): + self.assertEqual(qty1, qty2, msg) + + def test_01_rma_order_line(self): + for line in self.rma_customer_id.rma_line_ids: + line.with_context( + **{"default_rma_id": line.rma_id.id} + )._default_warehouse_id() + line._default_location_id() + line._onchange_delivery_address() + line._compute_in_shipment_count() + line._compute_out_shipment_count() + + # check assert if call reference_move_id onchange + self.assertEqual(line.product_id, line.reference_move_id.product_id) + self.assertEqual(line.product_qty, line.reference_move_id.product_uom_qty) + self.assertEqual( + line.location_id.location_id, line.reference_move_id.location_id + ) + self.assertEqual(line.origin, line.reference_move_id.picking_id.name) + self.assertEqual( + line.delivery_address_id, line.reference_move_id.picking_id.partner_id + ) + self.assertEqual( + line.qty_to_receive, line.reference_move_id.product_uom_qty + ) + line._onchange_product_id() + line._onchange_operation_id() + # check assert if call operation_id onchange + self.assertEqual(line.operation_id.receipt_policy, line.receipt_policy) + + data = {"customer_to_supplier": line.customer_to_supplier} + line = self.rma_line.new(data) + line._onchange_receipt_policy() + + data = {"lot_id": line.lot_id.id} + line = self.rma_line.new(data) + line._onchange_lot_id() + + line.action_view_in_shipments() + line.action_view_out_shipments() + self.rma_customer_id.action_view_supplier_lines() + with self.assertRaises(ValidationError): + line.rma_id.partner_id = self.partner_id.id + self.rma_customer_id.rma_line_ids[0].partner_id = self.env.ref( + "base.res_partner_3" + ).id + self.rma_customer_id.action_view_supplier_lines() + + def test_02_customer_rma(self): + self.rma_customer_id.rma_line_ids.action_rma_to_approve() + wizard = self.rma_make_picking.with_context( + **{ + "active_ids": self.rma_customer_id.rma_line_ids.ids, + "active_model": "rma.order.line", + "picking_type": "incoming", + "active_id": 1, + } + ).create({}) + wizard._create_picking() + res = self.rma_customer_id.rma_line_ids.action_view_in_shipments() + self.assertTrue("res_id" in res, "Incorrect number of pickings" "created") + picking = self.env["stock.picking"].browse(res["res_id"]) + self.assertEqual(len(picking), 1, "Incorrect number of pickings created") + moves = picking.move_ids + self.assertEqual(len(moves), 3, "Incorrect number of moves created") + lines = self.rma_customer_id.rma_line_ids + lines.env.invalidate_all() + self.assertEqual( + list(set(lines.mapped("qty_received"))), [0], "Wrong qty received" + ) + self.assertEqual( + list(set(lines.mapped("qty_to_deliver"))), [0], "Wrong qty to deliver" + ) + self.assertEqual( + list(set(lines.mapped("qty_outgoing"))), [0], "Wrong qty outgoing" + ) + self.assertEqual( + list(set(lines.mapped("qty_delivered"))), [0], "Wrong qty delivered" + ) + self.assertEqual( + sum(lines.mapped("in_shipment_count")), 3, "Incorrect In Shipment Count" + ) + self.assertEqual( + sum(lines.mapped("out_shipment_count")), 0, "Incorrect Out Shipment Count" + ) + self.assertEqual( + self.rma_customer_id.in_shipment_count, 1, "Incorrect In Shipment Count" + ) + self.assertEqual( + self.rma_customer_id.out_shipment_count, 0, "Incorrect Out Shipment Count" + ) + # product specific + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_1).qty_to_receive, + 3, + "Wrong qty to receive", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_1).qty_incoming, + 3, + "Wrong qty incoming", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_2).qty_to_receive, + 5, + "Wrong qty to receive", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_2).qty_incoming, + 5, + "Wrong qty incoming", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_3).qty_to_receive, + 2, + "Wrong qty to receive", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_3).qty_incoming, + 2, + "Wrong qty incoming", + ) + picking.action_assign() + for mv in picking.move_ids: + mv.quantity = mv.product_uom_qty + mv.picked = True + picking._action_done() + lines = self.rma_customer_id.rma_line_ids + self.assertEqual( + list(set(lines.mapped("qty_to_receive"))), [0], "Wrong qty to_receive" + ) + self.assertEqual( + list(set(lines.mapped("qty_incoming"))), [0], "Wrong qty incoming" + ) + self.assertEqual( + list(set(lines.mapped("qty_outgoing"))), [0], "Wrong qty outgoing" + ) + self.assertEqual( + list(set(lines.mapped("qty_delivered"))), [0], "Wrong qty delivered" + ) + # product specific + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_1).qty_received, + 3, + "Wrong qty received", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_1).qty_to_deliver, + 3, + "Wrong qty to_deliver", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_2).qty_received, + 5, + "Wrong qty received", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_2).qty_to_deliver, + 5, + "Wrong qty to_deliver", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_3).qty_received, + 2, + "Wrong qty received", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_3).qty_to_deliver, + 2, + "Wrong qty to_deliver", + ) + + wizard = self.rma_make_picking.with_context( + **{ + "active_id": 1, + "active_ids": self.rma_customer_id.rma_line_ids.ids, + "active_model": "rma.order.line", + "picking_type": "outgoing", + } + ).create({}) + wizard._create_picking() + res = self.rma_customer_id.rma_line_ids.action_view_out_shipments() + self.assertTrue("res_id" in res, "Incorrect number of pickings" "created") + picking = self.env["stock.picking"].browse(res["res_id"]) + moves = picking.move_ids + self.assertEqual(len(moves), 3, "Incorrect number of moves created") + lines = self.rma_customer_id.rma_line_ids + lines.env.invalidate_all() + self.assertEqual( + list(set(lines.mapped("qty_to_receive"))), [0], "Wrong qty to_receive" + ) + self.assertEqual( + list(set(lines.mapped("qty_incoming"))), [0], "Wrong qty incoming" + ) + self.assertEqual( + list(set(lines.mapped("qty_delivered"))), [0], "Wrong qty delivered" + ) + self.assertEqual( + sum(lines.mapped("in_shipment_count")), 3, "Incorrect In Shipment Count" + ) + self.assertEqual( + sum(lines.mapped("out_shipment_count")), + 3, + "Incorrect Out Shipment Count", + ) + self.assertEqual( + self.rma_customer_id.in_shipment_count, 1, "Incorrect In Shipment Count" + ) + self.assertEqual( + self.rma_customer_id.out_shipment_count, 1, "Incorrect Out Shipment Count" + ) + # product specific + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_1).qty_to_deliver, + 3, + "Wrong qty to_deliver", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_1).qty_outgoing, + 3, + "Wrong qty outgoing", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_2).qty_to_deliver, + 5, + "Wrong qty to_deliver", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_2).qty_outgoing, + 5, + "Wrong qty outgoing", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_3).qty_to_deliver, + 2, + "Wrong qty to_deliver", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_3).qty_outgoing, + 2, + "Wrong qty outgoing", + ) + picking.action_assign() + for mv in picking.move_ids: + mv.quantity = mv.product_uom_qty + mv.picked = True + picking._action_done() + lines = self.rma_customer_id.rma_line_ids + self.assertEqual( + list(set(lines.mapped("qty_to_receive"))), [0], "Wrong qty to_receive" + ) + self.assertEqual( + list(set(lines.mapped("qty_incoming"))), [0], "Wrong qty incoming" + ) + self.assertEqual( + list(set(lines.mapped("qty_outgoing"))), [0], "Wrong qty_outgoing" + ) + # product specific + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_1).qty_received, + 3, + "Wrong qty_received", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_1).qty_delivered, + 3, + "Wrong qty_delivered", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_2).qty_received, + 5, + "Wrong qty_received", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_2).qty_delivered, + 5, + "Wrong qty_delivered", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_3).qty_received, + 2, + "Wrong qty_received", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_3).qty_delivered, + 2, + "Wrong qty_delivered", + ) + self.rma_customer_id.rma_line_ids.action_rma_done() + self.assertEqual( + self.rma_customer_id.rma_line_ids.mapped("state"), + ["done", "done", "done"], + "Wrong State", + ) + self.rma_customer_id.action_view_in_shipments() + self.rma_customer_id.action_view_out_shipments() + self.rma_customer_id.action_view_lines() + + # DROPSHIP + def test_03_dropship(self): + for line in self.rma_droship_id.rma_line_ids: + line.operation_id = self.rma_ds_replace_op_id + line._onchange_operation_id() + line._onchange_delivery_address() + line.action_rma_to_approve() + line.action_rma_approve() + wizard = self.rma_make_picking.with_context( + **{ + "active_id": 1, + "active_ids": self.rma_droship_id.rma_line_ids.ids, + "active_model": "rma.order.line", + "picking_type": "incoming", + } + ).create({}) + wizard._create_picking() + res = self.rma_droship_id.rma_line_ids.action_view_in_shipments() + self.assertTrue("res_id" in res, "Incorrect number of pickings created") + picking = self.env["stock.picking"].browse(res["res_id"]) + self.assertEqual(len(picking), 1, "Incorrect number of pickings created") + moves = picking.move_ids + self.assertEqual(len(moves), 3, "Incorrect number of moves created") + lines = self.rma_droship_id.rma_line_ids + lines.env.invalidate_all() + self.assertEqual( + sum(lines.mapped("in_shipment_count")), 3, "Incorrect In Shipment Count" + ) + self.assertEqual( + sum(lines.mapped("out_shipment_count")), 0, "Incorrect Out Shipment Count" + ) + self.assertEqual( + self.rma_droship_id.in_shipment_count, 1, "Incorrect In Shipment Count" + ) + self.assertEqual( + self.rma_droship_id.out_shipment_count, 0, "Incorrect Out Shipment Count" + ) + wizard = self.make_supplier_rma.with_context( + **{ + "active_ids": self.rma_droship_id.rma_line_ids.ids, + "active_model": "rma.order.line", + "active_id": 1, + } + ).create({}) + wizard.make_supplier_rma() + lines = self.rma_droship_id.rma_line_ids.mapped("supplier_rma_line_ids") + lines.env.invalidate_all() + self.assertEqual( + list(set(lines.mapped("qty_received"))), [0], "Wrong qty_received" + ) + self.assertEqual( + list(set(lines.mapped("qty_outgoing"))), [0], "Wrong qty_outgoing" + ) + self.assertEqual(list(set(lines.mapped("qty_delivered"))), [0], "qty_delivered") + # product specific + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_1).qty_to_deliver, + 3, + "Wrong qty_to_deliver", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_2).qty_to_deliver, + 5, + "Wrong qty_to_deliver", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_3).qty_to_deliver, + 2, + "Wrong qty_to_deliver", + ) + lines = self.rma_droship_id.rma_line_ids + lines.env.invalidate_all() + self._check_equal_quantity( + lines.filtered( + lambda x: x.product_id == self.product_1 + ).qty_in_supplier_rma, + 3, + "Wrong qty_in_supplier_rma", + ) + self._check_equal_quantity( + lines.filtered( + lambda x: x.product_id == self.product_2 + ).qty_in_supplier_rma, + 5, + "Wrong qty_in_supplier_rma", + ) + self._check_equal_quantity( + lines.filtered( + lambda x: x.product_id == self.product_3 + ).qty_in_supplier_rma, + 2, + "Wrong qty_in_supplier_rma", + ) + self.assertEqual( + list(set(lines.mapped("qty_to_supplier_rma"))), + [0], + "Wrong qty_to_supplier_rma", + ) + for line in self.rma_droship_id.rma_line_ids: + line.action_rma_done() + self.assertEqual(line.mapped("state"), ["done"], "Wrong State") + + # Supplier RMA + def test_04_supplier_rma(self): + self.rma_supplier_id.rma_line_ids.action_rma_to_approve() + self.rma_supplier_id.rma_line_ids.operation_id = self.rma_sup_replace_op_id + self.rma_supplier_id.rma_line_ids._onchange_operation_id() + self.rma_supplier_id.rma_line_ids._onchange_delivery_address() + wizard = self.rma_make_picking.with_context( + **{ + "active_ids": self.rma_supplier_id.rma_line_ids.ids, + "active_model": "rma.order.line", + "picking_type": "outgoing", + "active_id": 2, + } + ).create({}) + wizard._create_picking() + res = self.rma_supplier_id.rma_line_ids.action_view_out_shipments() + self.assertTrue("res_id" in res, "Incorrect number of pickings" "created") + picking = self.rma_supplier_id.rma_line_ids._get_out_pickings() + partner = picking.partner_id + self.assertTrue(partner, "Partner is not defined or False") + moves = picking.move_ids + self.assertEqual(len(moves), 3, "Incorrect number of moves created") + + lines = self.rma_supplier_id.rma_line_ids + lines.env.invalidate_all() + self.assertEqual( + list(set(lines.mapped("qty_received"))), [0], "Wrong qty_received" + ) + self.assertEqual(list(set(lines.mapped("qty_delivered"))), [0], "qty_delivered") + self.assertEqual( + sum(lines.mapped("in_shipment_count")), 0, "Incorrect In Shipment Count" + ) + self.assertEqual( + sum(lines.mapped("out_shipment_count")), 3, "Incorrect Out Shipment Count" + ) + self.assertEqual( + self.rma_supplier_id.in_shipment_count, 0, "Incorrect In Shipment Count" + ) + self.assertEqual( + self.rma_supplier_id.out_shipment_count, 1, "Incorrect Out Shipment Count" + ) + # product specific + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_1).qty_to_receive, + 3, + "Wrong qty_to_receive", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_1).qty_to_deliver, + 3, + "Wrong qty_to_deliver", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_2).qty_to_receive, + 5, + "Wrong qty_to_receive", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_2).qty_to_deliver, + 5, + "Wrong qty_to_deliver", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_3).qty_to_receive, + 2, + "Wrong qty_to_receive", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_3).qty_to_deliver, + 2, + "Wrong qty_to_deliver", + ) + self.assertEqual( + list(set(lines.mapped("qty_incoming"))), [0], "Wrong qty_incoming" + ) + picking.action_assign() + for mv in picking.move_ids: + mv.quantity = mv.product_uom_qty + mv.picked = True + picking._action_done() + self.assertEqual( + list(set(lines.mapped("qty_incoming"))), [0], "Wrong qty_incoming" + ) + self.assertEqual( + list(set(lines.mapped("qty_to_deliver"))), [0], "Wrong qty_to_deliver" + ) + self.assertEqual( + list(set(lines.mapped("qty_received"))), [0], "Wrong qty_received" + ) + self.assertEqual(list(set(lines.mapped("qty_outgoing"))), [0], "qty_outgoing") + # product specific + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_1).qty_delivered, + 3, + "Wrong qty_delivered", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_1).qty_to_receive, + 3, + "Wrong qty_to_receive", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_1).qty_received, + 0, + "Wrong qty_received", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_2).qty_delivered, + 5, + "Wrong qty_delivered", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_2).qty_received, + 0, + "Wrong qty_received", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_3).qty_delivered, + 2, + "Wrong qty_delivered", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_3).qty_received, + 0, + "Wrong qty_received", + ) + wizard = self.rma_make_picking.with_context( + **{ + "active_id": 1, + "active_ids": self.rma_supplier_id.rma_line_ids.ids, + "active_model": "rma.order.line", + "picking_type": "incoming", + } + ).create({}) + wizard._create_picking() + res = self.rma_supplier_id.rma_line_ids.action_view_in_shipments() + self.assertTrue("res_id" in res, "Incorrect number of pickings" "created") + pickings = self.env["stock.picking"].browse(res["res_id"]) + self.assertEqual(len(pickings), 1, "Incorrect number of pickings created") + picking_in = pickings[0] + partner = picking_in.partner_id + self.assertTrue(partner, "Partner is not defined or False") + moves = picking.move_ids + self.assertEqual(len(moves), 3, "Incorrect number of moves created") + + lines = self.rma_supplier_id.rma_line_ids + lines.env.invalidate_all() + self.assertEqual( + list(set(lines.mapped("qty_to_deliver"))), [0], "qty_to_deliver" + ) + self.assertEqual( + sum(lines.mapped("in_shipment_count")), 3, "Incorrect In Shipment Count" + ) + self.assertEqual( + sum(lines.mapped("out_shipment_count")), 3, "Incorrect Out Shipment Count" + ) + self.assertEqual( + self.rma_supplier_id.in_shipment_count, 1, "Incorrect In Shipment Count" + ) + self.assertEqual( + self.rma_supplier_id.out_shipment_count, 1, "Incorrect Out Shipment Count" + ) + # product specific + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_1).qty_to_receive, + 3, + "Wrong qty_to_receive", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_2).qty_to_receive, + 5, + "Wrong qty_to_receive", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_3).qty_to_receive, + 2, + "Wrong qty_to_receive", + ) + picking_in.action_confirm() + picking_in.action_assign() + for mv in picking_in.move_line_ids: + mv.quantity = mv.quantity_product_uom + mv.picked = True + picking_in._action_done() + self.assertEqual( + list(set(lines.mapped("qty_outgoing"))), [0], "Wrong qty_outgoing" + ) + self.assertEqual( + list(set(lines.mapped("qty_incoming"))), [0], "Wrong qty_incoming" + ) + self.assertEqual( + list(set(lines.mapped("qty_to_deliver"))), [0], "qty_to_deliver" + ) + + # product specific + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_1).qty_delivered, + 3, + "Wrong qty_delivered", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_1).qty_received, + 3, + "Wrong qty_received", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_2).qty_delivered, + 5, + "Wrong qty_delivered", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_2).qty_received, + 5, + "Wrong qty_received", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_3).qty_delivered, + 2, + "Wrong qty_delivered", + ) + self._check_equal_quantity( + lines.filtered(lambda x: x.product_id == self.product_3).qty_received, + 2, + "Wrong qty_received", + ) + for line in self.rma_supplier_id.rma_line_ids: + line.action_rma_done() + self.assertEqual(line.state, "done", "Wrong State") + + def test_05_rma_order_line(self): + """Property rma_customer_operation_id on product or product category + correctly handled inside _onchange_product_id() + """ + rma_operation = self.env["rma.operation"].search([], limit=1) + self.assertTrue(rma_operation) + + # Case of product template + self.rma_customer_id.rma_line_ids.mapped("product_id").sudo().write( + {"rma_customer_operation_id": rma_operation.id} + ) + for line in self.rma_customer_id.rma_line_ids: + data = {"product_id": line.product_id.id} + new_line = self.rma_line.new(data) + self.assertFalse(new_line.operation_id) + self.assertTrue(new_line.product_id.rma_customer_operation_id) + self.assertTrue(new_line.product_id.categ_id.rma_customer_operation_id) + new_line._onchange_product_id() + self.assertEqual(new_line.operation_id, rma_operation) + + # Case of product category + self.rma_customer_id.rma_line_ids.mapped("product_id").sudo().write( + {"rma_customer_operation_id": False} + ) + self.rma_customer_id.rma_line_ids.mapped("product_id.categ_id").sudo().write( + {"rma_customer_operation_id": rma_operation.id} + ) + + for line in self.rma_customer_id.rma_line_ids: + data = {"product_id": line.product_id.id} + new_line = self.rma_line.new(data) + self.assertFalse(new_line.operation_id) + self.assertFalse(new_line.product_id.rma_customer_operation_id) + self.assertTrue(new_line.product_id.categ_id.rma_customer_operation_id) + new_line._onchange_product_id() + self.assertEqual(new_line.operation_id, rma_operation) + + def test_06_warehouse_mismatch(self): + """Mismatch between operation warehouse and stock rule warehouse is raised. + + * Create a second warehouse that is resupplied from the main warehouse + * Update an RMA to receive into the second warehouse + * When creating pickings, it is raised that the rules from the RMA + * config are not used. + """ + wh2 = self.env["stock.warehouse"].create( + { + "name": "Shop.", + "code": "SHP", + } + ) + wh2.resupply_wh_ids = self.env.ref("stock.warehouse0") + wh2.rma_in_this_wh = True + wh2.lot_rma_id = self.env["stock.location"].create( + { + "name": "WH2 RMA", + "usage": "internal", + "location_id": wh2.lot_stock_id.id, + } + ) + rma = self.rma_customer_id.copy() + rma.rma_line_ids = self.rma_customer_id.rma_line_ids[0].copy() + rma.rma_line_ids.product_id.sudo().route_ids += wh2.resupply_route_ids + rma_form = Form(rma) + rma_form.in_warehouse_id = wh2 + rma_form.save() + rma.rma_line_ids.action_rma_approve() + wizard = self.rma_make_picking.with_context( + **{ + "active_ids": rma.rma_line_ids.ids, + "active_model": "rma.order.line", + "picking_type": "incoming", + "active_id": 1, + } + ).create({}) + with self.assertRaisesRegex(UserError, "No rule found"): + wizard._create_picking() + + def test_07_no_zero_qty_moves(self): + rma_lines = self.rma_customer_id.rma_line_ids + rma_lines.write({"receipt_policy": "delivered"}) + self.assertEqual(sum(rma_lines.mapped("qty_to_receive")), 0) + wizard = self.rma_make_picking.with_context( + **{ + "active_ids": rma_lines.ids, + "active_model": "rma.order.line", + "picking_type": "incoming", + "active_id": 1, + } + ).create({}) + with self.assertRaisesRegex(ValidationError, "No quantity to transfer"): + wizard._create_picking() + + def test_08_supplier_rma_single_line(self): + rma_line_id = self.rma_supplier_id.rma_line_ids[0].id + wizard = self.rma_make_picking.with_context( + active_ids=[rma_line_id], + active_model="rma.order.line", + picking_type="outgoing", + active_id=2, + ).create({}) + wizard._create_picking() + picking = self.rma_supplier_id.rma_line_ids[0]._get_out_pickings() + partner = picking.partner_id + self.assertTrue(partner, "Partner is not defined or False") + moves = picking.move_ids + self.assertEqual(len(moves), 1, "Incorrect number of moves created") diff --git a/rma/views/product_view.xml b/rma/views/product_view.xml new file mode 100644 index 00000000..7a0dc401 --- /dev/null +++ b/rma/views/product_view.xml @@ -0,0 +1,54 @@ + + + + product.category.form + product.category + + + + + + + + + + + + + + product.template.stock.property.form.inherit + product.template + + + + + + + + + + + + diff --git a/rma/views/res_config_settings_views.xml b/rma/views/res_config_settings_views.xml new file mode 100644 index 00000000..82982e2f --- /dev/null +++ b/rma/views/res_config_settings_views.xml @@ -0,0 +1,74 @@ + + + + + res.config.settings.view.form.inherit.rma + res.config.settings + + + + +
+

Return Merchandise Authorization

+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ + + Settings + ir.actions.act_window + res.config.settings + form + inline + {'module' : 'rma'} + + +
diff --git a/rma/views/res_partner_view.xml b/rma/views/res_partner_view.xml new file mode 100644 index 00000000..fd3e277f --- /dev/null +++ b/rma/views/res_partner_view.xml @@ -0,0 +1,28 @@ + + + + + res.partner.form - rma + res.partner + + +
+ +
+
+
+ +
diff --git a/rma/views/rma_menu.xml b/rma/views/rma_menu.xml new file mode 100644 index 00000000..9b569705 --- /dev/null +++ b/rma/views/rma_menu.xml @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rma/views/rma_operation_view.xml b/rma/views/rma_operation_view.xml new file mode 100644 index 00000000..3629a3bb --- /dev/null +++ b/rma/views/rma_operation_view.xml @@ -0,0 +1,89 @@ + + + + rma.operation.tree + rma.operation + + + + + + + + + + + + + rma.operation.form + rma.operation + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Customer Operations + rma.operation + tree,form + {'default_type': "customer"} + [('type','=', 'customer')] + + + + + Supplier Operations + rma.operation + tree,form + {'default_type': "supplier"} + [('type','=', 'supplier')] + + + + diff --git a/rma/views/rma_order_line_view.xml b/rma/views/rma_order_line_view.xml new file mode 100644 index 00000000..887f541d --- /dev/null +++ b/rma/views/rma_order_line_view.xml @@ -0,0 +1,547 @@ + + + + rma.order.line.tree + rma.order.line + + + + + + + + + + + + + + + + + + + + + rma.order.line.supplier.tree + rma.order.line + + + + + + + + + + + + + + + + + + + + rma.order.line.form + rma.order.line + +
+
+
+ +
+ + + + + +
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+
+ + + rma.order.line.supplier.form + rma.order.line + + primary + + + Customer RMA + + + Supplier + {'res_partner_search_mode': 'supplier'} + + + 1 + + + [('picking_id.partner_id', '=', partner_id), + ('location_id.usage', '=', 'supplier'), + ('state', '=', 'done')] + + + [('type','=','supplier')] + + + + + + rma.order.line.select + rma.order.line + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Customer RMA + rma.order.line + [('type','=', 'customer')] + {"search_default_assigned_to_filter":1} + tree,form + + + + + Supplier RMA + rma.order.line + [('type','=', 'supplier')] + {"search_default_assigned_to_filter":1, "supplier":1} + tree,form + + + + + + tree + + + + + + form + + + + + + Request Approval + + + code + +if records.filtered(lambda x: x.state == "draft"): + records.filtered(lambda x: x.state == "draft").action_rma_to_approve() + + + + + Cancel + + + code + + records.action_rma_cancel() + + +
diff --git a/rma/views/rma_order_view.xml b/rma/views/rma_order_view.xml new file mode 100644 index 00000000..6e1172b5 --- /dev/null +++ b/rma/views/rma_order_view.xml @@ -0,0 +1,327 @@ + + + + rma.order.tree + rma.order + + + + + + + + + + + + rma.order.supplier.tree + rma.order + + + + + + + + + + + + rma.order.form + rma.order + +
+
+ +
+ + + + +
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ + + + + + rma.order.supplier.form + rma.order + + primary + + + rma.group_rma_supplier_user + + + Supplier + {'res_partner_search_mode': 'supplier'} + + + + + + + + + { + 'form_view_ref':'rma.view_rma_line_supplier_form', + 'default_rma_id': id, + 'default_partner_id': partner_id, + 'supplier': 1, + 'hide_title': True} + + + + [('type','=','supplier')] + + + 1 + + + 1 + + + 0 + + + 0 + + + + + + rma.order.select + rma.order + + + + + + + + + + + + + + + + Customer RMA Group + rma.order + [('type','=', 'customer')] + {'customer':1} + tree,form + + + + + Supplier RMA Group + rma.order + [('type','=', 'supplier')] + {'supplier':1} + tree,form + + + + + + tree + + + + + + form + + + + + diff --git a/rma/views/stock_view.xml b/rma/views/stock_view.xml new file mode 100644 index 00000000..cf7b0a4b --- /dev/null +++ b/rma/views/stock_view.xml @@ -0,0 +1,26 @@ + + + + rma.move.form + stock.move + + + + + + + + + + + + stock.route.form + + stock.route + + + + + diff --git a/rma/views/stock_warehouse.xml b/rma/views/stock_warehouse.xml new file mode 100644 index 00000000..701edd8e --- /dev/null +++ b/rma/views/stock_warehouse.xml @@ -0,0 +1,22 @@ + + + + view_warehouse_form + stock.warehouse + + + + + + + + + + + + + + + + + diff --git a/rma/wizards/__init__.py b/rma/wizards/__init__.py new file mode 100644 index 00000000..7989b077 --- /dev/null +++ b/rma/wizards/__init__.py @@ -0,0 +1,4 @@ +from . import rma_add_stock_move +from . import rma_make_picking +from . import rma_order_line_make_supplier_rma +from . import rma_add_serial diff --git a/rma/wizards/rma_add_serial.py b/rma/wizards/rma_add_serial.py new file mode 100644 index 00000000..043617cd --- /dev/null +++ b/rma/wizards/rma_add_serial.py @@ -0,0 +1,157 @@ +# Copyright 2022 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class RmaAddSerialWiz(models.TransientModel): + _name = "rma.add.serial.wiz" + _description = "Wizard to add rma lines from Serial/Lot numbers" + + rma_id = fields.Many2one( + comodel_name="rma.order", string="RMA Order", readonly=True, ondelete="cascade" + ) + partner_id = fields.Many2one( + comodel_name="res.partner", string="Partner", readonly=True + ) + partner_shipping_id = fields.Many2one( + string="Deliver To", + comodel_name="res.partner", + ) + lot_ids = fields.Many2many( + comodel_name="stock.lot", + string="Lots/Serials selected", + ) + + @api.model + def default_get(self, fields_list): + res = super().default_get(fields_list) + rma_obj = self.env["rma.order"] + rma_id = self.env.context["active_ids"] or [] + active_model = self.env.context["active_model"] + if not rma_id: + return res + assert active_model == "rma.order", "Bad context propagation" + + rma = rma_obj.browse(rma_id) + res["rma_id"] = rma.id + res["partner_id"] = rma.partner_id.id + return res + + @api.onchange("partner_id") + def onchange_partner_id(self): + if not self.partner_id: + self.update( + { + "partner_shipping_id": False, + } + ) + return + + self = self.with_company(self.rma_id.company_id) + addr = self.partner_id.address_get(["delivery"]) + self.update( + { + "partner_shipping_id": addr["delivery"], + } + ) + + def _prepare_rma_line_from_lot_vals(self, lot): + operation = self.rma_id.operation_default_id + if not operation: + if self.env.context.get("customer"): + operation = ( + lot.product_id.rma_customer_operation_id + or lot.product_id.categ_id.rma_customer_operation_id + ) + else: + operation = ( + lot.product_id.rma_supplier_operation_id + or lot.product_id.categ_id.rma_supplier_operation_id + ) + if not operation: + operation = self.env["rma.operation"].search( + [("type", "=", self.rma_id.type)], limit=1 + ) + if not operation: + raise ValidationError(_("Please define an operation first")) + + if not operation.in_route_id or not operation.out_route_id: + route = self.env["stock.route"].search( + [("rma_selectable", "=", True)], limit=1 + ) + if not route: + raise ValidationError(_("Please define an RMA route")) + + in_warehouse = self.rma_id.in_warehouse_id or operation.in_warehouse_id + in_route = self.rma_id.in_route_id or operation.in_route_id + out_warehouse = self.rma_id.out_warehouse_id or operation.out_warehouse_id + out_route = self.rma_id.out_route_id or operation.out_route_id + if not in_warehouse or not out_warehouse: + warehouse = self.env["stock.warehouse"].search( + [ + ("company_id", "=", self.rma_id.company_id.id), + ("lot_rma_id", "!=", False), + ], + limit=1, + ) + if not warehouse: + raise ValidationError( + _("Please define a warehouse with a default RMA location") + ) + in_warehouse = in_warehouse or warehouse + out_warehouse = out_warehouse or warehouse + location = self.rma_id.location_id + if not location: + location = ( + operation.location_id + or operation.in_warehouse_id.lot_rma_id + or in_warehouse.lot_rma_id + or out_warehouse.lot_rma_id + ) + + product_qty = 1 # serial + if lot.product_id.tracking == "lot": + # TODO: improve logic, allow to specify qty? + product_qty = 1 + + vals = { + "partner_id": self.partner_id.id, + "description": self.rma_id.description, + "product_id": lot.product_id.id, + "lot_id": lot.id, + "uom_id": lot.product_id.uom_id.id, + "operation_id": operation.id, + "product_qty": product_qty, + "delivery_address_id": self.partner_shipping_id.id or self.partner_id.id, + "rma_id": self.rma_id.id, + "receipt_policy": operation.receipt_policy, + "delivery_policy": operation.delivery_policy, + "in_warehouse_id": in_warehouse.id, + "out_warehouse_id": out_warehouse.id, + "in_route_id": in_route.id, + "out_route_id": out_route.id, + "location_id": location.id, + } + return vals + + def action_confirm(self): + rma_line_obj = self.env["rma.order.line"] + existing_lots = self.rma_id.mapped("rma_line_ids.lot_id") + for lot in self.lot_ids: + if lot in existing_lots: + raise ValidationError( + _("Lot/Serial Number %s already added.") % lot.name + ) + + vals = self._prepare_rma_line_from_lot_vals(lot) + rec = rma_line_obj.create(vals) + # Ensure that configuration on the operation is applied (like + # policies). + # TODO MIG: in v16 the usage of such onchange can be removed in + # favor of (pre)computed stored editable fields for all policies + # and configuration in the RMA operation. + rec._onchange_operation_id() + rec.price_unit = rec._get_price_unit() + return {"type": "ir.actions.act_window_close"} diff --git a/rma/wizards/rma_add_serial_views.xml b/rma/wizards/rma_add_serial_views.xml new file mode 100644 index 00000000..4a1cac90 --- /dev/null +++ b/rma/wizards/rma_add_serial_views.xml @@ -0,0 +1,102 @@ + + + + rma.add.serial.wiz.customer + rma.add.serial.wiz + +
+ + + + + + +
+
+ +
+
+ + + Add from Lot/Serial Numbers + ir.actions.act_window + rma.add.serial.wiz + form + new + + + + + + + rma.order.form - rma.add.serial.wiz + rma.order + + + +
+
+
+ +
+
+ + + Add from Stock Move + ir.actions.act_window + rma_add_stock_move + form + new + + + + + + + rma.order.form - stock.move wizard + rma.order + + + +