Create lot for output product when needed
When the output product has a sequence and a lot is required, we create a new lot to set on the output move. Closes #11923
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
* Create lot for output product when needed
|
||||
* Assign all possible productions when trying
|
||||
|
||||
Version 6.6.0 - 2022-10-31
|
||||
|
||||
@@ -28,6 +28,7 @@ def register():
|
||||
module='production', type_='model')
|
||||
Pool.register(
|
||||
stock.LotTrace,
|
||||
production.Production_Lot,
|
||||
module='production', type_='model', depends=['stock_lot'])
|
||||
Pool.register(
|
||||
bom.OpenBOMTree,
|
||||
|
||||
@@ -15,7 +15,7 @@ from trytond.model import (
|
||||
from trytond.modules.company.model import employee_field, set_employee
|
||||
from trytond.modules.product import price_digits, round_price
|
||||
from trytond.modules.stock.shipment import ShipmentAssignMixin
|
||||
from trytond.pool import Pool
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
from trytond.pyson import Bool, Eval, If
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
@@ -830,3 +830,27 @@ class Production(ShipmentAssignMixin, Workflow, ModelSQL, ModelView):
|
||||
if self.warehouse:
|
||||
return (self.warehouse.production_output_location
|
||||
or self.warehouse.storage_location)
|
||||
|
||||
|
||||
class Production_Lot(metaclass=PoolMeta):
|
||||
__name__ = 'production'
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('done')
|
||||
def done(cls, productions):
|
||||
pool = Pool()
|
||||
Lot = pool.get('stock.lot')
|
||||
Move = pool.get('stock.move')
|
||||
lots, moves = [], []
|
||||
for production in productions:
|
||||
for move in production.outputs:
|
||||
if not move.lot and move.product.lot_is_required(
|
||||
move.from_location, move.to_location):
|
||||
move.add_lot()
|
||||
if move.lot:
|
||||
lots.append(move.lot)
|
||||
moves.append(move)
|
||||
Lot.save(lots)
|
||||
Move.save(moves)
|
||||
super().done(productions)
|
||||
|
||||
@@ -47,7 +47,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_lot'),
|
||||
]
|
||||
|
||||
setup(name=name,
|
||||
version=version,
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
====================================
|
||||
Stock Lot Number Production 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)
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules(['stock_lot', 'production'])
|
||||
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> Production = Model.get('production')
|
||||
>>> Production = Model.get('production')
|
||||
>>> Sequence = Model.get('ir.sequence')
|
||||
>>> SequenceType = Model.get('ir.sequence.type')
|
||||
>>> UoM = Model.get('product.uom')
|
||||
|
||||
Create company::
|
||||
|
||||
>>> _ = create_company()
|
||||
>>> company = get_company()
|
||||
|
||||
Create lot sequence::
|
||||
|
||||
>>> sequence_type, = SequenceType.find(
|
||||
... [('name', '=', "Stock Lot")], limit=1)
|
||||
>>> sequence = Sequence(name="Lot", sequence_type=sequence_type)
|
||||
>>> sequence.save()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> unit, = UoM.find([('name', '=', 'Unit')])
|
||||
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = "Product"
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('10.0000')
|
||||
>>> template.lot_required = ['storage']
|
||||
>>> template.lot_sequence = sequence
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Make a production::
|
||||
|
||||
>>> production = Production()
|
||||
>>> output = production.outputs.new()
|
||||
>>> output.from_location = production.location
|
||||
>>> output.to_location = production.warehouse.storage_location
|
||||
>>> output.product = product
|
||||
>>> output.quantity = 1
|
||||
>>> output.unit_price = Decimal(0)
|
||||
>>> output.currency = production.company.currency
|
||||
>>> production.click('wait')
|
||||
>>> production.click('assign_force')
|
||||
>>> production.click('run')
|
||||
>>> production.click('done')
|
||||
>>> production.state
|
||||
'done'
|
||||
|
||||
>>> output, = production.outputs
|
||||
>>> bool(output.lot)
|
||||
True
|
||||
@@ -112,3 +112,14 @@ class Product(metaclass=PoolMeta):
|
||||
def lot_is_required(self, from_, to):
|
||||
'Is product lot required for move with "from_" and "to" location ?'
|
||||
return any(l.type in (self.lot_required or []) for l in [from_, to])
|
||||
|
||||
def create_lot(self):
|
||||
pool = Pool()
|
||||
Lot = pool.get('stock.lot')
|
||||
if self.lot_sequence:
|
||||
lot = Lot(product=self)
|
||||
try:
|
||||
lot.on_change_product()
|
||||
except AttributeError:
|
||||
pass
|
||||
return lot
|
||||
|
||||
@@ -433,6 +433,12 @@ class Move(metaclass=PoolMeta):
|
||||
def add_lots_wizard(cls, moves):
|
||||
pass
|
||||
|
||||
def add_lot(self):
|
||||
if not self.lot and self.product:
|
||||
lot = self.product.create_lot()
|
||||
if lot:
|
||||
self.lot = lot
|
||||
|
||||
def check_lot(self):
|
||||
"Check if lot is required"
|
||||
if (self.state == 'done'
|
||||
|
||||
Reference in New Issue
Block a user