parent
feb2269f59
commit
e32064d5f3
|
@ -6,6 +6,7 @@ from .unit_load import (UnitLoad, UnitLoadMove, MoveUnitLoad,
|
|||
MoveUnitLoadStart)
|
||||
from .stock import (Move, UnitLoadsByLocations,
|
||||
UnitLoadsByLocationsStart)
|
||||
from .shipment import ShipmentOut
|
||||
|
||||
|
||||
def register():
|
||||
|
@ -16,6 +17,7 @@ def register():
|
|||
Move,
|
||||
MoveUnitLoadStart,
|
||||
UnitLoadsByLocationsStart,
|
||||
ShipmentOut,
|
||||
module='stock_unit_load', type_='model')
|
||||
Pool.register(
|
||||
MoveUnitLoad,
|
||||
|
|
|
@ -338,4 +338,8 @@ msgstr "Abrir"
|
|||
|
||||
msgctxt "view:stock.unit_loads_by_locations.start:"
|
||||
msgid "Unit loads by Locations"
|
||||
msgstr "Unidades de carga por ubicación"
|
||||
msgstr "Unidades de carga por ubicación"
|
||||
|
||||
msgctxt "view:stock.shipment.out:"
|
||||
msgid "ULs"
|
||||
msgstr "UdCs"
|
|
@ -0,0 +1,69 @@
|
|||
# The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
from trytond.model import fields
|
||||
from trytond.pool import PoolMeta, Pool
|
||||
from trytond.pyson import Eval
|
||||
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
__all__ = ['ShipmentOut']
|
||||
|
||||
|
||||
class ShipmentOut:
|
||||
__name__ = 'stock.shipment.out'
|
||||
|
||||
unit_loads = fields.Function(
|
||||
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')
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(ShipmentOut, cls).__setup__()
|
||||
for _field_name in ('inventory_moves', 'outgoing_moves'):
|
||||
_field = getattr(cls, _field_name)
|
||||
if _field.states.get('readonly'):
|
||||
_field.states['readonly'] |= Eval('unit_loads')
|
||||
else:
|
||||
_field.states['readonly'] = Eval('unit_loads')
|
||||
if 'unit_loads' not in _field.depends:
|
||||
_field.depends.append('unit_loads')
|
||||
|
||||
def get_unit_loads(self, name=None):
|
||||
if not self.outgoing_moves:
|
||||
return []
|
||||
uls = set(m.unit_load.id for m in self.outgoing_moves if m.unit_load)
|
||||
return list(uls)
|
||||
|
||||
@classmethod
|
||||
def set_unit_loads(cls, records, name, value):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def search_unit_loads(cls, name, clause):
|
||||
_field = 'moves.unit_load'
|
||||
if '.' in name:
|
||||
_field += '.%s' % name[10:]
|
||||
return [(_field, ) + tuple(clause[1:])]
|
||||
|
||||
@fields.depends('unit_loads', 'outgoing_moves')
|
||||
def on_change_unit_loads(self):
|
||||
moves = []
|
||||
ul_ids = [ul.id for ul in self.unit_loads]
|
||||
if self.outgoing_moves:
|
||||
moves.extend([m for m in self.outgoing_moves if m.unit_load.id in ul_ids])
|
||||
for ul in self.unit_loads:
|
||||
if ul.id in [m.unit_load.id for m in moves]:
|
||||
continue
|
||||
new_moves = ul._get_new_moves({'from_location': self.warehouse_output.id,
|
||||
'to_location': self.customer_location.id,
|
||||
'planned_date': self.planned_date,
|
||||
'effective_date': self.effective_date})
|
||||
moves.extend(new_moves)
|
||||
self.outgoing_moves = moves
|
||||
|
||||
def _get_inventory_move(self, move):
|
||||
res = super(ShipmentOut, self)._get_inventory_move(move)
|
||||
res.unit_load = move.unit_load
|
||||
return res
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
<!-- Shipment out -->
|
||||
<record model="ir.ui.view" id="shipment_out_view_form">
|
||||
<field name="model">stock.shipment.out</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">shipment_out_form</field>
|
||||
<field name="inherit" ref="stock.shipment_out_view_form"/>
|
||||
</record>
|
||||
</data>
|
||||
</tryton>
|
3
stock.py
3
stock.py
|
@ -17,7 +17,8 @@ class Move:
|
|||
__name__ = 'stock.move'
|
||||
|
||||
unit_load = fields.Many2One('stock.unit_load', 'Unit load',
|
||||
ondelete='RESTRICT', select=True)
|
||||
ondelete='RESTRICT', select=True,
|
||||
readonly=True)
|
||||
|
||||
|
||||
class UnitLoadsByLocationsStart(ModelView):
|
||||
|
|
|
@ -9,3 +9,4 @@ xml:
|
|||
configuration.xml
|
||||
unit_load.xml
|
||||
stock.xml
|
||||
shipment.xml
|
||||
|
|
37
unit_load.py
37
unit_load.py
|
@ -1,6 +1,8 @@
|
|||
# The COPYRIGHT file at the top level of this repository contains the full
|
||||
# copyright notices and license terms.
|
||||
import datetime
|
||||
from functools import partial
|
||||
from itertools import groupby
|
||||
from sql import Literal, Null
|
||||
from sql.aggregate import Max
|
||||
from sql.conditionals import Coalesce
|
||||
|
@ -105,6 +107,10 @@ class UnitLoad(ModelView, ModelSQL):
|
|||
def get_code_readonly(self, name):
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def default_state(cls):
|
||||
return 'draft'
|
||||
|
||||
@classmethod
|
||||
def create(cls, vlist):
|
||||
model_sequence = Pool().get('ir.sequence')
|
||||
|
@ -381,17 +387,36 @@ class UnitLoad(ModelView, ModelSQL):
|
|||
cls.raise_user_error('wrong_move_location', (record.rec_name, to_location.rec_name))
|
||||
if max(m.planned_date or m.effective_date for m in record.last_moves) > at_date:
|
||||
cls.raise_user_error('wrong_move_date', (record.rec_name, at_date))
|
||||
new_moves = Move.copy(record.last_moves, {'origin': None,
|
||||
'shipment': None,
|
||||
'from_location': from_location.id,
|
||||
'to_location': to_location.id,
|
||||
'planned_date': at_date,
|
||||
'effective_date': at_date})
|
||||
new_moves = record._get_new_moves({'from_location': from_location.id,
|
||||
'to_location': to_location.id,
|
||||
'planned_date': at_date})
|
||||
to_create.extend(new_moves)
|
||||
if to_create:
|
||||
Move.save(to_create)
|
||||
return Move.browse(map(int, to_create))
|
||||
|
||||
def _get_new_moves(self, default_values={}):
|
||||
pool = Pool()
|
||||
Move = pool.get('stock.move')
|
||||
Uom = pool.get('product.uom')
|
||||
|
||||
default_values.update({'origin': None,
|
||||
'shipment': None,
|
||||
'effective_date': default_values.get('planned_date') or None}
|
||||
)
|
||||
moves = []
|
||||
keyfunc = partial(self._get_group_move_key, self.last_moves)
|
||||
data = sorted(self.last_moves, key=keyfunc)
|
||||
for key, grouped_moves in groupby(data, key=keyfunc):
|
||||
_grouped_moves = list(grouped_moves)
|
||||
move, = Move.copy([_grouped_moves[0]], default_values)
|
||||
move.quantity = sum(Uom.compute_qty(m.uom, m.quantity, move.uom) for m in _grouped_moves)
|
||||
moves.append(move)
|
||||
return moves
|
||||
|
||||
def _get_group_move_key(self, moves, move):
|
||||
return (move.to_location.id, move.product.id)
|
||||
|
||||
def get_state(self, name=None):
|
||||
pool = Pool()
|
||||
Move = pool.get('stock.move')
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
||||
copyright notices and license terms. -->
|
||||
<data>
|
||||
<xpath expr="/form" position="inside">
|
||||
<xpath expr="/form/field[@name='effective_date']" position="after">
|
||||
<label name="unit_load"/>
|
||||
<field name="unit_load"/>
|
||||
</xpath>
|
||||
|
|
|
@ -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='inventory_moves']" position="before">
|
||||
<page id="uls" string="ULs">
|
||||
<field name="unit_loads" colspan="4" widget="many2many"/>
|
||||
</page>
|
||||
</xpath>
|
||||
</data>
|
Loading…
Reference in New Issue