From e9e547fdb8b61739987fc0dba516efedd0cd1248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 10 Sep 2022 17:35:38 +0200 Subject: [PATCH] Add carrier_carriage module issue11623 review443451003 --- __init__.py | 3 ++ message.xml | 3 -- sale.py | 37 +++++++------ stock.py | 104 ++++++++++++++++++++++++------------- view/shipment_out_form.xml | 2 +- 5 files changed, 91 insertions(+), 58 deletions(-) diff --git a/__init__.py b/__init__.py index ead2a34770..6c2f1cd6e1 100644 --- a/__init__.py +++ b/__init__.py @@ -4,6 +4,9 @@ from trytond.pool import Pool from . import account, party, sale, stock +from .stock import ShipmentCostSaleMixin + +__all__ = ['register', 'ShipmentCostSaleMixin'] def register(): diff --git a/message.xml b/message.xml index 720ef46876..7b6020a990 100644 --- a/message.xml +++ b/message.xml @@ -6,9 +6,6 @@ this repository contains the full copyright notices and license terms. --> To confirm sale "%(sale)s" you must change the carrier "%(carrier)s". - - A sale can have only one shipment cost line. - To invoice shipment cost of "%(shipment)s", you must define an account revenue for product "%(product)s". diff --git a/sale.py b/sale.py index b07d9a0e29..45e81190d3 100644 --- a/sale.py +++ b/sale.py @@ -4,7 +4,7 @@ from decimal import Decimal from trytond import backend from trytond.i18n import gettext -from trytond.model import ModelView, Unique, Workflow, fields +from trytond.model import ModelView, Workflow, fields from trytond.modules.product import price_digits, round_price from trytond.modules.sale.exceptions import SaleConfirmError from trytond.pool import Pool, PoolMeta @@ -214,10 +214,10 @@ class Sale(metaclass=PoolMeta): with Transaction().set_context(_shipment_cost_invoiced=list()): super().process(sales) - def _get_carrier_context(self): + def _get_carrier_context(self, carrier): return {} - def compute_shipment_cost(self): + def compute_shipment_cost(self, carrier): pool = Pool() Date = pool.get('ir.date') Currency = pool.get('currency.currency') @@ -227,9 +227,9 @@ class Sale(metaclass=PoolMeta): if line.type == 'line' and line.product and line.product.type in Line.get_move_product_types()) - if self.carrier and stockable: - with Transaction().set_context(self._get_carrier_context()): - cost, currency_id = self.carrier.get_sale_price() + if stockable: + with Transaction().set_context(self._get_carrier_context(carrier)): + cost, currency_id = carrier.get_sale_price() if cost is not None: with Transaction().set_context(company=self.company.id): today = Date.today() @@ -241,8 +241,8 @@ class Sale(metaclass=PoolMeta): def set_shipment_cost(self): cost = None - if self.shipment_cost_method: - cost = self.compute_shipment_cost() + if self.carrier and self.shipment_cost_method: + cost = self.compute_shipment_cost(self.carrier) removed = [] unit_price = None lines = list(self.lines or []) @@ -254,15 +254,15 @@ class Sale(metaclass=PoolMeta): removed.append(line) if cost is not None: lines.append(self.get_shipment_cost_line( - cost, unit_price=unit_price)) + self.carrier, cost, unit_price=unit_price)) self.lines = lines return removed - def get_shipment_cost_line(self, cost, unit_price=None): + def get_shipment_cost_line(self, carrier, cost, unit_price=None): pool = Pool() SaleLine = pool.get('sale.line') - product = self.carrier.carrier_product + product = carrier.carrier_product sequence = None if self.lines: @@ -319,15 +319,18 @@ class Line(metaclass=PoolMeta): @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'), - ] # shipment_cost is needed to compute the unit_price cls.unit_price.depends.add('shipment_cost') + @classmethod + def __register__(cls, module): + table_h = cls.__table_handler__(module) + + super().__register__(module) + + # Migration from 6.4: drop shipment cost unique + table_h.drop_constraint('sale_shipment_cost_unique') + @fields.depends('shipment_cost', 'unit_price') def compute_unit_price(self): unit_price = super().compute_unit_price() diff --git a/stock.py b/stock.py index f1330906f3..06209e7dc7 100644 --- a/stock.py +++ b/stock.py @@ -10,14 +10,15 @@ from trytond.transaction import Transaction from .exceptions import InvoiceShipmentCostError -class ShipmentOut(metaclass=PoolMeta): - __name__ = 'stock.shipment.out' +class ShipmentCostSaleMixin: + __slots__ = () cost_sale_currency_used = fields.Function(fields.Many2One( 'currency.currency', "Cost Sale Currency", states={ 'invisible': Eval('cost_method') != 'shipment', - 'readonly': (Eval('state').in_(['done', 'cancelled']) + 'readonly': ( + Eval('shipment_cost_sale_readonly', True) | ~Eval('cost_edit', False)), }), 'on_change_with_cost_sale_currency_used', setter='set_cost') @@ -26,13 +27,14 @@ class ShipmentOut(metaclass=PoolMeta): states={ 'invisible': Eval('cost_method') != 'shipment', 'required': Bool(Eval('cost_sale')), - 'readonly': Eval('state').in_(['done', 'cancelled']), + 'readonly': Eval('shipment_cost_sale_readonly', True), }) cost_sale_used = fields.Function(fields.Numeric( "Cost Sale", digits=price_digits, states={ 'invisible': Eval('cost_method') != 'shipment', - 'readonly': (Eval('state').in_(['done', 'cancelled']) + 'readonly': ( + Eval('shipment_cost_sale_readonly', True) | ~Eval('cost_edit', False)), }), 'on_change_with_cost_sale_used', setter='set_cost') @@ -42,34 +44,17 @@ class ShipmentOut(metaclass=PoolMeta): 'invisible': Eval('cost_method') != 'shipment', }) - cost_invoice_line = fields.Many2One('account.invoice.line', - 'Cost Invoice Line', readonly=True) + cost_invoice_line = fields.Many2One( + 'account.invoice.line', "Cost Invoice Line", readonly=True) cost_method = fields.Selection( - 'get_cost_methods', 'Cost Method', readonly=True) + 'get_cost_methods', "Cost Method", readonly=True) - @classmethod - def __register__(cls, module): - table_h = cls.__table_handler__(module) - cursor = Transaction().connection.cursor() - table = cls.__table__() + shipment_cost_sale_readonly = fields.Function( + fields.Boolean("Shipment Cost Sale Read Only"), + 'on_change_with_shipment_cost_sale_readonly') - # Migration from 5.8: rename cost into cost_sale - if (table_h.column_exist('cost') - and not table_h.column_exist('cost_sale')): - table_h.column_rename('cost', 'cost_sale') - if (table_h.column_exist('cost_currency') - and not table_h.column_exist('cost_sale_currency')): - table_h.column_rename('cost_currency', 'cost_sale_currency') - - cost_method_exists = table_h.column_exist('cost_method') - - super().__register__(module) - - # Migration from 6.0: fill new cost_method field - if not cost_method_exists: - cursor.execute(*table.update( - columns=[table.cost_method], - values=['shipment'])) + def on_change_with_shipment_cost_sale_readonly(self, name=None): + raise NotImplementedError @fields.depends('carrier', 'cost_method', methods=['_get_carrier_context']) def _compute_costs(self): @@ -87,17 +72,19 @@ class ShipmentOut(metaclass=PoolMeta): return costs @fields.depends( - 'state', 'cost_sale', 'cost_edit', methods=['_compute_costs']) + 'shipment_cost_sale_readonly', 'cost_sale', 'cost_edit', + methods=['_compute_costs']) def on_change_with_cost_sale_used(self, name=None): - if not self.cost_edit and self.state not in {'cancelled', 'done'}: + if not self.cost_edit and not self.shipment_cost_sale_readonly: return self._compute_costs()['cost_sale'] else: return self.cost_sale @fields.depends( - 'state', 'cost_sale_currency', 'cost_edit', methods=['_compute_costs']) + 'shipment_cost_sale_readonly', 'cost_sale_currency', 'cost_edit', + methods=['_compute_costs']) def on_change_with_cost_sale_currency_used(self, name=None): - if not self.cost_edit and self.state not in {'cancelled', 'done'}: + if not self.cost_edit and not self.shipment_cost_sale_readonly: return self._compute_costs()['cost_sale_currency'] elif self.cost_sale_currency: return self.cost_sale_currency.id @@ -135,7 +122,6 @@ class ShipmentOut(metaclass=PoolMeta): 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( @@ -155,8 +141,46 @@ class ShipmentOut(metaclass=PoolMeta): self.cost_sale_currency, self.cost_sale, self.company.currency, round=False) cost -= cost_sale - elif self.cost_method == 'order': - sales = {m.sale for m in self.outgoing_moves if m.sale} + return cost + + +class ShipmentOut(ShipmentCostSaleMixin, metaclass=PoolMeta): + __name__ = 'stock.shipment.out' + + @classmethod + def __register__(cls, module): + table_h = cls.__table_handler__(module) + cursor = Transaction().connection.cursor() + table = cls.__table__() + + # Migration from 5.8: rename cost into cost_sale + if (table_h.column_exist('cost') + and not table_h.column_exist('cost_sale')): + table_h.column_rename('cost', 'cost_sale') + if (table_h.column_exist('cost_currency') + and not table_h.column_exist('cost_sale_currency')): + table_h.column_rename('cost_currency', 'cost_sale_currency') + + cost_method_exists = table_h.column_exist('cost_method') + + super().__register__(module) + + # Migration from 6.0: fill new cost_method field + if not cost_method_exists: + cursor.execute(*table.update( + columns=[table.cost_method], + values=['shipment'])) + + @fields.depends('state') + def on_change_with_shipment_cost_sale_readonly(self, name=None): + return self.state in {'done', 'cancelled'} + + def _get_shipment_cost(self): + cost = super()._get_shipment_cost() + if self.cost_method == 'order': + sales = { + m.sale for m in self.outgoing_moves + if m.sale and m.sale.shipment_cost_method == 'order'} for sale in sales: shipment_cost = sum( (s.cost_used or 0) for s in sale.shipments @@ -165,6 +189,12 @@ class ShipmentOut(metaclass=PoolMeta): cost -= max(cost_sale - shipment_cost, 0) return cost + def get_cost_invoice_line(self, invoice): + invoice_line = super().get_cost_invoice_line(invoice) + if invoice_line: + invoice_line.cost_shipments = [self] + return invoice_line + @classmethod @ModelView.button @Workflow.transition('done') diff --git a/view/shipment_out_form.xml b/view/shipment_out_form.xml index 924706c24b..ff721ebf64 100644 --- a/view/shipment_out_form.xml +++ b/view/shipment_out_form.xml @@ -6,7 +6,7 @@ this repository contains the full copyright notices and license terms. -->