diff --git a/modules/carrier_carriage/__init__.py b/modules/carrier_carriage/__init__.py index 5c2c8eef28..46c0820717 100644 --- a/modules/carrier_carriage/__init__.py +++ b/modules/carrier_carriage/__init__.py @@ -18,6 +18,7 @@ def register(): sale.Sale, sale.Line, sale.Carriage, + stock.ShipmentCostSale, stock.Carriage_Sale, account.InvoiceLine, module='carrier_carriage', type_='model', diff --git a/modules/carrier_carriage/sale.py b/modules/carrier_carriage/sale.py index 139954856a..83aee852c4 100644 --- a/modules/carrier_carriage/sale.py +++ b/modules/carrier_carriage/sale.py @@ -98,6 +98,13 @@ class Sale(metaclass=PoolMeta): default.setdefault('after_carriages') return super().copy(sales, default=default) + @property + def _cost_shipments(self): + shipments = super()._cost_shipments + for shipment in self.shipments: + shipments.extend(shipment.carriages) + return shipments + class Line(metaclass=PoolMeta): __name__ = 'sale.line' diff --git a/modules/carrier_carriage/stock.py b/modules/carrier_carriage/stock.py index 27607a9f8b..27584de782 100644 --- a/modules/carrier_carriage/stock.py +++ b/modules/carrier_carriage/stock.py @@ -136,6 +136,15 @@ class _ShipmentMixin: return super().copy(shipments, default=default) +class ShipmentCostSale(metaclass=PoolMeta): + __name__ = 'stock.shipment.cost_sale' + + @classmethod + def __setup__(cls): + super().__setup__() + cls.shipment.selection.append(('stock.shipment.carriage', "Carriage")) + + class Carriage_Sale(ShipmentCostSaleMixin, metaclass=PoolMeta): __name__ = 'stock.shipment.carriage' diff --git a/modules/sale_shipment_cost/__init__.py b/modules/sale_shipment_cost/__init__.py index 6c2f1cd6e1..184f092bc8 100644 --- a/modules/sale_shipment_cost/__init__.py +++ b/modules/sale_shipment_cost/__init__.py @@ -18,6 +18,7 @@ def register(): sale.ConfigurationSaleMethod, sale.Sale, sale.Line, + stock.ShipmentCostSale, stock.ShipmentOut, module='sale_shipment_cost', type_='model') Pool.register( diff --git a/modules/sale_shipment_cost/sale.py b/modules/sale_shipment_cost/sale.py index 4a78897a29..a5de846c56 100644 --- a/modules/sale_shipment_cost/sale.py +++ b/modules/sale_shipment_cost/sale.py @@ -85,6 +85,8 @@ class Sale(metaclass=PoolMeta): states={ 'readonly': Eval('state') != 'draft', }) + shipment_costs = fields.One2Many( + 'stock.shipment.cost_sale', 'sale', "Shipment Costs", readonly=True) @classmethod def __register__(cls, module): @@ -227,6 +229,59 @@ class Sale(metaclass=PoolMeta): with Transaction().set_context(_shipment_cost_invoiced=list()): super().process(sales) + @classmethod + def _process_invoice_shipment_states(cls, sales): + pool = Pool() + ShipmentOut = pool.get('stock.shipment.out') + ShipmentCostSale = pool.get('stock.shipment.cost_sale') + + sent, not_sent = [], [] + for sale in sales: + if sale.shipment_cost_method == 'order': + if sale.shipment_state == 'sent': + sent.append(sale) + else: + not_sent.append(sale) + + super()._process_invoice_shipment_states(sales) + + to_save, to_delete, shipments = [], [], set() + for sale in sent: + if sale.shipment_state != 'sent': + to_delete.extend(sale.shipment_costs) + shipments.update(sale.shipments) + for sale in not_sent: + if sale.shipment_state == 'sent': + to_save.extend(sale._get_shipment_costs()) + shipments.update(sale.shipments) + + ShipmentCostSale.delete(to_delete) + ShipmentCostSale.save(to_save) + ShipmentOut.set_shipment_cost(shipments) + + @property + def _cost_shipments(self): + "Return the shipments to apply cost sale" + return list(self.shipments) + + def _get_shipment_costs(self): + "Yield shipment costs" + pool = Pool() + ShipmentCostSale = pool.get('stock.shipment.cost_sale') + cost = self.shipment_cost_amount + shipments = self._cost_shipments + sum_ = sum(s.cost_used for s in shipments) + for shipment in shipments: + if sum_: + factor = shipment.cost_used / sum_ + else: + factor = Decimal(1) / len(shipments) + yield ShipmentCostSale( + shipment=shipment, + sale=self, + amount=round_price(cost * factor), + currency=self.currency) + def _get_carrier_context(self, carrier): return {} diff --git a/modules/sale_shipment_cost/stock.py b/modules/sale_shipment_cost/stock.py index f2f85467a2..d985e6ee95 100644 --- a/modules/sale_shipment_cost/stock.py +++ b/modules/sale_shipment_cost/stock.py @@ -1,7 +1,7 @@ # 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.i18n import gettext -from trytond.model import ModelView, Workflow, fields +from trytond.model import ModelSQL, ModelView, Workflow, fields from trytond.modules.product import price_digits, round_price from trytond.pool import Pool, PoolMeta from trytond.pyson import Bool, Eval @@ -44,6 +44,9 @@ class ShipmentCostSaleMixin: 'invisible': Eval('cost_method') != 'shipment', }) + cost_sales = fields.One2Many( + 'stock.shipment.cost_sale', 'shipment', "Cost Sales", readonly=True) + cost_invoice_line = fields.Many2One( 'account.invoice.line', "Cost Invoice Line", readonly=True) cost_method = fields.Selection( @@ -135,15 +138,32 @@ class ShipmentCostSaleMixin: pool = Pool() Currency = pool.get('currency.currency') cost = super()._get_shipment_cost() - if self.cost_method == 'shipment': - if self.cost_sale: - cost_sale = Currency.compute( - self.cost_sale_currency, self.cost_sale, - self.company.currency, round=False) - cost -= cost_sale + if self.cost_sale: + cost_sale = Currency.compute( + self.cost_sale_currency, self.cost_sale, + self.company.currency, round=False) + cost -= cost_sale + for line in self.cost_sales: + cost_sale = Currency.compute( + line.currency, line.amount, + self.company.currency, round=False) + cost -= cost_sale return cost +class ShipmentCostSale(ModelSQL): + "Shipment Cost Sale" + __name__ = 'stock.shipment.cost_sale' + + shipment = fields.Reference( + "Shipment", [ + ('stock.shipment.out', "Customer"), + ], required=True) + sale = fields.Many2One('sale.sale', "Sale", required=True) + amount = fields.Numeric("Amount", digits=price_digits, required=True) + currency = fields.Many2One('currency.currency', "Currency", required=True) + + class ShipmentOut(ShipmentCostSaleMixin, metaclass=PoolMeta): __name__ = 'stock.shipment.out' @@ -175,20 +195,6 @@ class ShipmentOut(ShipmentCostSaleMixin, metaclass=PoolMeta): 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 - if s.state == 'done' and s != self) - cost_sale = sale.shipment_cost_amount - 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: