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