Allow load ULs in done state.

This commit is contained in:
Sergio Morillo 2016-01-28 23:37:01 +01:00
parent 91431c360a
commit 0ef0ca7892
5 changed files with 212 additions and 16 deletions

128
load.py
View File

@ -1,8 +1,11 @@
# The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import fields, ModelView, Workflow
from functools import partial
from itertools import groupby
from trytond.model import fields, ModelView, Workflow, Model
from trytond.pool import PoolMeta, Pool
from trytond.pyson import Eval
from trytond.pyson import Eval, Bool, Not
from trytond.transaction import Transaction
from trytond.wizard import Wizard, StateTransition, StateView, Button
@ -52,6 +55,8 @@ class LoadOrder:
ul_origin_restrict = fields.Boolean('Restrict UL origin',
states={'readonly': Eval('state').in_(['cancel', 'done'])},
depends=['state'])
ul_quantity = fields.Function(fields.Float('ULs', digits=(16, 0)),
'get_ul_quantity')
@classmethod
def __setup__(cls):
@ -69,7 +74,10 @@ class LoadOrder:
'ul_origin': 'UL "%s" does not belong to any origin of this load order.',
'ul_overload': 'All valid lines of load order "%s" are complete. Cannot load more ULs.',
'ul_data': 'Product data of UL "%s" does not match with any line of load order "%s".',
'draft_ul': 'Cannot change state to Draft for load order "%s" because it has loaded ULs.'})
'draft_ul': 'Cannot change state to Draft for load order "%s" because it has loaded ULs.',
'pending_uls': 'You have loaded less ULs (%s) than expected (%s).',
'sale_confirmed': 'Cannot force loading ULs because sale "%s" is confirmed.'
})
@classmethod
def default_ul_origin_restrict(cls):
@ -130,8 +138,9 @@ class LoadOrder:
for item in grouped_items:
new_moves = item._get_new_moves({'from_location': sale_line.from_location.id,
'to_location': sale_line.to_location.id,
'start_date': self.start_date,
'end_date': self.end_date})
'start_date': self.end_date,
'end_date': self.end_date,
'state': 'draft'})
move, = [m for m in new_moves if m.product == item.product]
move.origin = sale_line
moves.append(move)
@ -146,15 +155,84 @@ class LoadOrder:
Move.save(other_moves)
return moves
def _update_sale(self, new_uls):
pool = Pool()
Move = pool.get('stock.move')
if not self.sale:
return
if self.sale.state not in ('draft', 'quotation'):
self.raise_user_error('sale_confirmed', self.sale.rec_name)
keyfunc = partial(self._group_sale_line_key, new_uls)
items = sorted(new_uls, key=keyfunc)
for key, grouped_items in groupby(items, key=keyfunc):
_groupitems = list(grouped_items)
key_dict = dict(key)
_fields = key_dict.keys()
def get_line_values(line):
line_values = []
for _field in _fields:
value = getattr(line, _field, None)
if isinstance(value, Model):
value = int(value)
line_values.append(value)
return line_values
sale_line = [l for l in self.sale.lines
if get_line_values(l) == key_dict.values()]
if not sale_line:
sale_line = self._get_load_sale_line(key, _groupitems)
sale_line.sale = self.sale
else:
sale_line, = sale_line
self._update_sale_line(sale_line, _groupitems)
sale_line.save()
shipment = sale_line.sale.shipments[0]
outgoing_moves = self._get_shipment_moves(sale_line, _groupitems)
inventory_moves = []
for move in outgoing_moves:
move.shipment = shipment
_inventory = shipment._get_inventory_move(move)
_inventory.start_date = self.start_date
inventory_moves.append(_inventory)
Move.save(outgoing_moves + inventory_moves)
Move.assign(outgoing_moves)
Move.do(inventory_moves)
to_do = []
for move in self.outgoing_moves:
if move.state == 'draft':
_new_move = self._get_inventory_move(move)
_new_move.save()
to_do.extend([move, _new_move])
if to_do:
Move.do(to_do)
def _update_sale_line(self, sale_line, items):
sale_line.ul_quantity += len(items)
sale_line.quantity += sum(sale_line.unit.compute_qty(
item.uom, item.quantity, sale_line.unit) for item in items)
def _get_items(self):
return self.unit_loads
def get_ul_quantity(self, name=None):
if not self.lines:
return 0
return sum(l.ul_quantity or 0 for l in self.lines)
@classmethod
def do(cls, records):
pool = Pool()
Move = pool.get('stock.move')
super(LoadOrder, cls).do(records)
cls._check_loaded_quantity(records)
moves = []
for record in records:
moves.extend(
@ -163,6 +241,13 @@ class LoadOrder:
Move.save(moves)
Move.do([m for r in records for l in r.lines for m in l.moves])
@classmethod
def _check_loaded_quantity(cls, records):
for record in records:
if record.ul_quantity > len(record.unit_loads):
cls.raise_user_warning('pending_uls_%s' % record.id, 'pending_uls',
(len(record.unit_loads), int(record.ul_quantity)))
@classmethod
def draft(cls, records):
for record in records:
@ -261,6 +346,8 @@ class LoadOrder:
UL.save(unit_loads)
self._update_sale(unit_loads)
def check_ul_data_match(self, lines, unit_load):
valid_lines = []
for line in lines:
@ -313,7 +400,10 @@ class LoadUnitLoadData(ModelView):
__name__ = 'carrier.load_uls.data'
load_order = fields.Many2One('carrier.load.order', 'Order',
readonly=True)
readonly=True,
depends=['standalone', 'order_state'])
order_state = fields.Char('State', readonly=True)
standalone = fields.Boolean('Standalone', readonly=True)
ul_code = fields.Char('UL')
uls_to_load = fields.One2Many('stock.unit_load', None, 'ULs to load',
domain=[('state', '=', 'done')])
@ -337,8 +427,13 @@ class LoadUnitLoad(Wizard):
data = StateView('carrier.load_uls.data',
'carrier_load_ul.load_uls_data_view_form',
[Button('Exit', 'end', 'tryton-cancel'),
Button('Unload ULs', 'unload_', 'tryton-clear'),
Button('Do', 'do_', 'tryton-ok'),
Button('Unload ULs', 'unload_', 'tryton-clear',
states={'invisible': Eval('order_state') == 'done',
'readonly': Eval('order_state') == 'done'}),
Button('Do', 'do_', 'tryton-ok',
states={'readonly': Eval('ul_code') | Eval('uls_to_load'),
'invisible': Not(Bool(Eval('standalone'))) |
(Eval('order_state') == 'done')}),
Button('Load', 'load_', 'tryton-list-add', default=True)])
load_ = StateTransition()
unload_ = StateTransition()
@ -358,9 +453,11 @@ class LoadUnitLoad(Wizard):
return 'data'
def default_data(self, fields):
order = self._get_load_order()
order, standalone = self._get_load_order()
res = {'load_order': order.id,
'loaded_uls': 0}
'loaded_uls': 0,
'standalone': standalone,
'order_state': order.state}
if order.unit_loads:
res['loaded_uls'] = len(order.unit_loads)
return res
@ -372,7 +469,7 @@ class LoadUnitLoad(Wizard):
if not self.data.ul_code and not self.data.uls_to_load:
self.raise_user_error('ul_required')
order = self._get_load_order()
order, _ = self._get_load_order()
uls = []
if self.data.ul_code:
ul = UL.search([('code', '=', self.data.ul_code)])
@ -391,7 +488,8 @@ class LoadUnitLoad(Wizard):
pool = Pool()
Order = pool.get('carrier.load.order')
Order.do([self._get_load_order()])
order, _ = self._get_load_order()
Order.do([order])
# TODO: print reports
return 'end'
@ -400,8 +498,8 @@ class LoadUnitLoad(Wizard):
Order = pool.get('carrier.load.order')
if Transaction().context.get('active_model') == LoadOrder.__name__:
return Order(Transaction().context.get('active_id'))
return Order(self.order.load_order.id)
return Order(Transaction().context.get('active_id')), False
return Order(self.order.load_order.id), True
def transition_unload_(self):
pool = Pool()
@ -487,4 +585,4 @@ class RoadTransportNote:
for ul in order.unit_loads if ul.product.id == product.id) or None
if not res:
return super(RoadTransportNote, cls).product_weight(order, product, language)
return res
return res

