Initial commit: Odoo 18.0-20251222 extra-addons
Some checks failed
pre-commit / pre-commit (push) Has been cancelled
tests / Detect unreleased dependencies (push) Has been cancelled
tests / test with OCB (push) Has been cancelled
tests / test with Odoo (push) Has been cancelled

This commit is contained in:
tocmo0nlord
2026-03-13 20:43:25 +00:00
parent 36e847a7df
commit adbe430761
9472 changed files with 1265727 additions and 0 deletions

View File

@@ -0,0 +1,103 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association
==================================
Partner Invoicing Mode At Shipping
==================================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:16c4a3109be6a2c99f0bc01e5a245a479a985547e144fca59f0994796dd377dc
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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/license-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 <https://github.com/OCA/account-invoicing/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 <https://github.com/OCA/account-invoicing/issues/new?body=module:%20partner_invoicing_mode_at_shipping%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
-------
* Camptocamp
Contributors
------------
- `Camptocamp <https://www.camptocamp.com>`__:
- Thierry Ducrest <thierry.ducrest@camptocamp.com>
- Phuc (Tran Thanh) <phuc@trobz.com>
- Nils Coenen <nils.coenen@nico-solutions.de>
- Chau Le <chaulb@trobz.com>
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 <https://github.com/OCA/account-invoicing/tree/18.0/partner_invoicing_mode_at_shipping>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@@ -0,0 +1,2 @@
from . import models
from .hooks import pre_init_hook

View File

@@ -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.1",
"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",
}

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!-- Queue Job Channel -->
<record id="invoice_at_shipping" model="queue.job.channel">
<field name="name">invoice_at_shipping</field>
<field name="parent_id" ref="queue_job.channel_root" />
</record>
<!-- Job Functions -->
<record id="job_function_invoicing_at_shipping" model="queue.job.function">
<field name="model_id" ref="stock.model_stock_picking" />
<field name="method">_invoicing_at_shipping</field>
<field name="channel_id" ref="invoice_at_shipping" />
</record>
</odoo>

View File

@@ -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)

View File

@@ -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 <anna080678@gmail.com>\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 ""

View File

@@ -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 <sami.bouzidi@camptocamp.com>\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' !"

View File

@@ -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 <stefano.consolaro@mymage.it>\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'!"

View File

@@ -0,0 +1,85 @@
# 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 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: 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
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_picking
msgid "Transfer"
msgstr ""
#. module: partner_invoicing_mode_at_shipping
#. odoo-python
#: code:addons/partner_invoicing_mode_at_shipping/models/sale_order.py:0
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
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
msgid ""
"You cannot configure the partner %(partner)s with Invoicing Mode 'At "
"Shipping' and 'One Invoice Per Shipping'!"
msgstr ""

View File

@@ -0,0 +1,13 @@
# Copyright 2023 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from openupgradelib import openupgrade
# pylint: disable=odoo-addons-relative-import
from odoo.addons.partner_invoicing_mode_at_shipping.hooks import (
_add_one_invoice_per_shipping,
)
@openupgrade.migrate()
def migrate(env, version):
_add_one_invoice_per_shipping(env)

View File

@@ -0,0 +1,3 @@
from . import res_partner
from . import stock_picking
from . import sale_order

View File

@@ -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,
),
)

View File

@@ -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),
]

View File

@@ -0,0 +1,56 @@
# 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.sudo()._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.sudo()._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()
)

View File

@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"

View File

