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