changeset 0680360327f9 in modules/sale_shipment_cost:default
details: 
https://hg.tryton.org/modules/sale_shipment_cost?cmd=changeset&node=0680360327f9
description:
        Create invoice line cost for shipment from sale line

        issue10799
        review350741002
diffstat:

 __init__.py                           |   2 +
 account.py                            |  12 +++++
 message.xml                           |   3 +
 sale.py                               |  74 +++++++++++++++++++++-------------
 stock.py                              |   1 +
 tests/scenario_sale_shipment_cost.rst |   3 +
 6 files changed, 67 insertions(+), 28 deletions(-)

diffs (183 lines):

diff -r 0afe01c0fac8 -r 0680360327f9 __init__.py
--- a/__init__.py       Sun Oct 10 22:42:47 2021 +0200
+++ b/__init__.py       Mon Oct 11 18:47:59 2021 +0200
@@ -2,12 +2,14 @@
 # this repository contains the full copyright notices and license terms.
 
 from trytond.pool import Pool
+from . import account
 from . import sale
 from . import stock
 
 
 def register():
     Pool.register(
+        account.InvoiceLine,
         sale.Configuration,
         sale.ConfigurationSaleMethod,
         sale.Sale,
diff -r 0afe01c0fac8 -r 0680360327f9 account.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/account.py        Mon Oct 11 18:47:59 2021 +0200
@@ -0,0 +1,12 @@
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+from trytond.model import fields
+from trytond.pool import PoolMeta
+
+
+class InvoiceLine(metaclass=PoolMeta):
+    __name__ = 'account.invoice.line'
+
+    cost_shipments = fields.One2Many(
+        'stock.shipment.out', 'cost_invoice_line', "Cost of Shipments",
+        readonly=True)
diff -r 0afe01c0fac8 -r 0680360327f9 message.xml
--- a/message.xml       Sun Oct 10 22:42:47 2021 +0200
+++ b/message.xml       Mon Oct 11 18:47:59 2021 +0200
@@ -6,6 +6,9 @@
         <record model="ir.message" id="msg_sale_invalid_carrier">
             <field name="text">To confirm sale "%(sale)s" you must change the 
carrier "%(carrier)s".</field>
         </record>
+        <record model="ir.message" id="msg_sale_shipment_cost_unique">
+            <field name="text">A sale can have only one shipment cost 
line.</field>
+        </record>
         <record model="ir.message" 
id="msg_shipment_cost_invoice_missing_account_revenue">
             <field name="text">To invoice shipment cost of "%(shipment)s", you 
must define an account revenue for product "%(product)s".</field>
         </record>
diff -r 0afe01c0fac8 -r 0680360327f9 sale.py
--- a/sale.py   Sun Oct 10 22:42:47 2021 +0200
+++ b/sale.py   Mon Oct 11 18:47:59 2021 +0200
@@ -4,7 +4,7 @@
 
 from trytond import backend
 from trytond.i18n import gettext
-from trytond.model import ModelView, Workflow, fields
+from trytond.model import ModelView, Workflow, Unique, fields
 from trytond.transaction import Transaction
 from trytond.pyson import Eval, If
 from trytond.pool import Pool, PoolMeta
@@ -205,6 +205,12 @@
                         carrier=sale.carrier.rec_name))
         super(Sale, cls).confirm(sales)
 
+    @classmethod
+    @ModelView.button
+    def process(cls, sales):
+        with Transaction().set_context(_shipment_cost_invoiced=set()):
+            super().process(sales)
+
     def _get_carrier_context(self):
         return {}
 
@@ -301,47 +307,59 @@
             shipment.carrier = self.carrier
         return shipment
 
