diff --git a/partner_invoicing_mode_at_shipping/README.rst b/partner_invoicing_mode_at_shipping/README.rst new file mode 100644 index 00000000000..7663fa5f874 --- /dev/null +++ b/partner_invoicing_mode_at_shipping/README.rst @@ -0,0 +1,99 @@ +================================== +Partner Invoicing Mode At Shipping +================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:6f96589039ddad82b6acdcd148f04264085935d83c2fc147507bf3ab3ae41c1b + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Faccount--invoicing-lightgray.png?logo=github + :target: https://github.com/OCA/account-invoicing/tree/18.0/partner_invoicing_mode_at_shipping + :alt: OCA/account-invoicing +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/account-invoicing-18-0/account-invoicing-18-0-partner_invoicing_mode_at_shipping + :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/account-invoicing&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to select a At shipping invoicing mode for a +customer. It is based on partner_invoicing_mode. When this mode is +selected the customer will be invoiced automatically on delivery of the +goods. + +Another option is the 'One Invoice Per Shipping'. That one is not +compatible with the 'At shipping' invoicing mode. In that case, the +invoicing validation will occur at a different moment (monthly, ...). + +**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 +------- + +* Camptocamp + +Contributors +------------ + +- `Camptocamp `__: + + - Thierry Ducrest + +- Phuc (Tran Thanh) + +- Nils Coenen + +- Chau Le + +Other credits +------------- + +The development and migration of this module has been financially +supported by: + +- Camptocamp + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/account-invoicing `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/partner_invoicing_mode_at_shipping/__init__.py b/partner_invoicing_mode_at_shipping/__init__.py new file mode 100644 index 00000000000..6d58305f5dd --- /dev/null +++ b/partner_invoicing_mode_at_shipping/__init__.py @@ -0,0 +1,2 @@ +from . import models +from .hooks import pre_init_hook diff --git a/partner_invoicing_mode_at_shipping/__manifest__.py b/partner_invoicing_mode_at_shipping/__manifest__.py new file mode 100644 index 00000000000..2e1ae7e39fc --- /dev/null +++ b/partner_invoicing_mode_at_shipping/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2020 Camptocamp +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "Partner Invoicing Mode At Shipping", + "version": "18.0.1.0.0", + "summary": "Create invoices automatically when goods are shipped.", + "author": "Camptocamp, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/account-invoicing", + "license": "AGPL-3", + "category": "Accounting & Finance", + "data": [ + "data/queue_job_data.xml", + "views/res_partner.xml", + ], + "depends": ["account", "partner_invoicing_mode", "queue_job", "stock"], + "external_dependencies": { + "python": ["openupgradelib"], + }, + "pre_init_hook": "pre_init_hook", +} diff --git a/partner_invoicing_mode_at_shipping/data/queue_job_data.xml b/partner_invoicing_mode_at_shipping/data/queue_job_data.xml new file mode 100644 index 00000000000..b5f70b53f5c --- /dev/null +++ b/partner_invoicing_mode_at_shipping/data/queue_job_data.xml @@ -0,0 +1,15 @@ + + + + + invoice_at_shipping + + + + + + + _invoicing_at_shipping + + + diff --git a/partner_invoicing_mode_at_shipping/hooks.py b/partner_invoicing_mode_at_shipping/hooks.py new file mode 100644 index 00000000000..e6a69d915ed --- /dev/null +++ b/partner_invoicing_mode_at_shipping/hooks.py @@ -0,0 +1,23 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from openupgradelib import openupgrade + + +def _add_one_invoice_per_shipping(env): + if not openupgrade.column_exists(env.cr, "sale_order", "one_invoice_per_shipping"): + field_spec = [ + ( + "one_invoice_per_shipping", + "sale.order", + "sale_order", + "boolean", + "boolean", + "partner_invoicing_mode_at_shipping", + False, + ) + ] + openupgrade.add_fields(env, field_spec) + + +def pre_init_hook(env): + _add_one_invoice_per_shipping(env) diff --git a/partner_invoicing_mode_at_shipping/i18n/es.po b/partner_invoicing_mode_at_shipping/i18n/es.po new file mode 100644 index 00000000000..61af664fb58 --- /dev/null +++ b/partner_invoicing_mode_at_shipping/i18n/es.po @@ -0,0 +1,97 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * partner_invoicing_mode_at_shipping +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-06-29 10:47+0000\n" +"Last-Translator: Anna Martínez \n" +"Language-Team: none\n" +"Language: es\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 4.17\n" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model.fields.selection,name:partner_invoicing_mode_at_shipping.selection__res_partner__invoicing_mode__at_shipping +msgid "At Shipping" +msgstr "En envío" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model.fields,help:partner_invoicing_mode_at_shipping.field_res_partner__one_invoice_per_shipping +#: model:ir.model.fields,help:partner_invoicing_mode_at_shipping.field_res_users__one_invoice_per_shipping +msgid "" +"Check this if you want to create one invoice per shipping using the partner " +"invoicing mode that should be different than 'At Shipping'." +msgstr "" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model,name:partner_invoicing_mode_at_shipping.model_res_partner +msgid "Contact" +msgstr "Contacto" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_res_partner__invoicing_mode +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_res_users__invoicing_mode +msgid "Invoicing Mode" +msgstr "Modo de facturación" + +#. module: partner_invoicing_mode_at_shipping +#. odoo-python +#: code:addons/partner_invoicing_mode_at_shipping/models/stock_picking.py:0 +#, python-format +msgid "Nothing to invoice." +msgstr "Nada para Facturar." + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_res_partner__one_invoice_per_shipping +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_res_users__one_invoice_per_shipping +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_sale_order__one_invoice_per_shipping +msgid "One Invoice Per Shipping" +msgstr "" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model,name:partner_invoicing_mode_at_shipping.model_sale_order +msgid "Sales Order" +msgstr "Pedido de venta" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model,name:partner_invoicing_mode_at_shipping.model_stock_move +msgid "Stock Move" +msgstr "Movimiento de existencias" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model,name:partner_invoicing_mode_at_shipping.model_stock_picking +msgid "Transfer" +msgstr "Transferencia" + +#. module: partner_invoicing_mode_at_shipping +#. odoo-python +#: code:addons/partner_invoicing_mode_at_shipping/models/sale_order.py:0 +#, python-format +msgid "" +"Validate the invoices generated by shipping for the invoicing mode " +"%(invoicing_mode_name)s" +msgstr "" + +#. module: partner_invoicing_mode_at_shipping +#. odoo-python +#: code:addons/partner_invoicing_mode_at_shipping/models/res_partner.py:0 +#, python-format +msgid "" +"You cannot configure the partner %(partner)s with 'One Invoice Per Order' " +"and 'One Invoice Per Shipping'!" +msgstr "" + +#. module: partner_invoicing_mode_at_shipping +#. odoo-python +#: code:addons/partner_invoicing_mode_at_shipping/models/res_partner.py:0 +#, python-format +msgid "" +"You cannot configure the partner %(partner)s with Invoicing Mode 'At " +"Shipping' and 'One Invoice Per Shipping'!" +msgstr "" diff --git a/partner_invoicing_mode_at_shipping/i18n/fr.po b/partner_invoicing_mode_at_shipping/i18n/fr.po new file mode 100644 index 00000000000..a0cca2a2d9c --- /dev/null +++ b/partner_invoicing_mode_at_shipping/i18n/fr.po @@ -0,0 +1,106 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * partner_invoicing_mode_at_shipping +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-11-06 14:06+0000\n" +"Last-Translator: samibc2c \n" +"Language-Team: none\n" +"Language: fr\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.6.2\n" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model.fields.selection,name:partner_invoicing_mode_at_shipping.selection__res_partner__invoicing_mode__at_shipping +msgid "At Shipping" +msgstr "A l'expédition" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model.fields,help:partner_invoicing_mode_at_shipping.field_res_partner__one_invoice_per_shipping +#: model:ir.model.fields,help:partner_invoicing_mode_at_shipping.field_res_users__one_invoice_per_shipping +msgid "" +"Check this if you want to create one invoice per shipping using the partner " +"invoicing mode that should be different than 'At Shipping'." +msgstr "" +"Cochez si vous souhaitez créer une facture par expédition en utilisant le " +"mode de facturation du partenaire, qui doit être différent de 'A " +"l'expédition'." + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model,name:partner_invoicing_mode_at_shipping.model_res_partner +msgid "Contact" +msgstr "Contact" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_res_partner__invoicing_mode +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_res_users__invoicing_mode +msgid "Invoicing Mode" +msgstr "Mode de facturation" + +#. module: partner_invoicing_mode_at_shipping +#. odoo-python +#: code:addons/partner_invoicing_mode_at_shipping/models/stock_picking.py:0 +#, python-format +msgid "Nothing to invoice." +msgstr "Rien à facturer." + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_res_partner__one_invoice_per_shipping +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_res_users__one_invoice_per_shipping +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_sale_order__one_invoice_per_shipping +msgid "One Invoice Per Shipping" +msgstr "Une facture par expédition" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model,name:partner_invoicing_mode_at_shipping.model_sale_order +msgid "Sales Order" +msgstr "Bon de commande" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model,name:partner_invoicing_mode_at_shipping.model_stock_move +msgid "Stock Move" +msgstr "Mouvement de stock" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model,name:partner_invoicing_mode_at_shipping.model_stock_picking +msgid "Transfer" +msgstr "Transfert" + +#. module: partner_invoicing_mode_at_shipping +#. odoo-python +#: code:addons/partner_invoicing_mode_at_shipping/models/sale_order.py:0 +#, python-format +msgid "" +"Validate the invoices generated by shipping for the invoicing mode " +"%(invoicing_mode_name)s" +msgstr "" +"Valider les factures générées par l'expédition pour le mode de facturation " +"%(invoicing_mode_name)s" + +#. module: partner_invoicing_mode_at_shipping +#. odoo-python +#: code:addons/partner_invoicing_mode_at_shipping/models/res_partner.py:0 +#, python-format +msgid "" +"You cannot configure the partner %(partner)s with 'One Invoice Per Order' " +"and 'One Invoice Per Shipping'!" +msgstr "" +"Vous ne pouvez pas configurer le partenaire %(partner)s with 'Une facture " +"par commande' et 'Une facture par expédition' !" + +#. module: partner_invoicing_mode_at_shipping +#. odoo-python +#: code:addons/partner_invoicing_mode_at_shipping/models/res_partner.py:0 +#, python-format +msgid "" +"You cannot configure the partner %(partner)s with Invoicing Mode 'At " +"Shipping' and 'One Invoice Per Shipping'!" +msgstr "" +"Vous ne pouvez pas configurer le partenaire %(partner)s avec le mode de " +"facturation 'à l'expédition' et 'Une facture par expédition' !" diff --git a/partner_invoicing_mode_at_shipping/i18n/it.po b/partner_invoicing_mode_at_shipping/i18n/it.po new file mode 100644 index 00000000000..5082725eec0 --- /dev/null +++ b/partner_invoicing_mode_at_shipping/i18n/it.po @@ -0,0 +1,106 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * partner_invoicing_mode_at_shipping +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-07-15 07:37+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.6.2\n" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model.fields.selection,name:partner_invoicing_mode_at_shipping.selection__res_partner__invoicing_mode__at_shipping +msgid "At Shipping" +msgstr "Alla spedizione" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model.fields,help:partner_invoicing_mode_at_shipping.field_res_partner__one_invoice_per_shipping +#: model:ir.model.fields,help:partner_invoicing_mode_at_shipping.field_res_users__one_invoice_per_shipping +msgid "" +"Check this if you want to create one invoice per shipping using the partner " +"invoicing mode that should be different than 'At Shipping'." +msgstr "" +"Selezionare questa opzione se si vuole creare una fattura per spedizione " +"utilizzando il modo di fatturazione del partner che deve essere diverso da " +"'Alla spedizione'." + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model,name:partner_invoicing_mode_at_shipping.model_res_partner +msgid "Contact" +msgstr "Contatto" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_res_partner__invoicing_mode +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_res_users__invoicing_mode +msgid "Invoicing Mode" +msgstr "Modo fatturazione" + +#. module: partner_invoicing_mode_at_shipping +#. odoo-python +#: code:addons/partner_invoicing_mode_at_shipping/models/stock_picking.py:0 +#, python-format +msgid "Nothing to invoice." +msgstr "Nulla da fatturare." + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_res_partner__one_invoice_per_shipping +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_res_users__one_invoice_per_shipping +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_sale_order__one_invoice_per_shipping +msgid "One Invoice Per Shipping" +msgstr "Una fattura per spedizione" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model,name:partner_invoicing_mode_at_shipping.model_sale_order +msgid "Sales Order" +msgstr "Ordine di vendita" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model,name:partner_invoicing_mode_at_shipping.model_stock_move +msgid "Stock Move" +msgstr "Movimento di magazzino" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model,name:partner_invoicing_mode_at_shipping.model_stock_picking +msgid "Transfer" +msgstr "Trasferimento" + +#. module: partner_invoicing_mode_at_shipping +#. odoo-python +#: code:addons/partner_invoicing_mode_at_shipping/models/sale_order.py:0 +#, python-format +msgid "" +"Validate the invoices generated by shipping for the invoicing mode " +"%(invoicing_mode_name)s" +msgstr "" +"Validare la fattura generata dalla spedizione per il metodo di fatturazione " +"%(invoicing_mode_name)s" + +#. module: partner_invoicing_mode_at_shipping +#. odoo-python +#: code:addons/partner_invoicing_mode_at_shipping/models/res_partner.py:0 +#, python-format +msgid "" +"You cannot configure the partner %(partner)s with 'One Invoice Per Order' " +"and 'One Invoice Per Shipping'!" +msgstr "" +"Non si può configurare il partner %(partner)s con 'Una fattura per ordine' e " +"'Una fattura per spedizione'!" + +#. module: partner_invoicing_mode_at_shipping +#. odoo-python +#: code:addons/partner_invoicing_mode_at_shipping/models/res_partner.py:0 +#, python-format +msgid "" +"You cannot configure the partner %(partner)s with Invoicing Mode 'At " +"Shipping' and 'One Invoice Per Shipping'!" +msgstr "" +"Non si può configurare il partner %(partner)s con il metodo di fatturazione " +"'Alla spedizione' e 'Una fattura per spedizione'!" diff --git a/partner_invoicing_mode_at_shipping/i18n/partner_invoicing_mode_at_shipping.pot b/partner_invoicing_mode_at_shipping/i18n/partner_invoicing_mode_at_shipping.pot new file mode 100644 index 00000000000..801cb53f05f --- /dev/null +++ b/partner_invoicing_mode_at_shipping/i18n/partner_invoicing_mode_at_shipping.pot @@ -0,0 +1,94 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * partner_invoicing_mode_at_shipping +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.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: partner_invoicing_mode_at_shipping +#: model:ir.model.fields.selection,name:partner_invoicing_mode_at_shipping.selection__res_partner__invoicing_mode__at_shipping +msgid "At Shipping" +msgstr "" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model.fields,help:partner_invoicing_mode_at_shipping.field_res_partner__one_invoice_per_shipping +#: model:ir.model.fields,help:partner_invoicing_mode_at_shipping.field_res_users__one_invoice_per_shipping +msgid "" +"Check this if you want to create one invoice per shipping using the partner " +"invoicing mode that should be different than 'At Shipping'." +msgstr "" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model,name:partner_invoicing_mode_at_shipping.model_res_partner +msgid "Contact" +msgstr "" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_res_partner__invoicing_mode +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_res_users__invoicing_mode +msgid "Invoicing Mode" +msgstr "" + +#. module: partner_invoicing_mode_at_shipping +#. odoo-python +#: code:addons/partner_invoicing_mode_at_shipping/models/stock_picking.py:0 +#, python-format +msgid "Nothing to invoice." +msgstr "" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_res_partner__one_invoice_per_shipping +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_res_users__one_invoice_per_shipping +#: model:ir.model.fields,field_description:partner_invoicing_mode_at_shipping.field_sale_order__one_invoice_per_shipping +msgid "One Invoice Per Shipping" +msgstr "" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model,name:partner_invoicing_mode_at_shipping.model_sale_order +msgid "Sales Order" +msgstr "" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model,name:partner_invoicing_mode_at_shipping.model_stock_move +msgid "Stock Move" +msgstr "" + +#. module: partner_invoicing_mode_at_shipping +#: model:ir.model,name:partner_invoicing_mode_at_shipping.model_stock_picking +msgid "Transfer" +msgstr "" + +#. module: partner_invoicing_mode_at_shipping +#. odoo-python +#: code:addons/partner_invoicing_mode_at_shipping/models/sale_order.py:0 +#, python-format +msgid "" +"Validate the invoices generated by shipping for the invoicing mode " +"%(invoicing_mode_name)s" +msgstr "" + +#. module: partner_invoicing_mode_at_shipping +#. odoo-python +#: code:addons/partner_invoicing_mode_at_shipping/models/res_partner.py:0 +#, python-format +msgid "" +"You cannot configure the partner %(partner)s with 'One Invoice Per Order' " +"and 'One Invoice Per Shipping'!" +msgstr "" + +#. module: partner_invoicing_mode_at_shipping +#. odoo-python +#: code:addons/partner_invoicing_mode_at_shipping/models/res_partner.py:0 +#, python-format +msgid "" +"You cannot configure the partner %(partner)s with Invoicing Mode 'At " +"Shipping' and 'One Invoice Per Shipping'!" +msgstr "" diff --git a/partner_invoicing_mode_at_shipping/models/__init__.py b/partner_invoicing_mode_at_shipping/models/__init__.py new file mode 100644 index 00000000000..ddbf4e06b0d --- /dev/null +++ b/partner_invoicing_mode_at_shipping/models/__init__.py @@ -0,0 +1,3 @@ +from . import res_partner +from . import stock_picking +from . import sale_order diff --git a/partner_invoicing_mode_at_shipping/models/res_partner.py b/partner_invoicing_mode_at_shipping/models/res_partner.py new file mode 100644 index 00000000000..6b3351fa5d3 --- /dev/null +++ b/partner_invoicing_mode_at_shipping/models/res_partner.py @@ -0,0 +1,51 @@ +# Copyright 2020 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +from odoo import api, fields, models +from odoo.exceptions import ValidationError + + +class ResPartner(models.Model): + _inherit = "res.partner" + + invoicing_mode = fields.Selection( + selection_add=[("at_shipping", "At Shipping")], + ondelete={"at_shipping": "set default"}, + ) + + one_invoice_per_shipping = fields.Boolean( + index=True, + help="Check this if you want to create one invoice per shipping using the" + " partner invoicing mode that should be different than 'At Shipping'.", + ) + + @api.model + def _commercial_fields(self): + return super()._commercial_fields() + [ + "one_invoice_per_shipping", + ] + + @api.constrains( + "invoicing_mode", "one_invoice_per_shipping", "one_invoice_per_order" + ) + def _check_invoicing_mode_one_invoice_per_shipping(self): + for partner in self: + if ( + partner.invoicing_mode == "at_shipping" + and partner.one_invoice_per_shipping + ): + raise ValidationError( + self.env._( + "You cannot configure the partner %(partner)s with " + "Invoicing Mode 'At Shipping' and 'One Invoice Per Shipping'!", + partner=partner.name, + ), + ) + if partner.one_invoice_per_shipping and partner.one_invoice_per_order: + raise ValidationError( + self.env._( + "You cannot configure the partner %(partner)s with " + "'One Invoice Per Order' and 'One Invoice Per Shipping'!", + partner=partner.name, + ), + ) diff --git a/partner_invoicing_mode_at_shipping/models/sale_order.py b/partner_invoicing_mode_at_shipping/models/sale_order.py new file mode 100644 index 00000000000..d570971210f --- /dev/null +++ b/partner_invoicing_mode_at_shipping/models/sale_order.py @@ -0,0 +1,92 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import api, fields, models + + +class SaleOrder(models.Model): + _inherit = "sale.order" + + one_invoice_per_shipping = fields.Boolean( + compute="_compute_one_invoice_per_shipping", + store=True, + index=True, + ) + + @api.depends("partner_invoice_id") + def _compute_one_invoice_per_shipping(self): + """ + Compute this field (instead a related) to avoid computing all + related sale orders if option changed on partner level. + """ + for order in self: + order.one_invoice_per_shipping = ( + order.partner_invoice_id.one_invoice_per_shipping + ) + + def generate_invoices( + self, + companies=None, + invoicing_mode="standard", + last_execution_field="invoicing_mode_standard_last_execution", + ): + saleorders = super().generate_invoices( + companies=companies, + invoicing_mode=invoicing_mode, + last_execution_field=last_execution_field, + ) + # Validate the preceding generated invoices in draft mode. + description = self.env._( + "Validate the invoices generated by shipping for the " + "invoicing mode %(invoicing_mode_name)s" + ) + self.with_delay( + description=description + )._validate_per_shipping_generated_invoices( + companies=companies, invoicing_mode=invoicing_mode + ) + + return saleorders + + @api.model + def _validate_per_shipping_generated_invoices( + self, companies=None, invoicing_mode="standard" + ) -> str: + """ + This will validate all draft invoices that have been generated. + + :param companies: _description_, defaults to None + :type companies: _type_, optional + :param invoicing_mode: _description_, defaults to "standard" + :type invoicing_mode: str, optional + :return: String result for queue job + :rtype: AccountMove + """ + if companies is None: + companies = self.env.company + invoices = self.env["account.move"].search( + self._get_per_shipping_to_validate_invoices_domain( + companies=companies, invoicing_mode=invoicing_mode + ) + ) + for invoice in invoices: + invoice.with_delay()._validate_invoice() + for partner, __invoices in invoices.partition("partner_id").items(): + partner._update_next_invoice_date() + return ",".join(invoices.mapped("display_name")) + + def _get_per_shipping_to_validate_invoices_domain( + self, companies, invoicing_mode="standard" + ) -> list: + """ + This will return the domain for invoices that should be posted. + + :return: Domain + :rtype: list + """ + return [ + ("company_id", "in", companies.ids), + ("move_type", "in", ("out_invoice", "out_refund")), + ("state", "=", "draft"), + ("partner_id.one_invoice_per_shipping", "=", True), + ("partner_id.invoicing_mode", "=", invoicing_mode), + ] diff --git a/partner_invoicing_mode_at_shipping/models/stock_picking.py b/partner_invoicing_mode_at_shipping/models/stock_picking.py new file mode 100644 index 00000000000..74ac087ae24 --- /dev/null +++ b/partner_invoicing_mode_at_shipping/models/stock_picking.py @@ -0,0 +1,52 @@ +# Copyright 2020 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +from odoo import api, models + + +class StockPicking(models.Model): + _inherit = "stock.picking" + + def _action_done(self): + res = super()._action_done() + for picking in self: + if picking._invoice_at_shipping(): + picking.with_delay()._invoicing_at_shipping() + return res + + def _invoice_at_shipping(self): + """Check if picking must be invoiced at shipping.""" + self.ensure_one() + return self.picking_type_code == "outgoing" and ( + self.sale_id.partner_invoice_id.invoicing_mode == "at_shipping" + or self.sale_id.partner_invoice_id.one_invoice_per_shipping + ) + + def _invoicing_at_shipping_validation(self, invoices): + return invoices.filtered( + lambda invoice: invoice.partner_id.invoicing_mode == "at_shipping" + ) + + @api.model + def _invoicing_at_shipping(self): + self.ensure_one() + sales = self._get_sales_order_to_invoice() + # Split invoice creation on partner sales grouping on invoice settings + sales_one_invoice_per_order = sales.filtered( + "partner_invoice_id.one_invoice_per_order" + ) + invoices = self.env["account.move"] + if sales_one_invoice_per_order: + invoices |= sales_one_invoice_per_order._create_invoices(grouped=True) + sales_many_invoice_per_order = sales - sales_one_invoice_per_order + if sales_many_invoice_per_order: + invoices |= sales_many_invoice_per_order._create_invoices(grouped=False) + # The invoices per picking will use the invoicing_mode + for invoice in self._invoicing_at_shipping_validation(invoices): + invoice.with_delay()._validate_invoice() + return invoices or self.env._("Nothing to invoice.") + + def _get_sales_order_to_invoice(self): + return self.move_ids.sale_line_id.order_id.filtered( + lambda r: r._get_invoiceable_lines() + ) diff --git a/partner_invoicing_mode_at_shipping/pyproject.toml b/partner_invoicing_mode_at_shipping/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/partner_invoicing_mode_at_shipping/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/partner_invoicing_mode_at_shipping/readme/CONTRIBUTORS.md b/partner_invoicing_mode_at_shipping/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..fd3082e3509 --- /dev/null +++ b/partner_invoicing_mode_at_shipping/readme/CONTRIBUTORS.md @@ -0,0 +1,7 @@ +- [Camptocamp](https://www.camptocamp.com): + + > - Thierry Ducrest \<\> + +- Phuc (Tran Thanh) \<\> +- Nils Coenen \<\> +- Chau Le \<\> diff --git a/partner_invoicing_mode_at_shipping/readme/CREDITS.md b/partner_invoicing_mode_at_shipping/readme/CREDITS.md new file mode 100644 index 00000000000..c2d2a1e6b83 --- /dev/null +++ b/partner_invoicing_mode_at_shipping/readme/CREDITS.md @@ -0,0 +1,3 @@ +The development and migration of this module has been financially supported by: + +- Camptocamp diff --git a/partner_invoicing_mode_at_shipping/readme/DESCRIPTION.md b/partner_invoicing_mode_at_shipping/readme/DESCRIPTION.md new file mode 100644 index 00000000000..a59d643c323 --- /dev/null +++ b/partner_invoicing_mode_at_shipping/readme/DESCRIPTION.md @@ -0,0 +1,8 @@ +This module allows to select a At shipping invoicing mode for a +customer. It is based on partner_invoicing_mode. When this mode is +selected the customer will be invoiced automatically on delivery of the +goods. + +Another option is the 'One Invoice Per Shipping'. That one is not +compatible with the 'At shipping' invoicing mode. In that case, the +invoicing validation will occur at a different moment (monthly, ...). diff --git a/partner_invoicing_mode_at_shipping/static/description/icon.png b/partner_invoicing_mode_at_shipping/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/partner_invoicing_mode_at_shipping/static/description/icon.png differ diff --git a/partner_invoicing_mode_at_shipping/static/description/index.html b/partner_invoicing_mode_at_shipping/static/description/index.html new file mode 100644 index 00000000000..81aeb998cb3 --- /dev/null +++ b/partner_invoicing_mode_at_shipping/static/description/index.html @@ -0,0 +1,450 @@ + + + + + +Partner Invoicing Mode At Shipping + + + +
+