View File

@ -3,6 +3,15 @@
this repository contains the full copyright notices and license terms. -->
<tryton>
<data>
<!-- Force load and unload UL -->
<record model="res.group" id="group_force_unload">
<field name="name">Force load UL</field>
</record>
<record model="res.user-res.group" id="user_admin_group_force_unload">
<field name="user" ref="res.user_admin"/>
<field name="group" ref="group_force_unload"/>
</record>
<!-- Configuration -->
<record model="ir.ui.view" id="carrier_configuration_view_form">
<field name="model">carrier.configuration</field>
@ -82,5 +91,21 @@ this repository contains the full copyright notices and license terms. -->
<record model="ir.action.report" id="carrier_load.report_load_sheet">
<field name="report">carrier_load_ul/load_sheet.odt</field>
</record>
<!-- Wizard Force load UL -->
<record model="ir.action.wizard" id="wizard_force_load_ul">
<field name="name">Load UL</field>
<field name="wiz_name">carrier.load_uls</field>
<field name="model">carrier.load.order</field>
</record>
<record model="ir.action.keyword" id="act_force_load_ul_keyword1">
<field name="keyword">form_action</field>
<field name="model">carrier.load.order,-1</field>
<field name="action" ref="wizard_force_load_ul"/>
</record>
<record model="ir.action-res.group" id="wizard_force_load_ul_group_load">
<field name="action" ref="wizard_force_load_ul"/>
<field name="group" ref="group_force_unload"/>
</record>
</data>
</tryton>

