Files
tryton/modules/stock_product_location/location.py
T
Cédric Krier 00757cfb12 Do not fail to get product location for shipment without warehouse
The warehouse of internal shipment is computed and may be empty if the from
location does not have a warehouse.

Closes #13129
(grafted from f4f85f4d31f0afe83bb8662d1c15ceecadbd753e)

--HG--
branch : 7.0
2024-04-13 13:52:43 +02:00

95 lines
3.3 KiB
Python

# 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 (
MatchMixin, ModelSQL, ModelView, fields, sequence_ordered)
from trytond.pool import PoolMeta
from trytond.pyson import Bool, Eval, If
class ProductLocation(sequence_ordered(), ModelSQL, ModelView, MatchMixin):
'''
Product Location
It defines the default storage location by warehouse for a product.
'''
__name__ = 'stock.product.location'
template = fields.Many2One(
'product.template', "Product",
required=True, ondelete='CASCADE',
domain=[
If(Bool(Eval('product')),
('products', '=', Eval('product')),
()),
])
product = fields.Many2One(
'product.product', "Variant", ondelete='CASCADE',
domain=[
If(Bool(Eval('template')),
('template', '=', Eval('template')),
()),
])
warehouse = fields.Many2One('stock.location', 'Warehouse', required=True,
domain=[('type', '=', 'warehouse')], ondelete='CASCADE')
location = fields.Many2One('stock.location', 'Storage Location',
required=True, ondelete='CASCADE',
domain=[
('type', '=', 'storage'),
('parent', 'child_of', If(Bool(Eval('warehouse')),
[Eval('warehouse')], [])),
])
@classmethod
def __register__(cls, module_name):
table = cls.__table_handler__(module_name)
super().__register__(module_name)
# Migration from 5.6: Add template on locations
table.not_null_action('product', 'remove')
@fields.depends('product', '_parent_product.template')
def on_change_product(self):
if self.product:
self.template = self.product.template
class Move(metaclass=PoolMeta):
__name__ = 'stock.move'
def set_product_location(self, field='to_location', **pattern):
assert field in {'from_location', 'to_location'}
if (getattr(self, 'shipment', None)
and getattr(self.shipment, 'warehouse', None)):
pattern.setdefault('warehouse', self.shipment.warehouse.id)
elif getattr(self, 'production', None):
pattern.setdefault('warehouse', self.production.warehouse.id)
if self.product:
pattern.setdefault('template', self.product.template.id)
pattern.setdefault('product', self.product.id)
locations = self.product.locations + self.product.template.locations
for product_location in locations:
if product_location.match(pattern):
setattr(self, field, product_location.location)
break
class ShipmentIn(metaclass=PoolMeta):
__name__ = 'stock.shipment.in'
def _get_inventory_move(self, incoming_move):
move = super()._get_inventory_move(incoming_move)
if move:
move.set_product_location(warehouse=self.warehouse.id)
return move
class ShipmentOutReturn(metaclass=PoolMeta):
__name__ = 'stock.shipment.out.return'
def _get_inventory_move(self, incoming_move):
move = super()._get_inventory_move(incoming_move)
if move:
move.set_product_location(warehouse=self.warehouse.id)
return move