Partner Invoicing Mode At Shipping

+ + +

Beta License: AGPL-3 OCA/account-invoicing Translate me on Weblate Try me on Runboat

+

This module allows to select a At shipping invoicing mode for a +customer. It is based on partner_invoicing_mode. When this mode is +selected the customer will be invoiced automatically on delivery of the +goods.

+

Another option is the ‘One Invoice Per Shipping’. That one is not +compatible with the ‘At shipping’ invoicing mode. In that case, the +invoicing validation will occur at a different moment (monthly, …).

+

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

+
    +
  • Camptocamp
  • +
+
+
+

Contributors

+ +
+
+

Other credits

+

The development and migration of this module has been financially +supported by:

+
    +
  • Camptocamp
  • +
+
+
+

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.

+

This module is part of the OCA/account-invoicing project on GitHub.

+

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

+
+
+
+ + diff --git a/partner_invoicing_mode_at_shipping/tests/__init__.py b/partner_invoicing_mode_at_shipping/tests/__init__.py new file mode 100644 index 00000000000..5fa78f34aa5 --- /dev/null +++ b/partner_invoicing_mode_at_shipping/tests/__init__.py @@ -0,0 +1 @@ +from . import test_invoice_mode_at_shipping, test_invoice_mode_group_delivery diff --git a/partner_invoicing_mode_at_shipping/tests/common.py b/partner_invoicing_mode_at_shipping/tests/common.py new file mode 100644 index 00000000000..17d5192d86f --- /dev/null +++ b/partner_invoicing_mode_at_shipping/tests/common.py @@ -0,0 +1,33 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo.addons.partner_invoicing_mode.tests.common import CommonPartnerInvoicingMode + + +class InvoiceModeAtShippingCommon(CommonPartnerInvoicingMode): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls._create_order() + + @classmethod + def _create_order(cls): + cls.so1 = cls.env["sale.order"].create( + { + "partner_id": cls.partner.id, + "partner_invoice_id": cls.partner.id, + "partner_shipping_id": cls.partner.id, + "order_line": [ + ( + 0, + 0, + { + "name": "Line one", + "product_id": cls.product.id, + "product_uom_qty": 4, + "product_uom": cls.product.uom_id.id, + "price_unit": 123, + }, + ) + ], + } + ) diff --git a/partner_invoicing_mode_at_shipping/tests/test_invoice_mode_at_shipping.py b/partner_invoicing_mode_at_shipping/tests/test_invoice_mode_at_shipping.py new file mode 100644 index 00000000000..4e8578d5019 --- /dev/null +++ b/partner_invoicing_mode_at_shipping/tests/test_invoice_mode_at_shipping.py @@ -0,0 +1,100 @@ +# Copyright 2020 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +from odoo.tools import mute_logger + +from .common import InvoiceModeAtShippingCommon + + +class TestInvoiceModeAtShipping(InvoiceModeAtShippingCommon): + def test_invoice_created_at_shipping(self): + """Check that an invoice is created when goods are shipped.""" + self.partner.invoicing_mode = "at_shipping" + self.so1.action_confirm() + for picking in self.so1.picking_ids: + for move in picking.move_ids: + move.quantity = move.product_uom_qty + picking.action_assign() + with mute_logger("odoo.addons.queue_job.delay"): + picking.with_context(queue_job__no_delay=True).button_validate() + self.assertEqual(len(self.so1.invoice_ids), 1) + self.assertEqual(self.so1.invoice_ids.state, "posted") + + def test_invoice_not_created_at_shipping(self): + """Check that an invoice is not created when goods are shipped.""" + self.partner.invoicing_mode = "standard" + self.so1.action_confirm() + for picking in self.so1.picking_ids: + for move in picking.move_ids: + move.quantity = move.product_uom_qty + picking.action_assign() + with mute_logger("odoo.addons.queue_job.delay"): + picking.with_context(queue_job__no_delay=True).button_validate() + self.assertEqual(len(self.so1.invoice_ids), 0) + + def test_picking_multi_order_single_invoice(self): + """A picking for more than one sale order creating a single invoice""" + self.partner.invoicing_mode = "at_shipping" + self.partner.one_invoice_per_order = False + for order in self.so1, self.so2: + order.action_confirm() + + # Effectively merge both pickings + picking = self.so1.picking_ids + self.so2.picking_ids.move_ids.picking_id = picking + # Transfer the remaining picking with moves + for move in picking.move_ids: + move.quantity = move.product_uom_qty + picking.action_assign() + with mute_logger("odoo.addons.queue_job.delay"): + picking.with_context(queue_job__no_delay=True).button_validate() + self.assertEqual(len(self.so1.invoice_ids), 1) + self.assertEqual(self.so1.invoice_ids.state, "posted") + self.assertEqual(self.so1.invoice_ids, self.so2.invoice_ids) + + def test_picking_multi_order_multi_invoice(self): + """A picking for more than one sale order creates more than one invoice""" + self.partner.invoicing_mode = "at_shipping" + self.partner.one_invoice_per_order = True + for order in self.so1, self.so2: + order.action_confirm() + + # Effectively merge both pickings + picking = self.so1.picking_ids + self.so2.picking_ids.move_ids.picking_id = picking + # Transfer the remaining picking with moves + for move in picking.move_ids: + move.quantity = move.product_uom_qty + picking.action_assign() + with mute_logger("odoo.addons.queue_job.delay"): + picking.with_context(queue_job__no_delay=True).button_validate() + self.assertEqual(len(self.so1.invoice_ids), 1) + self.assertEqual(self.so1.invoice_ids.state, "posted") + self.assertEqual(len(self.so2.invoice_ids), 1) + self.assertEqual(self.so2.invoice_ids.state, "posted") + self.assertNotEqual(self.so1.invoice_ids, self.so2.invoice_ids) + + def test_picking_backorder(self): + """In case of a backorder, another invoice is created""" + self.partner.invoicing_mode = "at_shipping" + self.so1.action_confirm() + picking = self.so1.picking_ids + picking.move_ids.quantity = 2 + picking.action_assign() + with mute_logger("odoo.addons.queue_job.delay"): + picking.with_context( + skip_backorder=True, queue_job__no_delay=True + ).button_validate() + self.assertEqual(len(self.so1.invoice_ids), 1) + self.assertEqual(self.so1.invoice_ids.state, "posted") + + # Now process the backorder + backorder = self.so1.picking_ids - picking + backorder.move_ids.quantity = 2 + backorder.action_assign() + with mute_logger("odoo.addons.queue_job.delay"): + backorder.with_context(queue_job__no_delay=True).button_validate() + self.assertEqual(len(self.so1.invoice_ids), 2) + self.assertTrue( + all(invoice.state == "posted") for invoice in self.so1.invoice_ids + ) diff --git a/partner_invoicing_mode_at_shipping/tests/test_invoice_mode_group_delivery.py b/partner_invoicing_mode_at_shipping/tests/test_invoice_mode_group_delivery.py new file mode 100644 index 00000000000..94f9c2bb16b --- /dev/null +++ b/partner_invoicing_mode_at_shipping/tests/test_invoice_mode_group_delivery.py @@ -0,0 +1,87 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.exceptions import ValidationError + +from odoo.addons.queue_job.tests.common import trap_jobs + +from .common import InvoiceModeAtShippingCommon + + +class TestInvoiceModeAtShippingGrouped(InvoiceModeAtShippingCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.companies = cls.env["res.company"].search([]) + + def test_invoice_created_at_shipping_per_delivery(self): + """Check that an invoice is created when goods are shipped.""" + self.partner.invoicing_mode = "standard" + self.partner.one_invoice_per_shipping = True + self._create_order() + self.so1.action_confirm() + picking = self.so1.picking_ids + + # Deliver partially + picking.move_ids.write({"quantity": 2.0, "picked": True}) + with trap_jobs() as trap: + picking._action_done() + trap.assert_enqueued_job( + picking._invoicing_at_shipping, + ) + trap.perform_enqueued_jobs() + + self.assertEqual(picking.state, "done") + invoice = self.so1.invoice_ids + # Invoice is generated but is still draft + self.assertEqual( + "draft", + invoice.state, + ) + + backorder = self.so1.picking_ids - picking + self.assertTrue(backorder) + + backorder.move_ids.write({"quantity": 2.0, "picked": True}) + with trap_jobs() as trap: + backorder._action_done() + trap.assert_enqueued_job( + backorder._invoicing_at_shipping, + ) + with trap_jobs() as trap_invoice: + trap.perform_enqueued_jobs() + self.assertFalse(trap_invoice.enqueued_jobs) + invoice_2 = self.so1.invoice_ids - invoice + self.assertEqual( + "draft", + invoice_2.state, + ) + # Launch the invoicing + with trap_jobs() as trap: + self.env["sale.order"].cron_generate_standard_invoices() + trap.assert_enqueued_job( + self.env["sale.order"]._validate_per_shipping_generated_invoices, + args=(), + kwargs={"companies": self.companies, "invoicing_mode": "standard"}, + ) + with trap_jobs() as trap_invoice: + trap.perform_enqueued_jobs() + trap_invoice.assert_enqueued_job( + self.so1.invoice_ids[0]._validate_invoice + ) + trap_invoice.assert_enqueued_job( + self.so1.invoice_ids[1]._validate_invoice + ) + trap_invoice.perform_enqueued_jobs() + self.assertEqual("posted", invoice.state) + self.assertEqual("posted", invoice_2.state) + + def test_invoice_created_at_shipping_per_delivery_constrains(self): + with self.assertRaises(ValidationError): + self.partner.write( + {"one_invoice_per_shipping": True, "invoicing_mode": "at_shipping"} + ) + with self.assertRaises(ValidationError): + self.partner.write( + {"one_invoice_per_order": True, "one_invoice_per_shipping": True} + ) diff --git a/partner_invoicing_mode_at_shipping/views/res_partner.xml b/partner_invoicing_mode_at_shipping/views/res_partner.xml new file mode 100644 index 00000000000..00ebcef0dfb --- /dev/null +++ b/partner_invoicing_mode_at_shipping/views/res_partner.xml @@ -0,0 +1,18 @@ + + + + + view_partner_property_form + res.partner + + + + + + + + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000000..180fc49789b --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +# generated from manifests external_dependencies +openupgradelib diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 00000000000..0976c085bbc --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,2 @@ +odoo-addon-base_partition @ git+https://github.com/OCA/server-tools.git@refs/pull/3077/head#subdirectory=base_partition +odoo-addon-partner_invoicing_mode @ git+https://github.com/OCA/account-invoicing.git@refs/pull/1833/head#subdirectory=partner_invoicing_mode