Add unit loads to Shipment In Return.

This commit refs #10422
This commit is contained in:
jmpardo98 2020-10-30 12:57:53 +00:00 committed by Sergio Morillo
parent 381f1fed8f
commit 4c3f5275f9
8 changed files with 261 additions and 87 deletions

View File

@ -10,7 +10,8 @@ from .unit_load import (UnitLoad, UnitLoadMove, MoveUnitLoad,
DropUnitLoadUL, DropUnitLoadEndDate, CaseLabel)
from .stock import (Move, UnitLoadsByLocations,
UnitLoadsByLocationsStart, Move2)
from .shipment import ShipmentOut, ShipmentInternal, ShipmentOutReturn
from .shipment import (ShipmentOut, ShipmentInternal, ShipmentOutReturn,
ShipmentInReturn)
from .res import User
@ -32,6 +33,7 @@ def register():
ShipmentOut,
ShipmentInternal,
ShipmentOutReturn,
ShipmentInReturn,
BatchDropUnitLoadData,
BatchDropUnitLoadConfirm,
User,

View File

@ -766,6 +766,10 @@ msgctxt "model:ir.action,name:act_unit_loads_shipment_internal"
msgid "Internal Shipments"
msgstr "Albaranes internos"
msgctxt "model:ir.action,name:act_unit_loads_shipment_in_return"
msgid "Supplier Return Shipments"
msgstr "Albaranes devolución de proveedor"
msgctxt "model:ir.action,name:act_relate_shipment_out_unit_load"
msgid "Unit loads"
msgstr "Unidades de carga"
@ -774,6 +778,10 @@ msgctxt "model:ir.action,name:act_relate_shipment_out_return_unit_load"
msgid "Unit loads"
msgstr "Unidades de carga"
msgctxt "model:ir.action,name:act_relate_shipment_in_return_unit_load"
msgid "Unit loads"
msgstr "Unidades de carga"
msgctxt "field:stock.unit_load,shipment:"
msgid "Shipment"
msgstr "Albarán"
@ -876,4 +884,12 @@ msgstr "Unidades de carga"
msgctxt "view:stock.shipment.out.return:"
msgid "ULs"
msgstr "UdCs"
msgctxt "field:stock.shipment.in.return,unit_loads:"
msgid "Unit loads"
msgstr "Unidades de carga"
msgctxt "view:stock.shipment.in.return:"
msgid "ULs"
msgstr "UdCs"

View File

