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
This commit is contained in:
Cédric Krier committed 2021-03-23 15:33:02 +01:00
1 parent c1c8b4a8d3
commit 35614d981f
5 files changed
+237 -4

No files matched your search

+9 -1
View File
@@ -224,7 +224,7 @@ class Sale(metaclass=PoolMeta):
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 @@ class Sale(metaclass=PoolMeta):
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')
+4 -1
View File
@@ -63,7 +63,10 @@ for dep in info.get('depends', []):
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 = []
+29 -2
View File
@@ -209,9 +209,36 @@ class ShipmentOut(metaclass=PoolMeta):
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
+190
View File
@@ -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')
+5
View File
@@ -32,4 +32,9 @@ def suite():
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