changeset f5ae6da828ea in modules/sale_shipment_cost:default
details:
https://hg.tryton.org/modules/sale_shipment_cost?cmd=changeset&node=f5ae6da828ea
description:
Add unsold shipment cost to the outgoing moves
Even there is a shipment cost method if the cost sold is lower than the
actual
shipment cost, the difference must be added to the outgoing moves.
issue10149
review335731002
diffstat:
sale.py | 10 +-
setup.py | 5 +-
stock.py | 31 ++++-
tests/scenario_sale_shipment_cost_stock.rst | 190 ++++++++++++++++++++++++++++
tests/test_sale_shipment_cost.py | 5 +
5 files changed, 237 insertions(+), 4 deletions(-)
diffs (291 lines):
diff -r ea4abbc22660 -r f5ae6da828ea sale.py
--- a/sale.py Sat Mar 13 23:43:51 2021 +0100
+++ b/sale.py Tue Mar 23 15:33:02 2021 +0100
@@ -224,7 +224,7 @@
unit_price = None
lines = list(self.lines or [])
for line in self.lines:
- if line.type == 'line' and line.shipment_cost:
+ if line.type == 'line' and line.shipment_cost is not None:
if line.shipment_cost == cost:
unit_price = line.unit_price * Decimal(str(line.quantity))
lines.remove(line)
@@ -265,6 +265,14 @@
cost_line.amount = cost_line.on_change_with_amount()
return cost_line
+ @property
+ def shipment_cost_amount(self):
+ cost = Decimal(0)
+ for line in self.lines:
+ if line.type == 'line' and line.shipment_cost is not None:
+ cost += line.amount
+ return cost
+
def create_shipment(self, shipment_type):
pool = Pool()
Shipment = pool.get('stock.shipment.out')
diff -r ea4abbc22660 -r f5ae6da828ea setup.py
--- a/setup.py Sat Mar 13 23:43:51 2021 +0100
+++ b/setup.py Tue Mar 23 15:33:02 2021 +0100
@@ -63,7 +63,10 @@
requires.append(get_require_version('trytond_%s' % dep))
requires.append(get_require_version('trytond'))
-tests_require = [get_require_version('proteus')]
+tests_require = [
+ get_require_version('proteus'),
+ get_require_version('trytond_stock_shipment_cost'),
+ ]
for dep in ['account', 'party', 'stock', 'sale_promotion']:
tests_require.append(get_require_version('trytond_%s' % dep))
dependency_links = []
diff -r ea4abbc22660 -r f5ae6da828ea stock.py
--- a/stock.py Sat Mar 13 23:43:51 2021 +0100
+++ b/stock.py Tue Mar 23 15:33:02 2021 +0100
@@ -209,9 +209,36 @@
return invoice_line
def _get_shipment_cost(self):
+ pool = Pool()
+ Currency = pool.get('currency.currency')
cost = super()._get_shipment_cost()
- if all(not m.sale.shipment_cost_method for m in self.outgoing_moves):
- cost += self.cost_used
+ methods = {
+ m.sale.shipment_cost_method for m in self.outgoing_moves if m.sale}
+ if methods == {None}:
+ cost += self.cost_used or 0
+ if 'shipment' in methods:
+ if self.cost_sale:
+ cost_sale = Currency.compute(
+ self.cost_sale_currency, self.cost_sale,
+ self.company.currency, round=False)
+ else:
+ cost_sale = 0
+ delta = cost_sale - (self.cost_used or 0)
+ if delta < 0:
+ cost -= delta
+ if 'order' in methods and self.cost_used:
+ 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
+ if cost_sale < shipment_cost:
+ cost += self.cost_used or 0
+ elif cost_sale < shipment_cost + (self.cost_used or 0):
+ cost += shipment_cost + self.cost_used - cost_sale
return cost
@classmethod
diff -r ea4abbc22660 -r f5ae6da828ea tests/scenario_sale_shipment_cost_stock.rst
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/scenario_sale_shipment_cost_stock.rst Tue Mar 23 15:33:02
2021 +0100
@@ -0,0 +1,190 @@
+=================================
+Sale Shipment Cost Stock Scenario
+=================================
+
+Imports::
+
+ >>> from decimal import Decimal
+ >>> from proteus import Model
+ >>> from trytond.tests.tools import activate_modules
+ >>> from trytond.modules.company.tests.tools import (
+ ... create_company, get_company)
+ >>> from trytond.modules.account.tests.tools import (
+ ... create_chart, get_accounts)
+
+Activate modules::
+
+ >>> config = activate_modules([
+ ... 'sale_shipment_cost',
+ ... 'sale',
+ ... 'stock_shipment_cost',
+ ... ])
+
+ >>> Carrier = Model.get('carrier')
+ >>> CarrierSelection = Model.get('carrier.selection')
+ >>> Party = Model.get('party.party')
+ >>> ProductCategory = Model.get('product.category')
+ >>> ProductTemplate = Model.get('product.template')
+ >>> ProductUom = Model.get('product.uom')
+ >>> Sale = Model.get('sale.sale')
+ >>> ShipmentOut = Model.get('stock.shipment.out')
+
+Create company::
+
+ >>> _ = create_company()
+ >>> company = get_company()
+
+Create chart of accounts::
+
+ >>> _ = create_chart(company)
+ >>> accounts = get_accounts(company)
+
+Create customer::
+
+ >>> customer = Party(name='Customer')
+ >>> customer.save()
+
+Create account category::
+
+ >>> account_category = ProductCategory(name="Account Category")
+ >>> account_category.accounting = True
+ >>> account_category.account_revenue = accounts['revenue']
+ >>> account_category.save()
+
+Create product::
+
+ >>> unit, = ProductUom.find([('name', '=', 'Unit')])
+
+ >>> template = ProductTemplate()
+ >>> template.name = 'Product'
+ >>> template.default_uom = unit
+ >>> template.type = 'goods'
+ >>> template.salable = True
+ >>> template.list_price = Decimal('20')
+ >>> template.account_category = account_category
+ >>> template.save()
+ >>> product, = template.products
+
+ >>> carrier_template = ProductTemplate()
+ >>> carrier_template.name = 'Carrier Product'
+ >>> carrier_template.default_uom = unit
+ >>> carrier_template.type = 'service'
+ >>> carrier_template.salable = True
+ >>> carrier_template.list_price = Decimal('2')
+ >>> carrier_template.account_category = account_category
+ >>> carrier_template.save()
+ >>> carrier_product, = carrier_template.products
+ >>> carrier_product.cost_price = Decimal('5')
+ >>> carrier_product.save()
+
+Create carrier::
+
+ >>> carrier = Carrier()
+ >>> party = Party(name='Carrier')
+ >>> party.save()
+ >>> carrier.party = party
+ >>> carrier.carrier_product = carrier_product
+ >>> carrier.save()
+
+Use it as the default carrier::
+
+ >>> csc = CarrierSelection(carrier=carrier)
+ >>> csc.save()
+
+
+Sell product with no shipment cost::
+
+ >>> sale = Sale()
+ >>> sale.party = customer
+ >>> sale.carrier = carrier
+ >>> sale.shipment_cost_method = None
+ >>> line = sale.lines.new()
+ >>> line.product = product
+ >>> line.quantity = 1
+ >>> sale.click('quote')
+ >>> len(sale.lines)
+ 1
+ >>> sale.click('confirm')
+ >>> sale.click('process')
+ >>> sale.state
+ 'processing'
+
+ >>> shipment, = sale.shipments
+ >>> shipment.cost_used
+ Decimal('5.0000')
+ >>> shipment.click('assign_force')
+ >>> shipment.click('pick')
+ >>> shipment.click('pack')
+ >>> shipment.click('done')
+ >>> shipment.state
+ 'done'
+ >>> move, = shipment.outgoing_moves
+ >>> move.shipment_out_cost_price
+ Decimal('5.0000')
+
+Sell product with cost on shipment::
+
+ >>> sale = Sale()
+ >>> sale.party = customer
+ >>> sale.carrier = carrier
+ >>> sale.shipment_cost_method = 'shipment'
+ >>> line = sale.lines.new()
+ >>> line.product = product
+ >>> line.quantity = 1
+ >>> sale.click('quote')
+ >>> len(sale.lines)
+ 2
+ >>> sale.click('confirm')
+ >>> sale.click('process')
+ >>> sale.state
+ 'processing'
+
+ >>> shipment, = sale.shipments
+ >>> shipment.cost_used
+ Decimal('5.0000')
+ >>> shipment.cost_sale_used
+ Decimal('2.0000')
+ >>> shipment.click('assign_force')
+ >>> shipment.click('pick')
+ >>> shipment.click('pack')
+ >>> shipment.click('done')
+ >>> shipment.state
+ 'done'
+ >>> move, = shipment.outgoing_moves
+ >>> move.shipment_out_cost_price
+ Decimal('3.0000')
+
+Sell product with cost on order::
+
+ >>> sale = Sale()
+ >>> sale.party = customer
+ >>> sale.carrier = carrier
+ >>> sale.shipment_cost_method = 'order'
+ >>> line = sale.lines.new()
+ >>> line.product = product
+ >>> line.quantity = 1
+ >>> sale.click('quote')
+ >>> len(sale.lines)
+ 2
+ >>> sale.click('draft')
+ >>> sale.lines[-1].unit_price = Decimal('3.0000')
+ >>> sale.click('quote')
+ >>> sale.lines[-1].unit_price
+ Decimal('3.0000')
+ >>> sale.click('confirm')
+ >>> sale.click('process')
+ >>> sale.state
+ 'processing'
+
+ >>> shipment, = sale.shipments
+ >>> shipment.cost_used
+ Decimal('5.0000')
+ >>> shipment.click('assign_force')
+ >>> shipment.click('pick')
+ >>> shipment.click('pack')
+ >>> shipment.click('done')
+ >>> shipment.state
+ 'done'
+ >>> move, = shipment.outgoing_moves
+ >>> move.shipment_out_cost_price
+ Decimal('2.0000')
diff -r ea4abbc22660 -r f5ae6da828ea tests/test_sale_shipment_cost.py
--- a/tests/test_sale_shipment_cost.py Sat Mar 13 23:43:51 2021 +0100
+++ b/tests/test_sale_shipment_cost.py Tue Mar 23 15:33:02 2021 +0100
@@ -32,4 +32,9 @@
tearDown=doctest_teardown, encoding='utf-8',
checker=doctest_checker,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
+ suite.addTests(doctest.DocFileSuite(
+ 'scenario_sale_shipment_cost_stock.rst',
+ tearDown=doctest_teardown, encoding='utf-8',
+ checker=doctest_checker,
+ optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
return suite