@@ -0,0 +1,7 @@
- [Camptocamp](https://www.camptocamp.com):
> - Thierry Ducrest \<<thierry.ducrest@camptocamp.com>\>
- Phuc (Tran Thanh) \<<phuc@trobz.com>\>
- Nils Coenen \<<nils.coenen@nico-solutions.de>\>
- Chau Le \<<chaulb@trobz.com>\>

View File

@@ -0,0 +1,3 @@
The development and migration of this module has been financially supported by:
- Camptocamp

View File

@@ -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, ...).

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -0,0 +1,456 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>README.rst</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic, pre.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document">
<a class="reference external image-reference" href="https://odoo-community.org/get-involved?utm_source=readme">
<img alt="Odoo Community Association" src="https://odoo-community.org/readme-banner-image" />
</a>
<div class="section" id="partner-invoicing-mode-at-shipping">
<h1>Partner Invoicing Mode At Shipping</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:16c4a3109be6a2c99f0bc01e5a245a479a985547e144fca59f0994796dd377dc
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/license-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/account-invoicing/tree/18.0/partner_invoicing_mode_at_shipping"><img alt="OCA/account-invoicing" src="https://img.shields.io/badge/github-OCA%2Faccount--invoicing-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/account-invoicing-18-0/account-invoicing-18-0-partner_invoicing_mode_at_shipping"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/account-invoicing&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>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.</p>
<p>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, …).</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-1">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-2">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-3">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-4">Contributors</a></li>
<li><a class="reference internal" href="#other-credits" id="toc-entry-5">Other credits</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-6">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h2><a class="toc-backref" href="#toc-entry-1">Bug Tracker</a></h2>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/account-invoicing/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/account-invoicing/issues/new?body=module:%20partner_invoicing_mode_at_shipping%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h2><a class="toc-backref" href="#toc-entry-2">Credits</a></h2>
<div class="section" id="authors">
<h3><a class="toc-backref" href="#toc-entry-3">Authors</a></h3>
<ul class="simple">
<li>Camptocamp</li>
</ul>
</div>
<div class="section" id="contributors">
<h3><a class="toc-backref" href="#toc-entry-4">Contributors</a></h3>
<ul>
<li><p class="first"><a class="reference external" href="https://www.camptocamp.com">Camptocamp</a>:</p>
<blockquote>
<ul class="simple">
<li>Thierry Ducrest &lt;<a class="reference external" href="mailto:thierry.ducrest&#64;camptocamp.com">thierry.ducrest&#64;camptocamp.com</a>&gt;</li>
</ul>
</blockquote>
</li>
<li><p class="first">Phuc (Tran Thanh) &lt;<a class="reference external" href="mailto:phuc&#64;trobz.com">phuc&#64;trobz.com</a>&gt;</p>
</li>
<li><p class="first">Nils Coenen &lt;<a class="reference external" href="mailto:nils.coenen&#64;nico-solutions.de">nils.coenen&#64;nico-solutions.de</a>&gt;</p>
</li>
<li><p class="first">Chau Le &lt;<a class="reference external" href="mailto:chaulb&#64;trobz.com">chaulb&#64;trobz.com</a>&gt;</p>
</li>
</ul>
</div>
<div class="section" id="other-credits">
<h3><a class="toc-backref" href="#toc-entry-5">Other credits</a></h3>
<p>The development and migration of this module has been financially
supported by:</p>
<ul class="simple">
<li>Camptocamp</li>
</ul>
</div>
<div class="section" id="maintainers">
<h3><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h3>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>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.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/account-invoicing/tree/18.0/partner_invoicing_mode_at_shipping">OCA/account-invoicing</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1 @@
from . import test_invoice_mode_at_shipping, test_invoice_mode_group_delivery

View File

@@ -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,
},
)
],
}
)

View File

@@ -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.utils"):
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.utils"):
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.utils"):
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.utils"):
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.utils"):
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.utils"):
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
)

View File

@@ -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}
)

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!-- Copyright 2023 ACSONE SA/NV
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="view_partner_property_form" model="ir.ui.view">
<field name="name">view_partner_property_form</field>
<field name="model">res.partner</field>
<field
name="inherit_id"
ref="partner_invoicing_mode.view_partner_property_form"
/>
<field name="arch" type="xml">
<field name="one_invoice_per_order" position="after">
<field name="one_invoice_per_shipping" />
</field>
</field>
</record>
</odoo>