+28
-30
@@ -538,6 +538,19 @@ class Move(Workflow, ModelSQL, ModelView):
|
||||
def on_change_with_product_uom_category(self, name=None):
|
||||
return self.product.default_uom_category if self.product else None
|
||||
|
||||
@classmethod
|
||||
def default_internal_quantity(cls):
|
||||
# default value before compute of the field
|
||||
return 0
|
||||
|
||||
@fields.depends('quantity', 'unit', 'product')
|
||||
def on_change_with_internal_quantity(self):
|
||||
pool = Pool()
|
||||
UoM = pool.get('product.uom')
|
||||
if self.quantity is not None and self.unit and self.product:
|
||||
return UoM.compute_qty(
|
||||
self.unit, self.quantity, self.product.default_uom, round=True)
|
||||
|
||||
@fields.depends('from_location')
|
||||
def on_change_with_from_location_name(self, name=None):
|
||||
if self.from_location:
|
||||
@@ -724,13 +737,6 @@ class Move(Workflow, ModelSQL, ModelView):
|
||||
new_cost_price = cost_price
|
||||
return round_price(new_cost_price)
|
||||
|
||||
@staticmethod
|
||||
def _get_internal_quantity(quantity, unit, product):
|
||||
Uom = Pool().get('product.uom')
|
||||
internal_quantity = Uom.compute_qty(
|
||||
unit, quantity, product.default_uom, round=True)
|
||||
return internal_quantity
|
||||
|
||||
def set_effective_date(self):
|
||||
pool = Pool()
|
||||
Date = pool.get('ir.date')
|
||||
@@ -974,33 +980,36 @@ class Move(Workflow, ModelSQL, ModelView):
|
||||
default.setdefault('outcome_moves', None)
|
||||
return super().copy(moves, default=default)
|
||||
|
||||
def compute_fields(self, field_names=None):
|
||||
cls = self.__class__
|
||||
values = super().compute_fields(field_names=field_names)
|
||||
if (not field_names
|
||||
or (cls.internal_quantity.on_change_with & field_names)):
|
||||
internal_quantity = self.on_change_with_internal_quantity()
|
||||
if getattr(self, 'internal_quantity', None) != internal_quantity:
|
||||
values['internal_quantity'] = internal_quantity
|
||||
return values
|
||||
|
||||
@classmethod
|
||||
def create(cls, vlist):
|
||||
pool = Pool()
|
||||
Product = pool.get('product.product')
|
||||
Uom = pool.get('product.uom')
|
||||
context = Transaction().context
|
||||
|
||||
vlist = [x.copy() for x in vlist]
|
||||
# Use ordered dict to optimize cache alignment
|
||||
products, units = OrderedDict(), OrderedDict()
|
||||
products = OrderedDict()
|
||||
for vals in vlist:
|
||||
if vals.get('product') is not None:
|
||||
products[vals['product']] = None
|
||||
if vals.get('unit') is not None:
|
||||
units[vals['unit']] = None
|
||||
id2product = {p.id: p for p in Product.browse(products.keys())}
|
||||
id2unit = {u.id: u for u in Uom.browse(units.keys())}
|
||||
for vals in vlist:
|
||||
assert vals.get('state', cls.default_state()
|
||||
) in ['draft', 'staging']
|
||||
product = id2product[int(vals['product'])]
|
||||
unit = id2unit[int(vals['unit'])]
|
||||
internal_quantity = cls._get_internal_quantity(
|
||||
vals['quantity'], unit, product)
|
||||
vals['internal_quantity'] = internal_quantity
|
||||
if context.get('_product_replacement', True):
|
||||
vals['product'] = product.replacement.id
|
||||
if vals.get('product') is not None:
|
||||
product = id2product[int(vals['product'])]
|
||||
if context.get('_product_replacement', True):
|
||||
vals['product'] = product.replacement.id
|
||||
moves = super().create(vlist)
|
||||
cls.check_period_closed(moves)
|
||||
return moves
|
||||
@@ -1025,28 +1034,17 @@ class Move(Workflow, ModelSQL, ModelView):
|
||||
|
||||
super().write(*args)
|
||||
|
||||
to_write = []
|
||||
unit_price_update = []
|
||||
actions = iter(args)
|
||||
for moves, values in zip(actions, actions):
|
||||
if any(f not in cls._allow_modify_closed_period for f in values):
|
||||
cls.check_period_closed(moves)
|
||||
for move in moves:
|
||||
internal_quantity = cls._get_internal_quantity(
|
||||
move.quantity, move.unit, move.product)
|
||||
if (internal_quantity != move.internal_quantity
|
||||
and internal_quantity
|
||||
!= values.get('internal_quantity')):
|
||||
to_write.extend(([move], {
|
||||
'internal_quantity': internal_quantity,
|
||||
}))
|
||||
if (move.state == 'done'
|
||||
and ('unit_price' in values
|
||||
or 'currency' in values)):
|
||||
unit_price_update.append(move)
|
||||
|
||||
if to_write:
|
||||
cls.write(*to_write)
|
||||
if unit_price_update:
|
||||
cls.write(unit_price_update, {'unit_price_updated': True})
|
||||
|
||||
|
||||
@@ -84,8 +84,10 @@ class Move(metaclass=PoolMeta):
|
||||
"Internal Volume", readonly=True,
|
||||
help="The volume of the moved product in liter.")
|
||||
|
||||
@classmethod
|
||||
def _get_internal_weight(cls, quantity, unit, product):
|
||||
@fields.depends(
|
||||
'quantity', 'unit', 'product',
|
||||
methods=['on_change_with_internal_quantity'])
|
||||
def on_change_with_internal_weight(self):
|
||||
pool = Pool()
|
||||
Uom = pool.get('product.uom')
|
||||
ModelData = pool.get('ir.model.data')
|
||||
@@ -94,19 +96,22 @@ class Move(metaclass=PoolMeta):
|
||||
|
||||
# Use first the weight from product_measurements
|
||||
# as it could include some handling weight
|
||||
if product.weight is not None:
|
||||
internal_quantity = cls._get_internal_quantity(
|
||||
quantity, unit, product)
|
||||
return Uom.compute_qty(
|
||||
product.weight_uom, internal_quantity * product.weight, kg,
|
||||
round=False)
|
||||
elif unit.category == kg.category:
|
||||
return Uom.compute_qty(unit, quantity, kg, round=False)
|
||||
else:
|
||||
return None
|
||||
if self.product and self.product.weight is not None:
|
||||
internal_quantity = self.on_change_with_internal_quantity()
|
||||
if internal_quantity is not None:
|
||||
return Uom.compute_qty(
|
||||
self.product.weight_uom,
|
||||
internal_quantity * self.product.weight,
|
||||
kg,
|
||||
round=False)
|
||||
elif (self.quantity is not None
|
||||
and self.unit and self.unit.category == kg.category):
|
||||
return Uom.compute_qty(self.unit, self.quantity, kg, round=False)
|
||||
|
||||
@classmethod
|
||||
def _get_internal_volume(cls, quantity, unit, product):
|
||||
@fields.depends(
|
||||
'quantity', 'unit', 'product',
|
||||
methods=['on_change_with_internal_quantity'])
|
||||
def on_change_with_internal_volume(self):
|
||||
pool = Pool()
|
||||
Uom = pool.get('product.uom')
|
||||
ModelData = pool.get('ir.model.data')
|
||||
@@ -115,61 +120,33 @@ class Move(metaclass=PoolMeta):
|
||||
|
||||
# Use first the volume from product_measurements
|
||||
# as it could include some handling volume
|
||||
if product.volume is not None:
|
||||
internal_quantity = cls._get_internal_quantity(
|
||||
quantity, unit, product)
|
||||
if self.product and self.product.volume is not None:
|
||||
internal_quantity = self.on_change_with_internal_quantity()
|
||||
if internal_quantity is not None:
|
||||
return Uom.compute_qty(
|
||||
self.product.volume_uom,
|
||||
internal_quantity * self.product.volume,
|
||||
liter,
|
||||
round=False)
|
||||
elif (self.quantity is not None
|
||||
and self.unit and self.unit.category == liter.category):
|
||||
return Uom.compute_qty(
|
||||
product.volume_uom, internal_quantity * product.volume, liter,
|
||||
round=False)
|
||||
elif unit.category == liter.category:
|
||||
return Uom.compute_qty(unit, quantity, liter, round=False)
|
||||
else:
|
||||
return None
|
||||
self.unit, self.quantity, liter, round=False)
|
||||
|
||||
@classmethod
|
||||
def create(cls, vlist):
|
||||
pool = Pool()
|
||||
Product = pool.get('product.product')
|
||||
Uom = pool.get('product.uom')
|
||||
|
||||
vlist = [v.copy() for v in vlist]
|
||||
for values in vlist:
|
||||
product = Product(values['product'])
|
||||
unit = Uom(values['unit'])
|
||||
quantity = values['quantity']
|
||||
internal_weight = cls._get_internal_weight(quantity, unit, product)
|
||||
if internal_weight is not None:
|
||||
def compute_fields(self, field_names=None):
|
||||
cls = self.__class__
|
||||
values = super().compute_fields(field_names=field_names)
|
||||
if (not field_names
|
||||
or (cls.internal_weight.on_change_with & field_names)):
|
||||
internal_weight = self.on_change_with_internal_weight()
|
||||
if self.internal_weight != internal_weight:
|
||||
values['internal_weight'] = internal_weight
|
||||
internal_volume = cls._get_internal_volume(quantity, unit, product)
|
||||
if internal_volume is not None:
|
||||
if (not field_names
|
||||
or (cls.internal_volume.on_change_with & field_names)):
|
||||
internal_volume = self.on_change_with_internal_volume()
|
||||
if getattr(self, 'internal_volume', None) != internal_volume:
|
||||
values['internal_volume'] = internal_volume
|
||||
return super().create(vlist)
|
||||
|
||||
@classmethod
|
||||
def write(cls, *args):
|
||||
super().write(*args)
|
||||
|
||||
to_write = []
|
||||
actions = iter(args)
|
||||
for moves, values in zip(actions, actions):
|
||||
for move in moves:
|
||||
write = {}
|
||||
internal_weight = cls._get_internal_weight(
|
||||
move.quantity, move.unit, move.product)
|
||||
if (internal_weight is not None
|
||||
and internal_weight != move.internal_weight
|
||||
and internal_weight != values.get('internal_weight')):
|
||||
write['internal_weight'] = internal_weight
|
||||
internal_volume = cls._get_internal_volume(
|
||||
move.quantity, move.unit, move.product)
|
||||
if (internal_volume is not None
|
||||
and internal_volume != move.internal_volume
|
||||
and internal_volume != values.get('internal_volume')):
|
||||
write['internal_volume'] = internal_volume
|
||||
if write:
|
||||
to_write.extend(([move], write))
|
||||
if to_write:
|
||||
cls.write(*to_write)
|
||||
return values
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
|
||||
Reference in New Issue
Block a user