From b9eff72791eca293d7cb094971facf6647d778c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 27 Feb 2015 11:57:58 +0100 Subject: [PATCH] Set sale shipment cost on sale only at quotation For performance reason, it is better to compute the shipment cost only at quotation instead of when lines are changed. issue4531 review5991002 --- CHANGELOG | 1 + doc/index.rst | 3 +- sale.py | 101 +++++++++++--------------- tests/scenario_sale_shipment_cost.rst | 10 +-- 4 files changed, 52 insertions(+), 63 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 3cac8c054e..5990adc719 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Set sale shipment cost on sale only at quotation * Allow to change the carrier until the shipment is done Version 3.4.0 - 2014-10-20 diff --git a/doc/index.rst b/doc/index.rst index fc3addc512..b0679def4f 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -11,7 +11,8 @@ Two new fields are added to *Sale* and *Sale Configuration*: - *On Order*: The cost will be computed once for the sale. - *On Shipment*: The cost will be compted for each shipments. -Once a carrier is selected a new line is appended with the shipment cost. +At the quotation if a carrier is selected a new line is appended with the +shipment cost but the added line can be modified when going back to draft. Three new fields are added to *Customer Shipment*: diff --git a/sale.py b/sale.py index 67c5f712c8..d02a4fe675 100644 --- a/sale.py +++ b/sale.py @@ -1,6 +1,6 @@ # 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.model import ModelView, Workflow, fields from trytond.transaction import Transaction from trytond.pyson import Eval, Bool from trytond.pool import Pool, PoolMeta @@ -54,90 +54,77 @@ class Sale: config = Config(1) return config.sale_shipment_cost_method + @classmethod + @ModelView.button + @Workflow.transition('quotation') + def quote(cls, sales): + super(Sale, cls).quote(sales) + for sale in sales: + sale.set_shipment_cost() + cls.save(sales) + def _get_carrier_context(self): return {} - @fields.depends(methods=['lines']) - def on_change_carrier(self): - self.on_change_lines() - - @fields.depends('carrier', 'party', 'currency', 'sale_date', - 'shipment_cost_method', 'lines') - def on_change_lines(self): + def set_shipment_cost(self): pool = Pool() - Product = pool.get('product.product') - Currency = pool.get('currency.currency') - SaleLine = pool.get('sale.line') Date = pool.get('ir.date') - - today = Date.today() + Currency = pool.get('currency.currency') cost, currency_id = 0, None if self.carrier: with Transaction().set_context(self._get_carrier_context()): cost, currency_id = self.carrier.get_sale_price() - party = None - party_context = {} - if self.party: - if self.party.lang: - party_context['language'] = self.party.lang.code - cost_line = None products = [line.product for line in self.lines or [] if getattr(line, 'product', None)] stockable = any(product.type in ('goods', 'assets') for product in products) if cost and currency_id and stockable: + today = Date.today() date = self.sale_date or today with Transaction().set_context(date=date): cost = Currency.compute(Currency(currency_id), cost, self.currency) - product = self.carrier.carrier_product - with Transaction().set_context(party_context): - description = Product(product.id).rec_name - taxes = [] - cost_line = SaleLine( - **SaleLine.default_get(SaleLine._fields.keys())) - cost_line.type = 'line' - cost_line.product = product - cost_line.description = description - cost_line.quantity = 1 # XXX - cost_line.unit = product.sale_uom - cost_line.unit_price = cost - cost_line.shipment_cost = cost - cost_line.amount = cost - cost_line.taxes = taxes - cost_line.sequence = 9999 # XXX - pattern = cost_line._get_tax_rule_pattern() - for tax in product.customer_taxes_used: - if party and party.customer_tax_rule: - tax_ids = party.customer_tax_rule.apply(tax, pattern) - if tax_ids: - taxes.extend(tax_ids) - continue - taxes.append(tax.id) - if party and party.customer_tax_rule: - tax_ids = party.customer_tax_rule.apply(None, pattern) - if tax_ids: - taxes.extend(tax_ids) + cost_line = self.get_shipment_cost_line(cost) lines = list(self.lines or []) for line in self.lines: - if getattr(line, 'shipment_cost', None): - if line.shipment_cost != cost: - lines.remove(line) - if cost_line: - cost_line.description = getattr( - line, 'description', '') - else: - cost_line = None - break + if line.type != 'line' or not line.shipment_cost: + continue + if cost_line and line.shipment_cost == cost: + cost_line = None + else: + lines.remove(line) if cost_line: lines.append(cost_line) self.lines = lines - super(Sale, self).on_change_lines() + def get_shipment_cost_line(self, cost): + pool = Pool() + SaleLine = pool.get('sale.line') + + product = self.carrier.carrier_product + + sequence = None + if self.lines: + last_line = self.lines[-1] + if last_line.sequence is not None: + sequence = last_line.sequence + 1 + + cost_line = SaleLine( + sale=self, + sequence=sequence, + type='line', + product=product, + quantity=1, # XXX + unit=product.sale_uom, + shipment_cost=cost, + ) + cost_line.on_change_product() + cost_line.unit_price = cost_line.amount = cost + return cost_line def create_shipment(self, shipment_type): Shipment = Pool().get('stock.shipment.out') diff --git a/tests/scenario_sale_shipment_cost.rst b/tests/scenario_sale_shipment_cost.rst index d57b21a847..45131ba172 100644 --- a/tests/scenario_sale_shipment_cost.rst +++ b/tests/scenario_sale_shipment_cost.rst @@ -129,14 +129,14 @@ Sale products with cost on shipment:: >>> sale_line = sale.lines.new() >>> sale_line.product = product >>> sale_line.quantity = 5.0 + >>> sale.click('quote') >>> cost_line = sale.lines[-1] >>> cost_line.product == carrier_product True >>> cost_line.quantity - 1 + 1.0 >>> cost_line.amount Decimal('3.00') - >>> sale.click('quote') >>> sale.click('confirm') >>> sale.click('process') >>> sale.state @@ -190,14 +190,14 @@ Sale products with cost on order:: >>> sale_line = sale.lines.new() >>> sale_line.product = product >>> sale_line.quantity = 3.0 + >>> sale.click('quote') >>> cost_line = sale.lines[-1] >>> cost_line.product == carrier_product True - >>> cost_line.quantity == 1 - True + >>> cost_line.quantity + 1.0 >>> cost_line.amount Decimal('3.00') - >>> sale.click('quote') >>> sale.click('confirm') >>> sale.click('process') >>> sale.state