Loaded end date on parallel moves when drop last move.

This commit refs #21995
This commit is contained in:
José Miguel Pardo Salar 2022-02-10 13:23:29 +01:00 committed by Sergio Morillo
parent 8b1b5a2680
commit 7f6e42b2e7
11 changed files with 337 additions and 37 deletions

View File

@ -19,6 +19,7 @@ def register():
configuration.ConfigurationSequence,
configuration.ConfigurationULProductionType,
configuration.ConfigurationDoUlDrop,
configuration.ProductionConfiguration,
configuration.ConfigurationProposeDropEndDate,
stock.Move,
MoveUnitLoadStart,

View File

@ -3,12 +3,11 @@
from trytond.model import ModelSQL, fields
from trytond.pool import PoolMeta, Pool
from trytond.pyson import Eval, Id
from trytond.transaction import Transaction
from trytond.tools.multivalue import migrate_property
from trytond.modules.company.model import CompanyValueMixin
from trytond import backend
__all__ = ['Configuration', 'ConfigurationSequence',
'ConfigurationULProductionType']
from sql import Table
class Configuration(metaclass=PoolMeta):
@ -29,9 +28,6 @@ class Configuration(metaclass=PoolMeta):
case_category = fields.Many2One('product.category', 'Case Category')
do_ul_drop = fields.MultiValue(fields.Boolean('Do Unit Load move on drop',
help='If checked drop UL moves will be done.'))
propose_drop_end_date = fields.MultiValue(
fields.Boolean('Propose Unit Load move''s end date on drop',
help='If checked drop UL move''s end date will be proposed.'))
@classmethod
def multivalue_model(cls, field):
@ -55,11 +51,6 @@ class Configuration(metaclass=PoolMeta):
return cls.multivalue_model(
'do_ul_drop').default_do_ul_drop()
@classmethod
def default_propose_drop_end_date(cls, **pattern):
return cls.multivalue_model(
'propose_drop_end_date').default_propose_drop_end_date()
@classmethod
def write(cls, *args):
UnitLoad = Pool().get('stock.unit_load')
@ -151,13 +142,61 @@ class ConfigurationULProductionType(ModelSQL, CompanyValueMixin):
return 'location'
class ProductionConfiguration(metaclass=PoolMeta):
__name__ = 'production.configuration'
propose_drop_end_date = fields.MultiValue(
fields.Selection([
(None, ''),
('start_date', 'Start date'),
('last_drop', 'Last drop'),
], 'Propose drop UL end date',
help="Determines how drop UL move''s end date will be proposed."))
@classmethod
def default_propose_drop_end_date(cls, **pattern):
return cls.multivalue_model(
'propose_drop_end_date').default_propose_drop_end_date()
class ConfigurationProposeDropEndDate(ModelSQL, CompanyValueMixin):
"Configuration Propose Drop End Date"
__name__ = 'stock.configuration.propose_drop_end_date'
__name__ = 'production.configuration.propose_drop_end_date'
propose_drop_end_date = fields.Boolean('Propose drop''s end date')
propose_drop_end_date = fields.Selection([
(None, ''),
('start_date', 'Start date'),
('last_drop', 'Last drop')], 'Propose drop UL end date')
@classmethod
def __register__(cls, module_name):
TableHandler = backend.get('TableHandler')
table = TableHandler(cls, module_name)
cursor = Transaction().connection.cursor()
old_table = 'stock_configuration_propose_drop_end_date'
to_update, values = False, []
if TableHandler.table_exist(old_table):
TableHandler.table_rename(old_table, cls._table)
to_update = True
sql_table = Table(old_table)
cursor.execute(*sql_table.select(
sql_table.id,
where=sql_table.propose_drop_end_date == True))
values = [r[0] for r in cursor.fetchall()]
table.drop_column('propose_drop_end_date')
super().__register__(module_name)
if to_update and values:
sql_table = cls.__table__()
cursor.execute(*sql_table.update(
columns=[sql_table.propose_drop_end_date],
values=['start_date'],
where=sql_table.id.in_(values)))
@classmethod
def default_propose_drop_end_date(cls):
return False
return None

View File