-    def create_invoice(self):
-        pool = Pool()
-        InvoiceLine = pool.get('account.invoice.line')
-        Shipment = pool.get('stock.shipment.out')
-
-        invoice = super().create_invoice()
-        if invoice and self.shipment_cost_method == 'shipment':
-            invoice_lines = []
-            # Copy shipments to avoid losing changes as the cache is cleared
-            # after invoice line save because shipment is a Function field
-            shipments = list(self.shipments)
-            for shipment in shipments:
-                if (shipment.state == 'done'
-                        and shipment.carrier
-                        and not shipment.cost_invoice_line):
-                    invoice_line = shipment.get_cost_invoice_line(invoice)
-                    if not invoice_line:
-                        continue
-                    invoice_line.invoice = invoice
-                    invoice_lines.append(invoice_line)
-                    shipment.cost_invoice_line = invoice_line
-            InvoiceLine.save(invoice_lines)
-            Shipment.save(shipments)
-        return invoice
-
 
 class Line(metaclass=PoolMeta):
     __name__ = 'sale.line'
     shipment_cost = fields.Numeric('Shipment Cost', digits=price_digits)
 
+    @classmethod
+    def __setup__(cls):
+        super().__setup__()
+        t = cls.__table__()
+        cls._sql_constraints += [
+            ('sale_shipment_cost_unique',
+                Unique(t, t.sale, t.shipment_cost),
+                'sale_shipment_cost.msg_sale_shipment_cost_unique'),
+            ]
+
+    def get_invoice_line(self):
+        context = Transaction().context
+        shipment_cost_invoiced = context.get('_shipment_cost_invoiced')
+        lines = super().get_invoice_line()
+        if (self.sale.shipment_cost_method == 'shipment'
+                and self.shipment_cost
+                and shipment_cost_invoiced is not None):
+            for shipment in self.sale.shipments:
+                if (shipment.state == 'done'
+                        and shipment.carrier
+                        and not shipment.cost_invoice_line
+                        and shipment.id not in shipment_cost_invoiced):
+                    invoice_line = shipment.get_cost_invoice_line(
+                        self.sale._get_invoice_sale())
+                    if invoice_line:
+                        invoice_line.origin = self
+                        lines.append(invoice_line)
+                        shipment_cost_invoiced.add(shipment.id)
+        return lines
+
     def _get_invoice_line_quantity(self):
         quantity = super()._get_invoice_line_quantity()
         if self.shipment_cost:
             if self.sale.shipment_cost_method == 'shipment':
-                return 0
+                quantity = 0
             elif (self.sale.shipment_cost_method == 'order'
                     and self.sale.invoice_method == 'shipment'):
                 shipments = self.sale.shipments
                 if (not shipments
                         or all(s.state != 'done' for s in shipments)):
-                    return 0
+                    quantity = 0
+        return quantity
+
+    def _get_invoiced_quantity(self):
+        quantity = super()._get_invoiced_quantity()
+        if self.shipment_cost:
+            if self.sale.shipment_cost_method == 'shipment':
+                quantity = 0
         return quantity
 
 
diff -r 0afe01c0fac8 -r 0680360327f9 stock.py
--- a/stock.py  Sun Oct 10 22:42:47 2021 +0200
+++ b/stock.py  Mon Oct 11 18:47:59 2021 +0200
@@ -152,6 +152,7 @@
         invoice_line.unit_price = round_price(cost)
         invoice_line.product = product
         invoice_line.on_change_product()
+        invoice_line.cost_shipments = [self]
 
         if not invoice_line.account:
             raise InvoiceShipmentCostError(
diff -r 0afe01c0fac8 -r 0680360327f9 tests/scenario_sale_shipment_cost.rst
--- a/tests/scenario_sale_shipment_cost.rst     Sun Oct 10 22:42:47 2021 +0200
+++ b/tests/scenario_sale_shipment_cost.rst     Mon Oct 11 18:47:59 2021 +0200
@@ -170,6 +170,9 @@
     >>> shipment.state
     'done'
 
+    >>> shipment.cost_invoice_line.amount
+    Decimal('3.00')
+
 Check customer invoice::
 
     >>> sale.reload()

Reply via email to