first commit
This commit is contained in:
235
modules/stock_product_location_place/stock.py
Normal file
235
modules/stock_product_location_place/stock.py
Normal file
@@ -0,0 +1,235 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model import ModelSQL, ModelView, Unique, fields
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
from trytond.pyson import Eval, If
|
||||
|
||||
|
||||
class ProductLocationPlace(ModelSQL, ModelView):
|
||||
__name__ = 'stock.product.location.place'
|
||||
_rec_name = 'place'
|
||||
|
||||
template = fields.Many2One(
|
||||
'product.template', "Product",
|
||||
required=True, ondelete='CASCADE',
|
||||
domain=[
|
||||
If(Eval('product'),
|
||||
('products', '=', Eval('product', -1)),
|
||||
()),
|
||||
])
|
||||
product = fields.Many2One(
|
||||
'product.product', "Variant", ondelete='CASCADE',
|
||||
domain=[
|
||||
If(Eval('template'),
|
||||
('template', '=', Eval('template', -1)),
|
||||
()),
|
||||
])
|
||||
location = fields.Many2One(
|
||||
'stock.location', "Storage Location",
|
||||
required=True, ondelete='CASCADE',
|
||||
domain=[
|
||||
('type', '=', 'storage'),
|
||||
])
|
||||
place = fields.Char(
|
||||
"Place", required=True,
|
||||
help="The place where the product is always stored in the location.")
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
t = cls.__table__()
|
||||
cls._sql_constraints += [
|
||||
('template_product_location_unique',
|
||||
Unique(t, t.template, t.product, t.location),
|
||||
'stock_product_location_place.'
|
||||
'msg_stock_product_location_unique'),
|
||||
]
|
||||
|
||||
@fields.depends('product', '_parent_product.template')
|
||||
def on_change_product(self):
|
||||
if self.product:
|
||||
self.template = self.product.template
|
||||
|
||||
@classmethod
|
||||
def default_location(cls):
|
||||
pool = Pool()
|
||||
Location = pool.get('stock.location')
|
||||
warehouse = Location.get_default_warehouse()
|
||||
if warehouse:
|
||||
warehouse = Location(warehouse)
|
||||
if (warehouse.storage_location
|
||||
and warehouse.storage_location.type == 'storage'):
|
||||
return warehouse.storage_location.id
|
||||
elif (warehouse.picking_location
|
||||
and warehouse.picking_location.type == 'storage'):
|
||||
return warehouse.picking_location.id
|
||||
|
||||
|
||||
class Move(metaclass=PoolMeta):
|
||||
__name__ = 'stock.move'
|
||||
|
||||
from_place = fields.Many2One(
|
||||
'stock.product.location.place', "From Place", readonly=True,
|
||||
domain=[
|
||||
If(~Eval('state').in_(['done', 'cancelled']),
|
||||
['OR',
|
||||
('template.products', '=', Eval('product', -1)),
|
||||
('product', '=', Eval('product', -1)),
|
||||
],
|
||||
('location', '=', Eval('from_location', -1)),
|
||||
),
|
||||
])
|
||||
to_place = fields.Many2One(
|
||||
'stock.product.location.place', "To Place", readonly=True,
|
||||
domain=[
|
||||
If(~Eval('state').in_(['done', 'cancelled']),
|
||||
['OR',
|
||||
('template.products', '=', Eval('product', -1)),
|
||||
('product', '=', Eval('product', -1)),
|
||||
],
|
||||
('location', '=', Eval('to_location', -1)),
|
||||
),
|
||||
])
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
cls._allow_modify_closed_period |= {'from_place', 'to_place'}
|
||||
|
||||
@fields.depends('from_location', 'product')
|
||||
def on_change_with_from_place(self):
|
||||
if self.product and self.from_location:
|
||||
return self.product.get_place(self.from_location)
|
||||
|
||||
@fields.depends('to_location', 'product')
|
||||
def on_change_with_to_place(self):
|
||||
if self.product and self.to_location:
|
||||
return self.product.get_place(self.to_location)
|
||||
|
||||
@fields.depends('from_place')
|
||||
def on_change_with_from_location_name(self, name=None):
|
||||
name = super().on_change_with_from_location_name(name=name)
|
||||
if self.from_place:
|
||||
name = ' @ '.join(
|
||||
filter(None, [name, self.from_place.rec_name])).strip()
|
||||
return name
|
||||
|
||||
@fields.depends('to_place')
|
||||
def on_change_with_to_location_name(self, name=None):
|
||||
name = super().on_change_with_to_location_name(name=name)
|
||||
if self.to_place:
|
||||
name = ' @ '.join(
|
||||
filter(None, [name, self.to_place.rec_name])).strip()
|
||||
return name
|
||||
|
||||
def compute_fields(self, field_names=None):
|
||||
cls = self.__class__
|
||||
values = super().compute_fields(field_names=field_names)
|
||||
if getattr(self, 'state', None) not in {'done', 'cancelled'}:
|
||||
if (field_names is None
|
||||
or cls.from_place.on_change_with & field_names):
|
||||
from_place = self.on_change_with_from_place()
|
||||
if getattr(self, 'from_place', None) != from_place:
|
||||
values['from_place'] = from_place
|
||||
if (field_names is None
|
||||
or cls.to_place.on_change_with & field_names):
|
||||
to_place = self.on_change_with_to_place()
|
||||
if getattr(self, 'to_place', None) != to_place:
|
||||
values['to_place'] = to_place
|
||||
return values
|
||||
|
||||
@classmethod
|
||||
def write(cls, *args):
|
||||
# clean places as they maybe no more valid
|
||||
actions = iter(args)
|
||||
args = []
|
||||
for moves, values in zip(actions, actions):
|
||||
if {'product', 'from_location', 'to_location'} & values.keys():
|
||||
values = values.copy()
|
||||
values.setdefault('from_place')
|
||||
values.setdefault('to_place')
|
||||
args.extend((moves, values))
|
||||
|
||||
super().write(*args)
|
||||
|
||||
|
||||
class ShipmentIn(metaclass=PoolMeta):
|
||||
__name__ = 'stock.shipment.in'
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
i = cls.inventory_moves.order.index(('to_location', 'ASC'))
|
||||
cls.inventory_moves.order.insert(i + 1, ('to_place', 'ASC'))
|
||||
|
||||
|
||||
class ShipmentInReturn(metaclass=PoolMeta):
|
||||
__name__ = 'stock.shipment.in.return'
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
i = cls.moves.order.index(('from_location', 'ASC'))
|
||||
cls.moves.order.insert(i + 1, ('from_place', 'ASC'))
|
||||
|
||||
|
||||
class ShipmentOut(metaclass=PoolMeta):
|
||||
__name__ = 'stock.shipment.out'
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
i = cls.inventory_moves.order.index(('from_location', 'ASC'))
|
||||
cls.inventory_moves.order.insert(i + 1, ('from_place', 'ASC'))
|
||||
|
||||
|
||||
class ShipmentOutReturn(metaclass=PoolMeta):
|
||||
__name__ = 'stock.shipment.out.return'
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
i = cls.inventory_moves.order.index(('to_location', 'ASC'))
|
||||
cls.inventory_moves.order.insert(i + 1, ('to_place', 'ASC'))
|
||||
|
||||
|
||||
class ShipmentInternal(metaclass=PoolMeta):
|
||||
__name__ = 'stock.shipment.internal'
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
i = cls.moves.order.index(('from_location', 'ASC'))
|
||||
cls.moves.order.insert(i + 1, ('from_place', 'ASC'))
|
||||
|
||||
i = cls.outgoing_moves.order.index(('from_location', 'ASC'))
|
||||
cls.outgoing_moves.order.insert(i + 1, ('from_place', 'ASC'))
|
||||
|
||||
i = cls.incoming_moves.order.index(('to_location', 'ASC'))
|
||||
cls.incoming_moves.order.insert(i + 1, ('to_place', 'ASC'))
|
||||
|
||||
|
||||
class InventoryLine(metaclass=PoolMeta):
|
||||
__name__ = 'stock.inventory.line'
|
||||
|
||||
place = fields.Many2One(
|
||||
'stock.product.location.place', "Place",
|
||||
domain=['OR',
|
||||
('template.products', '=', Eval('product', -1)),
|
||||
('product', '=', Eval('product', -1)),
|
||||
])
|
||||
|
||||
@fields.depends(
|
||||
'inventory_location', 'product',
|
||||
methods=['on_change_with_inventory_location'])
|
||||
def on_change_with_place(self):
|
||||
location = (self.inventory_location
|
||||
or self.on_change_with_inventory_location())
|
||||
if self.product and location:
|
||||
return self.product.get_place(location)
|
||||
|
||||
@fields.depends(methods=['on_change_with_place'])
|
||||
def update_for_complete(self, quantity):
|
||||
super().update_for_complete(quantity)
|
||||
self.place = self.on_change_with_place()
|
||||
Reference in New Issue
Block a user