@ -30,5 +30,12 @@
<field name="name">Unit load</field>
<field name="sequence_type" ref="sequence_type_unit_load"/>
</record>
<!-- Production configuration form -->
<record model="ir.ui.view" id="production_configuration_view_form">
<field name="model">production.configuration</field>
<field name="inherit" ref="production.production_configuration_view_form"/>
<field name="name">production_configuration_form</field>
</record>
</data>
</tryton>

View File

@ -532,6 +532,14 @@ msgctxt "selection:stock.unit_load.move,state:"
msgid "Staging"
msgstr "En proceso"
msgctxt "selection:production.configuration,propose_drop_end_date:"
msgid "Start date"
msgstr "Fecha inicio"
msgctxt "selection:production.configuration,propose_drop_end_date:"
msgid "Last drop"
msgstr "Último volcado"
msgctxt "view:stock.unit_load.do_move_start:"
msgid "Start moving UL"
msgstr "Iniciar mover UdC"
@ -688,6 +696,10 @@ msgctxt "field:stock.unit_load.do_drop.data,drop_cases_quantity:"
msgid "Cases to drop"
msgstr "Bultos a volcar"
msgctxt "field:stock.unit_load.do_drop.data,parallel:"
msgid "Parallel"
msgstr "Paralelo"
msgctxt "field:stock.unit_load.do_drop_failed,location:"
msgid "Return location"
msgstr "Ubicación de retorno"
@ -896,13 +908,13 @@ msgctxt "help:stock.configuration,do_ul_drop:"
msgid "If checked drop UL moves will be done."
msgstr "Si se marca los movimientos de volcado de una UdC se finalizarán."
msgctxt "field:stock.configuration,propose_drop_end_date:"
msgid "Propose Unit Load move's end date on drop"
msgstr "Proponer fecha fin en volcado de Unidad de carga"
msgctxt "field:production.configuration,propose_drop_end_date:"
msgid "Propose drop UL end date"
msgstr "Proponer fecha fin volcado UdC"
msgctxt "help:stock.configuration,propose_drop_end_date:"
msgid "If checked drop UL move's end date will be proposed."
msgstr "Si se marca la fecha fin de volcado de una UdC se propondrá."
msgctxt "help:production.configuration,propose_drop_end_date:"
msgid "Determines how drop UL move's end date will be proposed."
msgstr "Indica cómo se establece la fecha fin de volcado de una UdC."
msgctxt "view:stock.configuration:"
msgid "Unit Load"

View File

@ -54,7 +54,14 @@ dependency_links = {
'trytond-stock_move_time@%(branch)s'
'#egg=datalife_stock_move_time' % {
'branch': branch,
}
},
'stock_move_done2cancel':
'git+https://gitlab.com/datalifeit/'
'trytond-stock_move_done2cancel@%(branch)s'
'#egg=datalife_stock_move_done2cancel-%(series)s' % {
'branch': branch,
'series': series
},
}
requires = []

View File

@ -109,6 +109,16 @@ class Move(metaclass=PoolMeta):
UnitLoad.set_state(uls)
return moves
@classmethod
def init_end_date(cls):
pool = Pool()
Configuration = pool.get('production.configuration')
conf = Configuration(1)
if conf.propose_drop_end_date == 'last_drop':
return False
return super().init_end_date()
class Move2(metaclass=PoolMeta):
__name__ = 'stock.move'

View File

