From 5c2927fdd63f2882aa4759f640455aa87029b76f Mon Sep 17 00:00:00 2001 From: Don Kendall Date: Tue, 6 Jan 2026 21:30:35 -0500 Subject: [PATCH 1/7] [16.0][MIG] purchase_container: backport from 18.0 Backport of purchase_container module from 18.0 to 16.0. Key backport changes: - Updated manifest version to 16.0.1.0.0 - Converted views to (16.0 syntax) - Converted to full chatter div structure - Converted Python expression attrs (invisible/readonly) to domain-based attrs syntax - Removed pyproject.toml (not used in 16.0) Features: - Add containers to purchase orders and stock pickings - Track container details (bill of lading, shipping agent, etc.) - Container state management (waiting, transit, arrived, locked) - Link containers to pickings and purchase orders - Incoterm tracking per container --- purchase_container/README.rst | 91 ++++ purchase_container/__init__.py | 1 + purchase_container/__manifest__.py | 21 + purchase_container/data/container.type.csv | 6 + purchase_container/data/cron_data.xml | 14 + purchase_container/i18n/it.po | 510 ++++++++++++++++++ purchase_container/i18n/pt_BR.po | 503 +++++++++++++++++ .../i18n/purchase_container.pot | 500 +++++++++++++++++ purchase_container/models/__init__.py | 6 + purchase_container/models/container_type.py | 9 + .../models/purchase_container.py | 265 +++++++++ purchase_container/models/purchase_order.py | 36 ++ purchase_container/models/stock_picking.py | 9 + purchase_container/readme/CONTRIBUTORS.md | 3 + purchase_container/readme/DESCRIPTION.md | 3 + .../security/ir.model.access.csv | 6 + .../static/description/icon.png | Bin 0 -> 10254 bytes purchase_container/static/description/img.png | Bin 0 -> 112949 bytes .../static/description/index.html | 430 +++++++++++++++ purchase_container/tests/__init__.py | 1 + purchase_container/tests/test_module.py | 78 +++ purchase_container/views/container_type.xml | 50 ++ purchase_container/views/purchase.xml | 44 ++ .../views/purchase_container.xml | 199 +++++++ purchase_container/views/stock_picking.xml | 22 + .../odoo/addons/purchase_container | 1 + setup/purchase_container/setup.py | 6 + 27 files changed, 2814 insertions(+) create mode 100644 purchase_container/README.rst create mode 100644 purchase_container/__init__.py create mode 100644 purchase_container/__manifest__.py create mode 100644 purchase_container/data/container.type.csv create mode 100644 purchase_container/data/cron_data.xml create mode 100644 purchase_container/i18n/it.po create mode 100644 purchase_container/i18n/pt_BR.po create mode 100644 purchase_container/i18n/purchase_container.pot create mode 100644 purchase_container/models/__init__.py create mode 100644 purchase_container/models/container_type.py create mode 100644 purchase_container/models/purchase_container.py create mode 100644 purchase_container/models/purchase_order.py create mode 100644 purchase_container/models/stock_picking.py create mode 100644 purchase_container/readme/CONTRIBUTORS.md create mode 100644 purchase_container/readme/DESCRIPTION.md create mode 100644 purchase_container/security/ir.model.access.csv create mode 100644 purchase_container/static/description/icon.png create mode 100644 purchase_container/static/description/img.png create mode 100644 purchase_container/static/description/index.html create mode 100644 purchase_container/tests/__init__.py create mode 100644 purchase_container/tests/test_module.py create mode 100644 purchase_container/views/container_type.xml create mode 100644 purchase_container/views/purchase.xml create mode 100644 purchase_container/views/purchase_container.xml create mode 100644 purchase_container/views/stock_picking.xml create mode 120000 setup/purchase_container/odoo/addons/purchase_container create mode 100644 setup/purchase_container/setup.py diff --git a/purchase_container/README.rst b/purchase_container/README.rst new file mode 100644 index 00000000000..687b93641ff --- /dev/null +++ b/purchase_container/README.rst @@ -0,0 +1,91 @@ +================== +Purchase Container +================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:baa8fdb1bf7c768b597127f43206886bc305180a2ea9536616b333d388fdd394 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpurchase--workflow-lightgray.png?logo=github + :target: https://github.com/OCA/purchase-workflow/tree/16.0/purchase_container + :alt: OCA/purchase-workflow +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/purchase-workflow-16-0/purchase-workflow-16-0-purchase_container + :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/purchase-workflow&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Add containers to purchase orders and stock pickings. + +|Purchase container image| + +.. |Purchase container image| image:: https://raw.githubusercontent.com/OCA/purchase-workflow/16.0/purchase_container/static/description/img.png + +**Table of contents** + +.. contents:: + :local: + +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 +------- + +* Akretion + +Contributors +------------ + +- Akretion + + - Olivier Nibart + - Mathieu Delva + +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. + +.. |maintainer-nayatec| image:: https://github.com/nayatec.png?size=40px + :target: https://github.com/nayatec + :alt: nayatec + +Current `maintainer `__: + +|maintainer-nayatec| + +This module is part of the `OCA/purchase-workflow `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/purchase_container/__init__.py b/purchase_container/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/purchase_container/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/purchase_container/__manifest__.py b/purchase_container/__manifest__.py new file mode 100644 index 00000000000..93acc574343 --- /dev/null +++ b/purchase_container/__manifest__.py @@ -0,0 +1,21 @@ +{ + "name": "Purchase Container", + "summary": """Add containers to purchase orders and stock pickings.""", + "version": "16.0.1.0.0", + "license": "AGPL-3", + "maintainers": ["nayatec"], + "author": "Akretion, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/purchase-workflow", + "depends": [ + "purchase_stock", + ], + "data": [ + "data/container.type.csv", + "data/cron_data.xml", + "views/container_type.xml", + "views/purchase.xml", + "views/purchase_container.xml", + "views/stock_picking.xml", + "security/ir.model.access.csv", + ], +} diff --git a/purchase_container/data/container.type.csv b/purchase_container/data/container.type.csv new file mode 100644 index 00000000000..1a166b474e3 --- /dev/null +++ b/purchase_container/data/container.type.csv @@ -0,0 +1,6 @@ +id,name +container_20,20' +container_40,40' +container_40HC,40' HC +container_lcl,LCL +container_lcl_air,LCL Air diff --git a/purchase_container/data/cron_data.xml b/purchase_container/data/cron_data.xml new file mode 100644 index 00000000000..048e8733fcd --- /dev/null +++ b/purchase_container/data/cron_data.xml @@ -0,0 +1,14 @@ + + + Recompute purchase container state + + + 1 + days + +records = model.search([("state", "in", ["waiting", "transit"])]) +if records: + records._compute_state() + + + diff --git a/purchase_container/i18n/it.po b/purchase_container/i18n/it.po new file mode 100644 index 00000000000..91554974299 --- /dev/null +++ b/purchase_container/i18n/it.po @@ -0,0 +1,510 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_container +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-11-10 10:44+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.10.4\n" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.container_type_view_form +msgid "40HC" +msgstr "40HC" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__date_ata +msgid "ATA Date" +msgstr "Data ATA" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__date_atd +msgid "ATD Date" +msgstr "Data ATD" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_needaction +msgid "Action Needed" +msgstr "Azione richiesta" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_ids +msgid "Activities" +msgstr "Attività" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_exception_decoration +msgid "Activity Exception Decoration" +msgstr "Decorazione eccezione attività" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_state +msgid "Activity State" +msgstr "Stato attività" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_type_icon +msgid "Activity Type Icon" +msgstr "Icona tipo attività" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__date_ata +msgid "Actual Time Of Arrival" +msgstr "Ora di arrivo attuale" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__date_atd +msgid "Actual Time Of Departure" +msgstr "Ora di partenza attuale" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Arrival" +msgstr "Arrivo" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__arrival_location_id +msgid "Arrival Location" +msgstr "Località di arrivo" + +#. module: purchase_container +#: model:ir.model.fields.selection,name:purchase_container.selection__purchase_container__state__arrived +msgid "Arrived" +msgstr "Arrivato" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_attachment_count +msgid "Attachment Count" +msgstr "Conteggio allegati" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__bill_of_lading_ref +msgid "Bill Of Lading No." +msgstr "N° della bolla di carico" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__weight +msgid "Bruto Weight" +msgstr "Peso lordo" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_stock_picking__container_id +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Container" +msgstr "Contenitore" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__code +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Container Reference" +msgstr "Riferimento contenitore" + +#. module: purchase_container +#: model:ir.actions.act_window,name:purchase_container.container_type_action +#: model:ir.ui.menu,name:purchase_container.menu_container_type +msgid "Container Types" +msgstr "Tipi contenitore" + +#. module: purchase_container +#: model:ir.actions.act_window,name:purchase_container.purchase_container_action +#: model:ir.model.fields,field_description:purchase_container.field_purchase_order__container_ids +#: model:ir.ui.menu,name:purchase_container.menu_procurement_management_container +msgid "Containers" +msgstr "Contenitori" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__cost +msgid "Cost" +msgstr "Costo" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__cost_currency_id +msgid "Cost Currency" +msgstr "Valuta costo" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__create_uid +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__create_date +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Departure" +msgstr "Partenza" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__departure_location_id +msgid "Departure Location" +msgstr "Località di partenza" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__description +msgid "Description" +msgstr "Descrizione" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__display_name +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__displayed_incoterm_id +msgid "Displayed Incoterm" +msgstr "Incoterm visualizzati" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__date_eta +msgid "ETA Date" +msgstr "Data ETA" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__date_etd +msgid "ETD Date" +msgstr "Data ETD" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__date_ett +msgid "ETT Date" +msgstr "Data ETT" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__date_eta +msgid "Estimated Time Of Arrival" +msgstr "Ora di arrivo stimata" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__date_etd +msgid "Estimated Time Of Departure" +msgstr "Ora di partenza stimata" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__date_ett +msgid "Estimated Time Of Travel" +msgstr "Tempo di viaggio stimato" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_follower_ids +msgid "Followers" +msgstr "Seguito da" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_partner_ids +msgid "Followers (Partners)" +msgstr "Seguito da (partner)" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__activity_type_icon +msgid "Font awesome icon e.g. fa-tasks" +msgstr "Icona Font Awesome es. fa-tasks" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_search +msgid "Group By" +msgstr "Raggruppa per" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__has_message +msgid "Has Message" +msgstr "Ha un messaggio" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__id +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__id +msgid "ID" +msgstr "ID" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_exception_icon +msgid "Icon" +msgstr "Icona" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__activity_exception_icon +msgid "Icon to indicate an exception activity." +msgstr "Icona per indicare un'attività eccezione." + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__message_needaction +msgid "If checked, new messages require your attention." +msgstr "Se selezionata, nuovi messaggi richiedono attenzione." + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "Se selezionata, alcuni messaggi hanno un errore di consegna." + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__incoterm_id +msgid "Incoterm" +msgstr "Incoterm" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_is_follower +msgid "Is Follower" +msgstr "Segue" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__is_locked +msgid "Is Locked" +msgstr "È bloccato" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__write_uid +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__write_date +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Lock" +msgstr "Blocco" + +#. module: purchase_container +#: model:ir.model.fields.selection,name:purchase_container.selection__purchase_container__state__locked +msgid "Locked" +msgstr "Bloccato" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__manual_incoterm_id +msgid "Manual Incoterm" +msgstr "Incoterm manuale" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_has_error +msgid "Message Delivery error" +msgstr "Errore di consegna messaggio" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_ids +msgid "Messages" +msgstr "Messaggi" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__my_activity_date_deadline +msgid "My Activity Deadline" +msgstr "Scadenza mia attività" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__name +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__name +msgid "Name" +msgstr "Nome" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_date_deadline +msgid "Next Activity Deadline" +msgstr "Scadenza prossima attività" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_summary +msgid "Next Activity Summary" +msgstr "Riepilogo prossima attività" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_type_id +msgid "Next Activity Type" +msgstr "Tipo prossima attività" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_needaction_counter +msgid "Number of Actions" +msgstr "Numero di azioni" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_has_error_counter +msgid "Number of errors" +msgstr "Numero di errori" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__message_needaction_counter +msgid "Number of messages requiring action" +msgstr "Numero di messaggi che richiedono un'azione" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "Numero di messaggi con errore di consegna" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_order_view_form_container +msgid "Open" +msgstr "Apri" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__package_qty +msgid "Package Qty" +msgstr "Q.tà collo" + +#. module: purchase_container +#: model:ir.model,name:purchase_container.model_purchase_order +msgid "Purchase Order" +msgstr "Ordine di acquisto" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Purchase Orders" +msgstr "Ordini di acquisto" + +#. module: purchase_container +#: model:ir.model,name:purchase_container.model_purchase_container +msgid "Purchase order related container" +msgstr "Contenitore relativo all'ordine di acquisto" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__purchase_order_count +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Purchases" +msgstr "Acquisti" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__purchase_order_rfq_count +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "RFQ" +msgstr "RdP" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__picking_count +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Receipts" +msgstr "Ricevute" + +#. module: purchase_container +#: model:ir.actions.server,name:purchase_container.ir_cron_recompute_purchase_container_state_ir_actions_server +msgid "Recompute purchase container state" +msgstr "Ricalcola stato container acquisto" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__picking_ids +msgid "Related Pickings" +msgstr "Prelievi correlati" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__purchase_order_ids +msgid "Related Purchases" +msgstr "Acquisti correlati" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_user_id +msgid "Responsible User" +msgstr "Utente responsabile" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__shipping_agent_id +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_search +msgid "Shipping Agent" +msgstr "Agente spedizione" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__state +msgid "State" +msgstr "Stato" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__activity_state +msgid "" +"Status based on activities\n" +"Overdue: Due date is already passed\n" +"Today: Activity date is today\n" +"Planned: Future activities." +msgstr "" +"Stato in base alle attività\n" +"Scaduto: la data richiesta è trascorsa\n" +"Oggi: la data attività è oggi\n" +"Pianificato: attività future." + +#. module: purchase_container +#: model:ir.model,name:purchase_container.model_stock_picking +msgid "Transfer" +msgstr "Trasferimento" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Transfers" +msgstr "Trasferimenti" + +#. module: purchase_container +#: model:ir.model.fields.selection,name:purchase_container.selection__purchase_container__state__transit +msgid "Transit" +msgstr "Transito" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__type_id +msgid "Type" +msgstr "Tipo" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__activity_exception_decoration +msgid "Type of the exception activity on record." +msgstr "Tipo di attività eccezione sul record." + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Unlock" +msgstr "Sblocca" + +#. module: purchase_container +#: model:ir.model,name:purchase_container.model_container_type +msgid "Usual containers" +msgstr "Contenitori consueto" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__volume +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Volume" +msgstr "Volume" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__volume_uom_id +msgid "Volume Units of Measure" +msgstr "Unità di misura del volume" + +#. module: purchase_container +#: model:ir.model.fields.selection,name:purchase_container.selection__purchase_container__state__waiting +msgid "Waiting" +msgstr "Attesa" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__website_message_ids +msgid "Website Messages" +msgstr "Messaggi sito web" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__website_message_ids +msgid "Website communication history" +msgstr "Cronologia comunicazioni sito web" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__weight_uom_id +msgid "Weight Unit of Measure" +msgstr "Unità di misura del peso" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__weight_uom_id +msgid "Weight Units of Measure" +msgstr "Unità di misura del peso" + +#~ msgid "SMS Delivery error" +#~ msgstr "Errore consegna SMS" diff --git a/purchase_container/i18n/pt_BR.po b/purchase_container/i18n/pt_BR.po new file mode 100644 index 00000000000..506b6c99030 --- /dev/null +++ b/purchase_container/i18n/pt_BR.po @@ -0,0 +1,503 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_container +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-09-03 19:43+0000\n" +"Last-Translator: Douglas Custódio \n" +"Language-Team: none\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 5.10.4\n" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.container_type_view_form +msgid "40HC" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__date_ata +msgid "ATA Date" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__date_atd +msgid "ATD Date" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_ids +msgid "Activities" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_exception_decoration +msgid "Activity Exception Decoration" +msgstr "Decoração de Exceção de Atividade" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_state +msgid "Activity State" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_type_icon +msgid "Activity Type Icon" +msgstr "Ícone do Tipo de Atividade" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__date_ata +msgid "Actual Time Of Arrival" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__date_atd +msgid "Actual Time Of Departure" +msgstr "" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Arrival" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__arrival_location_id +msgid "Arrival Location" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields.selection,name:purchase_container.selection__purchase_container__state__arrived +msgid "Arrived" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__bill_of_lading_ref +msgid "Bill Of Lading No." +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__weight +msgid "Bruto Weight" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_stock_picking__container_id +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Container" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__code +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Container Reference" +msgstr "" + +#. module: purchase_container +#: model:ir.actions.act_window,name:purchase_container.container_type_action +#: model:ir.ui.menu,name:purchase_container.menu_container_type +msgid "Container Types" +msgstr "" + +#. module: purchase_container +#: model:ir.actions.act_window,name:purchase_container.purchase_container_action +#: model:ir.model.fields,field_description:purchase_container.field_purchase_order__container_ids +#: model:ir.ui.menu,name:purchase_container.menu_procurement_management_container +msgid "Containers" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__cost +msgid "Cost" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__cost_currency_id +msgid "Cost Currency" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__create_uid +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__create_uid +msgid "Created by" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__create_date +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__create_date +msgid "Created on" +msgstr "" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Departure" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__departure_location_id +msgid "Departure Location" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__description +msgid "Description" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__display_name +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__display_name +msgid "Display Name" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__displayed_incoterm_id +msgid "Displayed Incoterm" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__date_eta +msgid "ETA Date" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__date_etd +msgid "ETD Date" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__date_ett +msgid "ETT Date" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__date_eta +msgid "Estimated Time Of Arrival" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__date_etd +msgid "Estimated Time Of Departure" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__date_ett +msgid "Estimated Time Of Travel" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__activity_type_icon +msgid "Font awesome icon e.g. fa-tasks" +msgstr "" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_search +msgid "Group By" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__has_message +msgid "Has Message" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__id +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__id +msgid "ID" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_exception_icon +msgid "Icon" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__activity_exception_icon +msgid "Icon to indicate an exception activity." +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__message_needaction +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__incoterm_id +msgid "Incoterm" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__is_locked +msgid "Is Locked" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__write_uid +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__write_date +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__write_date +msgid "Last Updated on" +msgstr "" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Lock" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields.selection,name:purchase_container.selection__purchase_container__state__locked +msgid "Locked" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__manual_incoterm_id +msgid "Manual Incoterm" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_ids +msgid "Messages" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__my_activity_date_deadline +msgid "My Activity Deadline" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__name +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__name +msgid "Name" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_date_deadline +msgid "Next Activity Deadline" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_summary +msgid "Next Activity Summary" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_type_id +msgid "Next Activity Type" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_has_error_counter +msgid "Number of errors" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__message_needaction_counter +msgid "Number of messages requiring action" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_order_view_form_container +msgid "Open" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__package_qty +msgid "Package Qty" +msgstr "" + +#. module: purchase_container +#: model:ir.model,name:purchase_container.model_purchase_order +msgid "Purchase Order" +msgstr "" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Purchase Orders" +msgstr "" + +#. module: purchase_container +#: model:ir.model,name:purchase_container.model_purchase_container +msgid "Purchase order related container" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__purchase_order_count +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Purchases" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__purchase_order_rfq_count +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "RFQ" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__picking_count +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Receipts" +msgstr "" + +#. module: purchase_container +#: model:ir.actions.server,name:purchase_container.ir_cron_recompute_purchase_container_state_ir_actions_server +msgid "Recompute purchase container state" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__picking_ids +msgid "Related Pickings" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__purchase_order_ids +msgid "Related Purchases" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_user_id +msgid "Responsible User" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__shipping_agent_id +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_search +msgid "Shipping Agent" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__state +msgid "State" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__activity_state +msgid "" +"Status based on activities\n" +"Overdue: Due date is already passed\n" +"Today: Activity date is today\n" +"Planned: Future activities." +msgstr "" + +#. module: purchase_container +#: model:ir.model,name:purchase_container.model_stock_picking +msgid "Transfer" +msgstr "" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Transfers" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields.selection,name:purchase_container.selection__purchase_container__state__transit +msgid "Transit" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__type_id +msgid "Type" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__activity_exception_decoration +msgid "Type of the exception activity on record." +msgstr "Tipo da atividade de exceção no registro." + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Unlock" +msgstr "" + +#. module: purchase_container +#: model:ir.model,name:purchase_container.model_container_type +msgid "Usual containers" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__volume +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Volume" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__volume_uom_id +msgid "Volume Units of Measure" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields.selection,name:purchase_container.selection__purchase_container__state__waiting +msgid "Waiting" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__website_message_ids +msgid "Website Messages" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__website_message_ids +msgid "Website communication history" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__weight_uom_id +msgid "Weight Unit of Measure" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__weight_uom_id +msgid "Weight Units of Measure" +msgstr "" diff --git a/purchase_container/i18n/purchase_container.pot b/purchase_container/i18n/purchase_container.pot new file mode 100644 index 00000000000..c2768cf114a --- /dev/null +++ b/purchase_container/i18n/purchase_container.pot @@ -0,0 +1,500 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_container +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \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: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.container_type_view_form +msgid "40HC" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__date_ata +msgid "ATA Date" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__date_atd +msgid "ATD Date" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_ids +msgid "Activities" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_exception_decoration +msgid "Activity Exception Decoration" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_state +msgid "Activity State" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_type_icon +msgid "Activity Type Icon" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__date_ata +msgid "Actual Time Of Arrival" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__date_atd +msgid "Actual Time Of Departure" +msgstr "" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Arrival" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__arrival_location_id +msgid "Arrival Location" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields.selection,name:purchase_container.selection__purchase_container__state__arrived +msgid "Arrived" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__bill_of_lading_ref +msgid "Bill Of Lading No." +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__weight +msgid "Bruto Weight" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_stock_picking__container_id +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Container" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__code +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Container Reference" +msgstr "" + +#. module: purchase_container +#: model:ir.actions.act_window,name:purchase_container.container_type_action +#: model:ir.ui.menu,name:purchase_container.menu_container_type +msgid "Container Types" +msgstr "" + +#. module: purchase_container +#: model:ir.actions.act_window,name:purchase_container.purchase_container_action +#: model:ir.model.fields,field_description:purchase_container.field_purchase_order__container_ids +#: model:ir.ui.menu,name:purchase_container.menu_procurement_management_container +msgid "Containers" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__cost +msgid "Cost" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__cost_currency_id +msgid "Cost Currency" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__create_uid +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__create_uid +msgid "Created by" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__create_date +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__create_date +msgid "Created on" +msgstr "" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Departure" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__departure_location_id +msgid "Departure Location" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__description +msgid "Description" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__display_name +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__display_name +msgid "Display Name" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__displayed_incoterm_id +msgid "Displayed Incoterm" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__date_eta +msgid "ETA Date" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__date_etd +msgid "ETD Date" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__date_ett +msgid "ETT Date" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__date_eta +msgid "Estimated Time Of Arrival" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__date_etd +msgid "Estimated Time Of Departure" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__date_ett +msgid "Estimated Time Of Travel" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__activity_type_icon +msgid "Font awesome icon e.g. fa-tasks" +msgstr "" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_search +msgid "Group By" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__has_message +msgid "Has Message" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__id +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__id +msgid "ID" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_exception_icon +msgid "Icon" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__activity_exception_icon +msgid "Icon to indicate an exception activity." +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__message_needaction +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__incoterm_id +msgid "Incoterm" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__is_locked +msgid "Is Locked" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__write_uid +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__write_date +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__write_date +msgid "Last Updated on" +msgstr "" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Lock" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields.selection,name:purchase_container.selection__purchase_container__state__locked +msgid "Locked" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__manual_incoterm_id +msgid "Manual Incoterm" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_ids +msgid "Messages" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__my_activity_date_deadline +msgid "My Activity Deadline" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_container_type__name +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__name +msgid "Name" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_date_deadline +msgid "Next Activity Deadline" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_summary +msgid "Next Activity Summary" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_type_id +msgid "Next Activity Type" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__message_has_error_counter +msgid "Number of errors" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__message_needaction_counter +msgid "Number of messages requiring action" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_order_view_form_container +msgid "Open" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__package_qty +msgid "Package Qty" +msgstr "" + +#. module: purchase_container +#: model:ir.model,name:purchase_container.model_purchase_order +msgid "Purchase Order" +msgstr "" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Purchase Orders" +msgstr "" + +#. module: purchase_container +#: model:ir.model,name:purchase_container.model_purchase_container +msgid "Purchase order related container" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__purchase_order_count +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Purchases" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__purchase_order_rfq_count +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "RFQ" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__picking_count +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Receipts" +msgstr "" + +#. module: purchase_container +#: model:ir.actions.server,name:purchase_container.ir_cron_recompute_purchase_container_state_ir_actions_server +msgid "Recompute purchase container state" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__picking_ids +msgid "Related Pickings" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__purchase_order_ids +msgid "Related Purchases" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__activity_user_id +msgid "Responsible User" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__shipping_agent_id +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_search +msgid "Shipping Agent" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__state +msgid "State" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__activity_state +msgid "" +"Status based on activities\n" +"Overdue: Due date is already passed\n" +"Today: Activity date is today\n" +"Planned: Future activities." +msgstr "" + +#. module: purchase_container +#: model:ir.model,name:purchase_container.model_stock_picking +msgid "Transfer" +msgstr "" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Transfers" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields.selection,name:purchase_container.selection__purchase_container__state__transit +msgid "Transit" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__type_id +msgid "Type" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__activity_exception_decoration +msgid "Type of the exception activity on record." +msgstr "" + +#. module: purchase_container +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Unlock" +msgstr "" + +#. module: purchase_container +#: model:ir.model,name:purchase_container.model_container_type +msgid "Usual containers" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__volume +#: model_terms:ir.ui.view,arch_db:purchase_container.purchase_container_view_form +msgid "Volume" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__volume_uom_id +msgid "Volume Units of Measure" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields.selection,name:purchase_container.selection__purchase_container__state__waiting +msgid "Waiting" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__website_message_ids +msgid "Website Messages" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__website_message_ids +msgid "Website communication history" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,help:purchase_container.field_purchase_container__weight_uom_id +msgid "Weight Unit of Measure" +msgstr "" + +#. module: purchase_container +#: model:ir.model.fields,field_description:purchase_container.field_purchase_container__weight_uom_id +msgid "Weight Units of Measure" +msgstr "" diff --git a/purchase_container/models/__init__.py b/purchase_container/models/__init__.py new file mode 100644 index 00000000000..63183983787 --- /dev/null +++ b/purchase_container/models/__init__.py @@ -0,0 +1,6 @@ +from . import ( + container_type, + purchase_container, + purchase_order, + stock_picking, +) diff --git a/purchase_container/models/container_type.py b/purchase_container/models/container_type.py new file mode 100644 index 00000000000..a366b72a2cb --- /dev/null +++ b/purchase_container/models/container_type.py @@ -0,0 +1,9 @@ +from odoo import fields, models + + +class ContainerType(models.Model): + _name = "container.type" + _description = "Usual containers" + + name = fields.Char() + description = fields.Char() diff --git a/purchase_container/models/purchase_container.py b/purchase_container/models/purchase_container.py new file mode 100644 index 00000000000..a3f48a64060 --- /dev/null +++ b/purchase_container/models/purchase_container.py @@ -0,0 +1,265 @@ +from datetime import date + +from odoo import api, fields, models + + +class PurchaseContainer(models.Model): + _name = "purchase.container" + _description = "Purchase order related container" + _inherit = ["mail.thread", "mail.activity.mixin"] + _order = "id desc" + + name = fields.Char(compute="_compute_name", store=True, readonly=True, index=True) + code = fields.Char( + string="Container Reference", + compute="_compute_code", + inverse="_inverse_code", + store=True, + required=True, + copy=False, + ) + bill_of_lading_ref = fields.Char("Bill Of Lading No.", copy=False) + shipping_agent_id = fields.Many2one( + comodel_name="res.partner", string="Shipping Agent" + ) + type_id = fields.Many2one(comodel_name="container.type") + package_qty = fields.Integer(copy=False) + cost = fields.Float(digits="Product Price", copy=False) + cost_currency_id = fields.Many2one("res.currency", "Cost Currency", copy=False) + volume = fields.Float(digits="Volume", copy=False) + volume_uom_id = fields.Many2one( + "uom.uom", + string="Volume Units of Measure", + domain=lambda self: [ + ("category_id", "=", self.env.ref("uom.product_uom_categ_vol").id) + ], + default=lambda self: self.env[ + "product.template" + ]._get_volume_uom_id_from_ir_config_parameter(), + ) + weight = fields.Float(string="Bruto Weight", digits="Stock Weight", copy=False) + weight_uom_id = fields.Many2one( + "uom.uom", + string="Weight Units of Measure", + domain=lambda self: [ + ("category_id", "=", self.env.ref("uom.product_uom_categ_kgm").id) + ], + help="Weight Unit of Measure", + default=lambda self: self.env[ + "product.template" + ]._get_weight_uom_id_from_ir_config_parameter(), + ) + purchase_order_ids = fields.Many2many( + "purchase.order", string="Related Purchases", copy=False + ) + purchase_order_count = fields.Integer( + string="Purchases", compute="_compute_purchase_order_count" + ) + purchase_order_rfq_count = fields.Integer( + string="RFQ", compute="_compute_purchase_order_rfq_count" + ) + picking_ids = fields.One2many( + comodel_name="stock.picking", + inverse_name="container_id", + string="Related Pickings", + ) + picking_count = fields.Integer(string="Receipts", compute="_compute_picking_count") + + incoterm_id = fields.Many2one( + "account.incoterms", compute="_compute_incoterm_id", store=False, readonly=True + ) + manual_incoterm_id = fields.Many2one("account.incoterms") + displayed_incoterm_id = fields.Many2one( + "account.incoterms", + compute="_compute_displayed_incoterm_id", + inverse="_inverse_displayed_incoterm_id", + store=True, + tracking=True, + ) + + departure_location_id = fields.Many2one("res.partner") + arrival_location_id = fields.Many2one("res.partner") + date_eta = fields.Date( + string="ETA Date", help="Estimated Time Of Arrival", tracking=True + ) + date_etd = fields.Date( + string="ETD Date", help="Estimated Time Of Departure", tracking=True + ) + date_ata = fields.Date( + string="ATA Date", help="Actual Time Of Arrival", tracking=True + ) + date_atd = fields.Date( + string="ATD Date", help="Actual Time Of Departure", tracking=True + ) + date_ett = fields.Char( + string="ETT Date", + help="Estimated Time Of Travel", + compute="_compute_date_ett", + store=False, + tracking=True, + ) + + state = fields.Selection( + [ + ("waiting", "Waiting"), + ("transit", "Transit"), + ("arrived", "Arrived"), + ("locked", "Locked"), + ], + compute="_compute_state", + store=True, + tracking=True, + ) + is_locked = fields.Boolean() + + def _compute_incoterm_id(self): + for record in self: + record.incoterm_id = record.purchase_order_ids.filtered( + lambda po: po.incoterm_id + )[:1].incoterm_id + + @api.depends( + "manual_incoterm_id", "purchase_order_ids", "purchase_order_ids.incoterm_id" + ) + def _compute_displayed_incoterm_id(self): + for record in self: + record.displayed_incoterm_id = ( + record.manual_incoterm_id + if record.manual_incoterm_id + else record.incoterm_id + ) + + def _inverse_displayed_incoterm_id(self): + for record in self: + record.manual_incoterm_id = record.displayed_incoterm_id + + @api.depends("date_eta", "date_etd") + def _compute_date_ett(self): + for record in self: + record.date_ett = 0 + if record.date_eta and record.date_etd: + record.date_ett = record.date_eta - record.date_etd + + @api.depends("is_locked", "date_etd", "date_atd", "picking_ids.state") + def _compute_state(self): + for record in self: + departure_date = record.date_atd if record.date_atd else record.date_etd + + picking_states = set(record.picking_ids.mapped("state")) + if record.is_locked: + record.state = "locked" + elif picking_states and picking_states.issubset({"done", "cancel"}): + record.state = "arrived" + elif departure_date and departure_date <= date.today(): + record.state = "transit" + else: + record.state = "waiting" + + def button_lock(self): + self.is_locked = True + + def button_unlock(self): + self.is_locked = False + + @api.depends("code", "purchase_order_ids") + def _compute_name(self): + for record in self: + record.name = record.code + po = record.purchase_order_ids + if po: + record.name += " ({})".format(",".join(po.mapped("name"))) + + @api.model + def _code_transform(self, code): + return code.upper() if code else code + + @api.model + def _code_from_name(self, name): + words = name.split() if name else None + code = words[0] if words else False + return self._code_transform(code) + + @api.depends("name") + def _compute_code(self): + for record in self: + if not record.code: + record.code = record._code_from_name(record.name) + + def _inverse_code(self): + for record in self: + code = self._code_transform(record.code) + if record.code != code: + record.code = code + + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + vals.setdefault("code", self._code_from_name(vals.get("name"))) + return super().create(vals_list=vals_list) + + def _compute_purchase_order_count(self): + for record in self: + record.purchase_order_count = self.env["purchase.order"].search_count( + [ + ("state", "in", ("purchase", "done")), + ("container_ids", "=", self.id), + ], + ) + + def _compute_purchase_order_rfq_count(self): + for record in self: + record.purchase_order_rfq_count = self.env["purchase.order"].search_count( + [ + ("state", "in", ("draft", "sent", "to approve")), + ("container_ids", "=", self.id), + ], + ) + + def _compute_picking_count(self): + for record in self: + record.picking_count = len(record.picking_ids) + + def action_view_rfq(self): + self.ensure_one() + action = self.env["ir.actions.actions"]._for_xml_id("purchase.purchase_rfq") + action["domain"] = [ + ( + "id", + "in", + [ + po.id + for po in self.purchase_order_ids + if po.state in ("draft", "sent", "to approve") + ], + ) + ] + action["context"] = {"create": False} + return action + + def action_view_order(self): + self.ensure_one() + action = self.env["ir.actions.actions"]._for_xml_id( + "purchase.purchase_form_action" + ) + action["domain"] = [ + ( + "id", + "in", + [ + po.id + for po in self.purchase_order_ids + if po.state in ("purchase", "done") + ], + ) + ] + action["context"] = {"create": False} + return action + + def action_view_picking(self): + self.ensure_one() + action = self.env["ir.actions.actions"]._for_xml_id( + "stock.action_picking_tree_all" + ) + action["domain"] = [("id", "in", self.picking_ids.ids)] + action["context"] = {"create": False} + return action diff --git a/purchase_container/models/purchase_order.py b/purchase_container/models/purchase_order.py new file mode 100644 index 00000000000..15324f844c3 --- /dev/null +++ b/purchase_container/models/purchase_order.py @@ -0,0 +1,36 @@ +from odoo import Command, api, fields, models + + +class PurchaseOrder(models.Model): + _inherit = "purchase.order" + + container_ids = fields.Many2many( + "purchase.container", + string="Containers", + compute="_compute_container_ids", + inverse="_inverse_container_ids", + copy=False, + store=True, + index=True, + ) + + @api.depends("picking_ids.container_id") + def _compute_container_ids(self): + for purchase in self: + if purchase.picking_ids: + purchase.container_ids = [ + Command.set(purchase.picking_ids.container_id.ids) + ] + + def _inverse_container_ids(self): + pass + + def _prepare_picking(self): + # This function initialize the picking vals from the current order + vals = super()._prepare_picking() + # So if we have at least a container set on the order, we should + # initialize the picking container with one. + if self.container_ids: + # Arbitrarily, we take the first one by default + vals["container_id"] = self.container_ids[0].id + return vals diff --git a/purchase_container/models/stock_picking.py b/purchase_container/models/stock_picking.py new file mode 100644 index 00000000000..77b2cf41c52 --- /dev/null +++ b/purchase_container/models/stock_picking.py @@ -0,0 +1,9 @@ +from odoo import fields, models + + +class StockPicking(models.Model): + _inherit = "stock.picking" + + container_id = fields.Many2one( + "purchase.container", string="Container", copy=False, index=True + ) diff --git a/purchase_container/readme/CONTRIBUTORS.md b/purchase_container/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..629a218f062 --- /dev/null +++ b/purchase_container/readme/CONTRIBUTORS.md @@ -0,0 +1,3 @@ +* Akretion + * Olivier Nibart + * Mathieu Delva diff --git a/purchase_container/readme/DESCRIPTION.md b/purchase_container/readme/DESCRIPTION.md new file mode 100644 index 00000000000..e82102c0ed5 --- /dev/null +++ b/purchase_container/readme/DESCRIPTION.md @@ -0,0 +1,3 @@ +Add containers to purchase orders and stock pickings. + +![Purchase container image](../static/description/img.png) diff --git a/purchase_container/security/ir.model.access.csv b/purchase_container/security/ir.model.access.csv new file mode 100644 index 00000000000..b090883f165 --- /dev/null +++ b/purchase_container/security/ir.model.access.csv @@ -0,0 +1,6 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_purchase_container,purchase.container,model_purchase_container,purchase.group_purchase_user,1,1,1,1 +access_container_type,container.type,model_container_type,purchase.group_purchase_user,1,1,1,1 +access_purchase_container_manager,purchase.container,model_purchase_container,purchase.group_purchase_manager,1,1,1,1 +access_purchase_container_readonly,purchase.container,model_purchase_container,account.group_account_readonly,1,0,0,0 +access_purchase_container_invoice,purchase.container,model_purchase_container,account.group_account_invoice,1,1,0,0 diff --git a/purchase_container/static/description/icon.png b/purchase_container/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1dcc49c24f364e9adf0afbc6fc0bac6dbecdeb11 GIT binary patch literal 10254 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

