Handle remaining qty when synchronizing supplier and customer moves

issue6833
review39781002
This commit is contained in:
Nicolas Évrard committed 2018-03-13 14:14:18 +01:00
1 parent d6ba357f76
commit 1b1e5558f9
3 files changed
+202 -15

No files matched your search

+68 -15
View File
@@ -445,37 +445,90 @@ class ShipmentDrop(Workflow, ModelSQL, ModelView):
for shipment in shipments:
product_qty = defaultdict(lambda: 0)
product_cost = defaultdict(lambda: 0)
for c_move in shipment.customer_moves:
if c_move.state == 'cancel':
continue
product_qty[c_move.product] += UoM.compute_qty(
c_move.uom, c_move.quantity, c_move.product.default_uom,
round=False)
for s_move in shipment.supplier_moves:
if s_move.state == 'cancel':
continue
product_qty[s_move.product] += UoM.compute_qty(s_move.uom,
s_move.quantity, s_move.product.default_uom, round=False)
if s_move.cost_price:
internal_quantity = Decimal(str(s_move.internal_quantity))
product_cost[s_move.product] += (
s_move.unit_price * internal_quantity)
quantity = UoM.compute_qty(
s_move.uom, s_move.quantity, s_move.product.default_uom,
round=False)
if product_qty[s_move.product]:
if quantity <= product_qty[s_move.product]:
product_qty[s_move.product] -= quantity
continue
else:
out_quantity = (
quantity - product_qty[s_move.product])
out_quantity = UoM.compute_qty(
s_move.product.default_uom, out_quantity,
s_move.uom)
product_qty[s_move.product] = 0
else:
out_quantity = s_move.quantity
if not out_quantity:
continue
unit_price = UoM.compute_price(
s_move.product.default_uom, s_move.product.list_price,
s_move.uom)
new_customer_move = shipment._get_customer_move(s_move)
new_customer_move.quantity = out_quantity
new_customer_move.unit_price = unit_price
to_save.append(new_customer_move)
for product, cost in product_cost.iteritems():
qty = Decimal(str(product_qty[product]))
if qty:
product_cost[product] = (cost / qty).quantize(cost_exp)
for c_move in shipment.customer_moves:
if c_move.state == 'cancel':
for c_move in list(shipment.customer_moves) + to_save:
if c_move.id is not None and c_move.state == 'cancel':
continue
if product_qty[c_move.product] <= 0:
c_move.shipment = None
else:
move_qty = UoM.compute_qty(c_move.uom, c_move.quantity,
c_move.product.default_uom, round=False)
qty = min(product_qty[c_move.product], move_qty)
c_move.quantity = UoM.compute_qty(
c_move.cost_price = product_cost[c_move.product]
if c_move.id is None:
continue
if product_qty[c_move.product] > 0:
exc_qty = UoM.compute_qty(
c_move.product.default_uom,
qty, c_move.uom)
product_qty[c_move.product] -= qty
c_move.cost_price = product_cost[c_move.product]
to_save.append(c_move)
product_qty[c_move.product], c_move.uom)
removed_qty = UoM.compute_qty(
c_move.uom, min(exc_qty, c_move.quantity),
c_move.product.default_uom, round=False)
c_move.quantity = max(
0, c_move.uom.round(c_move.quantity - exc_qty))
product_qty[c_move.product] -= removed_qty
to_save.append(c_move)
if to_save:
Move.save(to_save)
def _get_customer_move(self, move):
pool = Pool()
Move = pool.get('stock.move')
return Move(
from_location=move.to_location,
to_location=self.customer.customer_location,
product=move.product,
uom=move.uom,
quantity=move.quantity,
shipment=self,
planned_date=self.planned_date,
company=move.company,
currency=move.company.currency,
unit_price=move.unit_price,
)
@classmethod
@ModelView.button
@Workflow.transition('waiting')
@@ -0,0 +1,129 @@
==================================
Sale Supply Drop Shipment Scenario
==================================
Imports::
>>> import datetime
>>> from dateutil.relativedelta import relativedelta
>>> from decimal import Decimal
>>> from proteus import Model, Wizard
>>> 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_fiscalyear, \
... create_chart, get_accounts
>>> from trytond.modules.account_invoice.tests.tools import \
... set_fiscalyear_invoice_sequences, create_payment_term
>>> today = datetime.date.today()
Install sale_supply_drop_shipment, sale, purchase::
>>> config = activate_modules([
... 'sale_supply_drop_shipment',
... 'sale',
... 'purchase',
... ])
Create company::
>>> _ = create_company()
>>> company = get_company()
Create fiscal year::
>>> fiscalyear = set_fiscalyear_invoice_sequences(
... create_fiscalyear(company))
>>> fiscalyear.click('create_period')
Create chart of accounts::
>>> _ = create_chart(company)
>>> accounts = get_accounts(company)
>>> revenue = accounts['revenue']
>>> expense = accounts['expense']
Create parties::
>>> Party = Model.get('party.party')
>>> supplier = Party(name='Supplier')
>>> supplier.save()
>>> customer = Party(name='Customer')
>>> customer.save()
Create product::
>>> ProductUom = Model.get('product.uom')
>>> ProductSupplier = Model.get('purchase.product_supplier')
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
>>> ProductTemplate = Model.get('product.template')
>>> template = ProductTemplate()
>>> template.name = 'product'
>>> template.default_uom = unit
>>> template.type = 'goods'
>>> template.purchasable = True
>>> template.salable = True
>>> template.list_price = Decimal('10')
>>> template.account_expense = expense
>>> template.account_revenue = revenue
>>> template.supply_on_sale = True
>>> template.save()
>>> product, = template.products
>>> product_supplier = ProductSupplier()
>>> product_supplier.product = template
>>> product_supplier.party = supplier
>>> product_supplier.drop_shipment = True
>>> product_supplier.lead_time = datetime.timedelta(0)
>>> product_supplier.save()
Create payment term::
>>> payment_term = create_payment_term()
>>> payment_term.save()
Sale 250 products::
>>> Sale = Model.get('sale.sale')
>>> sale = Sale()
>>> sale.party = customer
>>> sale.payment_term = payment_term
>>> sale_line = sale.lines.new()
>>> sale_line.product = product
>>> sale_line.quantity = 250
>>> sale.click('quote')
>>> sale.click('confirm')
>>> sale.click('process')
Create Purchase from Request::
>>> Purchase = Model.get('purchase.purchase')
>>> PurchaseRequest = Model.get('purchase.request')
>>> purchase_request, = PurchaseRequest.find()
>>> purchase_request.quantity
250.0
>>> create_purchase = Wizard('purchase.request.create_purchase',
... [purchase_request])
>>> purchase, = Purchase.find()
>>> purchase.payment_term = payment_term
>>> purchase.click('quote')
>>> purchase.click('confirm')
>>> purchase.click('process')
>>> purchase.state
u'processing'
>>> sale.reload()
>>> shipment, = sale.drop_shipments
The supplier sends more than expected::
>>> move, = shipment.supplier_moves
>>> move.quantity = 300
>>> shipment.click('ship')
Another move has been created to synchronize supplier and customer quantities::
>>> len(shipment.customer_moves)
2
>>> sum(m.quantity for m in shipment.customer_moves)
300.0
+5
View File
@@ -22,4 +22,9 @@ def suite():
tearDown=doctest_teardown, encoding='utf-8',
checker=doctest_checker,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
suite.addTests(doctest.DocFileSuite(
'scenario_sale_supply_drop_shipment_remaining_qty.rst',
tearDown=doctest_teardown, encoding='utf-8',
checker=doctest_checker,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
return suite