mirror of
https://github.com/OCA/rma.git
synced 2025-02-16 17:11:47 +02:00
[IMP] rma: use only procurement.group run to create stock transfers
Extra changes: - Change reception_move_ids to reception_move_id - Add test_rma_replace_pick_ship - Code and method reduction to simplify logic - Set route_ids (in/out) from procurements Co-authored-by: Michael Tietz TT48789 [UPD] Update rma.pot [BOT] post-merge updates Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: rma-17.0/rma-17.0-rma Translate-URL: https://translation.odoo-community.org/projects/rma-17-0/rma-17-0-rma/
This commit is contained in:
committed by
Víctor Martínez
parent
b3d9634e37
commit
90ce4f4201
@@ -7,7 +7,7 @@ Return Merchandise Authorization Management
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:ed3081bf9b94660a0e6b35acbc7a874023c57e4bc3a87f3762eabbb1c75ce2f4
|
||||
!! source digest: sha256:8f36869aece97a0f6af8aa5d76b446e9cf0bd589d914c1f5e12c628e87317021
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png
|
||||
@@ -140,6 +140,9 @@ Known issues / Roadmap
|
||||
- As soon as the picking is selected, the user should select the move,
|
||||
but perhaps stock.move \_rec_name could be improved to better show
|
||||
what the product of that move is.
|
||||
- Add RMA reception and/or RMA delivery on several steps - 2 or 3 -
|
||||
like normal receptions/deliveries. It should be a separate option
|
||||
inside the warehouse definition.
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
@@ -175,6 +178,8 @@ Contributors
|
||||
|
||||
- Antoni Marroig <amarroig@apsl.net>
|
||||
|
||||
- Michael Tietz (MT Software) mtietz@mt-software.de
|
||||
|
||||
Maintainers
|
||||
-----------
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{
|
||||
"name": "Return Merchandise Authorization Management",
|
||||
"summary": "Return Merchandise Authorization (RMA)",
|
||||
"version": "17.0.1.1.1",
|
||||
"version": "17.0.2.0.0",
|
||||
"development_status": "Production/Stable",
|
||||
"category": "RMA",
|
||||
"website": "https://github.com/OCA/rma",
|
||||
|
||||
13
rma/hooks.py
13
rma/hooks.py
@@ -1,4 +1,5 @@
|
||||
# Copyright 2020 Tecnativa - Ernesto Tejeda
|
||||
# Copyright 2023 Michael Tietz (MT Software) <mtietz@mt-software.de>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
|
||||
@@ -20,7 +21,9 @@ def post_init_hook(env):
|
||||
def create_rma_locations(warehouse):
|
||||
stock_location = env["stock.location"]
|
||||
if not warehouse.rma_loc_id:
|
||||
rma_location_vals = warehouse._get_rma_location_values()
|
||||
rma_location_vals = warehouse._get_rma_location_values(
|
||||
{"company_id": warehouse.company_id.id}, warehouse.code
|
||||
)
|
||||
warehouse.rma_loc_id = (
|
||||
stock_location.with_context(active_test=False)
|
||||
.create(rma_location_vals)
|
||||
@@ -57,11 +60,19 @@ def post_init_hook(env):
|
||||
whs.rma_in_type_id.return_picking_type_id = whs.rma_out_type_id.id
|
||||
whs.rma_out_type_id.return_picking_type_id = whs.rma_in_type_id.id
|
||||
|
||||
def create_rma_routes(warehouses):
|
||||
"""Create initially rma in/out stock.location.routes and stock.rules"""
|
||||
warehouses = warehouses.with_context(rma_post_init_hook=True)
|
||||
for wh in warehouses:
|
||||
route_vals = wh._create_or_update_route()
|
||||
wh.write(route_vals)
|
||||
|
||||
# Create rma locations and picking types
|
||||
warehouses = env["stock.warehouse"].search([])
|
||||
for warehouse in warehouses:
|
||||
create_rma_locations(warehouse)
|
||||
create_rma_picking_types(warehouse)
|
||||
create_rma_routes(warehouses)
|
||||
# Create rma sequence per company
|
||||
for company in env["res.company"].search([]):
|
||||
company.create_rma_index()
|
||||
|
||||
@@ -1531,11 +1531,21 @@ msgstr "Automatische RMA-Kundenbenachrichtigungen"
|
||||
msgid "RMA count"
|
||||
msgstr "RMA-Zählung"
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_in_route_id
|
||||
msgid "RMA in Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:mail.message.subtype,description:rma.mt_rma_draft
|
||||
msgid "RMA in draft state"
|
||||
msgstr "RMA im Entwurfszustand"
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_out_route_id
|
||||
msgid "RMA out Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_move__rma_receiver_ids
|
||||
msgid "RMA receivers"
|
||||
@@ -1735,6 +1745,11 @@ msgstr ""
|
||||
msgid "Return Picking"
|
||||
msgstr "Inbound Kommissionierung"
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model,name:rma.model_stock_return_picking_line
|
||||
msgid "Return Picking Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.actions.act_window,name:rma.rma_delivery_wizard_action
|
||||
#: model:ir.model.fields.selection,name:rma.selection__rma_delivery_wizard__type__return
|
||||
@@ -1758,6 +1773,13 @@ msgstr ""
|
||||
msgid "Returned"
|
||||
msgstr "Ist zurückgekommen"
|
||||
|
||||
#. module: rma
|
||||
#. odoo-python
|
||||
#: code:addons/rma/wizard/stock_picking_return.py:0
|
||||
#, python-format
|
||||
msgid "Returned Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_rma_tag__rma_ids
|
||||
msgid "Rma"
|
||||
|
||||
@@ -1445,11 +1445,21 @@ msgstr ""
|
||||
msgid "RMA count"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_in_route_id
|
||||
msgid "RMA in Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:mail.message.subtype,description:rma.mt_rma_draft
|
||||
msgid "RMA in draft state"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_out_route_id
|
||||
msgid "RMA out Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_move__rma_receiver_ids
|
||||
msgid "RMA receivers"
|
||||
@@ -1641,6 +1651,11 @@ msgstr ""
|
||||
msgid "Return Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model,name:rma.model_stock_return_picking_line
|
||||
msgid "Return Picking Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.actions.act_window,name:rma.rma_delivery_wizard_action
|
||||
#: model:ir.model.fields.selection,name:rma.selection__rma_delivery_wizard__type__return
|
||||
@@ -1662,6 +1677,13 @@ msgstr ""
|
||||
msgid "Returned"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#. odoo-python
|
||||
#: code:addons/rma/wizard/stock_picking_return.py:0
|
||||
#, python-format
|
||||
msgid "Returned Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_rma_tag__rma_ids
|
||||
msgid "Rma"
|
||||
|
||||
@@ -1598,11 +1598,21 @@ msgstr "Notificaciones automáticas de RMA"
|
||||
msgid "RMA count"
|
||||
msgstr "Cantidad de RMAs"
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_in_route_id
|
||||
msgid "RMA in Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:mail.message.subtype,description:rma.mt_rma_draft
|
||||
msgid "RMA in draft state"
|
||||
msgstr "RMA en estado borrador"
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_out_route_id
|
||||
msgid "RMA out Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_move__rma_receiver_ids
|
||||
msgid "RMA receivers"
|
||||
@@ -1803,6 +1813,11 @@ msgstr "Lugar de devolución"
|
||||
msgid "Return Picking"
|
||||
msgstr "Albarán de devolución"
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model,name:rma.model_stock_return_picking_line
|
||||
msgid "Return Picking Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.actions.act_window,name:rma.rma_delivery_wizard_action
|
||||
#: model:ir.model.fields.selection,name:rma.selection__rma_delivery_wizard__type__return
|
||||
@@ -1826,6 +1841,13 @@ msgstr ""
|
||||
msgid "Returned"
|
||||
msgstr "Devuelto"
|
||||
|
||||
#. module: rma
|
||||
#. odoo-python
|
||||
#: code:addons/rma/wizard/stock_picking_return.py:0
|
||||
#, python-format
|
||||
msgid "Returned Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_rma_tag__rma_ids
|
||||
msgid "Rma"
|
||||
|
||||
@@ -1584,11 +1584,21 @@ msgstr "Notifications RMA automatiques au client"
|
||||
msgid "RMA count"
|
||||
msgstr "Nombre de RMA"
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_in_route_id
|
||||
msgid "RMA in Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:mail.message.subtype,description:rma.mt_rma_draft
|
||||
msgid "RMA in draft state"
|
||||
msgstr "RMA au statut brouillon"
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_out_route_id
|
||||
msgid "RMA out Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_move__rma_receiver_ids
|
||||
msgid "RMA receivers"
|
||||
@@ -1789,6 +1799,11 @@ msgstr "Emplacement de retour"
|
||||
msgid "Return Picking"
|
||||
msgstr "Ordres de retour"
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model,name:rma.model_stock_return_picking_line
|
||||
msgid "Return Picking Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.actions.act_window,name:rma.rma_delivery_wizard_action
|
||||
#: model:ir.model.fields.selection,name:rma.selection__rma_delivery_wizard__type__return
|
||||
@@ -1812,6 +1827,13 @@ msgstr ""
|
||||
msgid "Returned"
|
||||
msgstr "Retourné"
|
||||
|
||||
#. module: rma
|
||||
#. odoo-python
|
||||
#: code:addons/rma/wizard/stock_picking_return.py:0
|
||||
#, python-format
|
||||
msgid "Returned Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_rma_tag__rma_ids
|
||||
msgid "Rma"
|
||||
|
||||
@@ -1591,11 +1591,21 @@ msgstr "Notifiche automatiche ai clienti RMA"
|
||||
msgid "RMA count"
|
||||
msgstr "Conteggio RMA"
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_in_route_id
|
||||
msgid "RMA in Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:mail.message.subtype,description:rma.mt_rma_draft
|
||||
msgid "RMA in draft state"
|
||||
msgstr "RMA in stato bozza"
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_out_route_id
|
||||
msgid "RMA out Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_move__rma_receiver_ids
|
||||
msgid "RMA receivers"
|
||||
@@ -1795,6 +1805,11 @@ msgstr "Ubicazione di reso"
|
||||
msgid "Return Picking"
|
||||
msgstr "Prelievo di reso"
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model,name:rma.model_stock_return_picking_line
|
||||
msgid "Return Picking Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.actions.act_window,name:rma.rma_delivery_wizard_action
|
||||
#: model:ir.model.fields.selection,name:rma.selection__rma_delivery_wizard__type__return
|
||||
@@ -1818,6 +1833,13 @@ msgstr ""
|
||||
msgid "Returned"
|
||||
msgstr "Restituito"
|
||||
|
||||
#. module: rma
|
||||
#. odoo-python
|
||||
#: code:addons/rma/wizard/stock_picking_return.py:0
|
||||
#, python-format
|
||||
msgid "Returned Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_rma_tag__rma_ids
|
||||
msgid "Rma"
|
||||
|
||||
@@ -1445,11 +1445,21 @@ msgstr ""
|
||||
msgid "RMA count"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_in_route_id
|
||||
msgid "RMA in Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:mail.message.subtype,description:rma.mt_rma_draft
|
||||
msgid "RMA in draft state"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_out_route_id
|
||||
msgid "RMA out Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_move__rma_receiver_ids
|
||||
msgid "RMA receivers"
|
||||
@@ -1641,6 +1651,11 @@ msgstr ""
|
||||
msgid "Return Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model,name:rma.model_stock_return_picking_line
|
||||
msgid "Return Picking Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.actions.act_window,name:rma.rma_delivery_wizard_action
|
||||
#: model:ir.model.fields.selection,name:rma.selection__rma_delivery_wizard__type__return
|
||||
@@ -1662,6 +1677,13 @@ msgstr ""
|
||||
msgid "Returned"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#. odoo-python
|
||||
#: code:addons/rma/wizard/stock_picking_return.py:0
|
||||
#, python-format
|
||||
msgid "Returned Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_rma_tag__rma_ids
|
||||
msgid "Rma"
|
||||
|
||||
@@ -1470,11 +1470,21 @@ msgstr "Notificações automáticas a clientes de RMA"
|
||||
msgid "RMA count"
|
||||
msgstr "Contagem de RMA"
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_in_route_id
|
||||
msgid "RMA in Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:mail.message.subtype,description:rma.mt_rma_draft
|
||||
msgid "RMA in draft state"
|
||||
msgstr "RMA em estado de rascunho"
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_out_route_id
|
||||
msgid "RMA out Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_move__rma_receiver_ids
|
||||
msgid "RMA receivers"
|
||||
@@ -1666,6 +1676,11 @@ msgstr ""
|
||||
msgid "Return Picking"
|
||||
msgstr "Operação de Devolução"
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model,name:rma.model_stock_return_picking_line
|
||||
msgid "Return Picking Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.actions.act_window,name:rma.rma_delivery_wizard_action
|
||||
#: model:ir.model.fields.selection,name:rma.selection__rma_delivery_wizard__type__return
|
||||
@@ -1687,6 +1702,13 @@ msgstr ""
|
||||
msgid "Returned"
|
||||
msgstr "Devolvido"
|
||||
|
||||
#. module: rma
|
||||
#. odoo-python
|
||||
#: code:addons/rma/wizard/stock_picking_return.py:0
|
||||
#, python-format
|
||||
msgid "Returned Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_rma_tag__rma_ids
|
||||
msgid "Rma"
|
||||
|
||||
@@ -1470,11 +1470,21 @@ msgstr ""
|
||||
msgid "RMA count"
|
||||
msgstr "Contagem de RMA"
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_in_route_id
|
||||
msgid "RMA in Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:mail.message.subtype,description:rma.mt_rma_draft
|
||||
msgid "RMA in draft state"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_out_route_id
|
||||
msgid "RMA out Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_move__rma_receiver_ids
|
||||
msgid "RMA receivers"
|
||||
@@ -1666,6 +1676,11 @@ msgstr ""
|
||||
msgid "Return Picking"
|
||||
msgstr "Retorno de Coleta"
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model,name:rma.model_stock_return_picking_line
|
||||
msgid "Return Picking Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.actions.act_window,name:rma.rma_delivery_wizard_action
|
||||
#: model:ir.model.fields.selection,name:rma.selection__rma_delivery_wizard__type__return
|
||||
@@ -1687,6 +1702,13 @@ msgstr ""
|
||||
msgid "Returned"
|
||||
msgstr "Retornado(a)"
|
||||
|
||||
#. module: rma
|
||||
#. odoo-python
|
||||
#: code:addons/rma/wizard/stock_picking_return.py:0
|
||||
#, python-format
|
||||
msgid "Returned Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_rma_tag__rma_ids
|
||||
msgid "Rma"
|
||||
|
||||
@@ -1437,11 +1437,21 @@ msgstr ""
|
||||
msgid "RMA count"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_in_route_id
|
||||
msgid "RMA in Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:mail.message.subtype,description:rma.mt_rma_draft
|
||||
msgid "RMA in draft state"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_out_route_id
|
||||
msgid "RMA out Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_move__rma_receiver_ids
|
||||
msgid "RMA receivers"
|
||||
@@ -1633,6 +1643,11 @@ msgstr ""
|
||||
msgid "Return Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model,name:rma.model_stock_return_picking_line
|
||||
msgid "Return Picking Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.actions.act_window,name:rma.rma_delivery_wizard_action
|
||||
#: model:ir.model.fields.selection,name:rma.selection__rma_delivery_wizard__type__return
|
||||
@@ -1654,6 +1669,13 @@ msgstr ""
|
||||
msgid "Returned"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#. odoo-python
|
||||
#: code:addons/rma/wizard/stock_picking_return.py:0
|
||||
#, python-format
|
||||
msgid "Returned Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_rma_tag__rma_ids
|
||||
msgid "Rma"
|
||||
|
||||
@@ -1468,11 +1468,21 @@ msgstr ""
|
||||
msgid "RMA count"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_in_route_id
|
||||
msgid "RMA in Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:mail.message.subtype,description:rma.mt_rma_draft
|
||||
msgid "RMA in draft state"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_out_route_id
|
||||
msgid "RMA out Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_move__rma_receiver_ids
|
||||
msgid "RMA receivers"
|
||||
@@ -1664,6 +1674,11 @@ msgstr ""
|
||||
msgid "Return Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model,name:rma.model_stock_return_picking_line
|
||||
msgid "Return Picking Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.actions.act_window,name:rma.rma_delivery_wizard_action
|
||||
#: model:ir.model.fields.selection,name:rma.selection__rma_delivery_wizard__type__return
|
||||
@@ -1685,6 +1700,13 @@ msgstr ""
|
||||
msgid "Returned"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#. odoo-python
|
||||
#: code:addons/rma/wizard/stock_picking_return.py:0
|
||||
#, python-format
|
||||
msgid "Returned Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_rma_tag__rma_ids
|
||||
msgid "Rma"
|
||||
|
||||
@@ -1447,11 +1447,21 @@ msgstr ""
|
||||
msgid "RMA count"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_in_route_id
|
||||
msgid "RMA in Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:mail.message.subtype,description:rma.mt_rma_draft
|
||||
msgid "RMA in draft state"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_warehouse__rma_out_route_id
|
||||
msgid "RMA out Route"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_stock_move__rma_receiver_ids
|
||||
msgid "RMA receivers"
|
||||
@@ -1643,6 +1653,11 @@ msgstr ""
|
||||
msgid "Return Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model,name:rma.model_stock_return_picking_line
|
||||
msgid "Return Picking Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.actions.act_window,name:rma.rma_delivery_wizard_action
|
||||
#: model:ir.model.fields.selection,name:rma.selection__rma_delivery_wizard__type__return
|
||||
@@ -1664,6 +1679,13 @@ msgstr ""
|
||||
msgid "Returned"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#. odoo-python
|
||||
#: code:addons/rma/wizard/stock_picking_return.py:0
|
||||
#, python-format
|
||||
msgid "Returned Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: rma
|
||||
#: model:ir.model.fields,field_description:rma.field_rma_tag__rma_ids
|
||||
msgid "Rma"
|
||||
|
||||
17
rma/migrations/17.0.1.2.0/post-migration.py
Normal file
17
rma/migrations/17.0.1.2.0/post-migration.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Copyright 2024 Tecnativa - Víctor Martínez
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openupgradelib import openupgrade
|
||||
|
||||
|
||||
@openupgrade.migrate()
|
||||
def migrate(env, version):
|
||||
"""Similar behavior to create_rma_routes of post_init_hook."""
|
||||
warehouses = env["stock.warehouse"].search([])
|
||||
warehouses = warehouses.with_context(rma_post_init_hook=True)
|
||||
for wh in warehouses:
|
||||
if not wh.rma_in_type_id or not wh.rma_out_type_id:
|
||||
data = wh._create_or_update_sequences_and_picking_types()
|
||||
wh.write(data)
|
||||
route_vals = wh._create_or_update_route()
|
||||
wh.write(route_vals)
|
||||
@@ -27,7 +27,7 @@ class ResPartner(models.Model):
|
||||
|
||||
def action_view_rma(self):
|
||||
self.ensure_one()
|
||||
action = self.sudo().env.ref("rma.rma_action").read()[0]
|
||||
action = self.env["ir.actions.act_window"]._for_xml_id("rma.rma_action")
|
||||
rma = self.rma_ids
|
||||
if len(rma) == 1:
|
||||
action.update(
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
# Copyright 2020 Tecnativa - Ernesto Tejeda
|
||||
# Copyright 2023 Tecnativa - Pedro M. Baeza
|
||||
# Copyright 2023 Michael Tietz (MT Software) <mtietz@mt-software.de>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
import logging
|
||||
from collections import Counter
|
||||
from collections import defaultdict
|
||||
from itertools import groupby
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import AccessError, ValidationError
|
||||
from odoo.tests import Form
|
||||
from odoo.tools import html2plaintext
|
||||
|
||||
from odoo.addons.stock.models.stock_move import PROCUREMENT_PRIORITIES
|
||||
@@ -259,18 +260,8 @@ class Rma(models.Model):
|
||||
)
|
||||
|
||||
def _compute_delivery_picking_count(self):
|
||||
# It is enough to count the moves to know how many pickings
|
||||
# there are because there will be a unique move linked to the
|
||||
# same picking and the same rma.
|
||||
rma_data = self.env["stock.move"].read_group(
|
||||
[("rma_id", "in", self.ids)],
|
||||
["rma_id", "picking_id"],
|
||||
["rma_id", "picking_id"],
|
||||
lazy=False,
|
||||
)
|
||||
mapped_data = Counter(map(lambda r: r["rma_id"][0], rma_data))
|
||||
for record in self:
|
||||
record.delivery_picking_count = mapped_data.get(record.id, 0)
|
||||
for rma in self:
|
||||
rma.delivery_picking_count = len(rma.delivery_move_ids.picking_id)
|
||||
|
||||
@api.depends(
|
||||
"delivery_move_ids",
|
||||
@@ -609,22 +600,85 @@ class Rma(models.Model):
|
||||
}
|
||||
|
||||
def _add_message_subscribe_partner(self):
|
||||
self.ensure_one()
|
||||
if self.partner_id and self.partner_id not in self.message_partner_ids:
|
||||
self.message_subscribe([self.partner_id.id])
|
||||
|
||||
def _product_is_storable(self, product=None):
|
||||
product = product or self.product_id
|
||||
return product.type in ["product", "consu"]
|
||||
|
||||
def _prepare_procurement_group_vals(self):
|
||||
return {
|
||||
"move_type": "direct",
|
||||
"partner_id": self and self.partner_shipping_id.id or False,
|
||||
"name": self and ", ".join(self.mapped("name")) or False,
|
||||
}
|
||||
|
||||
def _prepare_common_procurement_vals(
|
||||
self, warehouse=None, scheduled_date=None, group=None
|
||||
):
|
||||
self.ensure_one()
|
||||
group = group or self.procurement_group_id
|
||||
if not group:
|
||||
group = self.env["procurement.group"].create(
|
||||
self._prepare_procurement_group_vals()
|
||||
)
|
||||
return {
|
||||
"company_id": self.company_id,
|
||||
"group_id": group,
|
||||
"date_planned": scheduled_date or fields.Datetime.now(),
|
||||
"warehouse_id": warehouse or self.warehouse_id,
|
||||
"partner_id": group.partner_id.id,
|
||||
"priority": self.priority,
|
||||
}
|
||||
|
||||
def _prepare_reception_procurement_vals(self, group=None):
|
||||
"""This method is used only for reception and a specific RMA IN route."""
|
||||
vals = self._prepare_common_procurement_vals(group=group)
|
||||
vals["route_ids"] = self.warehouse_id.rma_in_route_id
|
||||
vals["rma_receiver_ids"] = [(6, 0, self.ids)]
|
||||
if self.move_id:
|
||||
vals["origin_returned_move_id"] = self.move_id.id
|
||||
return vals
|
||||
|
||||
def _prepare_reception_procurements(self):
|
||||
procurements = []
|
||||
group_model = self.env["procurement.group"]
|
||||
for rma in self:
|
||||
if not rma._product_is_storable():
|
||||
continue
|
||||
group = rma.procurement_group_id
|
||||
if not group:
|
||||
group = group_model.create(rma._prepare_procurement_group_vals())
|
||||
procurements.append(
|
||||
group_model.Procurement(
|
||||
rma.product_id,
|
||||
rma.product_uom_qty,
|
||||
rma.product_uom,
|
||||
rma.location_id,
|
||||
rma.product_id.display_name,
|
||||
group.name,
|
||||
rma.company_id,
|
||||
rma._prepare_reception_procurement_vals(group),
|
||||
)
|
||||
)
|
||||
return procurements
|
||||
|
||||
def action_confirm(self):
|
||||
"""Invoked when 'Confirm' button in rma form view is clicked."""
|
||||
self.ensure_one()
|
||||
self._ensure_required_fields()
|
||||
if self.state == "draft":
|
||||
if self.picking_id:
|
||||
reception_move = self._create_receptions_from_picking()
|
||||
else:
|
||||
reception_move = self._create_receptions_from_product()
|
||||
reception_move.picked = True
|
||||
self.write({"reception_move_id": reception_move.id, "state": "confirmed"})
|
||||
self._add_message_subscribe_partner()
|
||||
self._send_confirmation_email()
|
||||
self = self.filtered(lambda rma: rma.state == "draft")
|
||||
if not self:
|
||||
return
|
||||
procurements = self._prepare_reception_procurements()
|
||||
if procurements:
|
||||
self.env["procurement.group"].run(procurements)
|
||||
self.reception_move_id.picking_id.action_assign()
|
||||
self.write({"state": "confirmed"})
|
||||
for rma in self:
|
||||
rma._add_message_subscribe_partner()
|
||||
self._send_confirmation_email()
|
||||
|
||||
def action_refund(self):
|
||||
"""Invoked when 'Refund' button in rma form view is clicked
|
||||
@@ -663,11 +717,8 @@ class Rma(models.Model):
|
||||
self._ensure_can_be_replaced()
|
||||
# Force active_id to avoid issues when coming from smart buttons
|
||||
# in other models
|
||||
action = (
|
||||
self.env.ref("rma.rma_delivery_wizard_action")
|
||||
.sudo()
|
||||
.with_context(active_id=self.id)
|
||||
.read()[0]
|
||||
action = self.env["ir.actions.act_window"]._for_xml_id(
|
||||
"rma.rma_delivery_wizard_action"
|
||||
)
|
||||
action["name"] = "Replace product(s)"
|
||||
action["context"] = dict(self.env.context)
|
||||
@@ -686,11 +737,8 @@ class Rma(models.Model):
|
||||
self._ensure_can_be_returned()
|
||||
# Force active_id to avoid issues when coming from smart buttons
|
||||
# in other models
|
||||
action = (
|
||||
self.env.ref("rma.rma_delivery_wizard_action")
|
||||
.sudo()
|
||||
.with_context(active_id=self.id)
|
||||
.read()[0]
|
||||
action = self.env["ir.actions.act_window"]._for_xml_id(
|
||||
"rma.rma_delivery_wizard_action"
|
||||
)
|
||||
action["context"] = dict(self.env.context)
|
||||
action["context"].update(
|
||||
@@ -706,11 +754,8 @@ class Rma(models.Model):
|
||||
self._ensure_can_be_split()
|
||||
# Force active_id to avoid issues when coming from smart buttons
|
||||
# in other models
|
||||
action = (
|
||||
self.env.ref("rma.rma_split_wizard_action")
|
||||
.sudo()
|
||||
.with_context(active_id=self.id)
|
||||
.read()[0]
|
||||
action = self.env["ir.actions.act_window"]._for_xml_id(
|
||||
"rma.rma_split_wizard_action"
|
||||
)
|
||||
action["context"] = dict(self.env.context)
|
||||
action["context"].update(active_id=self.id, active_ids=self.ids)
|
||||
@@ -722,11 +767,8 @@ class Rma(models.Model):
|
||||
self._ensure_can_be_returned()
|
||||
# Force active_id to avoid issues when coming from smart buttons
|
||||
# in other models
|
||||
action = (
|
||||
self.env.ref("rma.rma_finalization_wizard_action")
|
||||
.sudo()
|
||||
.with_context(active_id=self.id)
|
||||
.read()[0]
|
||||
action = self.env["ir.actions.act_window"]._for_xml_id(
|
||||
"rma.rma_finalization_wizard_action"
|
||||
)
|
||||
action["context"] = dict(self.env.context)
|
||||
action["context"].update(active_id=self.id, active_ids=self.ids)
|
||||
@@ -734,7 +776,7 @@ class Rma(models.Model):
|
||||
|
||||
def action_cancel(self):
|
||||
"""Invoked when 'Cancel' button in rma form view is clicked."""
|
||||
self.mapped("reception_move_id")._action_cancel()
|
||||
self.reception_move_id._action_cancel()
|
||||
self.write({"state": "cancelled"})
|
||||
|
||||
def action_draft(self):
|
||||
@@ -759,25 +801,28 @@ class Rma(models.Model):
|
||||
"url": self.get_portal_url(),
|
||||
}
|
||||
|
||||
def action_view_receipt(self):
|
||||
"""Invoked when 'Receipt' smart button in rma form view is clicked."""
|
||||
def _action_view_pickings(self, pickings):
|
||||
self.ensure_one()
|
||||
# Force active_id to avoid issues when coming from smart buttons
|
||||
# in other models
|
||||
action = (
|
||||
self.env.ref("stock.action_picking_tree_all")
|
||||
.sudo()
|
||||
.with_context(active_id=self.id)
|
||||
.read()[0]
|
||||
)
|
||||
action.update(
|
||||
res_id=self.reception_move_id.picking_id.id,
|
||||
view_mode="form",
|
||||
view_id=False,
|
||||
views=False,
|
||||
action = self.env["ir.actions.act_window"]._for_xml_id(
|
||||
"stock.action_picking_tree_all"
|
||||
)
|
||||
if len(pickings) > 1:
|
||||
action["domain"] = [("id", "in", pickings.ids)]
|
||||
elif pickings:
|
||||
action.update(
|
||||
res_id=pickings.id,
|
||||
view_mode="form",
|
||||
view_id=False,
|
||||
views=False,
|
||||
)
|
||||
return action
|
||||
|
||||
def action_view_receipt(self):
|
||||
"""Invoked when 'Receipt' smart button in rma form view is clicked."""
|
||||
return self._action_view_pickings(self.mapped("reception_move_id.picking_id"))
|
||||
|
||||
def action_view_refund(self):
|
||||
"""Invoked when 'Refund' smart button in rma form view is clicked."""
|
||||
self.ensure_one()
|
||||
@@ -793,23 +838,7 @@ class Rma(models.Model):
|
||||
|
||||
def action_view_delivery(self):
|
||||
"""Invoked when 'Delivery' smart button in rma form view is clicked."""
|
||||
action = (
|
||||
self.env.ref("stock.action_picking_tree_all")
|
||||
.sudo()
|
||||
.with_context(active_id=self.id)
|
||||
.read()[0]
|
||||
)
|
||||
picking = self.delivery_move_ids.mapped("picking_id")
|
||||
if len(picking) > 1:
|
||||
action["domain"] = [("id", "in", picking.ids)]
|
||||
elif picking:
|
||||
action.update(
|
||||
res_id=picking.id,
|
||||
view_mode="form",
|
||||
view_id=False,
|
||||
views=False,
|
||||
)
|
||||
return action
|
||||
return self._action_view_pickings(self.mapped("delivery_move_ids.picking_id"))
|
||||
|
||||
# Validation business methods
|
||||
def _ensure_required_fields(self):
|
||||
@@ -925,83 +954,6 @@ class Rma(models.Model):
|
||||
)
|
||||
)
|
||||
|
||||
# Reception business methods
|
||||
def _create_receptions_from_picking(self):
|
||||
self.ensure_one()
|
||||
stock_return_picking_form = Form(
|
||||
self.env["stock.return.picking"].with_context(
|
||||
active_ids=self.picking_id.ids,
|
||||
active_id=self.picking_id.id,
|
||||
active_model="stock.picking",
|
||||
)
|
||||
)
|
||||
return_wizard = stock_return_picking_form.save()
|
||||
if self.location_id:
|
||||
return_wizard.location_id = self.location_id
|
||||
return_wizard.product_return_moves.filtered(
|
||||
lambda r: r.move_id != self.move_id
|
||||
).unlink()
|
||||
return_line = return_wizard.product_return_moves
|
||||
return_line.update(
|
||||
{
|
||||
"quantity": self.product_uom_qty,
|
||||
# The to_refund field is now True by default, which isn't right in the
|
||||
# RMA creation context
|
||||
"to_refund": False,
|
||||
}
|
||||
)
|
||||
# set_rma_picking_type is to override the copy() method of stock
|
||||
# picking and change the default picking type to rma picking type.
|
||||
picking_action = return_wizard.with_context(
|
||||
set_rma_picking_type=True
|
||||
).create_returns()
|
||||
picking_id = picking_action["res_id"]
|
||||
picking = self.env["stock.picking"].browse(picking_id)
|
||||
picking.origin = f"{self.name} ({picking.origin})"
|
||||
move = picking.move_ids
|
||||
move.priority = self.priority
|
||||
return move
|
||||
|
||||
def _create_receptions_from_product(self):
|
||||
self.ensure_one()
|
||||
picking = self.env["stock.picking"].create(self._prepare_picking_vals())
|
||||
picking.action_confirm()
|
||||
picking.action_assign()
|
||||
picking.message_post_with_source(
|
||||
"mail.message_origin_link",
|
||||
render_values={"self": picking, "origin": self},
|
||||
subtype_id=self.env["ir.model.data"]._xmlid_to_res_id("mail.mt_note"),
|
||||
)
|
||||
return picking.move_ids
|
||||
|
||||
def _prepare_picking_vals(self):
|
||||
return {
|
||||
"picking_type_id": self.warehouse_id.rma_in_type_id.id,
|
||||
"origin": self.name,
|
||||
"partner_id": self.partner_shipping_id.id,
|
||||
"location_id": self.partner_shipping_id.property_stock_customer.id,
|
||||
"location_dest_id": self.location_id.id,
|
||||
"move_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": self.product_id.id,
|
||||
# same text as origin move or product text in partner lang
|
||||
"name": self.move_id.name
|
||||
or self.product_id.with_context(
|
||||
lang=self.partner_id.lang or "en_US"
|
||||
).display_name,
|
||||
"location_id": (
|
||||
self.partner_shipping_id.property_stock_customer.id
|
||||
),
|
||||
"location_dest_id": self.location_id.id,
|
||||
"product_uom_qty": self.product_uom_qty,
|
||||
},
|
||||
)
|
||||
],
|
||||
}
|
||||
|
||||
# Extract business methods
|
||||
def extract_quantity(self, qty, uom):
|
||||
self.ensure_one()
|
||||
@@ -1075,44 +1027,101 @@ class Rma(models.Model):
|
||||
"rma_id": self.id,
|
||||
}
|
||||
|
||||
# Returning business methods
|
||||
def create_return(self, scheduled_date, qty=None, uom=None):
|
||||
"""Intended to be invoked by the delivery wizard"""
|
||||
def _delivery_should_be_grouped(self):
|
||||
"""Checks if the rmas should be grouped for the delivery process"""
|
||||
group_returns = self.env.company.rma_return_grouping
|
||||
if "rma_return_grouping" in self.env.context:
|
||||
group_returns = self.env.context.get("rma_return_grouping")
|
||||
return group_returns
|
||||
|
||||
def _delivery_group_key(self):
|
||||
"""Returns a key by which the rmas should be grouped for the delivery process"""
|
||||
self.ensure_one()
|
||||
return (self.partner_shipping_id.id, self.company_id.id, self.warehouse_id.id)
|
||||
|
||||
def _group_delivery_if_needed(self):
|
||||
"""Groups the given rmas by the returned key from _delivery_group_key
|
||||
by setting the procurement_group_id on the each rma if there is not yet on
|
||||
set"""
|
||||
if not self._delivery_should_be_grouped():
|
||||
return
|
||||
grouped_rmas = groupby(
|
||||
sorted(self, key=lambda rma: rma._delivery_group_key()),
|
||||
key=lambda rma: [rma._delivery_group_key()],
|
||||
)
|
||||
for _group, rmas in grouped_rmas:
|
||||
rmas = (
|
||||
self.browse()
|
||||
.concat(*list(rmas))
|
||||
.filtered(lambda rma: not rma.procurement_group_id)
|
||||
)
|
||||
if not rmas:
|
||||
continue
|
||||
proc_group = self.env["procurement.group"].create(
|
||||
rmas._prepare_procurement_group_vals()
|
||||
)
|
||||
rmas.write({"procurement_group_id": proc_group.id})
|
||||
|
||||
def _prepare_delivery_procurement_vals(self, scheduled_date=None):
|
||||
"""This method is used only for Delivery (not replace). It is important to set
|
||||
RMA Out route."""
|
||||
vals = self._prepare_common_procurement_vals(scheduled_date=scheduled_date)
|
||||
vals["rma_id"] = self.id
|
||||
vals["route_ids"] = self.warehouse_id.rma_out_route_id
|
||||
vals["move_orig_ids"] = [(6, 0, self.reception_move_id.ids)]
|
||||
return vals
|
||||
|
||||
def _prepare_delivery_procurements(self, scheduled_date=None, qty=None, uom=None):
|
||||
self._group_delivery_if_needed()
|
||||
procurements = []
|
||||
group_model = self.env["procurement.group"]
|
||||
for rma in self:
|
||||
if not rma.procurement_group_id:
|
||||
rma.procurement_group_id = group_model.create(
|
||||
rma._prepare_procurement_group_vals()
|
||||
)
|
||||
|
||||
vals = rma._prepare_delivery_procurement_vals(scheduled_date)
|
||||
group = vals.get("group_id")
|
||||
procurements.append(
|
||||
group_model.Procurement(
|
||||
rma.product_id,
|
||||
qty or rma.product_uom_qty,
|
||||
uom or rma.product_uom,
|
||||
rma.partner_shipping_id.property_stock_customer,
|
||||
rma.product_id.display_name,
|
||||
group.name,
|
||||
rma.company_id,
|
||||
vals,
|
||||
)
|
||||
)
|
||||
return procurements
|
||||
|
||||
# Returning business methods
|
||||
def create_return(self, scheduled_date, qty=None, uom=None):
|
||||
"""Intended to be invoked by the delivery wizard"""
|
||||
self._ensure_can_be_returned()
|
||||
self._ensure_qty_to_return(qty, uom)
|
||||
group_dict = {}
|
||||
rmas_to_return = self.filtered("can_be_returned")
|
||||
for record in rmas_to_return:
|
||||
key = (
|
||||
record.partner_shipping_id.id,
|
||||
record.company_id.id,
|
||||
record.warehouse_id,
|
||||
rmas_to_return = self.filtered(
|
||||
lambda rma: rma.can_be_returned and rma._product_is_storable()
|
||||
)
|
||||
procurements = rmas_to_return._prepare_delivery_procurements(
|
||||
scheduled_date, qty, uom
|
||||
)
|
||||
if procurements:
|
||||
self.env["procurement.group"].run(procurements)
|
||||
pickings = defaultdict(lambda: self.browse())
|
||||
for rma in rmas_to_return:
|
||||
picking = rma.delivery_move_ids.picking_id.sorted("id", reverse=True)[0]
|
||||
pickings[picking] |= rma
|
||||
rma.message_post(
|
||||
body=_(
|
||||
'Return: <a href="#" data-oe-model="stock.picking" '
|
||||
'data-oe-id="%(id)d">%(name)s</a> has been created.'
|
||||
)
|
||||
% ({"id": picking.id, "name": picking.name})
|
||||
)
|
||||
group_dict.setdefault(key, self.env["rma"])
|
||||
group_dict[key] |= record
|
||||
if group_returns:
|
||||
grouped_rmas = group_dict.values()
|
||||
else:
|
||||
grouped_rmas = rmas_to_return
|
||||
for rmas in grouped_rmas:
|
||||
origin = ", ".join(rmas.mapped("name"))
|
||||
picking_vals = rmas[0]._prepare_returning_picking_vals(origin)
|
||||
for rma in rmas:
|
||||
picking_vals["move_ids"].append(
|
||||
(0, 0, rma._prepare_returning_move_vals(scheduled_date, qty, uom))
|
||||
)
|
||||
picking = self.env["stock.picking"].create(picking_vals)
|
||||
for rma in rmas:
|
||||
rma.message_post(
|
||||
body=_(
|
||||
'Return: <a href="#" data-oe-model="stock.picking" '
|
||||
'data-oe-id="%(id)d">%(name)s</a> has been created.'
|
||||
)
|
||||
% ({"id": picking.id, "name": picking.name})
|
||||
)
|
||||
for picking, rmas in pickings.items():
|
||||
picking.action_confirm()
|
||||
picking.action_assign()
|
||||
picking.message_post_with_source(
|
||||
@@ -1122,42 +1131,53 @@ class Rma(models.Model):
|
||||
)
|
||||
rmas_to_return.write({"state": "waiting_return"})
|
||||
|
||||
def _prepare_returning_picking_vals(self, origin=None):
|
||||
self.ensure_one()
|
||||
return {
|
||||
"picking_type_id": self.warehouse_id.rma_out_type_id.id,
|
||||
"location_id": self.location_id.id,
|
||||
"location_dest_id": self.reception_move_id.location_id.id,
|
||||
"origin": origin or self.name,
|
||||
"partner_id": self.partner_shipping_id.id,
|
||||
"company_id": self.company_id.id,
|
||||
"move_ids": [],
|
||||
}
|
||||
def _prepare_replace_procurement_vals(self, warehouse=None, scheduled_date=None):
|
||||
"""This method is used only for Replace (not Delivery). We do not use any
|
||||
specific route here."""
|
||||
vals = self._prepare_common_procurement_vals(warehouse, scheduled_date)
|
||||
vals["rma_id"] = self.id
|
||||
return vals
|
||||
|
||||
def _prepare_returning_move_vals(self, scheduled_date, quantity=None, uom=None):
|
||||
self.ensure_one()
|
||||
return {
|
||||
"product_id": self.product_id.id,
|
||||
"name": self.product_id.with_context(
|
||||
lang=self.partner_shipping_id.lang or "en_US"
|
||||
).display_name,
|
||||
"product_uom_qty": quantity or self.product_uom_qty,
|
||||
"product_uom": uom and uom.id or self.product_uom.id,
|
||||
"location_id": self.location_id.id,
|
||||
"location_dest_id": self.reception_move_id.location_id.id,
|
||||
"date": scheduled_date,
|
||||
"rma_id": self.id,
|
||||
"move_orig_ids": [(4, self.reception_move_id.id)],
|
||||
"company_id": self.company_id.id,
|
||||
}
|
||||
def _prepare_replace_procurements(
|
||||
self, warehouse, scheduled_date, product, qty, uom
|
||||
):
|
||||
procurements = []
|
||||
group_model = self.env["procurement.group"]
|
||||
for rma in self:
|
||||
if not rma._product_is_storable(product):
|
||||
continue
|
||||
|
||||
if not rma.procurement_group_id:
|
||||
rma.procurement_group_id = group_model.create(
|
||||
rma._prepare_procurement_group_vals()
|
||||
)
|
||||
|
||||
vals = rma._prepare_replace_procurement_vals(warehouse, scheduled_date)
|
||||
group = vals.get("group_id")
|
||||
procurements.append(
|
||||
group_model.Procurement(
|
||||
product,
|
||||
qty,
|
||||
uom,
|
||||
rma.partner_shipping_id.property_stock_customer,
|
||||
product.display_name,
|
||||
group.name,
|
||||
rma.company_id,
|
||||
vals,
|
||||
)
|
||||
)
|
||||
return procurements
|
||||
|
||||
# Replacing business methods
|
||||
def create_replace(self, scheduled_date, warehouse, product, qty, uom):
|
||||
"""Intended to be invoked by the delivery wizard"""
|
||||
self.ensure_one()
|
||||
self._ensure_can_be_replaced()
|
||||
moves_before = self.delivery_move_ids
|
||||
self._action_launch_stock_rule(scheduled_date, warehouse, product, qty, uom)
|
||||
procurements = self._prepare_replace_procurements(
|
||||
warehouse, scheduled_date, product, qty, uom
|
||||
)
|
||||
if procurements:
|
||||
self.env["procurement.group"].run(procurements)
|
||||
new_moves = self.delivery_move_ids - moves_before
|
||||
body = ""
|
||||
# The product replacement could explode into several moves like in the case of
|
||||
@@ -1181,6 +1201,12 @@ class Rma(models.Model):
|
||||
)
|
||||
+ "\n"
|
||||
)
|
||||
for rma in self:
|
||||
rma._add_replace_message(body, qty, uom)
|
||||
self.write({"state": "waiting_replacement"})
|
||||
|
||||
def _add_replace_message(self, body, qty, uom):
|
||||
self.ensure_one()
|
||||
self.message_post(
|
||||
body=body
|
||||
or _(
|
||||
@@ -1193,74 +1219,13 @@ class Rma(models.Model):
|
||||
)
|
||||
% (
|
||||
{
|
||||
"id": product.id,
|
||||
"name": product.display_name,
|
||||
"id": self.id,
|
||||
"name": self.display_name,
|
||||
"qty": qty,
|
||||
"uom": uom.name,
|
||||
}
|
||||
)
|
||||
)
|
||||
if self.state != "waiting_replacement":
|
||||
self.state = "waiting_replacement"
|
||||
|
||||
def _action_launch_stock_rule(
|
||||
self,
|
||||
scheduled_date,
|
||||
warehouse,
|
||||
product,
|
||||
qty,
|
||||
uom,
|
||||
):
|
||||
"""Creates a delivery picking and launch stock rule. It is invoked by:
|
||||
rma.create_replace
|
||||
"""
|
||||
self.ensure_one()
|
||||
if self.product_id.type not in ("consu", "product"):
|
||||
return
|
||||
if not self.procurement_group_id:
|
||||
self.procurement_group_id = (
|
||||
self.env["procurement.group"]
|
||||
.create(
|
||||
{
|
||||
"name": self.name,
|
||||
"move_type": "direct",
|
||||
"partner_id": self.partner_shipping_id.id,
|
||||
}
|
||||
)
|
||||
.id
|
||||
)
|
||||
values = self._prepare_procurement_values(
|
||||
self.procurement_group_id, scheduled_date, warehouse
|
||||
)
|
||||
procurement = self.env["procurement.group"].Procurement(
|
||||
product,
|
||||
qty,
|
||||
uom,
|
||||
self.partner_shipping_id.property_stock_customer,
|
||||
self.product_id.display_name,
|
||||
self.procurement_group_id.name,
|
||||
self.company_id,
|
||||
values,
|
||||
)
|
||||
self.env["procurement.group"].run([procurement])
|
||||
return True
|
||||
|
||||
def _prepare_procurement_values(
|
||||
self,
|
||||
group_id,
|
||||
scheduled_date,
|
||||
warehouse,
|
||||
):
|
||||
self.ensure_one()
|
||||
return {
|
||||
"company_id": self.company_id,
|
||||
"group_id": group_id,
|
||||
"date_planned": scheduled_date,
|
||||
"warehouse_id": warehouse,
|
||||
"partner_id": self.partner_shipping_id.id,
|
||||
"rma_id": self.id,
|
||||
"priority": self.priority,
|
||||
}
|
||||
|
||||
# Mail business methods
|
||||
def _creation_subtype(self):
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Copyright 2020 Tecnativa - Ernesto Tejeda
|
||||
# Copyright 2023 Michael Tietz (MT Software) <mtietz@mt-software.de>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
@@ -23,7 +24,7 @@ class StockMove(models.Model):
|
||||
string="RMA receivers",
|
||||
copy=False,
|
||||
)
|
||||
# RMA that create the delivery movement to the customer
|
||||
# RMA that creates the out move
|
||||
rma_id = fields.Many2one(
|
||||
comodel_name="rma",
|
||||
string="RMA return",
|
||||
@@ -33,8 +34,8 @@ class StockMove(models.Model):
|
||||
def unlink(self):
|
||||
# A stock user could have no RMA permissions, so the ids wouldn't
|
||||
# be accessible due to record rules.
|
||||
rma_receiver = self.sudo().mapped("rma_receiver_ids")
|
||||
rma = self.sudo().mapped("rma_id")
|
||||
rma_receiver = self.sudo().rma_receiver_ids
|
||||
rma = self.sudo().rma_id
|
||||
res = super().unlink()
|
||||
rma_receiver.filtered(lambda x: x.state != "cancelled").write(
|
||||
{"state": "draft"}
|
||||
@@ -115,38 +116,22 @@ class StockMove(models.Model):
|
||||
res["rma_id"] = self.sudo().rma_id.id
|
||||
return res
|
||||
|
||||
def _prepare_return_rma_vals(self, original_picking):
|
||||
"""hook method for preparing an RMA from the 'return picking wizard'."""
|
||||
self.ensure_one()
|
||||
partner = original_picking.partner_id
|
||||
if hasattr(original_picking, "sale_id") and original_picking.sale_id:
|
||||
partner_invoice_id = original_picking.sale_id.partner_invoice_id.id
|
||||
partner_shipping_id = original_picking.sale_id.partner_shipping_id.id
|
||||
else:
|
||||
partner_invoice_id = partner.address_get(["invoice"]).get("invoice", False)
|
||||
partner_shipping_id = partner.address_get(["delivery"]).get(
|
||||
"delivery", False
|
||||
)
|
||||
return {
|
||||
"user_id": self.env.user.id,
|
||||
"partner_id": partner.id,
|
||||
"partner_shipping_id": partner_shipping_id,
|
||||
"partner_invoice_id": partner_invoice_id,
|
||||
"origin": original_picking.name,
|
||||
"picking_id": original_picking.id,
|
||||
"move_id": self.origin_returned_move_id.id,
|
||||
"product_id": self.origin_returned_move_id.product_id.id,
|
||||
"product_uom_qty": self.product_uom_qty,
|
||||
"product_uom": self.product_uom.id,
|
||||
"reception_move_id": self.id,
|
||||
"company_id": self.company_id.id,
|
||||
"location_id": self.location_dest_id.id,
|
||||
"state": "confirmed",
|
||||
}
|
||||
def _prepare_procurement_values(self):
|
||||
res = super()._prepare_procurement_values()
|
||||
if self.rma_id:
|
||||
res["rma_id"] = self.rma_id.id
|
||||
return res
|
||||
|
||||
|
||||
class StockRule(models.Model):
|
||||
_inherit = "stock.rule"
|
||||
|
||||
def _get_custom_move_fields(self):
|
||||
return super()._get_custom_move_fields() + ["rma_id"]
|
||||
move_fields = super()._get_custom_move_fields()
|
||||
move_fields += [
|
||||
"rma_id",
|
||||
"origin_returned_move_id",
|
||||
"move_orig_ids",
|
||||
"rma_receiver_ids",
|
||||
]
|
||||
return move_fields
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# Copyright 2020 Tecnativa - Ernesto Tejeda
|
||||
# Copyright 2023 Michael Tietz (MT Software) <mtietz@mt-software.de>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo import _, fields, models
|
||||
|
||||
|
||||
class StockWarehouse(models.Model):
|
||||
@@ -27,35 +28,39 @@ class StockWarehouse(models.Model):
|
||||
comodel_name="stock.location",
|
||||
string="RMA Location",
|
||||
)
|
||||
rma_in_route_id = fields.Many2one("stock.route", "RMA in Route")
|
||||
rma_out_route_id = fields.Many2one("stock.route", "RMA out Route")
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
"""To create an RMA location and link it with a new warehouse,
|
||||
this method is overridden instead of '_get_locations_values'
|
||||
method because the locations that are created with the
|
||||
values returned by that method are forced to be children
|
||||
of view_location_id, and we don't want that.
|
||||
"""
|
||||
res = super().create(vals_list)
|
||||
stock_location = self.env["stock.location"]
|
||||
for record in res:
|
||||
rma_location_vals = record._get_rma_location_values()
|
||||
record.rma_loc_id = stock_location.create(rma_location_vals).id
|
||||
return res
|
||||
|
||||
def _get_rma_location_values(self):
|
||||
def _get_rma_location_values(self, vals, code=False):
|
||||
"""this method is intended to be used by 'create' method
|
||||
to create a new RMA location to be linked to a new warehouse.
|
||||
"""
|
||||
company_id = vals.get(
|
||||
"company_id", self.default_get(["company_id"])["company_id"]
|
||||
)
|
||||
code = vals.get("code") or code or ""
|
||||
code = code.replace(" ", "").upper()
|
||||
view_location_id = vals.get("view_location_id")
|
||||
view_location = (
|
||||
view_location_id
|
||||
and self.view_location_id.browse(view_location_id)
|
||||
or self.view_location_id
|
||||
)
|
||||
return {
|
||||
"name": self.view_location_id.name,
|
||||
"name": view_location.name,
|
||||
"active": True,
|
||||
"return_location": True,
|
||||
"usage": "internal",
|
||||
"company_id": self.company_id.id,
|
||||
"company_id": company_id,
|
||||
"location_id": self.env.ref("rma.stock_location_rma").id,
|
||||
"barcode": self._valid_barcode(code + "-RMA", company_id),
|
||||
}
|
||||
|
||||
def _get_locations_values(self, vals, code=False):
|
||||
res = super()._get_locations_values(vals, code)
|
||||
res["rma_loc_id"] = self._get_rma_location_values(vals, code)
|
||||
return res
|
||||
|
||||
def _get_sequence_values(self, name=False, code=False):
|
||||
values = super()._get_sequence_values(name=name, code=code)
|
||||
values.update(
|
||||
@@ -77,12 +82,14 @@ class StockWarehouse(models.Model):
|
||||
return values
|
||||
|
||||
def _update_name_and_code(self, new_name=False, new_code=False):
|
||||
res = super()._update_name_and_code(new_name, new_code)
|
||||
for warehouse in self:
|
||||
sequence_data = warehouse._get_sequence_values()
|
||||
warehouse.rma_in_type_id.sequence_id.write(sequence_data["rma_in_type_id"])
|
||||
warehouse.rma_out_type_id.sequence_id.write(
|
||||
sequence_data["rma_out_type_id"]
|
||||
)
|
||||
return res
|
||||
|
||||
def _get_picking_type_create_values(self, max_sequence):
|
||||
data, next_sequence = super()._get_picking_type_create_values(max_sequence)
|
||||
@@ -116,12 +123,13 @@ class StockWarehouse(models.Model):
|
||||
|
||||
def _get_picking_type_update_values(self):
|
||||
data = super()._get_picking_type_update_values()
|
||||
data.update(
|
||||
{
|
||||
"rma_in_type_id": {"default_location_dest_id": self.rma_loc_id.id},
|
||||
"rma_out_type_id": {"default_location_src_id": self.rma_loc_id.id},
|
||||
}
|
||||
)
|
||||
picking_types = {
|
||||
"rma_in_type_id": {"default_location_dest_id": self.rma_loc_id.id},
|
||||
"rma_out_type_id": {"default_location_src_id": self.rma_loc_id.id},
|
||||
}
|
||||
if self.env.context.get("rma_post_init_hook"):
|
||||
return picking_types
|
||||
data.update(picking_types)
|
||||
return data
|
||||
|
||||
def _create_or_update_sequences_and_picking_types(self):
|
||||
@@ -138,3 +146,70 @@ class StockWarehouse(models.Model):
|
||||
{"return_picking_type_id": data.get("rma_out_type_id", False)}
|
||||
)
|
||||
return data
|
||||
|
||||
def _get_routes_values(self):
|
||||
res = super()._get_routes_values()
|
||||
rma_routes = {
|
||||
"rma_in_route_id": {
|
||||
"routing_key": "rma_in",
|
||||
"depends": ["active"],
|
||||
"route_update_values": {
|
||||
"name": self._format_routename("RMA In"),
|
||||
"active": self.active,
|
||||
},
|
||||
"route_create_values": {
|
||||
"warehouse_selectable": True,
|
||||
"company_id": self.company_id.id,
|
||||
"sequence": 100,
|
||||
},
|
||||
"rules_values": {
|
||||
"active": True,
|
||||
},
|
||||
},
|
||||
"rma_out_route_id": {
|
||||
"routing_key": "rma_out",
|
||||
"depends": ["active"],
|
||||
"route_update_values": {
|
||||
"name": self._format_routename("RMA Out"),
|
||||
"active": self.active,
|
||||
},
|
||||
"route_create_values": {
|
||||
"warehouse_selectable": True,
|
||||
"company_id": self.company_id.id,
|
||||
"sequence": 110,
|
||||
},
|
||||
"rules_values": {
|
||||
"active": True,
|
||||
},
|
||||
},
|
||||
}
|
||||
if self.env.context.get("rma_post_init_hook"):
|
||||
return rma_routes
|
||||
res.update(rma_routes)
|
||||
return res
|
||||
|
||||
def get_rules_dict(self):
|
||||
res = super().get_rules_dict()
|
||||
customer_loc, supplier_loc = self._get_partner_locations()
|
||||
for warehouse in self:
|
||||
res[warehouse.id].update(
|
||||
{
|
||||
"rma_in": [
|
||||
self.Routing(
|
||||
customer_loc,
|
||||
warehouse.rma_loc_id,
|
||||
warehouse.rma_in_type_id,
|
||||
"pull",
|
||||
)
|
||||
],
|
||||
"rma_out": [
|
||||
self.Routing(
|
||||
warehouse.rma_loc_id,
|
||||
customer_loc,
|
||||
warehouse.rma_out_type_id,
|
||||
"pull",
|
||||
)
|
||||
],
|
||||
}
|
||||
)
|
||||
return res
|
||||
|
||||
@@ -7,3 +7,4 @@
|
||||
- Giovanni Serra - Ooops \<<giovanni@ooops404.com>\>
|
||||
- [APSL-Nagarro](https://www.apsl.tech):
|
||||
- Antoni Marroig \<<amarroig@apsl.net>\>
|
||||
- Michael Tietz (MT Software) <mtietz@mt-software.de>
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
- As soon as the picking is selected, the user should select the move,
|
||||
but perhaps stock.move \_rec_name could be improved to better show
|
||||
what the product of that move is.
|
||||
- Add RMA reception and/or RMA delivery on several steps - 2 or 3 - like
|
||||
normal receptions/deliveries. It should be a separate option inside the
|
||||
warehouse definition.
|
||||
|
||||
@@ -366,7 +366,7 @@ ul.auto-toc {
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:ed3081bf9b94660a0e6b35acbc7a874023c57e4bc3a87f3762eabbb1c75ce2f4
|
||||
!! source digest: sha256:8f36869aece97a0f6af8aa5d76b446e9cf0bd589d914c1f5e12c628e87317021
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Production/Stable" src="https://img.shields.io/badge/maturity-Production%2FStable-green.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/rma/tree/17.0/rma"><img alt="OCA/rma" src="https://img.shields.io/badge/github-OCA%2Frma-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/rma-17-0/rma-17-0-rma"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/rma&target_branch=17.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
|
||||
<p>This module allows you to manage <a class="reference external" href="https://en.wikipedia.org/wiki/Return_merchandise_authorization">Return Merchandise Authorization
|
||||
@@ -493,6 +493,9 @@ team will be the default one if no team is set.</li>
|
||||
<li>As soon as the picking is selected, the user should select the move,
|
||||
but perhaps stock.move _rec_name could be improved to better show
|
||||
what the product of that move is.</li>
|
||||
<li>Add RMA reception and/or RMA delivery on several steps - 2 or 3 -
|
||||
like normal receptions/deliveries. It should be a separate option
|
||||
inside the warehouse definition.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="bug-tracker">
|
||||
@@ -527,6 +530,7 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
|
||||
<li>Antoni Marroig <<a class="reference external" href="mailto:amarroig@apsl.net">amarroig@apsl.net</a>></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Michael Tietz (MT Software) <a class="reference external" href="mailto:mtietz@mt-software.de">mtietz@mt-software.de</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="maintainers">
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
# Copyright 2020 Tecnativa - Ernesto Tejeda
|
||||
# Copyright 2023 Michael Tietz (MT Software) <mtietz@mt-software.de>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.tests import Form, TransactionCase, new_test_user, users
|
||||
from odoo.tests import Form, new_test_user, users
|
||||
from odoo.tools import mute_logger
|
||||
|
||||
from odoo.addons.base.tests.common import BaseCommon
|
||||
|
||||
from .. import hooks
|
||||
|
||||
|
||||
class TestRma(TransactionCase):
|
||||
class TestRma(BaseCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env = cls.env(
|
||||
context=dict(
|
||||
cls.env.context,
|
||||
mail_create_nolog=True,
|
||||
mail_create_nosubscribe=True,
|
||||
mail_notrack=True,
|
||||
no_reset_password=True,
|
||||
tracking_disable=True,
|
||||
)
|
||||
)
|
||||
cls.user_rma = new_test_user(
|
||||
cls.env,
|
||||
login="user_rma",
|
||||
@@ -72,6 +68,7 @@ class TestRma(TransactionCase):
|
||||
{"name": "[Test] It's out of warranty. To be scrapped"}
|
||||
)
|
||||
cls.env.ref("rma.group_rma_manual_finalization").users |= cls.env.user
|
||||
cls.warehouse = cls.env.ref("stock.warehouse0")
|
||||
# Ensure grouping
|
||||
cls.env.company.rma_return_grouping = True
|
||||
|
||||
@@ -95,7 +92,7 @@ class TestRma(TransactionCase):
|
||||
rma = self._create_rma(partner, product, qty, location)
|
||||
rma.action_confirm()
|
||||
rma.reception_move_id.quantity = rma.product_uom_qty
|
||||
rma.reception_move_id.picking_id._action_done()
|
||||
rma.reception_move_id.picking_id.button_validate()
|
||||
return rma
|
||||
|
||||
def _create_delivery(self):
|
||||
@@ -132,6 +129,49 @@ class TestRma(TransactionCase):
|
||||
|
||||
|
||||
class TestRmaCase(TestRma):
|
||||
def test_post_init_hook(self):
|
||||
warehouse = self.env["stock.warehouse"].create(
|
||||
{
|
||||
"name": "Test warehouse",
|
||||
"code": "code",
|
||||
"company_id": self.env.company.id,
|
||||
}
|
||||
)
|
||||
hooks.post_init_hook(self.env)
|
||||
self.assertTrue(warehouse.rma_in_type_id)
|
||||
self.assertEqual(
|
||||
warehouse.rma_in_type_id.default_location_dest_id, warehouse.rma_loc_id
|
||||
)
|
||||
self.assertEqual(
|
||||
warehouse.rma_out_type_id.default_location_src_id, warehouse.rma_loc_id
|
||||
)
|
||||
self.assertTrue(warehouse.rma_loc_id)
|
||||
self.assertTrue(warehouse.rma_in_route_id)
|
||||
self.assertTrue(warehouse.rma_out_route_id)
|
||||
|
||||
def test_rma_replace_pick_ship(self):
|
||||
self.warehouse.write({"delivery_steps": "pick_ship"})
|
||||
rma = self._create_rma(self.partner, self.product, 1, self.rma_loc)
|
||||
rma.action_confirm()
|
||||
rma.reception_move_id.quantity = 1
|
||||
rma.reception_move_id.picking_id.button_validate()
|
||||
self.assertEqual(rma.reception_move_id.picking_id.state, "done")
|
||||
self.assertEqual(rma.state, "received")
|
||||
res = rma.action_replace()
|
||||
wizard_form = Form(self.env[res["res_model"]].with_context(**res["context"]))
|
||||
wizard_form.product_id = self.product
|
||||
wizard_form.product_uom_qty = rma.product_uom_qty
|
||||
wizard = wizard_form.save()
|
||||
wizard.action_deliver()
|
||||
self.assertEqual(rma.delivery_picking_count, 2)
|
||||
out_pickings = rma.mapped("delivery_move_ids.picking_id")
|
||||
self.assertIn(
|
||||
self.warehouse.pick_type_id, out_pickings.mapped("picking_type_id")
|
||||
)
|
||||
self.assertIn(
|
||||
self.warehouse.out_type_id, out_pickings.mapped("picking_type_id")
|
||||
)
|
||||
|
||||
def test_computed(self):
|
||||
# If partner changes, the invoice address is set
|
||||
rma = self.env["rma"].new()
|
||||
@@ -169,7 +209,7 @@ class TestRmaCase(TestRma):
|
||||
move.product_id = product_2
|
||||
move.product_uom_qty = 15
|
||||
picking = picking_form.save()
|
||||
picking._action_done()
|
||||
picking.button_validate()
|
||||
rma.picking_id = picking
|
||||
rma.move_id = picking.move_ids
|
||||
self.assertEqual(rma.product_id, product_2)
|
||||
@@ -207,13 +247,18 @@ class TestRmaCase(TestRma):
|
||||
self.assertEqual(rma.state, "confirmed")
|
||||
rma.reception_move_id.quantity = 9
|
||||
with self.assertRaises(ValidationError):
|
||||
rma.reception_move_id.picking_id._action_done()
|
||||
res = rma.reception_move_id.picking_id.button_validate()
|
||||
wizard = (
|
||||
self.env[res["res_model"]].with_context(**res["context"]).create({})
|
||||
)
|
||||
wizard.process()
|
||||
rma.reception_move_id.quantity = 10
|
||||
rma.reception_move_id.picking_id._action_done()
|
||||
rma.reception_move_id.picking_id.button_validate()
|
||||
self.assertEqual(rma.reception_move_id.picking_id.state, "done")
|
||||
self.assertEqual(rma.reception_move_id.quantity, 10)
|
||||
self.assertEqual(rma.state, "received")
|
||||
|
||||
@mute_logger("odoo.models.unlink")
|
||||
def test_cancel(self):
|
||||
# cancel a draft RMA
|
||||
rma = self._create_rma(self.partner, self.product)
|
||||
@@ -333,7 +378,7 @@ class TestRmaCase(TestRma):
|
||||
# line of refund_1
|
||||
self.assertEqual(len(refund_1.invoice_line_ids), 3)
|
||||
self.assertEqual(
|
||||
refund_1.invoice_line_ids.mapped("rma_id"),
|
||||
refund_1.invoice_line_ids.rma_id,
|
||||
(rma_1 | rma_2 | rma_3),
|
||||
)
|
||||
self.assertEqual(
|
||||
@@ -524,6 +569,13 @@ class TestRmaCase(TestRma):
|
||||
all_rmas = rma_1 | rma_2 | rma_3 | rma_4
|
||||
self.assertEqual(all_rmas.mapped("state"), ["received"] * 4)
|
||||
self.assertEqual(all_rmas.mapped("can_be_returned"), [True] * 4)
|
||||
all_in_pickings = all_rmas.mapped("reception_move_id.picking_id")
|
||||
self.assertEqual(
|
||||
all_in_pickings.mapped("picking_type_id"), self.warehouse.rma_in_type_id
|
||||
)
|
||||
self.assertEqual(
|
||||
all_in_pickings.mapped("location_dest_id"), self.warehouse.rma_loc_id
|
||||
)
|
||||
# Mass return of those four RMAs
|
||||
delivery_wizard = (
|
||||
self.env["rma.delivery.wizard"]
|
||||
@@ -534,6 +586,10 @@ class TestRmaCase(TestRma):
|
||||
# Two pickings were created
|
||||
pick_1 = (rma_1 | rma_2 | rma_3).mapped("delivery_move_ids.picking_id")
|
||||
pick_2 = rma_4.delivery_move_ids.picking_id
|
||||
self.assertEqual(pick_1.picking_type_id, self.warehouse.rma_out_type_id)
|
||||
self.assertEqual(pick_1.location_id, self.warehouse.rma_loc_id)
|
||||
self.assertEqual(pick_2.picking_type_id, self.warehouse.rma_out_type_id)
|
||||
self.assertEqual(pick_2.location_id, self.warehouse.rma_loc_id)
|
||||
self.assertEqual(len(pick_1), 1)
|
||||
self.assertEqual(len(pick_2), 1)
|
||||
self.assertNotEqual(pick_1, pick_2)
|
||||
@@ -549,7 +605,7 @@ class TestRmaCase(TestRma):
|
||||
# line of picking_1
|
||||
self.assertEqual(len(pick_1.move_ids), 3)
|
||||
self.assertEqual(
|
||||
pick_1.move_ids.mapped("rma_id"),
|
||||
pick_1.move_ids.rma_id,
|
||||
(rma_1 | rma_2 | rma_3),
|
||||
)
|
||||
self.assertEqual(
|
||||
@@ -620,14 +676,14 @@ class TestRmaCase(TestRma):
|
||||
origin_moves = origin_delivery.move_ids
|
||||
self.assertTrue(origin_moves[0].rma_ids)
|
||||
self.assertTrue(origin_moves[1].rma_ids)
|
||||
rmas = origin_moves.mapped("rma_ids")
|
||||
rmas = origin_moves.rma_ids
|
||||
self.assertEqual(rmas.mapped("state"), ["confirmed"] * 2)
|
||||
# Each reception move is linked one of the generated RMAs
|
||||
reception = self.env["stock.picking"].browse(picking_action["res_id"])
|
||||
reception_moves = reception.move_ids
|
||||
self.assertTrue(reception_moves[0].rma_receiver_ids)
|
||||
self.assertTrue(reception_moves[1].rma_receiver_ids)
|
||||
self.assertEqual(reception_moves.mapped("rma_receiver_ids"), rmas)
|
||||
self.assertEqual(reception_moves.rma_receiver_ids, rmas)
|
||||
# Validate the reception picking to set rmas to 'received' state
|
||||
reception_moves[0].quantity = reception_moves[0].product_uom_qty
|
||||
reception_moves[1].quantity = reception_moves[1].product_uom_qty
|
||||
@@ -645,7 +701,7 @@ class TestRmaCase(TestRma):
|
||||
rma = rma_form.save()
|
||||
rma.action_confirm()
|
||||
rma.reception_move_id.quantity = 10
|
||||
rma.reception_move_id.picking_id._action_done()
|
||||
rma.reception_move_id.picking_id.button_validate()
|
||||
# Return quantity 4 of the same product to the customer
|
||||
delivery_form = Form(
|
||||
self.env["rma.delivery.wizard"].with_context(
|
||||
@@ -686,6 +742,7 @@ class TestRmaCase(TestRma):
|
||||
self.assertEqual(new_rma.move_id.quantity, 10)
|
||||
self.assertEqual(new_rma.reception_move_id.quantity, 10)
|
||||
|
||||
@mute_logger("odoo.models.unlink")
|
||||
def test_rma_to_receive_on_delete_invoice(self):
|
||||
rma = self._create_confirm_receive(self.partner, self.product, 10, self.rma_loc)
|
||||
rma.action_refund()
|
||||
|
||||
@@ -1,8 +1,25 @@
|
||||
# Copyright 2020 Tecnativa - Ernesto Tejeda
|
||||
# Copyright 2023 Michael Tietz (MT Software) <mtietz@mt-software.de>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
from copy import deepcopy
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tools import float_compare
|
||||
|
||||
|
||||
class ReturnPickingLine(models.TransientModel):
|
||||
_inherit = "stock.return.picking.line"
|
||||
|
||||
def _prepare_rma_vals(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
"move_id": self.move_id.id,
|
||||
"product_id": self.move_id.product_id.id,
|
||||
"product_uom_qty": self.quantity,
|
||||
"product_uom": self.product_id.uom_id.id,
|
||||
"location_id": self.wizard_id.location_id.id or self.move_id.location_id.id,
|
||||
}
|
||||
|
||||
|
||||
class ReturnPicking(models.TransientModel):
|
||||
@@ -48,6 +65,52 @@ class ReturnPicking(models.TransientModel):
|
||||
location_id = return_picking_type.default_location_dest_id.id
|
||||
self.location_id = location_id
|
||||
|
||||
def _prepare_rma_partner_values(self):
|
||||
self.ensure_one()
|
||||
partner = self.picking_id.partner_id
|
||||
partner_address = partner.address_get(["invoice", "delivery"])
|
||||
partner_invoice_id = partner_address.get("invoice", False)
|
||||
partner_shipping_id = partner_address.get("delivery", False)
|
||||
return (
|
||||
partner,
|
||||
partner_invoice_id and partner.browse(partner_invoice_id) or partner,
|
||||
partner_shipping_id and partner.browse(partner_shipping_id) or partner,
|
||||
)
|
||||
|
||||
def _prepare_rma_vals(self):
|
||||
partner, partner_invoice, partner_shipping = self._prepare_rma_partner_values()
|
||||
origin = self.picking_id.name
|
||||
vals = self.env["rma"]._prepare_procurement_group_vals()
|
||||
vals["partner_id"] = partner_shipping.id
|
||||
vals["name"] = origin
|
||||
group = self.env["procurement.group"].create(vals)
|
||||
return {
|
||||
"user_id": self.env.user.id,
|
||||
"partner_id": partner.id,
|
||||
"partner_shipping_id": partner_shipping.id,
|
||||
"partner_invoice_id": partner_invoice.id,
|
||||
"origin": origin,
|
||||
"picking_id": self.picking_id.id,
|
||||
"company_id": self.company_id.id,
|
||||
"procurement_group_id": group.id,
|
||||
}
|
||||
|
||||
def _prepare_rma_vals_list(self):
|
||||
vals_list = []
|
||||
for return_picking in self:
|
||||
global_vals = return_picking._prepare_rma_vals()
|
||||
for line in return_picking.product_return_moves:
|
||||
if (
|
||||
not line.move_id
|
||||
or float_compare(line.quantity, 0, line.product_id.uom_id.rounding)
|
||||
<= 0
|
||||
):
|
||||
continue
|
||||
vals = deepcopy(global_vals)
|
||||
vals.update(line._prepare_rma_vals())
|
||||
vals_list.append(vals)
|
||||
return vals_list
|
||||
|
||||
def create_returns(self):
|
||||
"""Override create_returns method for creating one or more
|
||||
'confirmed' RMAs after return a delivery picking in case
|
||||
@@ -57,10 +120,6 @@ class ReturnPicking(models.TransientModel):
|
||||
as the 'Receipt'.
|
||||
"""
|
||||
if self.create_rma:
|
||||
# set_rma_picking_type is to override the copy() method of stock
|
||||
# picking and change the default picking type to rma picking type
|
||||
self_with_context = self.with_context(set_rma_picking_type=True)
|
||||
res = super(ReturnPicking, self_with_context).create_returns()
|
||||
if not self.picking_id.partner_id:
|
||||
raise ValidationError(
|
||||
_(
|
||||
@@ -68,12 +127,30 @@ class ReturnPicking(models.TransientModel):
|
||||
"'Stock Picking' from which RMAs will be created"
|
||||
)
|
||||
)
|
||||
returned_picking = self.env["stock.picking"].browse(res["res_id"])
|
||||
vals_list = [
|
||||
move._prepare_return_rma_vals(self.picking_id)
|
||||
for move in returned_picking.move_ids
|
||||
]
|
||||
self.env["rma"].create(vals_list)
|
||||
return res
|
||||
else:
|
||||
return super().create_returns()
|
||||
vals_list = self._prepare_rma_vals_list()
|
||||
rmas = self.env["rma"].create(vals_list)
|
||||
rmas.action_confirm()
|
||||
picking = rmas.reception_move_id.picking_id
|
||||
picking = picking and picking[0] or picking
|
||||
ctx = dict(self.env.context)
|
||||
ctx.update(
|
||||
{
|
||||
"default_partner_id": picking.partner_id.id,
|
||||
"search_default_picking_type_id": picking.picking_type_id.id,
|
||||
"search_default_draft": False,
|
||||
"search_default_assigned": False,
|
||||
"search_default_confirmed": False,
|
||||
"search_default_ready": False,
|
||||
"search_default_planning_issues": False,
|
||||
"search_default_available": False,
|
||||
}
|
||||
)
|
||||
return {
|
||||
"name": _("Returned Picking"),
|
||||
"view_mode": "form,tree,calendar",
|
||||
"res_model": "stock.picking",
|
||||
"res_id": picking.id,
|
||||
"type": "ir.actions.act_window",
|
||||
"context": ctx,
|
||||
}
|
||||
return super().create_returns()
|
||||
|
||||
Reference in New Issue
Block a user