hJ( 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 literal 0 HcmV?d00001 diff --git a/purchase_container/static/description/index.html b/purchase_container/static/description/index.html new file mode 100644 index 00000000000..3ae1eb6dd06 --- /dev/null +++ b/purchase_container/static/description/index.html @@ -0,0 +1,430 @@ + + + + + +Purchase Container + + + +

+ + diff --git a/purchase_container/tests/__init__.py b/purchase_container/tests/__init__.py new file mode 100644 index 00000000000..d9b96c4fa5a --- /dev/null +++ b/purchase_container/tests/__init__.py @@ -0,0 +1 @@ +from . import test_module diff --git a/purchase_container/tests/test_module.py b/purchase_container/tests/test_module.py new file mode 100644 index 00000000000..e2eb37d7dab --- /dev/null +++ b/purchase_container/tests/test_module.py @@ -0,0 +1,78 @@ +from odoo import Command, fields + +from odoo.addons.base.tests.common import BaseCommon + + +class Test(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.partner = cls.env["res.partner"].create({"name": "Test Supplier"}) + cls.product = cls.env["product.product"].create({"name": "Test Product"}) + cls.cont_a = cls.env["purchase.container"].create({"code": "AA"}) + cls.cont_b = cls.env["purchase.container"].create({"code": "BB"}) + cls.incoterm_id = cls.env.ref("account.incoterm_FCA") + + def test_container_by_purchase(self): + # first PO + po = self.get_po() + po.button_confirm() + pick01 = po.picking_ids[0] + pick01.container_id = self.cont_a.id + self.assertIn(self.cont_a, po.container_ids) + self.assertEqual(self.cont_a.purchase_order_count, 1) + pick01.button_validate() + # this update triggers a new picking + po.order_line[0].product_qty = 7 + pick02 = po.picking_ids.filtered(lambda x: x.state != "done") + pick02.container_id = self.cont_b.id + pick02.button_validate() + self.assertEqual(pick02.state, "done") + self.assertIn(self.cont_b, po.container_ids) + self.assertEqual(self.cont_b.purchase_order_count, 1) + # second PO + po2 = po.copy() + po2.button_confirm() + pick11 = po2.picking_ids + pick11.container_id = self.cont_b.id + pick11.button_validate() + self.assertIn(self.cont_b, po2.container_ids) + self.assertEqual(pick11.state, "done") + self.assertEqual(len(self.cont_b.purchase_order_ids), 2) + self.assertEqual(self.cont_b.purchase_order_count, 1) + # this method is not computed because not a stored field + self.cont_b._compute_purchase_order_count() + self.assertEqual(self.cont_b.purchase_order_count, 2) + + self.cont_b._compute_incoterm_id() + self.assertEqual(self.cont_b.displayed_incoterm_id, self.incoterm_id) + + def test_action_views(self): + po = self.get_po() + po.button_confirm() + pick01 = po.picking_ids[0] + pick01.container_id = self.cont_a.id + self.cont_a.action_view_rfq() + self.cont_a.action_view_order() + self.cont_a.action_view_picking() + + def get_po(self): + return self.env["purchase.order"].create( + { + "partner_id": self.partner.id, + "date_planned": fields.Datetime.now(), + "incoterm_id": self.incoterm_id.id, + "order_line": [ + Command.create( + { + "name": "Test Line", + "product_id": self.product.id, + "product_qty": 4.0, + "product_uom": self.product.uom_po_id.id, + "price_unit": 1, + "date_planned": fields.Datetime.now(), + }, + ) + ], + } + ) diff --git a/purchase_container/views/container_type.xml b/purchase_container/views/container_type.xml new file mode 100644 index 00000000000..2c9fe41f734 --- /dev/null +++ b/purchase_container/views/container_type.xml @@ -0,0 +1,50 @@ + + + container.type + +
+ + + + + + + + + + +
+
+
+ + + container.type + + + + + + + + + + container.type + + + + + + + + + Container Types + container.type + list,form + + + +
diff --git a/purchase_container/views/purchase.xml b/purchase_container/views/purchase.xml new file mode 100644 index 00000000000..a4af217b79a --- /dev/null +++ b/purchase_container/views/purchase.xml @@ -0,0 +1,44 @@ + + + + purchase.order + + + + + + + + + + + + + + +
+ Container +

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+
+ + + purchase.container + + + + + + + + + + + + + + + + purchase.container + + + + + + + + + + + + + + + Containers + purchase.container + list,form + + + +
diff --git a/purchase_container/views/stock_picking.xml b/purchase_container/views/stock_picking.xml new file mode 100644 index 00000000000..1b5de599556 --- /dev/null +++ b/purchase_container/views/stock_picking.xml @@ -0,0 +1,22 @@ + + + + stock.picking + + + + + + + + + + stock.picking + + + + + + + + diff --git a/setup/purchase_container/odoo/addons/purchase_container b/setup/purchase_container/odoo/addons/purchase_container new file mode 120000 index 00000000000..9889edbf017 --- /dev/null +++ b/setup/purchase_container/odoo/addons/purchase_container @@ -0,0 +1 @@ +../../../../purchase_container \ No newline at end of file diff --git a/setup/purchase_container/setup.py b/setup/purchase_container/setup.py new file mode 100644 index 00000000000..28c57bb6403 --- /dev/null +++ b/setup/purchase_container/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) From cef755c4547946fd09d3d492e2474b923673f7a0 Mon Sep 17 00:00:00 2001 From: Don Kendall Date: Tue, 6 Jan 2026 21:51:00 -0500 Subject: [PATCH 2/7] fix(test): purchase_container In Odoo 16.0, you need to set quantity_done on moves before calling button_validate(). --- purchase_container/tests/test_module.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/purchase_container/tests/test_module.py b/purchase_container/tests/test_module.py index e2eb37d7dab..ac077327b81 100644 --- a/purchase_container/tests/test_module.py +++ b/purchase_container/tests/test_module.py @@ -13,6 +13,12 @@ def setUpClass(cls): cls.cont_b = cls.env["purchase.container"].create({"code": "BB"}) cls.incoterm_id = cls.env.ref("account.incoterm_FCA") + def _validate_picking(self, picking): + """Helper to validate picking by setting quantities and validating.""" + for move in picking.move_ids: + move.quantity_done = move.product_uom_qty + picking.button_validate() + def test_container_by_purchase(self): # first PO po = self.get_po() @@ -21,12 +27,12 @@ def test_container_by_purchase(self): pick01.container_id = self.cont_a.id self.assertIn(self.cont_a, po.container_ids) self.assertEqual(self.cont_a.purchase_order_count, 1) - pick01.button_validate() + self._validate_picking(pick01) # this update triggers a new picking po.order_line[0].product_qty = 7 pick02 = po.picking_ids.filtered(lambda x: x.state != "done") pick02.container_id = self.cont_b.id - pick02.button_validate() + self._validate_picking(pick02) self.assertEqual(pick02.state, "done") self.assertIn(self.cont_b, po.container_ids) self.assertEqual(self.cont_b.purchase_order_count, 1) @@ -35,7 +41,7 @@ def test_container_by_purchase(self): po2.button_confirm() pick11 = po2.picking_ids pick11.container_id = self.cont_b.id - pick11.button_validate() + self._validate_picking(pick11) self.assertIn(self.cont_b, po2.container_ids) self.assertEqual(pick11.state, "done") self.assertEqual(len(self.cont_b.purchase_order_ids), 2) From 4550d8404fb12ea041b6e4d1fd0821d95ac3d31e Mon Sep 17 00:00:00 2001 From: Don Kendall Date: Tue, 13 Jan 2026 16:45:49 -0500 Subject: [PATCH 3/7] [16.0][IMP] purchase_container: Add Kencove-specific fields and workflow Added fields from Kencove container tracking spreadsheet: - seal_number: Container seal number - warehouse_id: Destination warehouse (PA, ID, GA) - date_warehouse_eta: Warehouse ETA (separate from port ETA) - date_delivered: Delivery date to warehouse - date_received: Date inventory received into system - drayage_company_id: Local drayage/trucking company - per_diem_fees: Per diem and additional fees - per_diem_reason: Reason for additional fees - notes: Internal notes field Extended workflow states to match spreadsheet process: - in_progress, pos_confirmed, freight_notified, on_water - arrival_notice, drayage_confirmed, awaiting_gate_out - customs_hold, released, delivered, received - on_hold, ready_to_process, processed Updated views: - Reorganized form into notebook tabs - Added search filters by state - Added group by options for warehouse, state, etc. - Badge decorations for state display in list view Co-Authored-By: Claude Opus 4.5 --- purchase_container/README.rst | 1 + purchase_container/__manifest__.py | 5 +- .../models/purchase_container.py | 109 +++++-- .../static/description/index.html | 1 + .../views/purchase_container.xml | 286 +++++++++++++----- 5 files changed, 289 insertions(+), 113 deletions(-) diff --git a/purchase_container/README.rst b/purchase_container/README.rst index 687b93641ff..5ae4e5e5cac 100644 --- a/purchase_container/README.rst +++ b/purchase_container/README.rst @@ -56,6 +56,7 @@ Authors ------- * Akretion +* Kencove Contributors ------------ diff --git a/purchase_container/__manifest__.py b/purchase_container/__manifest__.py index 93acc574343..68dc6b884c8 100644 --- a/purchase_container/__manifest__.py +++ b/purchase_container/__manifest__.py @@ -1,13 +1,14 @@ { "name": "Purchase Container", "summary": """Add containers to purchase orders and stock pickings.""", - "version": "16.0.1.0.0", + "version": "16.0.1.1.0", "license": "AGPL-3", "maintainers": ["nayatec"], - "author": "Akretion, Odoo Community Association (OCA)", + "author": "Akretion, Kencove, Odoo Community Association (OCA)", "website": "https://github.com/OCA/purchase-workflow", "depends": [ "purchase_stock", + "stock", ], "data": [ "data/container.type.csv", diff --git a/purchase_container/models/purchase_container.py b/purchase_container/models/purchase_container.py index a3f48a64060..c51b42a850f 100644 --- a/purchase_container/models/purchase_container.py +++ b/purchase_container/models/purchase_container.py @@ -19,13 +19,31 @@ class PurchaseContainer(models.Model): copy=False, ) bill_of_lading_ref = fields.Char("Bill Of Lading No.", copy=False) + seal_number = fields.Char("Seal #", copy=False, help="Container seal number") shipping_agent_id = fields.Many2one( - comodel_name="res.partner", string="Shipping Agent" + comodel_name="res.partner", + string="Freight Forwarder", + help="Freight forwarding company (e.g., RL Swearer)", + ) + drayage_company_id = fields.Many2one( + comodel_name="res.partner", + string="Drayage Company", + help="Local drayage/trucking company for final delivery", ) type_id = fields.Many2one(comodel_name="container.type") package_qty = fields.Integer(copy=False) - cost = fields.Float(digits="Product Price", copy=False) + cost = fields.Float(digits="Product Price", copy=False, string="Ocean Freight Cost") cost_currency_id = fields.Many2one("res.currency", "Cost Currency", copy=False) + per_diem_fees = fields.Float( + digits="Product Price", + copy=False, + string="Per Diem / Add'l Fees", + help="Per diem and additional fees", + ) + per_diem_reason = fields.Text( + "Fee Reason", help="Reason for per diem or additional fees" + ) + notes = fields.Text(help="Internal notes about this container") volume = fields.Float(digits="Volume", copy=False) volume_uom_id = fields.Many2one( "uom.uom", @@ -77,20 +95,44 @@ class PurchaseContainer(models.Model): tracking=True, ) - departure_location_id = fields.Many2one("res.partner") - arrival_location_id = fields.Many2one("res.partner") + departure_location_id = fields.Many2one( + "res.partner", string="Port of Lading", help="Origin port" + ) + arrival_location_id = fields.Many2one( + "res.partner", string="Port of Discharge", help="Destination port" + ) + warehouse_id = fields.Many2one( + "stock.warehouse", + string="Destination Warehouse", + help="Final destination warehouse (PA, ID, GA)", + ) date_eta = fields.Date( - string="ETA Date", help="Estimated Time Of Arrival", tracking=True + string="Port ETA", help="Estimated Time Of Arrival at Port", tracking=True ) date_etd = fields.Date( string="ETD Date", help="Estimated Time Of Departure", tracking=True ) + date_warehouse_eta = fields.Date( + string="Warehouse ETA", + help="Estimated Time Of Arrival at final warehouse", + tracking=True, + ) date_ata = fields.Date( - string="ATA Date", help="Actual Time Of Arrival", tracking=True + string="ATA Date", help="Actual Time Of Arrival at Port", tracking=True ) date_atd = fields.Date( string="ATD Date", help="Actual Time Of Departure", tracking=True ) + date_delivered = fields.Date( + string="Delivered Date", + help="Date container was delivered to warehouse", + tracking=True, + ) + date_received = fields.Date( + string="Received Date", + help="Date inventory was received into system", + tracking=True, + ) date_ett = fields.Char( string="ETT Date", help="Estimated Time Of Travel", @@ -101,14 +143,24 @@ class PurchaseContainer(models.Model): state = fields.Selection( [ - ("waiting", "Waiting"), - ("transit", "Transit"), - ("arrived", "Arrived"), - ("locked", "Locked"), + ("in_progress", "In Progress"), + ("pos_confirmed", "POs Confirmed"), + ("freight_notified", "Freight Forwarder Notified"), + ("on_water", "On the Water"), + ("arrival_notice", "Arrival Notice"), + ("drayage_confirmed", "Drayage Confirmed"), + ("awaiting_gate_out", "Awaiting Gate Out"), + ("customs_hold", "Customs Hold"), + ("released", "Released for Delivery"), + ("delivered", "Delivered"), + ("received", "Received"), + ("on_hold", "On Hold"), + ("ready_to_process", "Ready to Process"), + ("processed", "Processed"), ], - compute="_compute_state", - store=True, + default="in_progress", tracking=True, + copy=False, ) is_locked = fields.Boolean() @@ -140,27 +192,30 @@ def _compute_date_ett(self): if record.date_eta and record.date_etd: record.date_ett = record.date_eta - record.date_etd - @api.depends("is_locked", "date_etd", "date_atd", "picking_ids.state") - def _compute_state(self): - for record in self: - departure_date = record.date_atd if record.date_atd else record.date_etd - - picking_states = set(record.picking_ids.mapped("state")) - if record.is_locked: - record.state = "locked" - elif picking_states and picking_states.issubset({"done", "cancel"}): - record.state = "arrived" - elif departure_date and departure_date <= date.today(): - record.state = "transit" - else: - record.state = "waiting" - def button_lock(self): + """Lock the container to prevent further changes.""" self.is_locked = True def button_unlock(self): + """Unlock the container to allow changes.""" self.is_locked = False + def action_set_on_water(self): + """Mark container as on the water (departed).""" + self.write({"state": "on_water", "date_atd": date.today()}) + + def action_set_arrival_notice(self): + """Mark container as having arrival notice.""" + self.write({"state": "arrival_notice"}) + + def action_set_delivered(self): + """Mark container as delivered to warehouse.""" + self.write({"state": "delivered", "date_delivered": date.today()}) + + def action_set_received(self): + """Mark container as received into inventory.""" + self.write({"state": "received", "date_received": date.today()}) + @api.depends("code", "purchase_order_ids") def _compute_name(self): for record in self: diff --git a/purchase_container/static/description/index.html b/purchase_container/static/description/index.html index 3ae1eb6dd06..76e5f762c6d 100644 --- a/purchase_container/static/description/index.html +++ b/purchase_container/static/description/index.html @@ -398,6 +398,7 @@

Credits

Authors

  • Akretion
  • +
  • Kencove
diff --git a/purchase_container/views/purchase_container.xml b/purchase_container/views/purchase_container.xml index e96b993ea0c..ae42c998e37 100644 --- a/purchase_container/views/purchase_container.xml +++ b/purchase_container/views/purchase_container.xml @@ -5,20 +5,11 @@
-
@@ -62,83 +53,130 @@ />
+
- Container +
- + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
@@ -154,13 +192,23 @@ + - + + + + + - - + @@ -170,16 +218,85 @@ + + + + + + + + + + + + + + + + @@ -189,6 +306,7 @@ Containers purchase.container list,form + {'search_default_group_state': 1} Date: Tue, 13 Jan 2026 17:31:53 -0500 Subject: [PATCH 4/7] [16.0][FIX] purchase_container: Fix test for Kencove base_unit_count field Create product via product.template to properly set base_unit_count field that has a non-null constraint in Kencove's database. Co-Authored-By: Claude Opus 4.5 --- purchase_container/tests/test_module.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/purchase_container/tests/test_module.py b/purchase_container/tests/test_module.py index ac077327b81..0745e2f0498 100644 --- a/purchase_container/tests/test_module.py +++ b/purchase_container/tests/test_module.py @@ -8,7 +8,14 @@ class Test(BaseCommon): def setUpClass(cls): super().setUpClass() cls.partner = cls.env["res.partner"].create({"name": "Test Supplier"}) - cls.product = cls.env["product.product"].create({"name": "Test Product"}) + # Create product template first with base_unit_count for Kencove requirement + product_tmpl = cls.env["product.template"].create( + { + "name": "Test Product", + "base_unit_count": 1, + } + ) + cls.product = product_tmpl.product_variant_id cls.cont_a = cls.env["purchase.container"].create({"code": "AA"}) cls.cont_b = cls.env["purchase.container"].create({"code": "BB"}) cls.incoterm_id = cls.env.ref("account.incoterm_FCA") From f0b86ef8577f02f79248c8b3fc1487d9db31540e Mon Sep 17 00:00:00 2001 From: Don Kendall Date: Tue, 13 Jan 2026 17:41:44 -0500 Subject: [PATCH 5/7] [16.0][FIX] purchase_container: Make test compatible with/without base_unit_count field Co-Authored-By: Claude Opus 4.5 --- purchase_container/tests/test_module.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/purchase_container/tests/test_module.py b/purchase_container/tests/test_module.py index 0745e2f0498..8ab70eb2b58 100644 --- a/purchase_container/tests/test_module.py +++ b/purchase_container/tests/test_module.py @@ -8,14 +8,16 @@ class Test(BaseCommon): def setUpClass(cls): super().setUpClass() cls.partner = cls.env["res.partner"].create({"name": "Test Supplier"}) - # Create product template first with base_unit_count for Kencove requirement + # Create product template first, then get product variant product_tmpl = cls.env["product.template"].create( { "name": "Test Product", - "base_unit_count": 1, } ) cls.product = product_tmpl.product_variant_id + # Set base_unit_count if the field exists (Kencove custom module) + if "base_unit_count" in cls.env["product.template"]._fields: + product_tmpl.base_unit_count = 1 cls.cont_a = cls.env["purchase.container"].create({"code": "AA"}) cls.cont_b = cls.env["purchase.container"].create({"code": "BB"}) cls.incoterm_id = cls.env.ref("account.incoterm_FCA") From 00c07d107dc4bb574083e6ac5e26645c8edac16e Mon Sep 17 00:00:00 2001 From: Don Kendall Date: Tue, 13 Jan 2026 22:09:38 -0500 Subject: [PATCH 6/7] feat(purchase_container): add document tracking, container lines, and tracking URLs - Add container.document model for tracking shipping documents (BOL, invoice, etc.) - Add container.document.type for configurable document types with required flag - Add container.line model for tracking products/quantities in containers - Add shipment tracking fields: carrier_id, vessel_name, voyage_number, tracking_number - Add tracking URL computation for major carriers (Maersk, MSC, Evergreen, etc.) - Add freight_forwarder_ref field for RL Swearer booking IDs - Add has_additional_fees boolean and per_diem fields - Add landed cost integration (many2many to stock.landed.cost) - Add comprehensive test coverage (27 tests) - Add default document types data (Commercial Invoice, Packing List, BOL, etc.) Co-Authored-By: Claude Opus 4.5 --- purchase_container/__manifest__.py | 8 +- .../data/container_document_type.xml | 91 ++++ purchase_container/models/__init__.py | 2 + .../models/container_document.py | 92 ++++ purchase_container/models/container_line.py | 104 ++++ .../models/purchase_container.py | 220 +++++++- .../security/ir.model.access.csv | 5 + purchase_container/tests/test_module.py | 498 +++++++++++++++++- .../views/container_document.xml | 201 +++++++ purchase_container/views/container_line.xml | 105 ++++ .../views/purchase_container.xml | 189 ++++++- 11 files changed, 1480 insertions(+), 35 deletions(-) create mode 100644 purchase_container/data/container_document_type.xml create mode 100644 purchase_container/models/container_document.py create mode 100644 purchase_container/models/container_line.py create mode 100644 purchase_container/views/container_document.xml create mode 100644 purchase_container/views/container_line.xml diff --git a/purchase_container/__manifest__.py b/purchase_container/__manifest__.py index 68dc6b884c8..aab489b8e02 100644 --- a/purchase_container/__manifest__.py +++ b/purchase_container/__manifest__.py @@ -1,7 +1,7 @@ { "name": "Purchase Container", "summary": """Add containers to purchase orders and stock pickings.""", - "version": "16.0.1.1.0", + "version": "16.0.1.2.0", "license": "AGPL-3", "maintainers": ["nayatec"], "author": "Akretion, Kencove, Odoo Community Association (OCA)", @@ -9,14 +9,18 @@ "depends": [ "purchase_stock", "stock", + "stock_landed_costs", ], "data": [ + "security/ir.model.access.csv", "data/container.type.csv", + "data/container_document_type.xml", "data/cron_data.xml", + "views/container_document.xml", + "views/container_line.xml", "views/container_type.xml", "views/purchase.xml", "views/purchase_container.xml", "views/stock_picking.xml", - "security/ir.model.access.csv", ], } diff --git a/purchase_container/data/container_document_type.xml b/purchase_container/data/container_document_type.xml new file mode 100644 index 00000000000..dcc3efe1423 --- /dev/null +++ b/purchase_container/data/container_document_type.xml @@ -0,0 +1,91 @@ + + + + + Commercial Invoice + 10 + True + Commercial invoice for customs clearance showing value and description of goods. + + + + Packing List + 20 + True + Detailed list of contents, cartons, weights, and dimensions. + + + + Bill of Lading (B/L) + 30 + True + Original bill of lading from carrier - document of title for cargo. + + + + Certificate of Origin + 40 + False + Document certifying country of origin for preferential duty rates. + + + + Customs Entry + 50 + False + Customs entry documentation and duty payment confirmation. + + + + Insurance Certificate + 60 + False + Marine cargo insurance certificate. + + + + ISF (10+2) + 70 + False + Importer Security Filing for US-bound shipments. + + + + Arrival Notice + 80 + False + Notification from carrier of vessel arrival at port. + + + + Delivery Order + 90 + False + Order authorizing release of cargo from terminal. + + + + Inspection Report + 100 + False + Pre-shipment or upon arrival inspection report. + + diff --git a/purchase_container/models/__init__.py b/purchase_container/models/__init__.py index 63183983787..cf25cb2e80a 100644 --- a/purchase_container/models/__init__.py +++ b/purchase_container/models/__init__.py @@ -1,4 +1,6 @@ from . import ( + container_document, + container_line, container_type, purchase_container, purchase_order, diff --git a/purchase_container/models/container_document.py b/purchase_container/models/container_document.py new file mode 100644 index 00000000000..f99e37ace80 --- /dev/null +++ b/purchase_container/models/container_document.py @@ -0,0 +1,92 @@ +from odoo import api, fields, models + + +class ContainerDocumentType(models.Model): + """Types of documents required for container shipments.""" + + _name = "container.document.type" + _description = "Container Document Type" + _order = "sequence, name" + + name = fields.Char(required=True, translate=True) + sequence = fields.Integer(default=10) + required = fields.Boolean( + default=False, + help="If checked, this document type is required for all containers", + ) + active = fields.Boolean(default=True) + description = fields.Text(help="Description or instructions for this document type") + + +class ContainerDocument(models.Model): + """Track shipping documents attached to containers.""" + + _name = "container.document" + _description = "Container Document" + _inherit = ["mail.thread", "mail.activity.mixin"] + _order = "container_id, document_type_id" + + container_id = fields.Many2one( + "purchase.container", + string="Container", + required=True, + ondelete="cascade", + index=True, + ) + document_type_id = fields.Many2one( + "container.document.type", + string="Document Type", + required=True, + ondelete="restrict", + ) + name = fields.Char(compute="_compute_name", store=True) + attachment_id = fields.Many2one( + "ir.attachment", + string="Attachment", + help="The uploaded document file", + ) + filename = fields.Char(related="attachment_id.name", string="Filename") + state = fields.Selection( + [ + ("missing", "Missing"), + ("pending", "Pending Review"), + ("approved", "Approved"), + ("rejected", "Rejected"), + ], + default="missing", + required=True, + tracking=True, + ) + reference = fields.Char( + help="External reference number for this document (e.g., invoice number)" + ) + date_received = fields.Date() + date_approved = fields.Date() + notes = fields.Text() + required = fields.Boolean( + related="document_type_id.required", string="Required", store=True + ) + + @api.depends("container_id.code", "document_type_id.name") + def _compute_name(self): + for record in self: + record.name = f"{record.container_id.code} - {record.document_type_id.name}" + + @api.onchange("attachment_id") + def _onchange_attachment_id(self): + """Auto-update state when attachment is added.""" + if self.attachment_id and self.state == "missing": + self.state = "pending" + self.date_received = fields.Date.today() + + def action_approve(self): + """Approve the document.""" + self.write({"state": "approved", "date_approved": fields.Date.today()}) + + def action_reject(self): + """Reject the document.""" + self.write({"state": "rejected"}) + + def action_reset(self): + """Reset to pending for re-review.""" + self.write({"state": "pending", "date_approved": False}) diff --git a/purchase_container/models/container_line.py b/purchase_container/models/container_line.py new file mode 100644 index 00000000000..372fd9f239f --- /dev/null +++ b/purchase_container/models/container_line.py @@ -0,0 +1,104 @@ +from odoo import api, fields, models + + +class ContainerLine(models.Model): + """Track individual products/quantities within a container.""" + + _name = "container.line" + _description = "Container Line" + _order = "container_id, sequence, id" + + container_id = fields.Many2one( + "purchase.container", + string="Container", + required=True, + ondelete="cascade", + index=True, + ) + sequence = fields.Integer(default=10) + product_id = fields.Many2one( + "product.product", + string="Product", + required=True, + domain=[("purchase_ok", "=", True)], + ) + product_tmpl_id = fields.Many2one( + related="product_id.product_tmpl_id", string="Product Template", store=True + ) + description = fields.Text() + quantity = fields.Float( + digits="Product Unit of Measure", + default=1.0, + required=True, + ) + product_uom_id = fields.Many2one( + "uom.uom", + string="Unit of Measure", + domain="[('category_id', '=', product_uom_category_id)]", + ) + product_uom_category_id = fields.Many2one( + related="product_id.uom_id.category_id", string="UoM Category" + ) + + # Carton/package information + carton_qty = fields.Integer( + string="Cartons", + help="Number of cartons/packages for this line", + ) + units_per_carton = fields.Float( + string="Units/Carton", + help="Number of units per carton", + ) + + # Weight and volume + weight = fields.Float( + digits="Stock Weight", + help="Total weight for this line", + ) + volume = fields.Float( + digits="Volume", + help="Total volume for this line (CBM)", + ) + + # Purchase order reference + purchase_line_id = fields.Many2one( + "purchase.order.line", + string="Purchase Order Line", + help="Link to the original purchase order line", + ) + purchase_order_id = fields.Many2one( + related="purchase_line_id.order_id", string="Purchase Order", store=True + ) + + # Landed cost allocation + landed_cost = fields.Monetary( + currency_field="currency_id", + help="Allocated landed cost for this line", + ) + currency_id = fields.Many2one( + "res.currency", + string="Currency", + default=lambda self: self.env.company.currency_id, + ) + + @api.onchange("product_id") + def _onchange_product_id(self): + """Set default values from product.""" + if self.product_id: + self.product_uom_id = self.product_id.uom_po_id or self.product_id.uom_id + self.description = self.product_id.display_name + + @api.onchange("carton_qty", "units_per_carton") + def _onchange_carton_info(self): + """Auto-calculate quantity from carton information.""" + if self.carton_qty and self.units_per_carton: + self.quantity = self.carton_qty * self.units_per_carton + + def name_get(self): + result = [] + for line in self: + name = f"{line.container_id.code}: {line.product_id.display_name}" + if line.quantity: + name += f" ({line.quantity} {line.product_uom_id.name or ''})" + result.append((line.id, name)) + return result diff --git a/purchase_container/models/purchase_container.py b/purchase_container/models/purchase_container.py index c51b42a850f..87278ad3d31 100644 --- a/purchase_container/models/purchase_container.py +++ b/purchase_container/models/purchase_container.py @@ -25,6 +25,10 @@ class PurchaseContainer(models.Model): string="Freight Forwarder", help="Freight forwarding company (e.g., RL Swearer)", ) + freight_forwarder_ref = fields.Char( + help="Freight forwarder booking/reference number (e.g., RL Swearer ID: B00064516)", + tracking=True, + ) drayage_company_id = fields.Many2one( comodel_name="res.partner", string="Drayage Company", @@ -34,11 +38,15 @@ class PurchaseContainer(models.Model): package_qty = fields.Integer(copy=False) cost = fields.Float(digits="Product Price", copy=False, string="Ocean Freight Cost") cost_currency_id = fields.Many2one("res.currency", "Cost Currency", copy=False) + has_additional_fees = fields.Boolean( + string="Has Add'l Fees", + help="Check if there are per diem or additional fees to note", + ) per_diem_fees = fields.Float( digits="Product Price", copy=False, string="Per Diem / Add'l Fees", - help="Per diem and additional fees", + help="Per diem and additional fees amount", ) per_diem_reason = fields.Text( "Fee Reason", help="Reason for per diem or additional fees" @@ -164,6 +172,62 @@ class PurchaseContainer(models.Model): ) is_locked = fields.Boolean() + # Document tracking + document_ids = fields.One2many( + "container.document", + "container_id", + string="Documents", + ) + document_count = fields.Integer(compute="_compute_document_count") + documents_complete = fields.Boolean( + string="Docs Complete", + compute="_compute_documents_complete", + store=True, + help="All required documents have been approved", + ) + + # Container line items + line_ids = fields.One2many( + "container.line", + "container_id", + string="Container Lines", + ) + line_count = fields.Integer(string="Lines", compute="_compute_line_count") + + # Shipment tracking + carrier_id = fields.Many2one( + "res.partner", + string="Shipping Carrier", + help="Ocean carrier / shipping line (e.g., Maersk, MSC, COSCO)", + ) + vessel_name = fields.Char(help="Name of the vessel/ship") + voyage_number = fields.Char(help="Voyage or trip number") + tracking_number = fields.Char( + help="Carrier tracking number or booking reference", + tracking=True, + ) + tracking_url = fields.Char( + compute="_compute_tracking_url", + help="URL to track shipment on carrier website", + ) + last_tracking_update = fields.Datetime( + help="When tracking information was last updated", + ) + tracking_status = fields.Char(help="Latest status from carrier tracking") + + # Landed cost integration + landed_cost_ids = fields.Many2many( + "stock.landed.cost", + string="Landed Costs", + help="Landed cost records associated with this container", + ) + landed_cost_count = fields.Integer(compute="_compute_landed_cost_count") + total_landed_cost = fields.Monetary( + compute="_compute_total_landed_cost", + currency_field="cost_currency_id", + help="Total landed costs applied to this container", + ) + def _compute_incoterm_id(self): for record in self: record.incoterm_id = record.purchase_order_ids.filtered( @@ -318,3 +382,157 @@ def action_view_picking(self): action["domain"] = [("id", "in", self.picking_ids.ids)] action["context"] = {"create": False} return action + + # Document tracking methods + def _compute_document_count(self): + for record in self: + record.document_count = len(record.document_ids) + + @api.depends("document_ids.state", "document_ids.required") + def _compute_documents_complete(self): + for record in self: + required_docs = record.document_ids.filtered(lambda d: d.required) + record.documents_complete = ( + all(doc.state == "approved" for doc in required_docs) + if required_docs + else True + ) + + def action_view_documents(self): + self.ensure_one() + return { + "name": "Container Documents", + "type": "ir.actions.act_window", + "res_model": "container.document", + "view_mode": "list,form", + "domain": [("container_id", "=", self.id)], + "context": {"default_container_id": self.id}, + } + + def action_create_required_documents(self): + """Create document records for all required document types.""" + self.ensure_one() + required_types = self.env["container.document.type"].search( + [("required", "=", True)] + ) + existing_types = self.document_ids.mapped("document_type_id") + for doc_type in required_types - existing_types: + self.env["container.document"].create( + { + "container_id": self.id, + "document_type_id": doc_type.id, + } + ) + return True + + # Container line methods + def _compute_line_count(self): + for record in self: + record.line_count = len(record.line_ids) + + def action_view_lines(self): + self.ensure_one() + return { + "name": "Container Lines", + "type": "ir.actions.act_window", + "res_model": "container.line", + "view_mode": "list,form", + "domain": [("container_id", "=", self.id)], + "context": {"default_container_id": self.id}, + } + + # Shipment tracking methods + def _compute_tracking_url(self): + """Generate tracking URL based on carrier. + + This can be extended to support different carrier tracking portals. + """ + for record in self: + url = False + if record.tracking_number and record.carrier_id: + carrier_name = (record.carrier_id.name or "").lower() + tracking = record.tracking_number + url = record._get_tracking_url_for_carrier(carrier_name, tracking) + record.tracking_url = url + + def _get_tracking_url_for_carrier(self, carrier_name, tracking): + """Get tracking URL for a specific carrier. + + Can be extended to add more carriers. + """ + base_urls = { + "maersk": "https://www.maersk.com/tracking/", + "msc": "https://www.msc.com/track-a-shipment?agencyPath=msc&trackingNumber=", + "cosco": "https://elines.coscoshipping.com/ebusiness/cargoTracking?trackNo=", + "hapag": ( + "https://www.hapag-lloyd.com/en/online-business/track/" + "track-by-container-solution.html?container=" + ), + "one": ( + "https://ecomm.one-line.com/one-ecom/manage-shipment/" + "cargo-tracking?trakNoParam=" + ), + "evergreen": ( + "https://www.shipmentlink.com/tvs2/jsp/" + "TVS2_ContainerTracking.jsp?cntr=" + ), + } + for key, url in base_urls.items(): + if key in carrier_name: + return url + tracking + # Generic tracking via searates + return "https://www.searates.com/container/tracking/?number=" + tracking + + def action_open_tracking(self): + """Open tracking URL in browser.""" + self.ensure_one() + if self.tracking_url: + return { + "type": "ir.actions.act_url", + "url": self.tracking_url, + "target": "new", + } + return False + + # Landed cost methods + def _compute_landed_cost_count(self): + for record in self: + record.landed_cost_count = len(record.landed_cost_ids) + + def _compute_total_landed_cost(self): + for record in self: + record.total_landed_cost = sum( + lc.amount_total + for lc in record.landed_cost_ids.filtered(lambda l: l.state == "done") + ) + + def action_view_landed_costs(self): + self.ensure_one() + action = self.env["ir.actions.actions"]._for_xml_id( + "stock_landed_costs.action_stock_landed_cost" + ) + action["domain"] = [("id", "in", self.landed_cost_ids.ids)] + action["context"] = {"default_container_id": self.id} + return action + + def action_create_landed_cost(self): + """Create a new landed cost record for this container.""" + self.ensure_one() + if not self.picking_ids: + return False + # Get done pickings for landed cost + done_pickings = self.picking_ids.filtered(lambda p: p.state == "done") + if not done_pickings: + return False + landed_cost = self.env["stock.landed.cost"].create( + { + "picking_ids": [(6, 0, done_pickings.ids)], + } + ) + self.landed_cost_ids = [(4, landed_cost.id)] + return { + "type": "ir.actions.act_window", + "res_model": "stock.landed.cost", + "view_mode": "form", + "res_id": landed_cost.id, + } diff --git a/purchase_container/security/ir.model.access.csv b/purchase_container/security/ir.model.access.csv index b090883f165..ab09cd059ec 100644 --- a/purchase_container/security/ir.model.access.csv +++ b/purchase_container/security/ir.model.access.csv @@ -4,3 +4,8 @@ access_container_type,container.type,model_container_type,purchase.group_purchas access_purchase_container_manager,purchase.container,model_purchase_container,purchase.group_purchase_manager,1,1,1,1 access_purchase_container_readonly,purchase.container,model_purchase_container,account.group_account_readonly,1,0,0,0 access_purchase_container_invoice,purchase.container,model_purchase_container,account.group_account_invoice,1,1,0,0 +access_container_document_type,container.document.type,model_container_document_type,purchase.group_purchase_user,1,1,1,1 +access_container_document,container.document,model_container_document,purchase.group_purchase_user,1,1,1,1 +access_container_document_readonly,container.document,model_container_document,account.group_account_readonly,1,0,0,0 +access_container_line,container.line,model_container_line,purchase.group_purchase_user,1,1,1,1 +access_container_line_readonly,container.line,model_container_line,account.group_account_readonly,1,0,0,0 diff --git a/purchase_container/tests/test_module.py b/purchase_container/tests/test_module.py index 8ab70eb2b58..74e6d63bce6 100644 --- a/purchase_container/tests/test_module.py +++ b/purchase_container/tests/test_module.py @@ -1,23 +1,34 @@ +from datetime import date, timedelta + from odoo import Command, fields +from odoo.tests.common import TransactionCase from odoo.addons.base.tests.common import BaseCommon -class Test(BaseCommon): +class TestPurchaseContainerBase(BaseCommon): + """Base test class with common setup for purchase container tests.""" + @classmethod def setUpClass(cls): super().setUpClass() cls.partner = cls.env["res.partner"].create({"name": "Test Supplier"}) - # Create product template first, then get product variant - product_tmpl = cls.env["product.template"].create( - { - "name": "Test Product", - } - ) - cls.product = product_tmpl.product_variant_id - # Set base_unit_count if the field exists (Kencove custom module) + # Handle base_unit_count: website_sale adds NOT NULL constraint but may not be + # loaded in test registry. Set DB default to handle schema mismatch. + if "base_unit_count" not in cls.env["product.template"]._fields: + cls.env.cr.execute( + """ + ALTER TABLE product_template + ALTER COLUMN base_unit_count SET DEFAULT 0; + ALTER TABLE product_product + ALTER COLUMN base_unit_count SET DEFAULT 0; + """ + ) + product_vals = {"name": "Test Product"} if "base_unit_count" in cls.env["product.template"]._fields: - product_tmpl.base_unit_count = 1 + product_vals["base_unit_count"] = 1 + product_tmpl = cls.env["product.template"].create(product_vals) + cls.product = product_tmpl.product_variant_id cls.cont_a = cls.env["purchase.container"].create({"code": "AA"}) cls.cont_b = cls.env["purchase.container"].create({"code": "BB"}) cls.incoterm_id = cls.env.ref("account.incoterm_FCA") @@ -28,7 +39,33 @@ def _validate_picking(self, picking): move.quantity_done = move.product_uom_qty picking.button_validate() + def get_po(self): + return self.env["purchase.order"].create( + { + "partner_id": self.partner.id, + "date_planned": fields.Datetime.now(), + "incoterm_id": self.incoterm_id.id, + "order_line": [ + Command.create( + { + "name": "Test Line", + "product_id": self.product.id, + "product_qty": 4.0, + "product_uom": self.product.uom_po_id.id, + "price_unit": 1, + "date_planned": fields.Datetime.now(), + }, + ) + ], + } + ) + + +class TestPurchaseContainer(TestPurchaseContainerBase): + """Tests for core purchase container functionality.""" + def test_container_by_purchase(self): + """Test container-purchase order relationships.""" # first PO po = self.get_po() po.button_confirm() @@ -63,6 +100,7 @@ def test_container_by_purchase(self): self.assertEqual(self.cont_b.displayed_incoterm_id, self.incoterm_id) def test_action_views(self): + """Test action view methods return proper actions.""" po = self.get_po() po.button_confirm() pick01 = po.picking_ids[0] @@ -71,23 +109,429 @@ def test_action_views(self): self.cont_a.action_view_order() self.cont_a.action_view_picking() - def get_po(self): - return self.env["purchase.order"].create( + def test_container_code_uppercase(self): + """Test that container code is converted to uppercase.""" + container = self.env["purchase.container"].create({"code": "test123"}) + self.assertEqual(container.code, "TEST123") + + def test_container_name_computation(self): + """Test container name includes code and PO references.""" + po = self.get_po() + po.button_confirm() + pick = po.picking_ids[0] + pick.container_id = self.cont_a.id + self.cont_a.purchase_order_ids = [(4, po.id)] + self.cont_a._compute_name() + self.assertIn("AA", self.cont_a.name) + self.assertIn(po.name, self.cont_a.name) + + +class TestContainerStateTransitions(TestPurchaseContainerBase): + """Tests for container state transitions and actions.""" + + def test_state_transitions(self): + """Test state transition actions.""" + container = self.env["purchase.container"].create( { - "partner_id": self.partner.id, - "date_planned": fields.Datetime.now(), - "incoterm_id": self.incoterm_id.id, - "order_line": [ - Command.create( - { - "name": "Test Line", - "product_id": self.product.id, - "product_qty": 4.0, - "product_uom": self.product.uom_po_id.id, - "price_unit": 1, - "date_planned": fields.Datetime.now(), - }, - ) - ], + "code": "STATE-TEST", + "state": "in_progress", + } + ) + self.assertEqual(container.state, "in_progress") + + # Test on_water transition + container.action_set_on_water() + self.assertEqual(container.state, "on_water") + self.assertEqual(container.date_atd, date.today()) + + # Test arrival notice transition + container.action_set_arrival_notice() + self.assertEqual(container.state, "arrival_notice") + + # Test delivered transition + container.action_set_delivered() + self.assertEqual(container.state, "delivered") + self.assertEqual(container.date_delivered, date.today()) + + # Test received transition + container.action_set_received() + self.assertEqual(container.state, "received") + self.assertEqual(container.date_received, date.today()) + + def test_container_lock_unlock(self): + """Test container lock and unlock functionality.""" + container = self.env["purchase.container"].create({"code": "LOCK-TEST"}) + self.assertFalse(container.is_locked) + + container.button_lock() + self.assertTrue(container.is_locked) + + container.button_unlock() + self.assertFalse(container.is_locked) + + def test_ett_computation(self): + """Test estimated transit time computation.""" + container = self.env["purchase.container"].create( + { + "code": "ETT-TEST", + "date_etd": date.today(), + "date_eta": date.today() + timedelta(days=30), + } + ) + container._compute_date_ett() + # date_ett is a Char field, so it stores the timedelta as a string + self.assertIn("30 days", container.date_ett) + + +class TestContainerFields(TestPurchaseContainerBase): + """Tests for container field functionality.""" + + def test_freight_forwarder_ref(self): + """Test freight forwarder reference field.""" + container = self.env["purchase.container"].create( + { + "code": "FF-TEST", + "freight_forwarder_ref": "B00064516", + } + ) + self.assertEqual(container.freight_forwarder_ref, "B00064516") + + def test_additional_fees_fields(self): + """Test additional fees boolean and amount fields.""" + container = self.env["purchase.container"].create( + { + "code": "FEES-TEST", + "has_additional_fees": True, + "per_diem_fees": 150.00, + "per_diem_reason": "Customs delay", + } + ) + self.assertTrue(container.has_additional_fees) + self.assertEqual(container.per_diem_fees, 150.00) + self.assertEqual(container.per_diem_reason, "Customs delay") + + def test_shipping_tracking_fields(self): + """Test shipping and tracking fields.""" + carrier = self.env["res.partner"].create({"name": "Maersk Line"}) + container = self.env["purchase.container"].create( + { + "code": "TRACK-TEST", + "carrier_id": carrier.id, + "vessel_name": "MSC Oscar", + "voyage_number": "VY2025001", + "tracking_number": "MSKU1234567", } ) + self.assertEqual(container.carrier_id, carrier) + self.assertEqual(container.vessel_name, "MSC Oscar") + self.assertEqual(container.voyage_number, "VY2025001") + self.assertEqual(container.tracking_number, "MSKU1234567") + + +class TestContainerTrackingUrl(TestPurchaseContainerBase): + """Tests for tracking URL computation.""" + + def test_tracking_url_maersk(self): + """Test tracking URL generation for Maersk.""" + carrier = self.env["res.partner"].create({"name": "Maersk Line"}) + container = self.env["purchase.container"].create( + { + "code": "URL-MAERSK", + "carrier_id": carrier.id, + "tracking_number": "MSKU1234567", + } + ) + container._compute_tracking_url() + self.assertIn("maersk.com", container.tracking_url) + self.assertIn("MSKU1234567", container.tracking_url) + + def test_tracking_url_msc(self): + """Test tracking URL generation for MSC.""" + carrier = self.env["res.partner"].create({"name": "MSC Mediterranean"}) + container = self.env["purchase.container"].create( + { + "code": "URL-MSC", + "carrier_id": carrier.id, + "tracking_number": "MSCU7654321", + } + ) + container._compute_tracking_url() + self.assertIn("msc.com", container.tracking_url) + + def test_tracking_url_generic(self): + """Test tracking URL generation for unknown carriers.""" + carrier = self.env["res.partner"].create({"name": "Unknown Carrier"}) + container = self.env["purchase.container"].create( + { + "code": "URL-GENERIC", + "carrier_id": carrier.id, + "tracking_number": "UNKN1234567", + } + ) + container._compute_tracking_url() + self.assertIn("searates.com", container.tracking_url) + + def test_tracking_url_no_carrier(self): + """Test tracking URL is empty without carrier.""" + container = self.env["purchase.container"].create( + { + "code": "URL-NONE", + "tracking_number": "TEST1234567", + } + ) + container._compute_tracking_url() + self.assertFalse(container.tracking_url) + + def test_action_open_tracking(self): + """Test open tracking action returns URL action.""" + carrier = self.env["res.partner"].create({"name": "Maersk"}) + container = self.env["purchase.container"].create( + { + "code": "ACTION-TRACK", + "carrier_id": carrier.id, + "tracking_number": "MSKU1234567", + } + ) + container._compute_tracking_url() + action = container.action_open_tracking() + self.assertEqual(action["type"], "ir.actions.act_url") + self.assertIn("maersk.com", action["url"]) + + +class TestContainerDocuments(TestPurchaseContainerBase): + """Tests for container document tracking.""" + + @classmethod + def setUpClass(cls): + super().setUpClass() + # Create document types + cls.doc_type_invoice = cls.env["container.document.type"].create( + { + "name": "Commercial Invoice", + "required": True, + "sequence": 10, + } + ) + cls.doc_type_packing = cls.env["container.document.type"].create( + { + "name": "Packing List", + "required": True, + "sequence": 20, + } + ) + cls.doc_type_cert = cls.env["container.document.type"].create( + { + "name": "Certificate of Origin", + "required": False, + "sequence": 30, + } + ) + + def test_document_creation(self): + """Test creating documents for a container.""" + container = self.env["purchase.container"].create({"code": "DOC-TEST"}) + doc = self.env["container.document"].create( + { + "container_id": container.id, + "document_type_id": self.doc_type_invoice.id, + } + ) + self.assertEqual(doc.state, "missing") + self.assertTrue(doc.required) + self.assertEqual(doc.container_id, container) + + def test_document_state_workflow(self): + """Test document state transitions.""" + container = self.env["purchase.container"].create({"code": "DOC-STATE"}) + doc = self.env["container.document"].create( + { + "container_id": container.id, + "document_type_id": self.doc_type_invoice.id, + "state": "missing", + } + ) + + # Move to pending + doc.state = "pending" + doc.date_received = date.today() + self.assertEqual(doc.state, "pending") + + # Approve + doc.action_approve() + self.assertEqual(doc.state, "approved") + self.assertEqual(doc.date_approved, date.today()) + + # Reset + doc.action_reset() + self.assertEqual(doc.state, "pending") + self.assertFalse(doc.date_approved) + + # Reject + doc.action_reject() + self.assertEqual(doc.state, "rejected") + + def test_documents_complete_computation(self): + """Test documents_complete field computation.""" + container = self.env["purchase.container"].create({"code": "DOC-COMPLETE"}) + + # No documents - should be complete (no required docs to check) + container._compute_documents_complete() + self.assertTrue(container.documents_complete) + + # Add required document in missing state + doc1 = self.env["container.document"].create( + { + "container_id": container.id, + "document_type_id": self.doc_type_invoice.id, + "state": "missing", + } + ) + container._compute_documents_complete() + self.assertFalse(container.documents_complete) + + # Approve the document + doc1.action_approve() + container._compute_documents_complete() + + # Add another required document + doc2 = self.env["container.document"].create( + { + "container_id": container.id, + "document_type_id": self.doc_type_packing.id, + "state": "missing", + } + ) + container._compute_documents_complete() + self.assertFalse(container.documents_complete) + + # Approve second document + doc2.action_approve() + container._compute_documents_complete() + self.assertTrue(container.documents_complete) + + def test_create_required_documents(self): + """Test action to create required document records.""" + container = self.env["purchase.container"].create({"code": "DOC-CREATE"}) + self.assertEqual(len(container.document_ids), 0) + + container.action_create_required_documents() + + # Should have created records for required document types + required_types = self.env["container.document.type"].search( + [("required", "=", True)] + ) + self.assertGreaterEqual(len(container.document_ids), len(required_types)) + + def test_document_count(self): + """Test document count computation.""" + container = self.env["purchase.container"].create({"code": "DOC-COUNT"}) + self.assertEqual(container.document_count, 0) + + self.env["container.document"].create( + { + "container_id": container.id, + "document_type_id": self.doc_type_invoice.id, + } + ) + container._compute_document_count() + self.assertEqual(container.document_count, 1) + + self.env["container.document"].create( + { + "container_id": container.id, + "document_type_id": self.doc_type_packing.id, + } + ) + container._compute_document_count() + self.assertEqual(container.document_count, 2) + + def test_action_view_documents(self): + """Test action to view documents.""" + container = self.env["purchase.container"].create({"code": "DOC-VIEW"}) + action = container.action_view_documents() + self.assertEqual(action["res_model"], "container.document") + # Domain is [('container_id', '=', container.id)] + self.assertEqual(action["domain"][0][2], container.id) + + +class TestContainerLines(TestPurchaseContainerBase): + """Tests for container line functionality.""" + + def test_line_creation(self): + """Test creating container lines.""" + container = self.env["purchase.container"].create({"code": "LINE-TEST"}) + line = self.env["container.line"].create( + { + "container_id": container.id, + "product_id": self.product.id, + "quantity": 100, + } + ) + self.assertEqual(line.container_id, container) + self.assertEqual(line.product_id, self.product) + self.assertEqual(line.quantity, 100) + + def test_line_carton_calculation(self): + """Test quantity calculation from carton info.""" + container = self.env["purchase.container"].create({"code": "LINE-CARTON"}) + line = self.env["container.line"].create( + { + "container_id": container.id, + "product_id": self.product.id, + "quantity": 0, + "carton_qty": 10, + "units_per_carton": 50, + } + ) + line._onchange_carton_info() + self.assertEqual(line.quantity, 500) + + def test_line_count(self): + """Test line count computation.""" + container = self.env["purchase.container"].create({"code": "LINE-COUNT"}) + self.assertEqual(container.line_count, 0) + + self.env["container.line"].create( + { + "container_id": container.id, + "product_id": self.product.id, + "quantity": 100, + } + ) + container._compute_line_count() + self.assertEqual(container.line_count, 1) + + def test_action_view_lines(self): + """Test action to view lines.""" + container = self.env["purchase.container"].create({"code": "LINE-VIEW"}) + action = container.action_view_lines() + self.assertEqual(action["res_model"], "container.line") + # Domain is [('container_id', '=', container.id)] + self.assertEqual(action["domain"][0][2], container.id) + + def test_line_product_onchange(self): + """Test product onchange sets defaults.""" + container = self.env["purchase.container"].create({"code": "LINE-ONCHANGE"}) + line = self.env["container.line"].create( + { + "container_id": container.id, + "product_id": self.product.id, + "quantity": 1, + } + ) + line._onchange_product_id() + self.assertEqual( + line.product_uom_id, self.product.uom_po_id or self.product.uom_id + ) + + +class TestContainerType(TransactionCase): + """Tests for container type model.""" + + def test_container_types_exist(self): + """Test that default container types are loaded.""" + types = self.env["container.type"].search([]) + type_names = types.mapped("name") + self.assertIn("20'", type_names) + self.assertIn("40'", type_names) + self.assertIn("40' HC", type_names) diff --git a/purchase_container/views/container_document.xml b/purchase_container/views/container_document.xml new file mode 100644 index 00000000000..ae0a5043322 --- /dev/null +++ b/purchase_container/views/container_document.xml @@ -0,0 +1,201 @@ + + + + + container.document.type + + + + + + + + + + + + + + + + + + + + + container.document.type + + + + + + + + + + + + Document Types + container.document.type + list,form + + + + + container.document + +
+
+
+ + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+ + + container.document + + + + + + + + + + + + + + + container.document + + + + + + + + + + + + + + + + + + + + + + + + Container Documents + container.document + list,form + {'search_default_group_container': 1} + + + + +
diff --git a/purchase_container/views/container_line.xml b/purchase_container/views/container_line.xml new file mode 100644 index 00000000000..f861c576b80 --- /dev/null +++ b/purchase_container/views/container_line.xml @@ -0,0 +1,105 @@ + + + + + container.line + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + container.line + + + + + + + + + + + + + + + + + + + + + container.line + + + + + + + + + + + + + + + + + Container Lines + container.line + list,form + {'search_default_group_container': 1} + +
diff --git a/purchase_container/views/purchase_container.xml b/purchase_container/views/purchase_container.xml index ae42c998e37..cec280016b4 100644 --- a/purchase_container/views/purchase_container.xml +++ b/purchase_container/views/purchase_container.xml @@ -52,6 +52,40 @@ string="Transfers" /> + + +
+ @@ -105,7 +143,7 @@ - + + + + +
+

Purchase Container

+ + +

Beta License: AGPL-3 OCA/purchase-workflow Translate me on Weblate Try me on Runboat

+

Add containers to purchase orders and stock pickings.

+

Purchase container image

+

Table of contents

+ +
+

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

+
    +
  • Akretion
  • +
+
+
+

Contributors

+
    +
  • Akretion
      +
    • Olivier Nibart
    • +
    • Mathieu Delva
    • +
    +
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

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.

+

Current maintainer:

+

nayatec

+

This module is part of the OCA/purchase-workflow project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+