@ -3,29 +3,29 @@
import datetime
from trytond.model import fields
from trytond.pool import PoolMeta
from trytond.pyson import Eval, Not, Bool
from trytond.pyson import Eval, Not, Bool, And
__all__ = ['ShipmentOut', 'ShipmentInternal', 'ShipmentOutReturn']
__all__ = ['ShipmentOut', 'ShipmentInternal', 'ShipmentOutReturn',
'ShipmentInReturn']
class ShipmentOut(metaclass=PoolMeta):
__name__ = 'stock.shipment.out'
class ShipmentUnitLoadMixin(object):
unit_loads = fields.Function(
fields.One2Many('stock.unit_load', None, 'Unit loads', states={
'readonly': (Eval('state') != 'draft') |
Not(Bool('warehouse')),
'invisible': (
(Eval('state') != 'draft') & ~Eval('unit_loads', []))
fields.One2Many('stock.unit_load', None, 'Unit loads',
states={
'readonly': Eval('state') != 'draft',
'invisible': And(
Eval('state') != 'draft',
Not(Bool(Eval('unit_loads', []))))
},
depends=['state', 'warehouse']),
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'):
super().__setup__()
for _field_name in cls._get_ul_readonly_fields_name():
_field = getattr(cls, _field_name)
if _field.states.get('readonly'):
_field.states['readonly'] |= Eval('unit_loads')
@ -35,10 +35,7 @@ class ShipmentOut(metaclass=PoolMeta):
_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)
pass
@classmethod
def set_unit_loads(cls, records, name, value):
@ -51,8 +48,28 @@ class ShipmentOut(metaclass=PoolMeta):
_field += '.%s' % name[10:]
return [(_field, ) + tuple(clause[1:])]
@classmethod
def _get_ul_readonly_fields_name(cls):
return []
class ShipmentOut(ShipmentUnitLoadMixin, metaclass=PoolMeta):
__name__ = 'stock.shipment.out'
@classmethod
def __setup__(cls):
super().__setup__()
cls.unit_loads.states['readonly'] |= Not(Bool(Eval('warehouse')))
cls.unit_loads.depends.append('warehouse')
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)
@fields.depends('unit_loads', 'outgoing_moves', 'warehouse_output',
'customer_location', 'end_date')
'customer_location', 'end_date')
def on_change_unit_loads(self):
moves = []
ul_ids = [ul.id for ul in self.unit_loads]
@ -78,33 +95,16 @@ class ShipmentOut(metaclass=PoolMeta):
res.unit_load = move.unit_load
return res
@classmethod
def _get_ul_readonly_fields_name(cls):
return ['inventory_moves', 'outgoing_moves']
class ShipmentInternal(metaclass=PoolMeta):
class ShipmentInternal(ShipmentUnitLoadMixin, metaclass=PoolMeta):
__name__ = 'stock.shipment.internal'
ul_quantity = fields.Function(
fields.Float('ULs', digits=(16, 0)), 'get_ul_quantity')
unit_loads = fields.Function(
fields.One2Many('stock.unit_load', None, 'Unit loads', states={
'readonly': Eval('state') != 'draft',
'invisible': (
(Eval('state') != 'draft') & ~Eval('unit_loads', []))
},
depends=['state']),
'get_unit_loads', setter='set_unit_loads',
searcher='search_unit_loads')
@classmethod
def __setup__(cls):
super(ShipmentInternal, cls).__setup__()
for _field_name in ('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_ul_quantity(self, name=None):
if not self.unit_loads:
@ -117,19 +117,8 @@ class ShipmentInternal(metaclass=PoolMeta):
uls = set(m.unit_load.id for m in self.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', 'moves', 'date_time_',
'from_location', 'to_location')
@fields.depends('unit_loads', 'moves', 'date_time_', 'from_location',
'to_location')
def on_change_unit_loads(self):
moves = []
ul_ids = [ul.id for ul in self.unit_loads]
@ -145,34 +134,19 @@ class ShipmentInternal(metaclass=PoolMeta):
moves.extend(new_moves)
self.moves = moves
@classmethod
def _get_ul_readonly_fields_name(cls):
return ['moves', 'outgoing_moves', 'incoming_moves']
class ShipmentOutReturn(metaclass=PoolMeta):
class ShipmentOutReturn(ShipmentUnitLoadMixin, metaclass=PoolMeta):
__name__ = 'stock.shipment.out.return'
unit_loads = fields.Function(
fields.One2Many('stock.unit_load', None, 'Unit loads',
states={
'readonly': (Eval('state') != 'draft') |
Not(Bool('warehouse')),
'invisible': (
(Eval('state') != 'draft') & Not(Bool(
Eval('unit_loads', []))))
},
depends=['state', 'warehouse']),
'get_unit_loads', setter='set_unit_loads',
searcher='search_unit_loads')
@classmethod
def __setup__(cls):
super().__setup__()
for _field_name in ('inventory_moves', 'incoming_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')
cls.unit_loads.states['readonly'] |= Not(Bool(Eval('warehouse')))
cls.unit_loads.depends.append('warehouse')
def get_unit_loads(self, name=None):
if not self.incoming_moves:
@ -180,17 +154,6 @@ class ShipmentOutReturn(metaclass=PoolMeta):
uls = set(m.unit_load.id for m in self.incoming_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', 'incoming_moves', 'effective_date',
'planned_date', 'start_time', 'warehouse_input', 'customer_location')
def on_change_unit_loads(self):
@ -217,3 +180,38 @@ class ShipmentOutReturn(metaclass=PoolMeta):
if move and incoming_move.unit_load:
move.unit_load = incoming_move.unit_load
return move
@classmethod
def _get_ul_readonly_fields_name(cls):
return ['inventory_moves', 'incoming_moves']
class ShipmentInReturn(ShipmentUnitLoadMixin, metaclass=PoolMeta):
__name__ = 'stock.shipment.in.return'
def get_unit_loads(self, name=None):
if not self.moves:
return []
uls = set(m.unit_load.id for m in self.moves if m.unit_load)
return list(uls)
@fields.depends('unit_loads', 'moves', 'from_location', 'to_location',
'end_date')
def on_change_unit_loads(self):
moves = []
ul_ids = [ul.id for ul in self.unit_loads]
if self.moves:
moves.extend(
[m for m in self.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._move(self.to_location,
self.end_date,
from_location=self.from_location)
moves.extend(new_moves)
self.moves = moves
@classmethod
def _get_ul_readonly_fields_name(cls):
return ['moves']

View File

@ -22,6 +22,12 @@ this repository contains the full copyright notices and license terms. -->
<field name="name">shipment_internal_form</field>
<field name="inherit" ref="stock.shipment_internal_view_form"/>
</record>
<!-- Shipment in return -->
<record model="ir.ui.view" id="shipment_in_return_view_form">
<field name="model">stock.shipment.in.return</field>
<field name="name">shipment_in_return_form</field>
<field name="inherit" ref="stock.shipment_in_return_view_form"/>
</record>
<!-- form relate -->
<record model="ir.action.act_window" id="act_unit_loads_shipment_out">
@ -54,6 +60,16 @@ this repository contains the full copyright notices and license terms. -->
<field name="model">stock.unit_load,-1</field>
<field name="action" ref="act_unit_loads_shipment_internal"/>
</record>
<record model="ir.action.act_window" id="act_unit_loads_shipment_in_return">
<field name="name">Supplier Return Shipments</field>
<field name="res_model">stock.shipment.in.return</field>
<field name="domain" eval="[('unit_loads', 'in', Eval('active_ids'))]" pyson="1"/>
</record>
<record model="ir.action.keyword" id="act_unit_loads_shipment_in_return_keyword1">
<field name="keyword">form_relate</field>
<field name="model">stock.unit_load,-1</field>
<field name="action" ref="act_unit_loads_shipment_in_return"/>
</record>
<!-- Form relate -->
<record model="ir.action.act_window" id="act_relate_shipment_out_unit_load">
@ -78,5 +94,17 @@ this repository contains the full copyright notices and license terms. -->
<field name="model">stock.shipment.out.return,-1</field>
<field name="action" ref="act_relate_shipment_out_return_unit_load"/>
</record>
<!-- Form relate -->
<record model="ir.action.act_window" id="act_relate_shipment_in_return_unit_load">
<field name="name">Unit loads</field>
<field name="res_model">stock.unit_load</field>
<field name="domain" eval="[('moves.shipment.id', 'in', Eval('active_ids'), 'stock.shipment.in.return')]" pyson="1"/>
</record>
<record model="ir.action.keyword" id="act_relate_shipment_in_return_unit_load_keyword">
<field name="keyword">form_relate</field>
<field name="model">stock.shipment.in.return,-1</field>
<field name="action" ref="act_relate_shipment_in_return_unit_load"/>
</record>
</data>
</tryton>

View File

@ -0,0 +1,114 @@
===========================
Shipment In Return Scenario
===========================
Imports::
>>> import datetime
>>> from trytond.tests.tools import activate_modules
>>> from proteus import Model, Wizard, Report
>>> from dateutil.relativedelta import relativedelta
>>> from decimal import Decimal
>>> from trytond.modules.company.tests.tools import create_company, \
... get_company
>>> now = datetime.datetime.now()
>>> tomorrow = now + relativedelta(days=1)
Install unit load Module::
>>> config = activate_modules('stock_unit_load')
Create company::
>>> _ = create_company()
>>> company = get_company()
Create product::
>>> ProductUom = Model.get('product.uom')
>>> ProductTemplate = Model.get('product.template')
>>> Product = Model.get('product.product')
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
>>> product = Product()
>>> template = ProductTemplate()
>>> template.name = 'Product'
>>> template.default_uom = unit
>>> template.type = 'goods'
>>> template.list_price = Decimal('20')
>>> template.cost_price = Decimal('8')
>>> template.save()
>>> product.template = template
>>> product.save()
Get stock locations::
>>> Location = Model.get('stock.location')
>>> production_loc, = Location.find([('type', '=', 'production')])
>>> storage_loc, = Location.find([('code', '=', 'STO')])
Create Supplier::
>>> Party = Model.get('party.party')
>>> supplier = Party(name='Supplier')
>>> supplier.save()
Create an unit load::
>>> UnitLoad = Model.get('stock.unit_load')
>>> unit_load = UnitLoad()
>>> unit_load.end_date = unit_load.start_date + relativedelta(minutes=5)
>>> unit_load.production_type = 'location'
>>> unit_load.production_location = production_loc
>>> unit_load.product = product
>>> unit_load.cases_quantity = 5
>>> unit_load.quantity = Decimal('35.0')
>>> move = unit_load.production_moves[0]
>>> move.to_location = storage_loc
>>> unit_load.save()
>>> unit_load.click('assign')
>>> unit_load.click('do')
>>> len(unit_load.ul_moves)
1
Create a shipment in return::
>>> ShipmentInReturn = Model.get('stock.shipment.in.return')
>>> shipment_in_return = ShipmentInReturn()
>>> shipment_in_return.company = company
>>> shipment_in_return.start_date = tomorrow
>>> shipment_in_return.supplier = supplier
>>> shipment_in_return.from_location = storage_loc
>>> shipment_in_return.save()
>>> len(shipment_in_return.moves)
0
Add unit load to shipment::
>>> shipment_in_return.unit_loads.append(unit_load)
>>> len(shipment_in_return.moves)
1
>>> shipment_in_return.moves[0].unit_load == unit_load
True
>>> shipment_in_return.save()
>>> shipment_in_return.click('wait')
>>> shipment_in_return.click('assign_try')
True
>>> shipment_in_return.click('done')
Check unit load::
>>> unit_load.reload()
>>> len(unit_load.ul_moves)
2
>>> unit_load.state
'done'
>>> unit_load.location.id == shipment_in_return.to_location.id
True

View File

@ -36,5 +36,10 @@ def suite():
tearDown=doctest_teardown, encoding='utf-8',
checker=doctest_checker,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
suite.addTests(doctest.DocFileSuite(
'scenario_shipment_in_return.rst',
tearDown=doctest_teardown, encoding='utf-8',
checker=doctest_checker,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
# TODO: uls by locations wizard
return suite

View File

@ -1505,6 +1505,7 @@ class UnitLoad(ModelSQL, ModelView):
'stock.shipment.out',
'stock.shipment.out.return',
'stock.shipment.internal',
'stock.shipment.in.return',
]
@classmethod

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[@name='moves']" position="before">
<page name="unit_loads" string="ULs">
<field name="unit_loads" colspan="4" widget="many2many"/>
</page>
</xpath>
</data>