@ -20,7 +20,7 @@ Imports::
Install unit load Module::
>>> config = activate_modules('stock_unit_load')
>>> config = activate_modules(['stock_unit_load'])
Create company::
@ -71,6 +71,9 @@ Get stock locations::
>>> storage3 = Location(name='Storage 3')
>>> storage3.parent = storage_loc
>>> storage3.save()
>>> production_loc2 = Location(name='Production 2', code='PROD2',
... type='production', parent=production_loc)
>>> production_loc2.save()
Create an unit load::
@ -424,12 +427,14 @@ Drop with do ul drop active::
'done'
Active stock configuration propose drop end date::
Active stock configuration propose drop end date with "start_date"::
>>> bool(configuration.propose_drop_end_date)
>>> ProductionConfiguration = Model.get('production.configuration')
>>> prod_conf = ProductionConfiguration(1)
>>> bool(prod_conf.propose_drop_end_date)
False
>>> configuration.propose_drop_end_date = True
>>> configuration.save()
>>> prod_conf.propose_drop_end_date = 'start_date'
>>> prod_conf.save()
Create new unit load and moves::
@ -475,4 +480,159 @@ Execute global drop wizard with proposed end date::
>>> unit_load3.reload()
>>> move = unit_load.drop_moves[0]
>>> move.state
'done'
Active stock configuration propose drop end date with "last_drop"::
>>> prod_conf.propose_drop_end_date = 'last_drop'
>>> prod_conf.save()
Create another unit loads::
>>> unit_load4 = UnitLoad()
>>> unit_load4.start_date = datetime.datetime.now() - relativedelta(days=1)
>>> unit_load4.end_date = unit_load4.start_date + relativedelta(minutes=15)
>>> unit_load4.production_type = 'location'
>>> unit_load4.production_location = production_loc
>>> unit_load4.product = product
>>> unit_load4.cases_quantity = 5
>>> unit_load4.quantity = 35.0
>>> move = unit_load4.production_moves[0]
>>> move.to_location = new_stor
>>> unit_load4.click('assign')
>>> unit_load4.click('do')
>>> unit_load5 = UnitLoad()
>>> unit_load5.start_date = datetime.datetime.now() - relativedelta(days=1)
>>> unit_load5.end_date = unit_load5.start_date + relativedelta(minutes=15)
>>> unit_load5.production_type = 'location'
>>> unit_load5.production_location = production_loc
>>> unit_load5.product = product
>>> unit_load5.cases_quantity = 5
>>> unit_load5.quantity = 35.0
>>> move = unit_load5.production_moves[0]
>>> move.to_location = new_stor
>>> unit_load5.click('assign')
>>> unit_load5.click('do')
>>> unit_load6 = UnitLoad()
>>> unit_load6.start_date = datetime.datetime.now() - relativedelta(days=1)
>>> unit_load6.end_date = unit_load6.start_date + relativedelta(minutes=15)
>>> unit_load6.production_type = 'location'
>>> unit_load6.production_location = production_loc
>>> unit_load6.product = product
>>> unit_load6.cases_quantity = 5
>>> unit_load6.quantity = 35.0
>>> move = unit_load6.production_moves[0]
>>> move.to_location = new_stor
>>> unit_load6.click('assign')
>>> unit_load6.click('do')
>>> unit_load7 = UnitLoad()
>>> unit_load7.start_date = datetime.datetime.now() - relativedelta(days=1)
>>> unit_load7.end_date = unit_load7.start_date + relativedelta(minutes=15)
>>> unit_load7.production_type = 'location'
>>> unit_load7.production_location = production_loc
>>> unit_load7.product = product
>>> unit_load7.cases_quantity = 5
>>> unit_load7.quantity = 35.0
>>> move = unit_load7.production_moves[0]
>>> move.to_location = new_stor
>>> unit_load7.click('assign')
>>> unit_load7.click('do')
>>> unit_load8 = UnitLoad()
>>> unit_load8.start_date = datetime.datetime.now() - relativedelta(days=1)
>>> unit_load8.end_date = unit_load8.start_date + relativedelta(minutes=15)
>>> unit_load8.production_type = 'location'
>>> unit_load8.production_location = production_loc
>>> unit_load8.product = product
>>> unit_load8.cases_quantity = 5
>>> unit_load8.quantity = 35.0
>>> move = unit_load8.production_moves[0]
>>> move.to_location = new_stor
>>> unit_load8.click('assign')
>>> unit_load8.click('do')
Execute global drop wizard with proposed end date::
>>> drop_ul = Wizard('stock.unit_load.do_drop', [])
>>> drop_ul.form.ul_code = unit_load4.code
>>> drop_ul.execute('pre_data')
>>> drop_ul.form.location = production_loc2
>>> not bool(drop_ul.form.end_date)
True
>>> drop_ul.execute('try_')
>>> unit_load4.reload()
>>> move, = unit_load4.drop_moves
>>> not bool(move.end_date)
True
>>> time.sleep(5)
>>> drop_ul = Wizard('stock.unit_load.do_drop', [])
>>> drop_ul.form.ul_code = unit_load5.code
>>> drop_ul.execute('pre_data')
>>> drop_ul.form.location = production_loc2
>>> drop_ul.form.parallel = True
>>> drop_ul.execute('try_')
>>> unit_load5.reload()
>>> move2, = unit_load5.drop_moves
>>> not bool(move2.end_date)
True
>>> move2.end_date = datetime.datetime.now()
>>> move2.save()
>>> time.sleep(5)
>>> drop_ul = Wizard('stock.unit_load.do_drop', [])
>>> drop_ul.form.ul_code = unit_load6.code
>>> drop_ul.execute('pre_data')
>>> drop_ul.form.location = production_loc2
>>> drop_ul.form.parallel = True
>>> drop_ul.execute('try_')
>>> unit_load6.reload()
>>> move3, = unit_load6.drop_moves
>>> not bool(move3.end_date)
True
>>> time.sleep(5)
>>> drop_ul = Wizard('stock.unit_load.do_drop', [])
>>> drop_ul.form.ul_code = unit_load7.code
>>> drop_ul.execute('pre_data')
>>> drop_ul.form.location = production_loc2
>>> drop_ul.form.parallel = True
>>> drop_ul.execute('try_')
>>> unit_load7.reload()
>>> move4, = unit_load7.drop_moves
>>> not bool(move4.end_date)
True
>>> unit_load7.click('assign')
>>> unit_load7.click('do')
>>> time.sleep(5)
>>> drop_ul = Wizard('stock.unit_load.do_drop', [])
>>> drop_ul.form.ul_code = unit_load8.code
>>> drop_ul.execute('pre_data')
>>> drop_ul.form.location = production_loc2
>>> now = datetime.datetime.now().replace(microsecond=0)
>>> drop_ul.form.end_date = now
>>> drop_ul.execute('try_')
>>> move.reload()
>>> move3.reload()
>>> move4.reload()
>>> not bool(move.end_date)
True
>>> bool(move3.end_date)
True
>>> move3.end_date == now
True
>>> move3.state
'done'
>>> bool(move4.end_date)
True
>>> move4.end_date == now
True
>>> move4.state
'done'