View File

@ -42,6 +42,14 @@ msgctxt "error:carrier.load.order:"
msgid "Cannot change state to Draft for load order \"%s\" because it has loaded ULs."
msgstr "No puede establecerse el estado Borrador para la orden \"%s\" porque tiene UdCs cargadas."
msgctxt "error:carrier.load.order:"
msgid "You have loaded less ULs (%s) than expected (%s)."
msgstr "Ha cargado menos UdCs (%s) de las esperadas (%s)."
msgctxt "error:carrier.load.order:"
msgid "Cannot force loading ULs because sale \"%s\" is confirmed."
msgstr "No puede forzar la carga de UdCs porque la Venta asociada \"%s\" está confirmada."
msgctxt "error:carrier.load_uls:"
msgid "Cannot find Unit load \"%s\"."
msgstr "No se ha podido encontrar la UdC \"%s\"."
@ -214,4 +222,8 @@ msgstr "Descargar"
msgctxt "odt:carrier.load.sheet:"
msgid "ULs"
msgstr "UdCs"
msgstr "UdCs"
msgctxt "model:ir.action,name:wizard_force_load_ul"
msgid "Load UL"
msgstr "Cargar UdC"

View File

@ -179,6 +179,7 @@ Create unit load::
>>> template.account_expense = expense
>>> template.account_revenue = revenue
>>> template.save()
>>> main_product = ul.product
Add other products to unit load::
@ -331,6 +332,12 @@ Unload UL::
Finish loading::
>>> start_load = Wizard('carrier.load_uls', [order])
>>> start_load.execute('do_') # doctest:
Traceback (most recent call last):
...
UserWarning: ('UserWarning', ('pending_uls_1', 'You have loaded less ULs (1) than expected (2).', ''))
>>> Model.get('res.user.warning')(user=config.user,
... name='pending_uls_1', always=True).save()
>>> start_load.execute('do_')
>>> order.reload()
>>> len(order.unit_loads)
@ -384,6 +391,59 @@ Check sale::
>>> order.outgoing_moves[0].quantity
2.0
Force load another UL::
>>> Unitload = Model.get('stock.unit_load')
>>> ul = create_unit_load(config=config, do_state=False,
... default_values={'start_date': datetime.datetime.now() + relativedelta(days=-1)})
>>> ul.product = main_product
>>> ul.save()
>>> move = ul.moves.new()
>>> move.planned_date = today
>>> move.product = product
>>> move.quantity = Decimal(2)
>>> move.from_location = ul.moves[0].from_location
>>> move.to_location = ul.moves[0].to_location
>>> move.currency = move.company.currency
>>> ul.save()
>>> ul.click('assign')
>>> ul.click('do')
>>> Model.get('res.user.warning')(user=config.user,
... name='loading_ul_origin_3', always=True).save()
>>> start_load = Wizard('carrier.load_uls', [order])
>>> start_load.form.ul_code = ul.code
>>> start_load.execute('load_')
>>> start_load.execute('end')
>>> sale = order.sale
>>> sale.reload()
>>> len(sale.lines)
1
>>> sale.lines[0].quantity
70.0
>>> shipment = sale.shipments[0]
>>> shipment.reload()
>>> len(shipment.unit_loads)
2
>>> ul in shipment.unit_loads
True
>>> len(shipment.outgoing_moves)
2
>>> len(shipment.inventory_moves)
2
>>> set(m.state for m in shipment.outgoing_moves)
set([u'assigned'])
>>> set(m.state for m in shipment.inventory_moves)
set([u'done'])
>>> order.reload()
>>> len(order.inventory_moves)
2
>>> sum(m.quantity for m in order.inventory_moves)
4.0
>>> len(order.outgoing_moves)
2
>>> sum(m.quantity for m in order.outgoing_moves)
4.0
Confirm load::
>>> load.click('confirm')

View File

@ -4,6 +4,7 @@ depends:
carrier_load
ir
res
sale_unit_load
stock_unit_load
xml: