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:
1 parent
c1c8b4a8d3
commit
35614d981f
5 files changed
+237
-4
No files matched your search
@@ -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')
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
@@ -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
|
||||
Reference in new issue
Block a user