View File

@ -798,7 +798,8 @@ class UnitLoad(ModelSQL, ModelView):
max_date, location_id = None, None
tup_rev = check_start_date and -1 or 1
for move in sorted([m for m in self.moves if m.product.id == product_id
], key=lambda x: (x.end_date or datetime.datetime.min,
], key=lambda x: (
x.end_date or x.start_date or datetime.datetime.min,
x.start_date or datetime.datetime.min)[::tup_rev],
reverse=True):
if move.state == 'cancelled':
@ -1590,7 +1591,7 @@ class UnitLoad(ModelSQL, ModelView):
return []
if not self.last_moves or not self.drop_moves:
return []
at_date = max(m.end_date for m in self.last_moves)
at_date = max(m.end_date or m.start_date for m in self.last_moves)
production_ids = list(map(int, self.production_moves))
return [m.id for m in self.moves if m.from_location.type in (
'production', 'lost_found') and m.to_location.type == 'storage' and
@ -1849,7 +1850,11 @@ class DropUnitLoadData(ModelView):
unit_load = fields.Many2One('stock.unit_load', 'Unit load', readonly=True)
start_date = fields.DateTime('Start date', required=True)
end_date = fields.DateTime('End date')
end_date = fields.DateTime('End date',
states={
'readonly': Bool(Eval('parallel')),
},
depends=['parallel'])
location = fields.Many2One('stock.location', 'Location', required=True,
domain=[('type', 'in', ('production', 'lost_found'))])
cases_quantity = fields.Float('Cases', readonly=True,
@ -1865,6 +1870,23 @@ class DropUnitLoadData(ModelView):
],
depends=['cases_digits', 'available_cases_quantity'])
cases_digits = fields.Integer('Cases Digits')
parallel = fields.Boolean('Parallel',
states={
'invisible': Not(Equal(Eval('propose_drop_end_date'), 'last_drop'))
},
depends=['propose_drop_end_date'])
propose_drop_end_date = fields.Selection('_get_propose_drop_end_date',
'Propose drop UL end date')
@fields.depends('parallel', 'end_date')
def on_change_parallel(self):
if self.parallel and self.end_date:
self.end_date = None
@classmethod
def _get_propose_drop_end_date(cls):
Conf = Pool().get('production.configuration')
return Conf.propose_drop_end_date.selection
class DropUnitLoadFailedProduct(ModelView):
@ -2010,7 +2032,7 @@ class DropUnitLoad(Wizard):
def default_data(self, fields):
pool = Pool()
tran = Transaction()
Conf = pool.get('stock.configuration')
Conf = pool.get('production.configuration')
User = pool.get('res.user')
Unitload = pool.get('stock.unit_load')
user = User(tran.user)
@ -2026,10 +2048,11 @@ class DropUnitLoad(Wizard):
'cases_quantity': unit_load.cases_quantity,
'available_cases_quantity': unit_load.available_cases_quantity,
'drop_cases_quantity': unit_load.available_cases_quantity,
'cases_digits': unit_load.cases_digits
'cases_digits': unit_load.cases_digits,
'propose_drop_end_date': conf.propose_drop_end_date,
}
if (tran.context.get('active_model') == Unitload.__name__ or
conf.propose_drop_end_date):
if (tran.context.get('active_model') == Unitload.__name__
or conf.propose_drop_end_date == 'start_date'):
res['end_date'] = drop_date
return res
@ -2123,18 +2146,37 @@ class DropUnitLoad(Wizard):
def transition_try_(self):
pool = Pool()
Unitload = pool.get('stock.unit_load')
Move = pool.get('stock.move')
Configuration = pool.get('stock.configuration')
ProductionConfiguration = pool.get('production.configuration')
configuration = Configuration(1)
prod_conf = ProductionConfiguration(1)
do = (self.data.end_date and configuration.do_ul_drop)
if Unitload.drop_try([self.current_ul],
to_location=self.data.location,
start_date=self.data.start_date,
end_date=self.data.end_date or datetime.datetime.now(),
end_date=self.data.end_date,
cases_quantity=self.data.drop_cases_quantity,
done_moves=do):
if (prod_conf.propose_drop_end_date == 'last_drop'
and not self.data.parallel):
moves = Move.search(self.get_last_drop_moves_domain())
moves = sorted(moves, key=lambda m: m.start_date, reverse=True)
to_write = []
for move in moves:
if move.end_date:
break
to_write.append(move)
if to_write:
Move.write(to_write, {'end_date': self.data.start_date})
uls = list(set(m.unit_load for m in to_write
if m.state != 'done'))
if uls:
Unitload.do(uls)
if not self.data.end_date:
elif (not self.data.end_date
and not prod_conf.propose_drop_end_date):
return 'end_date'
if Transaction().context.get('active_model') == Unitload.__name__:
return 'end'
@ -2165,6 +2207,19 @@ class DropUnitLoad(Wizard):
return 'end_date'
return 'end'
def get_last_drop_moves_domain(self):
return [
('unit_load', '!=', None),
('to_location', '=', self.data.location),
('start_date', '>=', datetime.datetime.combine(
self.data.start_date.date(), datetime.datetime.min.time())),
('start_date', '<', self.data.start_date),
['OR',
('end_date', '=', None),
('end_date', '<', self.data.end_date)
]
]
# TODO: implement odt report
class UnitLoadLabel(CompanyReport):

View File

@ -10,8 +10,6 @@
<field name="ul_production_type"/>
<label name="do_ul_drop"/>
<field name="do_ul_drop"/>
<label name="propose_drop_end_date"/>
<field name="propose_drop_end_date"/>
</xpath>
<xpath expr="/form/separator[@id='shipment']" position="before">
<separator id="categories" colspan="4" string="Product Categories"/>

View File

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. -->
<data>
<xpath expr="/form/field[@name='production_sequence']" position="after">
<label name="propose_drop_end_date"/>
<field name="propose_drop_end_date"/>
</xpath>
</data>

View File

@ -19,4 +19,6 @@
<label name="cases_quantity" string="/"/>
<field name="cases_quantity"/>
</group>
<label name="parallel"/>
<field name="parallel"/>
</form>