Allow load ULs in done state.
This commit is contained in:
parent
91431c360a
commit
0ef0ca7892
128
load.py
128
load.py
|
@ -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
|
||||
|
|
25
load.xml
25
load.xml
|
@ -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>
|
|
@ -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"
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -4,6 +4,7 @@ depends:
|
|||
carrier_load
|
||||
ir
|
||||
res
|
||||
sale_unit_load
|
||||
stock_unit_load
|
||||
|
||||
xml:
|
||||
|
|
Loading…
Reference in New Issue