Drop UL wizard improved to have unit load and do moves.

This commit refs #7068
This commit is contained in:
Javier Uribe 2019-01-29 14:00:02 +01:00
parent e14e623252
commit e4b107402c
13 changed files with 374 additions and 46 deletions

View File

@ -5,11 +5,13 @@ from .configuration import (Configuration, ConfigurationSequence,
ConfigurationULProductionType)
from .unit_load import (UnitLoad, UnitLoadMove, MoveUnitLoad,
MoveUnitLoadStart, UnitLoadLabel, DropUnitLoad,
DropUnitLoadStart, DropUnitLoadFailed, DropUnitLoadFailedProduct,
BatchDropUnitLoad, BatchDropUnitLoadData, BatchDropUnitLoadConfirm)
DropUnitLoadData, DropUnitLoadFailed, DropUnitLoadFailedProduct,
BatchDropUnitLoad, BatchDropUnitLoadData, BatchDropUnitLoadConfirm,
DropUnitLoadUL, DropUnitLoadEndDate)
from .stock import (Move, UnitLoadsByLocations,
UnitLoadsByLocationsStart)
from .shipment import ShipmentOut, ShipmentInternal
from .res import User
def register():
@ -21,7 +23,9 @@ def register():
UnitLoadMove,
Move,
MoveUnitLoadStart,
DropUnitLoadStart,
DropUnitLoadEndDate,
DropUnitLoadData,
DropUnitLoadUL,
DropUnitLoadFailed,
DropUnitLoadFailedProduct,
UnitLoadsByLocationsStart,
@ -29,6 +33,7 @@ def register():
ShipmentInternal,
BatchDropUnitLoadData,
BatchDropUnitLoadConfirm,
User,
module='stock_unit_load', type_='model')
Pool.register(
MoveUnitLoad,

View File

@ -364,6 +364,10 @@ msgctxt "model:ir.action,name:wizard_drop_unit_load"
msgid "Drop UL"
msgstr "Volcar UdC"
msgctxt "model:ir.action,name:wizard_global_drop_unit_load"
msgid "Drop UL"
msgstr "Volcar UdC"
msgctxt "model:ir.action,name:wizard_uls_by_locations"
msgid "ULs by Locations"
msgstr "UdCs por ubicación"
@ -394,6 +398,10 @@ msgctxt "model:ir.ui.menu,name:menu_unit_load"
msgid "Unit loads"
msgstr "Unidades de carga"
msgctxt "model:ir.ui.menu,name:menu_drop_ul"
msgid "Drop UL"
msgstr "Volcar UdC"
msgctxt "model:res.group,name:group_unit_load_batch_drop"
msgid "Unit load batch dropping"
msgstr "Volcado masivo de UdCs"
@ -590,11 +598,11 @@ msgctxt "model:ir.action,name:report_ul_label"
msgid "Label"
msgstr "Etiqueta"
msgctxt "wizard_button:stock.unit_load.do_drop,start,end:"
msgctxt "wizard_button:stock.unit_load.do_drop,data,end:"
msgid "Cancel"
msgstr "Cancelar"
msgctxt "wizard_button:stock.unit_load.do_drop,start,try_:"
msgctxt "wizard_button:stock.unit_load.do_drop,data,try_:"
msgid "OK"
msgstr "Aceptar"
@ -618,15 +626,15 @@ msgctxt "view:stock.unit_load.do_drop_failed.product:"
msgid "Dropping UL product data"
msgstr "Datos de volcado de UdC"
msgctxt "field:stock.unit_load.do_drop_start,start_date:"
msgctxt "field:stock.unit_load.do_drop.data,start_date:"
msgid "Start date"
msgstr "Fecha inicio"
msgctxt "field:stock.unit_load.do_drop_start,end_date:"
msgctxt "field:stock.unit_load.do_drop.data,end_date:"
msgid "End date"
msgstr "Fecha fin"
msgctxt "field:stock.unit_load.do_drop_start,location:"
msgctxt "field:stock.unit_load.do_drop.data,location:"
msgid "Location"
msgstr "Ubicación"
@ -646,10 +654,26 @@ msgctxt "field:stock.unit_load.do_drop_failed.product,product:"
msgid "Product"
msgstr "Producto"
msgctxt "wizard_button:stock.unit_load.do_drop,start,failed:"
msgctxt "field:stock.unit_load.do_drop.unit_load,ul_code:"
msgid "Unit load Code"
msgstr "Código UdC"
msgctxt "view:stock.unit_load.do_drop.unit_load:"
msgid "Introduce a new Unit load code to be dropped."
msgstr "Introduzca un nuevo Código de Unidad de carga para iniciar su volcado."
msgctxt "wizard_button:stock.unit_load.do_drop,data,failed:"
msgid "Set return locations"
msgstr "Definir ubs. retorno"
msgctxt "wizard_button:stock.unit_load.do_drop,unit_load,end:"
msgid "Cancel"
msgstr "Cancelar"
msgctxt "wizard_button:stock.unit_load.do_drop,unit_load,data:"
msgid "OK"
msgstr "Aceptar"
msgctxt "view:stock.unit_load.batch_drop.data:"
msgid "UL Batch dropping"
msgstr "Volcado masivo de UdCs"
@ -689,3 +713,27 @@ msgstr "Albarán cliente"
msgctxt "view:stock.unit_load:"
msgid "Last moves will be deleted."
msgstr "El último movimiento de UdC será eliminado."
msgctxt "error:stock.unit_load.do_drop:"
msgid "Cannot find Unit load \"%s\"."
msgstr "No se ha podido encontrar la UdC \"%s\"."
msgctxt "field:res.user,ul_drop_location:"
msgid "UL drop location"
msgstr "Ubicación volcado UdC"
msgctxt "field:stock.unit_load.do_drop.end_date,unit_load:"
msgid "Unit load"
msgstr "Unidad de carga"
msgctxt "view:stock.unit_load.do_drop.end_date:"
msgid "Waiting to drop (the end date will be set with the current time)."
msgstr "Esperando para volcar (la fecha fin utilizada será la hora actual)."
msgctxt "wizard_button:stock.unit_load.do_drop,end_date,end:"
msgid "Cancel"
msgstr "Cancelar"
msgctxt "wizard_button:stock.unit_load.do_drop,end_date,data:"
msgid "Go back"
msgstr "Atrás"

14
res.py Normal file
View File

@ -0,0 +1,14 @@
# The COPYRIGHT file at the top level of this repository contains the full
# copyright notices and license terms.
from trytond.pool import PoolMeta
from trytond.model import fields
__all__ = ['User']
class User:
__name__ = 'res.user'
__metaclass__ = PoolMeta
ul_drop_location = fields.Many2One('stock.location', 'UL drop location',
domain=[('type', 'in', ('production', 'drop'))])

11
res.xml Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full copyright notices and license terms. -->
<tryton>
<data>
<record model="ir.ui.view" id="user_drop_location_view_form">
<field name="model">res.user</field>
<field name="inherit" ref="res.user_view_form"/>
<field name="name">user_form</field>
</record>
</data>
</tryton>

View File

@ -82,7 +82,8 @@ class ShipmentInternal:
fields.One2Many('stock.unit_load', None, 'Unit loads',
states={'readonly': Eval('state') != 'draft'},
depends=['state']),
'get_unit_loads', setter='set_unit_loads', searcher='search_unit_loads')
'get_unit_loads', setter='set_unit_loads',
searcher='search_unit_loads')
@classmethod
def __setup__(cls):

View File

@ -11,10 +11,12 @@ Imports::
>>> from decimal import Decimal
>>> from trytond.modules.company.tests.tools import create_company, \
... get_company
>>> from trytond.modules.stock_unit_load.tests.tools import create_unit_load
>>> today = datetime.date.today()
>>> tomorrow = today + relativedelta(days=1)
>>> time_ = datetime.datetime.now().time()
>>> time_ = time_.replace(microsecond=0)
>>> import time
Install unit load Module::
@ -219,3 +221,113 @@ Confirm drop::
>>> bool(unit_load.available)
False
Create another unit load::
>>> unit_load = UnitLoad()
>>> unit_load.start_date = datetime.datetime.now() - relativedelta(days=1)
>>> unit_load.end_date = unit_load.start_date + relativedelta(minutes=15)
>>> unit_load.production_type = 'location'
>>> unit_load.production_location = production_loc
>>> unit_load.product = product
>>> unit_load.cases_quantity = 5
>>> unit_load.save()
Add moves::
>>> unit_load.quantity = Decimal('35.0')
>>> move = unit_load.production_moves[0]
>>> move.to_location = new_stor
>>> input_move = unit_load.production_moves.new()
>>> input_move.product = aux_product
>>> input_move.quantity = Decimal('4')
>>> input_move.from_location = storage_loc
>>> input_move.to_location = production_loc
>>> output_move = unit_load.production_moves.new()
>>> output_move.product = aux_product
>>> output_move.quantity = Decimal('4')
>>> output_move.from_location = production_loc
>>> output_move.to_location = new_stor
>>> unit_load.warehouse = warehouse_loc
>>> unit_load.save()
>>> unit_load.click('assign')
>>> unit_load.click('do')
Add ul location to user::
>>> User = Model.get('res.user')
>>> admin, = User.find([('login', '=', 'admin')])
>>> admin.ul_drop_location = production_loc
>>> admin.save()
Execute global drop wizard::
>>> drop_ul = Wizard('stock.unit_load.do_drop', [])
>>> drop_ul.form.ul_code = '123'
>>> drop_ul.execute('data') # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
UserError: Cannot find Unit load "123".
>>> drop_ul.form.ul_code = unit_load.code
>>> drop_ul.execute('data')
Check default data and behavior on global drop wizard::
>>> drop_ul.form.location == production_loc
True
>>> drop_ul.form.end_date == None
True
>>> drop_ul.execute('try_')
>>> unit_load.reload()
>>> move = unit_load.drop_moves[0]
>>> move.state
u'draft'
>>> move.end_date == move.start_date
True
>>> time.sleep(1)
>>> drop_ul.execute('do_')
>>> move.reload()
>>> move.state
u'done'
>>> move.end_date > move.start_date
True
Create another unit load::
>>> unit_load = UnitLoad()
>>> unit_load.start_date = datetime.datetime.now() - relativedelta(days=1)
>>> unit_load.end_date = unit_load.start_date + relativedelta(minutes=15)
>>> unit_load.production_type = 'location'
>>> unit_load.production_location = production_loc
>>> unit_load.product = product
>>> unit_load.cases_quantity = 5
>>> unit_load.save()
Add moves::
>>> unit_load.quantity = Decimal('35.0')
>>> move = unit_load.production_moves[0]
>>> move.to_location = new_stor
>>> input_move = unit_load.production_moves.new()
>>> input_move.product = aux_product
>>> input_move.quantity = Decimal('4')
>>> input_move.from_location = storage_loc
>>> input_move.to_location = production_loc
>>> output_move = unit_load.production_moves.new()
>>> output_move.product = aux_product
>>> output_move.quantity = Decimal('4')
>>> output_move.from_location = production_loc
>>> output_move.to_location = new_stor
>>> unit_load.click('assign')
>>> unit_load.click('do')
Execute global drop wizard with force::
>>> drop_ul = Wizard('stock.unit_load.do_drop', [])
>>> drop_ul.form.ul_code = unit_load.code
>>> drop_ul.execute('data')
>>> drop_ul.form.location = production_loc
>>> drop_ul.form.start_date = datetime.datetime.now() - relativedelta(minutes=30)
>>> drop_ul.execute('try_')
>>> drop_ul.form.location = storage3
>>> drop_ul.execute('force')
>>> drop_ul.execute('do_')

View File

@ -14,3 +14,4 @@ xml:
unit_load.xml
stock.xml
shipment.xml
res.xml

View File

@ -22,9 +22,10 @@ from trytond.modules.stock_move_time.stock import DATE_FORMAT
from trytond.wizard import Wizard, StateTransition, StateView, Button
__all__ = ['UnitLoad', 'UnitLoadMove', 'MoveUnitLoad',
'MoveUnitLoadStart', 'UnitLoadLabel', 'DropUnitLoadStart',
'MoveUnitLoadStart', 'UnitLoadLabel', 'DropUnitLoadData',
'DropUnitLoad', 'DropUnitLoadFailed', 'DropUnitLoadFailedProduct',
'BatchDropUnitLoad', 'BatchDropUnitLoadData', 'BatchDropUnitLoadConfirm']
'BatchDropUnitLoad', 'BatchDropUnitLoadData', 'BatchDropUnitLoadConfirm',
'DropUnitLoadUL', 'DropUnitLoadEndDate']
MOVE_CHANGES = ['product', 'uom', 'production_type', 'production_location',
'warehouse', 'production_moves', 'moves', 'production_state', 'company',
@ -1394,23 +1395,15 @@ class MoveUnitLoad(Wizard):
return 'end'
class DropUnitLoadStart(ModelView):
"""Start dropping unit load"""
__name__ = 'stock.unit_load.do_drop_start'
class DropUnitLoadData(ModelView):
"""Drop Unit Load data"""
__name__ = 'stock.unit_load.do_drop.data'
start_date = fields.DateTime('Start date', required=True)
end_date = fields.DateTime('End date', required=True)
end_date = fields.DateTime('End date')
location = fields.Many2One('stock.location', 'Location', required=True,
domain=[('type', 'in', ('production', 'drop'))])
@staticmethod
def default_start_date():
return datetime.datetime.now()
@staticmethod
def default_end_date():
return datetime.datetime.now()
class DropUnitLoadFailedProduct(ModelView):
"""Drop unit load product data"""
@ -1440,39 +1433,136 @@ class DropUnitLoadFailed(ModelView):
self.products = products
class DropUnitLoadUL(ModelView):
"""Drop Unit load UL"""
__name__ = 'stock.unit_load.do_drop.unit_load'
ul_code = fields.Char('Unit load Code', required=True)
class DropUnitLoadEndDate(ModelView):
"""Drop Unit load UL"""
__name__ = 'stock.unit_load.do_drop.end_date'
unit_load = fields.Many2One('stock.unit_load', 'Unit load', readonly=True)
class DropUnitLoad(Wizard):
"""Drop Unit load"""
__name__ = 'stock.unit_load.do_drop'
start = StateView('stock.unit_load.do_drop_start',
'stock_unit_load.unit_load_drop_start_view_form', [
start = StateTransition()
unit_load = StateView('stock.unit_load.do_drop.unit_load',
'stock_unit_load.unit_load_drop_unit_load_view_form',
[Button('Cancel', 'end', 'tryton-cancel'),
Button('OK', 'data', 'tryton-ok', default=True)])
data = StateView('stock.unit_load.do_drop.data',
'stock_unit_load.unit_load_drop_data_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Set return locations', 'failed', 'tryton-go-next'),
Button('OK', 'try_', 'tryton-ok', default=True)])
try_ = StateTransition()
end_date = StateView('stock.unit_load.do_drop.end_date',
'stock_unit_load.unit_load_drop_end_date_view_form', [
Button('Go back', 'go_back', 'tryton-go-previous'),
Button('OK', 'do_', 'tryton-ok', default=True)])
do_ = StateTransition()
go_back = StateTransition()
failed = StateView('stock.unit_load.do_drop_failed',
'stock_unit_load.unit_load_drop_failed_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('OK', 'force', 'tryton-ok', default=True)])
force = StateTransition()
@classmethod
def __setup__(cls):
super(DropUnitLoad, cls).__setup__()
cls._error_messages.update({
'invalid_ul': 'Cannot find Unit load "%s".'
})
@property
def current_ul(self):
pool = Pool()
Unitload = pool.get('stock.unit_load')
if Transaction().context.get('active_model') == Unitload.__name__:
return Unitload(Transaction().context['active_id'])
ul = Unitload.search([
('code', '=', self._get_ul_code())], limit=1)
if not ul:
self.raise_user_error('invalid_ul', self.unit_load.ul_code)
return ul[0]
def _get_ul_code(self):
return self.unit_load.ul_code
def transition_start(self):
pool = Pool()
Unitload = pool.get('stock.unit_load')
if Transaction().context.get('active_model') == Unitload.__name__:
return 'data'
return 'unit_load'
def default_data(self, fields):
pool = Pool()
User = pool.get('res.user')
Unitload = pool.get('stock.unit_load')
user = User(Transaction().user)
res = self.current_ul and {
'start_date': datetime.datetime.now(),
'location': (user.ul_drop_location.id
if user.ul_drop_location else None)
}
if Transaction().context.get('active_model') == Unitload.__name__:
res['end_date'] = datetime.datetime.now()
return res
def default_end_date(self, fields):
return {
'unit_load': self.current_ul.id
}
def transition_go_back(self):
pool = Pool()
Unitload = pool.get('stock.unit_load')
Unitload.cancel([self.current_ul])
return 'data'
def transition_do_(self):
pool = Pool()
Move = pool.get('stock.move')
Unitload = pool.get('stock.unit_load')
now = datetime.datetime.now()
moves = [m for m in self.current_ul.drop_moves
if m.to_location.id == self.data.location.id and
m.state != 'done' and m.end_date < now]
if moves:
Move.write(moves, {'end_date': now})
Unitload.do([self.current_ul])
if Transaction().context.get('active_model') == Unitload.__name__:
return 'end'
return 'unit_load'
def transition_try_(self):
pool = Pool()
Unitload = pool.get('stock.unit_load')
if Unitload.drop_try([Unitload(Transaction().context['active_id'])],
to_location=self.start.location,
start_date=self.start.start_date,
end_date=self.start.end_date):
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()):
if not self.data.end_date:
return 'end_date'
return 'end'
else:
return 'failed'
return 'failed'
def default_failed(self, fields):
pool = Pool()
Unitload = pool.get('stock.unit_load')
ul = Unitload(Transaction().context['active_id'])
ul = self.current_ul
res = {'products': []}
for move in ul.last_moves:
if move.product.id != ul.product.id:
@ -1483,15 +1573,15 @@ class DropUnitLoad(Wizard):
pool = Pool()
Ul = pool.get('stock.unit_load')
ul = Ul(Transaction().context.get('active_id'))
return_locs = {p.product.id: p.location.id
for p in self.failed.products}
Ul.drop([ul], to_location=self.start.location,
start_date=self.start.start_date,
Ul.drop([self.current_ul], to_location=self.data.location,
start_date=self.data.start_date,
extra_params={
'end_date': self.start.end_date,
'end_date': self.data.end_date or datetime.datetime.now(),
'return_locs': return_locs})
if not self.data.end_date:
return 'end_date'
return 'end'

View File

@ -137,11 +137,30 @@
<field name="action" ref="wizard_drop_unit_load"/>
<field name="group" ref="stock.group_stock"/>
</record>
<!-- Start dropping UL-->
<record model="ir.ui.view" id="unit_load_drop_start_view_form">
<field name="model">stock.unit_load.do_drop_start</field>
<!-- Wizard Drop UL global -->
<record model="ir.action.wizard" id="wizard_global_drop_unit_load">
<field name="name">Drop UL</field>
<field name="wiz_name">stock.unit_load.do_drop</field>
</record>
<!-- Unit load dropping UL-->
<record model="ir.ui.view" id="unit_load_drop_unit_load_view_form">
<field name="model">stock.unit_load.do_drop.unit_load</field>
<field name="type">form</field>
<field name="name">unit_load_drop_start_form</field>
<field name="name">unit_load_drop_unit_load_form</field>
</record>
<!-- Data dropping end date -->
<record model="ir.ui.view" id="unit_load_drop_end_date_view_form">
<field name="model">stock.unit_load.do_drop.end_date</field>
<field name="type">form</field>
<field name="name">unit_load_drop_end_date_form</field>
</record>
<!-- Data dropping UL-->
<record model="ir.ui.view" id="unit_load_drop_data_view_form">
<field name="model">stock.unit_load.do_drop.data</field>
<field name="type">form</field>
<field name="name">unit_load_drop_data_form</field>
</record>
<!-- Failed dropping UL-->
<record model="ir.ui.view" id="unit_load_drop_failed_view_form">
@ -172,6 +191,8 @@
<!-- Menus -->
<menuitem action="act_unit_load" id="menu_unit_load"
parent="stock.menu_stock" sequence="40" name="Unit loads"/>
<menuitem id="menu_drop_ul" name="Drop UL"
parent="menu_unit_load" action="wizard_global_drop_unit_load"/>
<!-- UL label report -->
<record model="ir.action.report" id="report_ul_label">
<field name="name">Label</field>

View File

@ -0,0 +1,7 @@
<?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full copyright notices and license terms. -->
<form>
<separator id="waiting_drop" string="Waiting to drop (the end date will be set with the current time)." colspan="4"/>
<label name="unit_load"/>
<field name="unit_load"/>
</form>

View File

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full copyright notices and license terms. -->
<form>
<separator id="ul_code" string="Introduce a new Unit load code to be dropped." colspan="4"/>
<label name="ul_code"/>
<field name="ul_code"/>
</form>

10
view/user_form.xml Normal file
View File

@ -0,0 +1,10 @@
<?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/notebook/page[@id='preferences']/field[@name='language']" position="after">
<label name="ul_drop_location"/>
<field name="ul_drop_location"/>
</xpath>
</data>