Manage move from supplier to customer

The stock move creates two invoices in this case. And it uses the origin of
the invoice lines to manage them from the move workflow.

issue7523
review70381002
This commit is contained in:
Cédric Krier committed 2018-10-04 09:06:38 +02:00
1 parent 6b3b308f21
commit 63419fc6eb
4 files changed
+205 -16

No files matched your search

+2
View File
@@ -1,3 +1,5 @@
* Manage move from supplier to customer
Version 5.0.0 - 2018-10-01
* Bug fixes (see mercurial logs for details)
* Remove support for Python 2.7
+23 -16
View File
@@ -48,17 +48,19 @@ def set_origin_consignment(func):
def wrapper(cls, moves):
pool = Pool()
InvoiceLine = pool.get('account.invoice.line')
lines = {}
to_save = []
move2line = {}
for move in moves:
if not move.origin:
line = move.get_invoice_line_consignment()
if line:
lines[move] = line
if lines:
InvoiceLine.save(list(lines.values()))
for move, line in lines.items():
lines = move.get_invoice_lines_consignment()
if lines:
to_save.extend(lines)
move2line[move] = lines[0]
if to_save:
InvoiceLine.save(to_save)
for move, line in move2line.items():
move.origin = line
cls.save(list(lines.keys()))
cls.save(list(move2line.keys()))
return func(cls, moves)
return wrapper
@@ -70,9 +72,8 @@ def unset_origin_consignment(func):
InvoiceLine = pool.get('account.invoice.line')
lines, to_save = [], []
for move in moves:
if (isinstance(move.origin, InvoiceLine)
and move.origin.origin == move):
lines.append(move.origin)
if isinstance(move.origin, InvoiceLine):
lines.extend(move.invoice_lines)
move.origin = None
to_save.append(move)
if lines:
@@ -85,6 +86,9 @@ def unset_origin_consignment(func):
class Move(metaclass=PoolMeta):
__name__ = 'stock.move'
invoice_lines = fields.One2Many(
'account.invoice.line', 'origin', "Invoice Lines", readonly=True)
@classmethod
def _get_origin(cls):
return super(Move, cls)._get_origin() + ['account.invoice.line']
@@ -102,15 +106,18 @@ class Move(metaclass=PoolMeta):
def _get_tax_rule_pattern(self):
return {}
def get_invoice_line_consignment(self):
def get_invoice_lines_consignment(self):
lines = []
if (self.from_location.type == 'supplier'
and self.to_location.type in {'storage', 'production'}
and self.to_location.type in {
'storage', 'production', 'customer'}
and self.from_location.consignment_party):
return self._get_supplier_invoice_line_consignment()
elif (self.from_location.type in {'storage', 'production'}
lines.append(self._get_supplier_invoice_line_consignment())
if (self.from_location.type in {'storage', 'production', 'supplier'}
and self.to_location.type == 'customer'
and self.from_location.consignment_party):
return self._get_customer_invoice_line_consignment()
lines.append(self._get_customer_invoice_line_consignment())
return lines
def _get_supplier_invoice_line_consignment(self):
pool = Pool()
@@ -0,0 +1,175 @@
===============================================
Stock Consignment Supplier to Customer Scenario
===============================================
Imports::
>>> 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_chart, \
... get_accounts, create_tax
Install stock_consignment::
>>> config = activate_modules('stock_consignment')
Create company::
>>> _ = create_company()
>>> company = get_company()
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()
Get stock locations::
>>> Location = Model.get('stock.location')
>>> warehouse_loc, = Location.find([('code', '=', 'WH')])
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
>>> storage_loc, = Location.find([('code', '=', 'STO')])
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
>>> output_loc, = Location.find([('code', '=', 'OUT')])
Create customer consignment location::
>>> customer_consignment_loc = Location()
>>> customer_consignment_loc.name = "Customer Consignment"
>>> customer_consignment_loc.type = 'storage'
>>> customer_consignment_loc.parent = customer_loc
>>> customer_consignment_loc.consignment_party = customer
>>> customer_consignment_loc.save()
Create supplier consignment location under customer consignment location::
>>> supplier_consignment_loc = Location()
>>> supplier_consignment_loc.name = "Supplier Consignment"
>>> supplier_consignment_loc.type = 'supplier'
>>> supplier_consignment_loc.parent = customer_consignment_loc
>>> supplier_consignment_loc.consignment_party = supplier
>>> supplier_consignment_loc.save()
Create account category::
>>> ProductCategory = Model.get('product.category')
>>> account_category = ProductCategory(name="Account Category")
>>> account_category.accounting = True
>>> account_category.account_expense = expense
>>> account_category.account_revenue = revenue
>>> account_category.save()
Create product::
>>> ProductUom = Model.get('product.uom')
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
>>> ProductTemplate = Model.get('product.template')
>>> Product = Model.get('product.product')
>>> product = Product()
>>> 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_category = account_category
>>> product_supplier = template.product_suppliers.new()
>>> product_supplier.party = supplier
>>> price = product_supplier.prices.new()
>>> price.quantity = 1
>>> price.unit_price = Decimal('4')
>>> template.save()
>>> product.template = template
>>> product.save()
Fill supplier consignment location::
>>> Shipment = Model.get('stock.shipment.internal')
>>> shipment = Shipment()
>>> shipment.from_location = supplier_loc
>>> shipment.to_location = supplier_consignment_loc
>>> move = shipment.moves.new()
>>> move.product = product
>>> move.quantity = 10
>>> move.from_location = supplier_loc
>>> move.to_location = supplier_consignment_loc
>>> shipment.click('wait')
>>> shipment.state
'waiting'
>>> shipment.click('assign_try')
True
>>> shipment.state
'assigned'
>>> shipment.click('done')
>>> shipment.state
'done'
Use supplier consignment stock by customer::
>>> shipment = Shipment()
>>> shipment.from_location = supplier_consignment_loc
>>> shipment.to_location = customer_loc
>>> move = shipment.moves.new()
>>> move.product = product
>>> move.quantity = 4
>>> move.from_location = supplier_consignment_loc
>>> move.to_location = customer_loc
>>> shipment.click('wait')
>>> shipment.state
'waiting'
>>> shipment.click('assign_try')
True
>>> shipment.state
'assigned'
>>> shipment.click('done')
>>> shipment.state
'done'
>>> move, = shipment.moves
>>> len(move.invoice_lines)
2
>>> move.origin in move.invoice_lines
True
Check supplier invoice line::
>>> InvoiceLine = Model.get('account.invoice.line')
>>> invoice_line, = InvoiceLine.find([('invoice_type', '=', 'in')])
>>> invoice_line.product == product
True
>>> invoice_line.quantity
4.0
>>> invoice_line.unit == unit
True
>>> invoice_line.unit_price
Decimal('4.0000')
>>> invoice_line.origin == move
True
Check customer invoice line::
>>> invoice_line, = InvoiceLine.find([('invoice_type', '=', 'out')])
>>> invoice_line.product == product
True
>>> invoice_line.quantity
4.0
>>> invoice_line.unit == unit
True
>>> invoice_line.unit_price
Decimal('10.0000')
>>> invoice_line.origin == move
True
+5
View File
@@ -25,4 +25,9 @@ def suite():
tearDown=doctest_teardown, encoding='utf-8',
checker=doctest_checker,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
suite.addTests(doctest.DocFileSuite(
'scenario_stock_consignment_supplier_customer.rst',
tearDown=doctest_teardown, encoding='utf-8',
checker=doctest_checker,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
return suite