[REF] *{stock,mrp}*: rename reserved fields
This commit rename product_uom_qty into reserved_uom_qty and product_qty into reserved_qty on stock move line to stop mistake them with the stock move quantities fields. Task: 2648449 Part-of: odoo/odoo#80434
This commit is contained in:
@@ -56,7 +56,7 @@ class ChooseDeliveryPackage(models.TransientModel):
|
||||
and not ml.result_package_id
|
||||
)
|
||||
if not move_line_ids:
|
||||
move_line_ids = picking_move_lines.filtered(lambda ml: float_compare(ml.product_uom_qty, 0.0,
|
||||
move_line_ids = picking_move_lines.filtered(lambda ml: float_compare(ml.reserved_uom_qty, 0.0,
|
||||
precision_rounding=ml.product_uom_id.rounding) > 0 and float_compare(ml.qty_done, 0.0,
|
||||
precision_rounding=ml.product_uom_id.rounding) == 0)
|
||||
|
||||
|
||||
@@ -1513,7 +1513,7 @@ class MrpProduction(models.Model):
|
||||
|
||||
# Remove the serial move line without reserved quantity. Post inventory will assigned all the non done moves
|
||||
# So those move lines are duplicated.
|
||||
backorders.move_raw_ids.move_line_ids.filtered(lambda ml: ml.product_id.tracking == 'serial' and ml.product_qty == 0).unlink()
|
||||
backorders.move_raw_ids.move_line_ids.filtered(lambda ml: ml.product_id.tracking == 'serial' and ml.reserved_qty == 0).unlink()
|
||||
|
||||
for old_wo, wo in zip(self.workorder_ids, backorders.workorder_ids):
|
||||
wo.qty_produced = max(old_wo.qty_produced - old_wo.qty_producing, 0)
|
||||
@@ -1921,19 +1921,19 @@ class MrpProduction(models.Model):
|
||||
new_moves_vals.append(move_vals[0])
|
||||
new_moves_quantity_to_split.append(uom_qty_to_split)
|
||||
elif move.raw_material_production_id:
|
||||
move.move_line_ids.product_uom_qty = 0
|
||||
move.move_line_ids[0].product_uom_qty = move.product_uom_qty
|
||||
move.move_line_ids.reserved_uom_qty = 0
|
||||
move.move_line_ids[0].reserved_uom_qty = move.product_uom_qty
|
||||
if backorder:
|
||||
new_moves = self.env['stock.move'].create(new_moves_vals)
|
||||
for move, quantity_to_split, new_move in zip(new_moves_origin, new_moves_quantity_to_split, new_moves):
|
||||
if move.raw_material_production_id:
|
||||
move.move_line_ids[0].copy({
|
||||
'move_id': new_move.id,
|
||||
'product_uom_qty': quantity_to_split,
|
||||
'reserved_uom_qty': quantity_to_split,
|
||||
'lot_id': move.move_line_ids[0].lot_id.id if move.move_line_ids[0].lot_id else 0,
|
||||
})
|
||||
move.with_context(bypass_reservation_update=True).move_line_ids.product_uom_qty = 0
|
||||
move.with_context(bypass_reservation_update=True).move_line_ids[0].product_uom_qty = move.product_uom_qty
|
||||
move.with_context(bypass_reservation_update=True).move_line_ids.reserved_uom_qty = 0
|
||||
move.with_context(bypass_reservation_update=True).move_line_ids[0].reserved_uom_qty = move.product_uom_qty
|
||||
for old_wo, wo in zip(production.workorder_ids, backorder.workorder_ids):
|
||||
wo.qty_produced = max(old_wo.qty_produced - old_wo.qty_producing, 0)
|
||||
wo.qty_producing = 1
|
||||
|
||||
@@ -788,7 +788,7 @@ class MrpWorkorder(models.Model):
|
||||
if move_line:
|
||||
if self.product_id.tracking == 'serial':
|
||||
raise UserError(_('You cannot produce the same serial number twice.'))
|
||||
move_line.product_uom_qty += self.qty_producing
|
||||
move_line.reserved_uom_qty += self.qty_producing
|
||||
move_line.qty_done += self.qty_producing
|
||||
else:
|
||||
quantity = self.product_uom_id._compute_quantity(self.qty_producing, self.product_id.uom_id, rounding_method='HALF-UP')
|
||||
@@ -797,7 +797,7 @@ class MrpWorkorder(models.Model):
|
||||
'move_id': production_move.id,
|
||||
'product_id': production_move.product_id.id,
|
||||
'lot_id': self.finished_lot_id.id,
|
||||
'product_uom_qty': self.qty_producing,
|
||||
'reserved_uom_qty': self.qty_producing,
|
||||
'product_uom_id': self.product_uom_id.id,
|
||||
'qty_done': self.qty_producing,
|
||||
'location_id': production_move.location_id.id,
|
||||
|
||||
@@ -70,7 +70,7 @@ class StockMoveLine(models.Model):
|
||||
def _reservation_is_updatable(self, quantity, reserved_quant):
|
||||
self.ensure_one()
|
||||
if self.produce_line_ids.lot_id:
|
||||
ml_remaining_qty = self.qty_done - self.product_uom_qty
|
||||
ml_remaining_qty = self.qty_done - self.reserved_uom_qty
|
||||
ml_remaining_qty = self.product_uom_id._compute_quantity(ml_remaining_qty, self.product_id.uom_id, rounding_method="HALF-UP")
|
||||
if float_compare(ml_remaining_qty, quantity, precision_rounding=self.product_id.uom_id.rounding) < 0:
|
||||
return False
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
<t t-set="move_lines" t-value="move.move_line_ids.filtered(lambda x: x.state == 'done' and x.qty_done)"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-set="move_lines" t-value="move.move_line_ids.filtered(lambda x: x.state != 'done' and x.product_qty)"/>
|
||||
<t t-set="move_lines" t-value="move.move_line_ids.filtered(lambda x: x.state != 'done' and x.reserved_qty)"/>
|
||||
</t>
|
||||
<t t-foreach="move_lines" t-as="move_line">
|
||||
<t t-if="move_line.product_uom_id.category_id == uom_categ_unit">
|
||||
@@ -142,7 +142,7 @@
|
||||
<span t-field="move_line.product_uom_id" groups="uom.group_uom"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span t-esc="move_line.product_uom_qty" t-if="move_line.state !='done'"/>
|
||||
<span t-esc="move_line.reserved_uom_qty" t-if="move_line.state !='done'"/>
|
||||
<span t-esc="move_line.qty_done" t-if="move_line.state =='done'"/>
|
||||
<span t-field="move_line.product_uom_id" groups="uom.group_uom"/>
|
||||
</t>
|
||||
|
||||
@@ -599,7 +599,7 @@ class TestMrpOrder(TestMrpCommon):
|
||||
# p2
|
||||
details_operation_form = Form(mo.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
|
||||
with details_operation_form.move_line_ids.edit(0) as line:
|
||||
line.qty_done = line.product_uom_qty
|
||||
line.qty_done = line.reserved_uom_qty
|
||||
with details_operation_form.move_line_ids.new() as line:
|
||||
line.qty_done = 1
|
||||
details_operation_form.save()
|
||||
@@ -609,7 +609,7 @@ class TestMrpOrder(TestMrpCommon):
|
||||
for i in range(len(details_operation_form.move_line_ids)):
|
||||
# reservation in shelf1: 3 lot1, shelf2: 3 lot1, stock: 4 lot2
|
||||
with details_operation_form.move_line_ids.edit(i) as line:
|
||||
line.qty_done = line.product_uom_qty
|
||||
line.qty_done = line.reserved_uom_qty
|
||||
with details_operation_form.move_line_ids.new() as line:
|
||||
line.qty_done = 2
|
||||
line.lot_id = first_lot_for_p1
|
||||
@@ -619,7 +619,7 @@ class TestMrpOrder(TestMrpCommon):
|
||||
details_operation_form.save()
|
||||
|
||||
move_1 = mo.move_raw_ids.filtered(lambda m: m.product_id == p1)
|
||||
# qty_done/product_uom_qty lot
|
||||
# qty_done/reserved_uom_qty lot
|
||||
# 3/3 lot 1 shelf 1
|
||||
# 1/1 lot 1 shelf 2
|
||||
# 2/2 lot 1 shelf 2
|
||||
@@ -666,7 +666,7 @@ class TestMrpOrder(TestMrpCommon):
|
||||
self.assertEqual(len(ml_p1), 2)
|
||||
self.assertEqual(sorted(ml_p1.mapped('qty_done')), [2.0, 3.0], 'Quantity done should be 1.0, 2.0 or 3.0')
|
||||
self.assertEqual(m_p1.quantity_done, 5.0, 'Total qty done should be 6.0')
|
||||
self.assertEqual(sum(ml_p1.mapped('product_uom_qty')), 5.0, 'Total qty reserved should be 5.0')
|
||||
self.assertEqual(sum(ml_p1.mapped('reserved_uom_qty')), 5.0, 'Total qty reserved should be 5.0')
|
||||
|
||||
mo.button_mark_done()
|
||||
self.assertEqual(mo.state, 'done', "Production order should be in done state.")
|
||||
@@ -707,7 +707,7 @@ class TestMrpOrder(TestMrpCommon):
|
||||
|
||||
mo.button_mark_done()
|
||||
self.assertTrue(all(s == 'done' for s in mo.move_raw_ids.mapped('state')))
|
||||
self.assertEqual(sum(mo.move_raw_ids.mapped('move_line_ids.product_uom_qty')), 0)
|
||||
self.assertEqual(sum(mo.move_raw_ids.mapped('move_line_ids.reserved_uom_qty')), 0)
|
||||
|
||||
def test_consumption_strict_1(self):
|
||||
""" Checks the constraints of a strict BOM without tracking when playing around
|
||||
|
||||
@@ -383,11 +383,11 @@ class TestUnbuild(TestMrpCommon):
|
||||
mo = mo_form.save()
|
||||
details_operation_form = Form(mo.move_raw_ids.filtered(lambda ml: ml.product_id == p2), view=self.env.ref('stock.view_stock_move_operations'))
|
||||
with details_operation_form.move_line_ids.edit(0) as ml:
|
||||
ml.qty_done = ml.product_uom_qty
|
||||
ml.qty_done = ml.reserved_uom_qty
|
||||
with details_operation_form.move_line_ids.edit(1) as ml:
|
||||
ml.qty_done = ml.product_uom_qty
|
||||
ml.qty_done = ml.reserved_uom_qty
|
||||
with details_operation_form.move_line_ids.edit(2) as ml:
|
||||
ml.qty_done = ml.product_uom_qty
|
||||
ml.qty_done = ml.reserved_uom_qty
|
||||
details_operation_form.save()
|
||||
|
||||
mo.button_mark_done()
|
||||
|
||||
@@ -265,7 +265,7 @@
|
||||
<field name="qty_done" invisible="1"/>
|
||||
<field name="product_id" invisible="1"/>
|
||||
<field name="product_uom_id" invisible="1"/>
|
||||
<field name="product_uom_qty" invisible="1"/>
|
||||
<field name="reserved_uom_qty" invisible="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="move_id" invisible="1"/>
|
||||
<field name="id" invisible="1"/>
|
||||
@@ -347,7 +347,7 @@
|
||||
<field name="qty_done" invisible="1"/>
|
||||
<field name="product_id" invisible="1"/>
|
||||
<field name="product_uom_id" invisible="1"/>
|
||||
<field name="product_uom_qty" invisible="1"/>
|
||||
<field name="reserved_uom_qty" invisible="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="move_id" invisible="1"/>
|
||||
<field name="id" invisible="1"/>
|
||||
|
||||
@@ -61,8 +61,8 @@ class MrpImmediateProduction(models.TransientModel):
|
||||
for move in production.move_raw_ids.filtered(lambda m: m.state not in ['done', 'cancel']):
|
||||
rounding = move.product_uom.rounding
|
||||
for move_line in move.move_line_ids:
|
||||
if move_line.product_uom_qty:
|
||||
move_line.qty_done = min(move_line.product_uom_qty, move_line.move_id.should_consume_qty)
|
||||
if move_line.reserved_uom_qty:
|
||||
move_line.qty_done = min(move_line.reserved_uom_qty, move_line.move_id.should_consume_qty)
|
||||
if float_compare(move.quantity_done, move.should_consume_qty, precision_rounding=rounding) >= 0:
|
||||
break
|
||||
if float_compare(move.product_uom_qty, move.quantity_done, precision_rounding=move.product_uom.rounding) == 1:
|
||||
|
||||
@@ -89,27 +89,27 @@ class MrpProduction(models.Model):
|
||||
rounding = ml.product_uom_id.rounding
|
||||
if float_compare(quantity, 0, precision_rounding=rounding) <= 0:
|
||||
break
|
||||
quantity_to_process = min(quantity, ml.product_uom_qty - ml.qty_done)
|
||||
quantity_to_process = min(quantity, ml.reserved_uom_qty - ml.qty_done)
|
||||
quantity -= quantity_to_process
|
||||
|
||||
new_quantity_done = (ml.qty_done + quantity_to_process)
|
||||
|
||||
# on which lot of finished product
|
||||
if float_compare(new_quantity_done, ml.product_uom_qty, precision_rounding=rounding) >= 0:
|
||||
if float_compare(new_quantity_done, ml.reserved_uom_qty, precision_rounding=rounding) >= 0:
|
||||
ml.write({
|
||||
'qty_done': new_quantity_done,
|
||||
'lot_id': self.lot_producing_id and self.lot_producing_id.id,
|
||||
})
|
||||
else:
|
||||
new_qty_reserved = ml.product_uom_qty - new_quantity_done
|
||||
new_qty_reserved = ml.reserved_uom_qty - new_quantity_done
|
||||
default = {
|
||||
'product_uom_qty': new_quantity_done,
|
||||
'reserved_uom_qty': new_quantity_done,
|
||||
'qty_done': new_quantity_done,
|
||||
'lot_id': self.lot_producing_id and self.lot_producing_id.id,
|
||||
}
|
||||
ml.copy(default=default)
|
||||
ml.with_context(bypass_reservation_update=True).write({
|
||||
'product_uom_qty': new_qty_reserved,
|
||||
'reserved_uom_qty': new_qty_reserved,
|
||||
'qty_done': 0
|
||||
})
|
||||
|
||||
@@ -120,7 +120,7 @@ class MrpProduction(models.Model):
|
||||
'product_id': self.product_id.id,
|
||||
'location_id': subcontract_move_id.location_id.id,
|
||||
'location_dest_id': subcontract_move_id.location_dest_id.id,
|
||||
'product_uom_qty': 0,
|
||||
'reserved_uom_qty': 0,
|
||||
'product_uom_id': self.product_uom_id.id,
|
||||
'qty_done': quantity,
|
||||
'lot_id': self.lot_producing_id and self.lot_producing_id.id,
|
||||
@@ -128,10 +128,10 @@ class MrpProduction(models.Model):
|
||||
if not self._get_quantity_to_backorder():
|
||||
ml_reserved = subcontract_move_id.move_line_ids.filtered(lambda ml:
|
||||
float_is_zero(ml.qty_done, precision_rounding=ml.product_uom_id.rounding) and
|
||||
not float_is_zero(ml.product_uom_qty, precision_rounding=ml.product_uom_id.rounding))
|
||||
not float_is_zero(ml.reserved_uom_qty, precision_rounding=ml.product_uom_id.rounding))
|
||||
ml_reserved.unlink()
|
||||
for ml in subcontract_move_id.move_line_ids:
|
||||
ml.product_uom_qty = ml.qty_done
|
||||
ml.reserved_uom_qty = ml.qty_done
|
||||
subcontract_move_id._recompute_state()
|
||||
|
||||
def _subcontracting_filter_to_done(self):
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
<field name="lot_id"
|
||||
attrs="{'invisible': [('tracking', 'not in', ('serial', 'lot'))], 'required': [('tracking', 'in', ('serial', 'lot'))]}"
|
||||
context="{'default_product_id': product_id, 'default_company_id': company_id}"/>
|
||||
<field name="product_uom_qty" readonly="1" force_save="1"/>
|
||||
<field name="reserved_uom_qty" readonly="1" force_save="1"/>
|
||||
<field name="qty_done"
|
||||
decoration-warning="product_uom_qty < qty_done"
|
||||
decoration-success="product_uom_qty == qty_done"/>
|
||||
decoration-warning="reserved_uom_qty < qty_done"
|
||||
decoration-success="reserved_uom_qty == qty_done"/>
|
||||
<field name="product_uom_id" groups="uom.group_uom"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
||||
@@ -821,7 +821,7 @@ class PosOrder(models.Model):
|
||||
'lines': [[0, 0, line] for line in order.lines.export_for_ui()],
|
||||
'statement_ids': [[0, 0, payment] for payment in order.payment_ids.export_for_ui()],
|
||||
'name': order.pos_reference,
|
||||
'uid': re.search('([0-9-] r){14}', order.pos_reference).group(0),
|
||||
'uid': re.search('([0-9-]){14}', order.pos_reference).group(0),
|
||||
'amount_paid': order.amount_paid,
|
||||
'amount_total': order.amount_total,
|
||||
'amount_tax': order.amount_tax,
|
||||
|
||||
@@ -141,7 +141,7 @@ class StockPicking(models.Model):
|
||||
else:
|
||||
move._action_assign()
|
||||
for move_line in move.move_line_ids:
|
||||
move_line.qty_done = move_line.product_uom_qty
|
||||
move_line.qty_done = move_line.reserved_uom_qty
|
||||
if float_compare(move.product_uom_qty, move.quantity_done, precision_rounding=move.product_uom.rounding) > 0:
|
||||
remaining_qty = move.product_uom_qty - move.quantity_done
|
||||
ml_vals = move._prepare_move_line_vals()
|
||||
@@ -151,7 +151,7 @@ class StockPicking(models.Model):
|
||||
else:
|
||||
move._action_assign()
|
||||
for move_line in move.move_line_ids:
|
||||
move_line.qty_done = move_line.product_uom_qty
|
||||
move_line.qty_done = move_line.reserved_uom_qty
|
||||
if float_compare(move.product_uom_qty, move.quantity_done, precision_rounding=move.product_uom.rounding) > 0:
|
||||
remaining_qty = move.product_uom_qty - move.quantity_done
|
||||
ml_vals = move._prepare_move_line_vals()
|
||||
|
||||
@@ -58,7 +58,7 @@ class TestCreatePicking(common.TestProductCommon):
|
||||
# Validate first shipment
|
||||
self.picking = self.po.picking_ids[0]
|
||||
for ml in self.picking.move_line_ids:
|
||||
ml.qty_done = ml.product_uom_qty
|
||||
ml.qty_done = ml.reserved_uom_qty
|
||||
self.picking._action_done()
|
||||
self.assertEqual(self.po.order_line.mapped('qty_received'), [7.0], 'Purchase: all products should be received')
|
||||
|
||||
|
||||
@@ -579,7 +579,7 @@ class Repair(models.Model):
|
||||
'location_dest_id': repair.location_id.id,
|
||||
'move_line_ids': [(0, 0, {'product_id': repair.product_id.id,
|
||||
'lot_id': repair.lot_id.id,
|
||||
'product_uom_qty': 0, # bypass reservation here
|
||||
'reserved_uom_qty': 0, # bypass reservation here
|
||||
'product_uom_id': repair.product_uom.id or repair.product_id.uom_id.id,
|
||||
'qty_done': repair.product_qty,
|
||||
'package_id': False,
|
||||
|
||||
@@ -83,7 +83,7 @@ class TestSaleExpectedDate(ValuationReconciliationTestCommon):
|
||||
# Check effective date, it should be date on which the first shipment successfully delivered to customer
|
||||
picking = sale_order.picking_ids[0]
|
||||
for ml in picking.move_line_ids:
|
||||
ml.qty_done = ml.product_uom_qty
|
||||
ml.qty_done = ml.reserved_uom_qty
|
||||
picking._action_done()
|
||||
self.assertEqual(picking.state, 'done', "Picking not processed correctly!")
|
||||
self.assertEqual(fields.Date.today(), sale_order.effective_date.date(), "Wrong effective date on sale order!")
|
||||
|
||||
@@ -556,7 +556,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
|
||||
'move_line_ids': [
|
||||
(0, 0, {
|
||||
'product_id': item1.id,
|
||||
'product_uom_qty': 0,
|
||||
'reserved_uom_qty': 0,
|
||||
'qty_done': 1,
|
||||
'product_uom_id': uom_dozen.id,
|
||||
'location_id': so1.picking_ids.location_id.id,
|
||||
@@ -564,7 +564,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
|
||||
}),
|
||||
(0, 0, {
|
||||
'product_id': item1.id,
|
||||
'product_uom_qty': 0,
|
||||
'reserved_uom_qty': 0,
|
||||
'qty_done': 1,
|
||||
'product_uom_id': uom_dozen.id,
|
||||
'location_id': so1.picking_ids.location_id.id,
|
||||
@@ -572,7 +572,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
|
||||
}),
|
||||
(0, 0, {
|
||||
'product_id': item1.id,
|
||||
'product_uom_qty': 0,
|
||||
'reserved_uom_qty': 0,
|
||||
'qty_done': 1,
|
||||
'product_uom_id': uom_dozen.id,
|
||||
'location_id': so1.picking_ids.location_id.id,
|
||||
|
||||
@@ -87,7 +87,7 @@ class Location(models.Model):
|
||||
_sql_constraints = [('barcode_company_uniq', 'unique (barcode,company_id)', 'The barcode for a location must be unique per company !'),
|
||||
('inventory_freq_nonneg', 'check(cyclic_inventory_frequency >= 0)', 'The inventory frequency (days) for a location must be non-negative')]
|
||||
|
||||
@api.depends('outgoing_move_line_ids.product_qty', 'incoming_move_line_ids.product_qty',
|
||||
@api.depends('outgoing_move_line_ids.reserved_qty', 'incoming_move_line_ids.reserved_qty',
|
||||
'outgoing_move_line_ids.state', 'incoming_move_line_ids.state',
|
||||
'outgoing_move_line_ids.product_id.weight', 'outgoing_move_line_ids.product_id.weight',
|
||||
'quant_ids.quantity', 'quant_ids.product_id.weight')
|
||||
@@ -101,9 +101,9 @@ class Location(models.Model):
|
||||
location.net_weight += quant.product_id.weight * quant.quantity
|
||||
location.forecast_weight = location.net_weight
|
||||
for line in incoming_move_lines:
|
||||
location.forecast_weight += line.product_id.weight * line.product_qty
|
||||
location.forecast_weight += line.product_id.weight * line.reserved_qty
|
||||
for line in outgoing_move_lines:
|
||||
location.forecast_weight -= line.product_id.weight * line.product_qty
|
||||
location.forecast_weight -= line.product_id.weight * line.reserved_qty
|
||||
|
||||
@api.depends('name', 'location_id.complete_name', 'usage')
|
||||
def _compute_complete_name(self):
|
||||
@@ -168,7 +168,7 @@ class Location(models.Model):
|
||||
for f in {'usage', 'scrap_location'}))
|
||||
reserved_quantities = self.env['stock.move.line'].search_count([
|
||||
('location_id', 'in', modified_locations.ids),
|
||||
('product_qty', '>', 0),
|
||||
('reserved_qty', '>', 0),
|
||||
])
|
||||
if reserved_quantities:
|
||||
raise UserError(_(
|
||||
@@ -264,7 +264,7 @@ class Location(models.Model):
|
||||
('product_id', '=', product.id),
|
||||
('location_dest_id', 'in', locations.ids),
|
||||
('state', 'not in', ['draft', 'done', 'cancel'])
|
||||
], ['location_dest_id', 'product_id', 'product_qty:array_agg', 'qty_done:array_agg', 'product_uom_id:array_agg'], ['location_dest_id'])
|
||||
], ['location_dest_id', 'product_id', 'reserved_qty:array_agg', 'qty_done:array_agg', 'product_uom_id:array_agg'], ['location_dest_id'])
|
||||
quant_data = self.env['stock.quant'].read_group([
|
||||
('product_id', '=', product.id),
|
||||
('location_id', 'in', locations.ids),
|
||||
@@ -273,7 +273,7 @@ class Location(models.Model):
|
||||
for values in move_line_data:
|
||||
uoms = self.env['uom.uom'].browse(values['product_uom_id'])
|
||||
qty_done = sum(max(ml_uom._compute_quantity(float(qty), product.uom_id), float(qty_reserved))
|
||||
for qty_reserved, qty, ml_uom in zip(values['product_qty'], values['qty_done'], list(uoms)))
|
||||
for qty_reserved, qty, ml_uom in zip(values['reserved_qty'], values['qty_done'], list(uoms)))
|
||||
qty_by_location[values['location_dest_id'][0]] = qty_done
|
||||
for values in quant_data:
|
||||
qty_by_location[values['location_id'][0]] += values['quantity']
|
||||
|
||||
@@ -130,7 +130,7 @@ class StockMove(models.Model):
|
||||
picking_type_id = fields.Many2one('stock.picking.type', 'Operation Type', compute='_compute_picking_type_id', store=True, check_company=True)
|
||||
is_inventory = fields.Boolean('Inventory')
|
||||
move_line_ids = fields.One2many('stock.move.line', 'move_id')
|
||||
move_line_nosuggest_ids = fields.One2many('stock.move.line', 'move_id', domain=['|', ('product_qty', '=', 0.0), ('qty_done', '!=', 0.0)])
|
||||
move_line_nosuggest_ids = fields.One2many('stock.move.line', 'move_id', domain=['|', ('reserved_qty', '=', 0.0), ('qty_done', '!=', 0.0)])
|
||||
origin_returned_move_id = fields.Many2one(
|
||||
'stock.move', 'Origin return move', copy=False, index=True,
|
||||
help='Move that created the return move', check_company=True)
|
||||
@@ -376,7 +376,7 @@ class StockMove(models.Model):
|
||||
detect errors. """
|
||||
raise UserError(_('The requested operation cannot be processed because of a programming error setting the `product_qty` field instead of the `product_uom_qty`.'))
|
||||
|
||||
@api.depends('move_line_ids.product_qty')
|
||||
@api.depends('move_line_ids.reserved_qty')
|
||||
def _compute_reserved_availability(self):
|
||||
""" Fill the `availability` field on a stock move, which is the actual reserved quantity
|
||||
and is represented by the aggregated `product_qty` on the linked move lines. If the move
|
||||
@@ -385,13 +385,13 @@ class StockMove(models.Model):
|
||||
if not any(self._ids):
|
||||
# onchange
|
||||
for move in self:
|
||||
reserved_availability = sum(move.move_line_ids.mapped('product_qty'))
|
||||
reserved_availability = sum(move.move_line_ids.mapped('reserved_qty'))
|
||||
move.reserved_availability = move.product_id.uom_id._compute_quantity(
|
||||
reserved_availability, move.product_uom, rounding_method='HALF-UP')
|
||||
else:
|
||||
# compute
|
||||
result = {data['move_id'][0]: data['product_qty'] for data in
|
||||
self.env['stock.move.line'].read_group([('move_id', 'in', self.ids)], ['move_id', 'product_qty'], ['move_id'])}
|
||||
result = {data['move_id'][0]: data['reserved_qty'] for data in
|
||||
self.env['stock.move.line'].read_group([('move_id', 'in', self.ids)], ['move_id', 'reserved_qty'], ['move_id'])}
|
||||
for move in self:
|
||||
move.reserved_availability = move.product_id.uom_id._compute_quantity(
|
||||
result.get(move.id, 0.0), move.product_uom, rounding_method='HALF-UP')
|
||||
@@ -489,7 +489,7 @@ class StockMove(models.Model):
|
||||
|
||||
@api.depends('move_line_ids', 'move_line_ids.lot_id', 'move_line_ids.qty_done')
|
||||
def _compute_lot_ids(self):
|
||||
domain_nosuggest = [('move_id', 'in', self.ids), ('lot_id', '!=', False), '|', ('qty_done', '!=', 0.0), ('product_qty', '=', 0.0)]
|
||||
domain_nosuggest = [('move_id', 'in', self.ids), ('lot_id', '!=', False), '|', ('qty_done', '!=', 0.0), ('reserved_qty', '=', 0.0)]
|
||||
domain_suggest = [('move_id', 'in', self.ids), ('lot_id', '!=', False), ('qty_done', '!=', 0.0)]
|
||||
lots_by_move_id_list = []
|
||||
for domain in [domain_nosuggest, domain_suggest]:
|
||||
@@ -754,7 +754,7 @@ class StockMove(models.Model):
|
||||
ml_to_update, ml_to_unlink = self.env['stock.move.line'].browse(ml_to_update), self.env['stock.move.line'].browse(ml_to_unlink)
|
||||
moves_not_to_recompute = self.env['stock.move'].browse(moves_not_to_recompute)
|
||||
|
||||
ml_to_update.write({'product_uom_qty': 0})
|
||||
ml_to_update.write({'reserved_uom_qty': 0})
|
||||
ml_to_unlink.unlink()
|
||||
# `write` on `stock.move.line` doesn't call `_recompute_state` (unlike to `unlink`),
|
||||
# so it must be called for each move where no move line has been deleted.
|
||||
@@ -1293,9 +1293,9 @@ class StockMove(models.Model):
|
||||
uom_quantity = float_round(uom_quantity, precision_digits=rounding)
|
||||
uom_quantity_back_to_product_uom = self.product_uom._compute_quantity(uom_quantity, self.product_id.uom_id, rounding_method='HALF-UP')
|
||||
if float_compare(quantity, uom_quantity_back_to_product_uom, precision_digits=rounding) == 0:
|
||||
vals = dict(vals, product_uom_qty=uom_quantity)
|
||||
vals = dict(vals, reserved_uom_qty=uom_quantity)
|
||||
else:
|
||||
vals = dict(vals, product_uom_qty=quantity, product_uom_id=self.product_id.uom_id.id)
|
||||
vals = dict(vals, reserved_uom_qty=quantity, product_uom_id=self.product_id.uom_id.id)
|
||||
package = None
|
||||
if reserved_quant:
|
||||
package = reserved_quant.package_id
|
||||
@@ -1366,7 +1366,7 @@ class StockMove(models.Model):
|
||||
uom_quantity = float_round(uom_quantity, precision_digits=rounding)
|
||||
uom_quantity_back_to_product_uom = to_update.product_uom_id._compute_quantity(uom_quantity, self.product_id.uom_id, rounding_method='HALF-UP')
|
||||
if to_update and float_compare(quantity, uom_quantity_back_to_product_uom, precision_digits=rounding) == 0:
|
||||
to_update.with_context(bypass_reservation_update=True).product_uom_qty += uom_quantity
|
||||
to_update.with_context(bypass_reservation_update=True).reserved_uom_qty += uom_quantity
|
||||
else:
|
||||
if self.product_id.tracking == 'serial':
|
||||
self.env['stock.move.line'].create([self._prepare_move_line_vals(quantity=1, reserved_quant=reserved_quant) for i in range(int(quantity))])
|
||||
@@ -1388,7 +1388,7 @@ class StockMove(models.Model):
|
||||
|
||||
def _action_assign(self):
|
||||
""" Reserve stock moves by creating their stock move lines. A stock move is
|
||||
considered reserved once the sum of `product_qty` for all its move lines is
|
||||
considered reserved once the sum of `reserved_qty` for all its move lines is
|
||||
equal to its `product_qty`. If it is less, the stock move is considered
|
||||
partially available.
|
||||
"""
|
||||
@@ -1425,7 +1425,7 @@ class StockMove(models.Model):
|
||||
qty_done += ml.product_uom_id._compute_quantity(ml.qty_done, ml.product_id.uom_id)
|
||||
grouped_move_lines_out[k] = qty_done
|
||||
for k, g in groupby(move_lines_out_reserved, key=_keys_out_groupby):
|
||||
grouped_move_lines_out[k] = sum(self.env['stock.move.line'].concat(*g).mapped('product_qty'))
|
||||
grouped_move_lines_out[k] = sum(self.env['stock.move.line'].concat(*g).mapped('reserved_qty'))
|
||||
available_move_lines = {key: grouped_move_lines_in[key] - grouped_move_lines_out.get(key, 0) for key in grouped_move_lines_in}
|
||||
# pop key if the quantity available amount to 0
|
||||
return dict((k, v) for k, v in available_move_lines.items() if v)
|
||||
@@ -1472,7 +1472,7 @@ class StockMove(models.Model):
|
||||
not ml.package_id and
|
||||
not ml.owner_id)
|
||||
if to_update:
|
||||
to_update[0].product_uom_qty += move.product_id.uom_id._compute_quantity(
|
||||
to_update[0].reserved_uom_qty += move.product_id.uom_id._compute_quantity(
|
||||
missing_reserved_quantity, move.product_uom, rounding_method='HALF-UP')
|
||||
else:
|
||||
move_line_vals_list.append(move._prepare_move_line_vals(quantity=missing_reserved_quantity))
|
||||
@@ -1509,11 +1509,11 @@ class StockMove(models.Model):
|
||||
available_move_lines = _get_available_move_lines(move)
|
||||
if not available_move_lines:
|
||||
continue
|
||||
for move_line in move.move_line_ids.filtered(lambda m: m.product_qty):
|
||||
for move_line in move.move_line_ids.filtered(lambda m: m.reserved_qty):
|
||||
if available_move_lines.get((move_line.location_id, move_line.lot_id, move_line.result_package_id, move_line.owner_id)):
|
||||
available_move_lines[(move_line.location_id, move_line.lot_id, move_line.result_package_id, move_line.owner_id)] -= move_line.product_qty
|
||||
available_move_lines[(move_line.location_id, move_line.lot_id, move_line.result_package_id, move_line.owner_id)] -= move_line.reserved_qty
|
||||
for (location_id, lot_id, package_id, owner_id), quantity in available_move_lines.items():
|
||||
need = move.product_qty - sum(move.move_line_ids.mapped('product_qty'))
|
||||
need = move.product_qty - sum(move.move_line_ids.mapped('reserved_qty'))
|
||||
# `quantity` is what is brought by chained done move lines. We double check
|
||||
# here this quantity is available on the quants themselves. If not, this
|
||||
# could be the result of an inventory adjustment that removed totally of
|
||||
@@ -1788,7 +1788,7 @@ class StockMove(models.Model):
|
||||
def _set_quantity_done_prepare_vals(self, qty):
|
||||
res = []
|
||||
for ml in self.move_line_ids:
|
||||
ml_qty = ml.product_uom_qty - ml.qty_done
|
||||
ml_qty = ml.reserved_uom_qty - ml.qty_done
|
||||
if float_compare(ml_qty, 0, precision_rounding=ml.product_uom_id.rounding) <= 0:
|
||||
continue
|
||||
# Convert move line qty into move uom
|
||||
@@ -1812,7 +1812,7 @@ class StockMove(models.Model):
|
||||
break
|
||||
|
||||
for ml in self.move_line_ids:
|
||||
if float_is_zero(ml.product_uom_qty, precision_rounding=ml.product_uom_id.rounding) and float_is_zero(ml.qty_done, precision_rounding=ml.product_uom_id.rounding):
|
||||
if float_is_zero(ml.reserved_uom_qty, precision_rounding=ml.product_uom_id.rounding) and float_is_zero(ml.qty_done, precision_rounding=ml.product_uom_id.rounding):
|
||||
res.append((2, ml.id))
|
||||
|
||||
if float_compare(qty, 0.0, precision_rounding=self.product_uom.rounding) > 0:
|
||||
@@ -1845,7 +1845,7 @@ class StockMove(models.Model):
|
||||
for move_line in move.move_line_ids:
|
||||
if move.has_tracking != 'none' and not (move_line.lot_id or move_line.lot_name):
|
||||
continue
|
||||
move_line.qty_done = move_line.product_uom_qty
|
||||
move_line.qty_done = move_line.reserved_uom_qty
|
||||
|
||||
def _clear_quantities_to_zero(self):
|
||||
self.filtered(lambda m: m.state in ('partially_available', 'assigned')).move_line_ids.qty_done = 0
|
||||
|
||||
@@ -29,10 +29,10 @@ class StockMoveLine(models.Model):
|
||||
product_id = fields.Many2one('product.product', 'Product', ondelete="cascade", check_company=True, domain="[('type', '!=', 'service'), '|', ('company_id', '=', False), ('company_id', '=', company_id)]")
|
||||
product_uom_id = fields.Many2one('uom.uom', 'Unit of Measure', required=True, domain="[('category_id', '=', product_uom_category_id)]")
|
||||
product_uom_category_id = fields.Many2one(related='product_id.uom_id.category_id')
|
||||
product_qty = fields.Float(
|
||||
reserved_qty = fields.Float(
|
||||
'Real Reserved Quantity', digits=0, copy=False,
|
||||
compute='_compute_product_qty', inverse='_set_product_qty', store=True)
|
||||
product_uom_qty = fields.Float(
|
||||
compute='_compute_reserved_qty', inverse='_set_product_qty', store=True)
|
||||
reserved_uom_qty = fields.Float(
|
||||
'Reserved', default=0.0, digits='Product Unit of Measure', required=True, copy=False)
|
||||
qty_done = fields.Float('Done', default=0.0, digits='Product Unit of Measure', copy=False)
|
||||
package_id = fields.Many2one(
|
||||
@@ -94,17 +94,17 @@ class StockMoveLine(models.Model):
|
||||
def _search_picking_type_id(self, operator, value):
|
||||
return [('picking_id.picking_type_id', operator, value)]
|
||||
|
||||
@api.depends('product_id', 'product_uom_id', 'product_uom_qty')
|
||||
def _compute_product_qty(self):
|
||||
@api.depends('product_id', 'product_uom_id', 'reserved_uom_qty')
|
||||
def _compute_reserved_qty(self):
|
||||
for line in self:
|
||||
line.product_qty = line.product_uom_id._compute_quantity(line.product_uom_qty, line.product_id.uom_id, rounding_method='HALF-UP')
|
||||
line.reserved_qty = line.product_uom_id._compute_quantity(line.reserved_uom_qty, line.product_id.uom_id, rounding_method='HALF-UP')
|
||||
|
||||
def _set_product_qty(self):
|
||||
""" The meaning of product_qty field changed lately and is now a functional field computing the quantity
|
||||
def _set_reserved_qty(self):
|
||||
""" The meaning of reserved_qty field changed lately and is now a functional field computing the quantity
|
||||
in the default product UoM. This code has been added to raise an error if a write is made given a value
|
||||
for `product_qty`, where the same write should set the `product_uom_qty` field instead, in order to
|
||||
for `reserved_qty`, where the same write should set the `reserved_uom_qty` field instead, in order to
|
||||
detect errors. """
|
||||
raise UserError(_('The requested operation cannot be processed because of a programming error setting the `product_qty` field instead of the `product_uom_qty`.'))
|
||||
raise UserError(_('The requested operation cannot be processed because of a programming error setting the `reserved_qty` field instead of the `reserved_uom_qty`.'))
|
||||
|
||||
@api.constrains('lot_id', 'product_id')
|
||||
def _check_lot_product(self):
|
||||
@@ -116,10 +116,10 @@ class StockMoveLine(models.Model):
|
||||
product_name=line.product_id.display_name
|
||||
))
|
||||
|
||||
@api.constrains('product_uom_qty')
|
||||
@api.constrains('reserved_uom_qty')
|
||||
def _check_reserved_done_quantity(self):
|
||||
for move_line in self:
|
||||
if move_line.state == 'done' and not float_is_zero(move_line.product_uom_qty, precision_digits=self.env['decimal.precision'].precision_get('Product Unit of Measure')):
|
||||
if move_line.state == 'done' and not float_is_zero(move_line.reserved_uom_qty, precision_digits=self.env['decimal.precision'].precision_get('Product Unit of Measure')):
|
||||
raise ValidationError(_('A done move line should never have a reserved quantity.'))
|
||||
|
||||
@api.constrains('qty_done')
|
||||
@@ -215,7 +215,7 @@ class StockMoveLine(models.Model):
|
||||
def _get_putaway_additional_qty(self):
|
||||
addtional_qty = {}
|
||||
for ml in self._origin:
|
||||
qty = max(ml.product_uom_id._compute_quantity(ml.qty_done, ml.product_id.uom_id), ml.product_uom_qty)
|
||||
qty = max(ml.product_uom_id._compute_quantity(ml.qty_done, ml.product_id.uom_id), ml.reserved_uom_qty)
|
||||
addtional_qty[ml.location_dest_id.id] = addtional_qty.get(ml.location_dest_id.id, 0) - qty
|
||||
return addtional_qty
|
||||
|
||||
@@ -226,7 +226,7 @@ class StockMoveLine(models.Model):
|
||||
ON
|
||||
stock_move_line (id, company_id, product_id, lot_id, location_id, owner_id, package_id)
|
||||
WHERE
|
||||
(state IS NULL OR state NOT IN ('cancel', 'done')) AND product_qty > 0""")
|
||||
(state IS NULL OR state NOT IN ('cancel', 'done')) AND reserved_qty > 0""")
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
@@ -334,31 +334,31 @@ class StockMoveLine(models.Model):
|
||||
package_level.unlink()
|
||||
|
||||
# When we try to write on a reserved move line any fields from `triggers` or directly
|
||||
# `product_uom_qty` (the actual reserved quantity), we need to make sure the associated
|
||||
# `reserved_uom_qty` (the actual reserved quantity), we need to make sure the associated
|
||||
# quants are correctly updated in order to not make them out of sync (i.e. the sum of the
|
||||
# move lines `product_uom_qty` should always be equal to the sum of `reserved_quantity` on
|
||||
# move lines `reserved_uom_qty` should always be equal to the sum of `reserved_quantity` on
|
||||
# the quants). If the new charateristics are not available on the quants, we chose to
|
||||
# reserve the maximum possible.
|
||||
if updates or 'product_uom_qty' in vals:
|
||||
if updates or 'reserved_uom_qty' in vals:
|
||||
for ml in self.filtered(lambda ml: ml.state in ['partially_available', 'assigned'] and ml.product_id.type == 'product'):
|
||||
|
||||
if 'product_uom_qty' in vals:
|
||||
new_product_uom_qty = ml.product_uom_id._compute_quantity(
|
||||
vals['product_uom_qty'], ml.product_id.uom_id, rounding_method='HALF-UP')
|
||||
# Make sure `product_uom_qty` is not negative.
|
||||
if float_compare(new_product_uom_qty, 0, precision_rounding=ml.product_id.uom_id.rounding) < 0:
|
||||
if 'reserved_uom_qty' in vals:
|
||||
new_reserved_uom_qty = ml.product_uom_id._compute_quantity(
|
||||
vals['reserved_uom_qty'], ml.product_id.uom_id, rounding_method='HALF-UP')
|
||||
# Make sure `reserved_uom_qty` is not negative.
|
||||
if float_compare(new_reserved_uom_qty, 0, precision_rounding=ml.product_id.uom_id.rounding) < 0:
|
||||
raise UserError(_('Reserving a negative quantity is not allowed.'))
|
||||
else:
|
||||
new_product_uom_qty = ml.product_qty
|
||||
new_reserved_uom_qty = ml.reserved_qty
|
||||
|
||||
# Unreserve the old charateristics of the move line.
|
||||
if not ml.move_id._should_bypass_reservation(ml.location_id):
|
||||
try:
|
||||
Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
|
||||
Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.reserved_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
|
||||
except UserError:
|
||||
# If we were not able to unreserve on tracked quants, we can use untracked ones.
|
||||
if ml.lot_id:
|
||||
Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
|
||||
Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.reserved_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
|
||||
else:
|
||||
raise
|
||||
|
||||
@@ -366,22 +366,22 @@ class StockMoveLine(models.Model):
|
||||
if not ml.move_id._should_bypass_reservation(updates.get('location_id', ml.location_id)):
|
||||
reserved_qty = 0
|
||||
try:
|
||||
q = Quant._update_reserved_quantity(ml.product_id, updates.get('location_id', ml.location_id), new_product_uom_qty, lot_id=updates.get('lot_id', ml.lot_id),
|
||||
q = Quant._update_reserved_quantity(ml.product_id, updates.get('location_id', ml.location_id), new_reserved_uom_qty, lot_id=updates.get('lot_id', ml.lot_id),
|
||||
package_id=updates.get('package_id', ml.package_id), owner_id=updates.get('owner_id', ml.owner_id), strict=True)
|
||||
reserved_qty = sum([x[1] for x in q])
|
||||
except UserError:
|
||||
if updates.get('lot_id'):
|
||||
# If we were not able to reserve on tracked quants, we can use untracked ones.
|
||||
try:
|
||||
q = Quant._update_reserved_quantity(ml.product_id, updates.get('location_id', ml.location_id), new_product_uom_qty, lot_id=False,
|
||||
q = Quant._update_reserved_quantity(ml.product_id, updates.get('location_id', ml.location_id), new_reserved_uom_qty, lot_id=False,
|
||||
package_id=updates.get('package_id', ml.package_id), owner_id=updates.get('owner_id', ml.owner_id), strict=True)
|
||||
reserved_qty = sum([x[1] for x in q])
|
||||
except UserError:
|
||||
pass
|
||||
if reserved_qty != new_product_uom_qty:
|
||||
new_product_uom_qty = ml.product_id.uom_id._compute_quantity(reserved_qty, ml.product_uom_id, rounding_method='HALF-UP')
|
||||
if reserved_qty != new_reserved_uom_qty:
|
||||
new_reserved_uom_qty = ml.product_id.uom_id._compute_quantity(reserved_qty, ml.product_uom_id, rounding_method='HALF-UP')
|
||||
moves_to_recompute_state |= ml.move_id
|
||||
ml.with_context(bypass_reservation_update=True).product_uom_qty = new_product_uom_qty
|
||||
ml.with_context(bypass_reservation_update=True).reserved_uom_qty = new_reserved_uom_qty
|
||||
|
||||
# When editing a done move line, the reserved availability of a potential chained move is impacted. Take care of running again `_action_assign` on the concerned moves.
|
||||
if updates or 'qty_done' in vals:
|
||||
@@ -443,7 +443,7 @@ class StockMoveLine(models.Model):
|
||||
# this is what move's `action_done` will do. So, we replicate the behavior here.
|
||||
if updates or 'qty_done' in vals:
|
||||
moves = self.filtered(lambda ml: ml.move_id.state == 'done').mapped('move_id')
|
||||
moves |= self.filtered(lambda ml: ml.move_id.state not in ('done', 'cancel') and ml.move_id.picking_id.immediate_transfer and not ml.product_uom_qty).mapped('move_id')
|
||||
moves |= self.filtered(lambda ml: ml.move_id.state not in ('done', 'cancel') and ml.move_id.picking_id.immediate_transfer and not ml.reserved_uom_qty).mapped('move_id')
|
||||
for move in moves:
|
||||
move.product_uom_qty = move.quantity_done
|
||||
next_moves._do_unreserve()
|
||||
@@ -464,12 +464,12 @@ class StockMoveLine(models.Model):
|
||||
precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
|
||||
for ml in self:
|
||||
# Unlinking a move line should unreserve.
|
||||
if ml.product_id.type == 'product' and not ml.move_id._should_bypass_reservation(ml.location_id) and not float_is_zero(ml.product_qty, precision_digits=precision):
|
||||
if ml.product_id.type == 'product' and not ml.move_id._should_bypass_reservation(ml.location_id) and not float_is_zero(ml.reserved_qty, precision_digits=precision):
|
||||
try:
|
||||
self.env['stock.quant']._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
|
||||
self.env['stock.quant']._update_reserved_quantity(ml.product_id, ml.location_id, -ml.reserved_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
|
||||
except UserError:
|
||||
if ml.lot_id:
|
||||
self.env['stock.quant']._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
|
||||
self.env['stock.quant']._update_reserved_quantity(ml.product_id, ml.location_id, -ml.reserved_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
|
||||
elif not self.env.context.get(MODULE_UNINSTALL_FLAG, False):
|
||||
raise # pylint: disable=raise-unlink-override
|
||||
moves = self.mapped('move_id')
|
||||
@@ -566,16 +566,16 @@ class StockMoveLine(models.Model):
|
||||
rounding = ml.product_uom_id.rounding
|
||||
|
||||
# if this move line is force assigned, unreserve elsewhere if needed
|
||||
if not ml.move_id._should_bypass_reservation(ml.location_id) and float_compare(ml.qty_done, ml.product_uom_qty, precision_rounding=rounding) > 0:
|
||||
if not ml.move_id._should_bypass_reservation(ml.location_id) and float_compare(ml.qty_done, ml.reserved_uom_qty, precision_rounding=rounding) > 0:
|
||||
qty_done_product_uom = ml.product_uom_id._compute_quantity(ml.qty_done, ml.product_id.uom_id, rounding_method='HALF-UP')
|
||||
extra_qty = qty_done_product_uom - ml.product_qty
|
||||
extra_qty = qty_done_product_uom - ml.reserved_qty
|
||||
ml._free_reservation(ml.product_id, ml.location_id, extra_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, ml_ids_to_ignore=ml_ids_to_ignore)
|
||||
# unreserve what's been reserved
|
||||
if not ml.move_id._should_bypass_reservation(ml.location_id) and ml.product_id.type == 'product' and ml.product_qty:
|
||||
if not ml.move_id._should_bypass_reservation(ml.location_id) and ml.product_id.type == 'product' and ml.reserved_qty:
|
||||
try:
|
||||
Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
|
||||
Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.reserved_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
|
||||
except UserError:
|
||||
Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
|
||||
Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.reserved_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
|
||||
|
||||
# move what's been actually done
|
||||
quantity = ml.product_uom_id._compute_quantity(ml.qty_done, ml.move_id.product_id.uom_id, rounding_method='HALF-UP')
|
||||
@@ -591,7 +591,7 @@ class StockMoveLine(models.Model):
|
||||
ml_ids_to_ignore.add(ml.id)
|
||||
# Reset the reserved quantity as we just moved it to the destination location.
|
||||
mls_todo.with_context(bypass_reservation_update=True).write({
|
||||
'product_uom_qty': 0.00,
|
||||
'reserved_uom_qty': 0.00,
|
||||
'date': fields.Datetime.now(),
|
||||
})
|
||||
|
||||
@@ -686,7 +686,7 @@ class StockMoveLine(models.Model):
|
||||
('location_id', '=', location_id.id),
|
||||
('owner_id', '=', owner_id.id if owner_id else False),
|
||||
('package_id', '=', package_id.id if package_id else False),
|
||||
('product_qty', '>', 0.0),
|
||||
('reserved_qty', '>', 0.0),
|
||||
('id', 'not in', tuple(ml_ids_to_ignore)),
|
||||
]
|
||||
|
||||
@@ -706,11 +706,11 @@ class StockMoveLine(models.Model):
|
||||
|
||||
rounding = self.product_uom_id.rounding
|
||||
for candidate in outdated_candidates:
|
||||
if float_compare(candidate.product_qty, quantity, precision_rounding=rounding) <= 0:
|
||||
quantity -= candidate.product_qty
|
||||
if float_compare(candidate.reserved_qty, quantity, precision_rounding=rounding) <= 0:
|
||||
quantity -= candidate.reserved_qty
|
||||
if candidate.qty_done:
|
||||
move_to_recompute_state |= candidate.move_id
|
||||
candidate.product_uom_qty = 0.0
|
||||
candidate.reserved_uom_qty = 0.0
|
||||
else:
|
||||
to_unlink_candidate_ids.add(candidate.id)
|
||||
if float_is_zero(quantity, precision_rounding=rounding):
|
||||
@@ -718,10 +718,10 @@ class StockMoveLine(models.Model):
|
||||
else:
|
||||
# split this move line and assign the new part to our extra move
|
||||
quantity_split = float_round(
|
||||
candidate.product_qty - quantity,
|
||||
candidate.reserved_qty - quantity,
|
||||
precision_rounding=self.product_uom_id.rounding,
|
||||
rounding_method='UP')
|
||||
candidate.product_uom_qty = self.product_id.uom_id._compute_quantity(quantity_split, candidate.product_uom_id, rounding_method='HALF-UP')
|
||||
candidate.reserved_uom_qty = self.product_id.uom_id._compute_quantity(quantity_split, candidate.product_uom_id, rounding_method='HALF-UP')
|
||||
move_to_recompute_state |= candidate.move_id
|
||||
break
|
||||
self.env['stock.move.line'].browse(to_unlink_candidate_ids).unlink()
|
||||
|
||||
@@ -74,8 +74,8 @@ class StockPackageLevel(models.Model):
|
||||
for rec, quant in ml_update_dict.items():
|
||||
rec.qty_done = quant
|
||||
else:
|
||||
package_level.move_line_ids.filtered(lambda ml: ml.product_qty == 0).unlink()
|
||||
package_level.move_line_ids.filtered(lambda ml: ml.product_qty != 0).write({'qty_done': 0})
|
||||
package_level.move_line_ids.filtered(lambda ml: ml.reserved_qty == 0).unlink()
|
||||
package_level.move_line_ids.filtered(lambda ml: ml.reserved_qty != 0).write({'qty_done': 0})
|
||||
|
||||
@api.depends('move_line_ids', 'move_line_ids.package_id', 'move_line_ids.result_package_id')
|
||||
def _compute_fresh_pack(self):
|
||||
@@ -95,7 +95,7 @@ class StockPackageLevel(models.Model):
|
||||
elif package_level.move_line_ids and not package_level.move_line_ids.filtered(lambda ml: ml.state == 'done'):
|
||||
if package_level.is_fresh_package:
|
||||
package_level.state = 'new'
|
||||
elif package_level._check_move_lines_map_quant_package(package_level.package_id, 'product_uom_qty'):
|
||||
elif package_level._check_move_lines_map_quant_package(package_level.package_id, 'reserved_uom_qty'):
|
||||
package_level.state = 'assigned'
|
||||
else:
|
||||
package_level.state = 'confirmed'
|
||||
|
||||
@@ -356,7 +356,7 @@ class Picking(models.Model):
|
||||
default=lambda self: self.env.user)
|
||||
move_line_ids = fields.One2many('stock.move.line', 'picking_id', 'Operations')
|
||||
move_line_ids_without_package = fields.One2many('stock.move.line', 'picking_id', 'Operations without package', domain=['|',('package_level_id', '=', False), ('picking_type_entire_packs', '=', False)])
|
||||
move_line_nosuggest_ids = fields.One2many('stock.move.line', 'picking_id', domain=[('product_qty', '=', 0.0)])
|
||||
move_line_nosuggest_ids = fields.One2many('stock.move.line', 'picking_id', domain=[('reserved_qty', '=', 0.0)])
|
||||
move_line_exist = fields.Boolean(
|
||||
'Has Pack Operations', compute='_compute_move_line_exist',
|
||||
help='Check the existence of pack operation on the picking')
|
||||
@@ -883,7 +883,7 @@ class Picking(models.Model):
|
||||
return move_ids_without_package.filtered(lambda move: not move.scrap_ids)
|
||||
|
||||
def _check_move_lines_map_quant_package(self, package):
|
||||
return package._check_move_lines_map_quant(self.move_line_ids.filtered(lambda ml: ml.package_id == package), 'product_qty')
|
||||
return package._check_move_lines_map_quant(self.move_line_ids.filtered(lambda ml: ml.package_id == package), 'reserved_qty')
|
||||
|
||||
def _get_entire_pack_location_dest(self, move_line_ids):
|
||||
location_dest_ids = move_line_ids.mapped('location_dest_id')
|
||||
@@ -952,7 +952,7 @@ class Picking(models.Model):
|
||||
picking_type = picking.picking_type_id
|
||||
precision_digits = self.env['decimal.precision'].precision_get('Product Unit of Measure')
|
||||
no_quantities_done = all(float_is_zero(move_line.qty_done, precision_digits=precision_digits) for move_line in picking.move_line_ids.filtered(lambda m: m.state not in ('done', 'cancel')))
|
||||
no_reserved_quantities = all(float_is_zero(move_line.product_qty, precision_rounding=move_line.product_uom_id.rounding) for move_line in picking.move_line_ids)
|
||||
no_reserved_quantities = all(float_is_zero(move_line.reserved_qty, precision_rounding=move_line.product_uom_id.rounding) for move_line in picking.move_line_ids)
|
||||
if no_reserved_quantities and no_quantities_done:
|
||||
pickings_without_quantities |= picking
|
||||
|
||||
@@ -1356,28 +1356,28 @@ class Picking(models.Model):
|
||||
precision_digits = self.env['decimal.precision'].precision_get('Product Unit of Measure')
|
||||
if float_is_zero(move_line_ids[0].qty_done, precision_digits=precision_digits):
|
||||
for line in move_line_ids:
|
||||
line.qty_done = line.product_uom_qty
|
||||
line.qty_done = line.reserved_uom_qty
|
||||
|
||||
for ml in move_line_ids:
|
||||
if float_compare(ml.qty_done, ml.product_uom_qty,
|
||||
if float_compare(ml.qty_done, ml.reserved_uom_qty,
|
||||
precision_rounding=ml.product_uom_id.rounding) >= 0:
|
||||
move_lines_to_pack |= ml
|
||||
else:
|
||||
quantity_left_todo = float_round(
|
||||
ml.product_uom_qty - ml.qty_done,
|
||||
ml.reserved_uom_qty - ml.qty_done,
|
||||
precision_rounding=ml.product_uom_id.rounding,
|
||||
rounding_method='UP')
|
||||
done_to_keep = ml.qty_done
|
||||
new_move_line = ml.copy(
|
||||
default={'product_uom_qty': 0, 'qty_done': ml.qty_done})
|
||||
vals = {'product_uom_qty': quantity_left_todo, 'qty_done': 0.0}
|
||||
default={'reserved_uom_qty': 0, 'qty_done': ml.qty_done})
|
||||
vals = {'reserved_uom_qty': quantity_left_todo, 'qty_done': 0.0}
|
||||
if pick.picking_type_id.code == 'incoming':
|
||||
if ml.lot_id:
|
||||
vals['lot_id'] = False
|
||||
if ml.lot_name:
|
||||
vals['lot_name'] = False
|
||||
ml.write(vals)
|
||||
new_move_line.write({'product_uom_qty': done_to_keep})
|
||||
new_move_line.write({'reserved_uom_qty': done_to_keep})
|
||||
move_lines_to_pack |= new_move_line
|
||||
if not package.package_type_id:
|
||||
package_type = move_lines_to_pack.move_id.product_packaging_id.package_type_id
|
||||
@@ -1387,7 +1387,7 @@ class Picking(models.Model):
|
||||
default_dest_location = move_lines_to_pack._get_default_dest_location()
|
||||
move_lines_to_pack.location_dest_id = default_dest_location._get_putaway_strategy(
|
||||
product=move_lines_to_pack.product_id,
|
||||
quantity=move_lines_to_pack.product_uom_qty,
|
||||
quantity=move_lines_to_pack.reserved_uom_qty,
|
||||
package=package)
|
||||
move_lines_to_pack.write({
|
||||
'result_package_id': package.id,
|
||||
@@ -1419,7 +1419,7 @@ class Picking(models.Model):
|
||||
and not ml.result_package_id
|
||||
)
|
||||
if not move_line_ids:
|
||||
move_line_ids = picking_move_lines.filtered(lambda ml: float_compare(ml.product_uom_qty, 0.0,
|
||||
move_line_ids = picking_move_lines.filtered(lambda ml: float_compare(ml.reserved_uom_qty, 0.0,
|
||||
precision_rounding=ml.product_uom_id.rounding) > 0 and float_compare(ml.qty_done, 0.0,
|
||||
precision_rounding=ml.product_uom_id.rounding) == 0)
|
||||
if move_line_ids:
|
||||
|
||||
@@ -1011,7 +1011,7 @@ class QuantPackage(models.Model):
|
||||
move_line_to_modify = self.env['stock.move.line'].search([
|
||||
('package_id', '=', package.id),
|
||||
('state', 'in', ('assigned', 'partially_available')),
|
||||
('product_qty', '!=', 0),
|
||||
('reserved_qty', '!=', 0),
|
||||
])
|
||||
move_line_to_modify.write({'package_id': False})
|
||||
package.mapped('quant_ids').sudo().write({'package_id': False})
|
||||
|
||||
@@ -495,7 +495,7 @@ class StockMove(models.Model):
|
||||
for move in picking.move_ids:
|
||||
# For assigned moves
|
||||
for move_line in move._get_move_lines():
|
||||
move_line.qty_done = move_line.product_uom_qty
|
||||
move_line.qty_done = move_line.reserved_uom_qty
|
||||
# Create move line for remaining qty
|
||||
missing_to_do = move.product_qty - move.quantity_done
|
||||
missing_to_do = move.product_uom._compute_quantity(missing_to_do, move.product_uom, rounding_method='HALF-UP')
|
||||
|
||||
@@ -219,13 +219,13 @@ class ReceptionReport(models.AbstractModel):
|
||||
out.move_line_ids.move_id = new_out
|
||||
assigned_amount = 0
|
||||
for move_line_id in new_out.move_line_ids:
|
||||
if assigned_amount + move_line_id.product_qty > qty_to_link:
|
||||
new_move_line = move_line_id.copy({'product_uom_qty': 0, 'qty_done': 0})
|
||||
new_move_line.product_uom_qty = move_line_id.product_uom_qty
|
||||
move_line_id.product_uom_qty = out.product_id.uom_id._compute_quantity(qty_to_link - assigned_amount, out.product_uom, rounding_method='HALF-UP')
|
||||
new_move_line.product_uom_qty -= out.product_id.uom_id._compute_quantity(move_line_id.product_qty, out.product_uom, rounding_method='HALF-UP')
|
||||
if assigned_amount + move_line_id.reserved_qty > qty_to_link:
|
||||
new_move_line = move_line_id.copy({'reserved_uom_qty': 0, 'qty_done': 0})
|
||||
new_move_line.reserved_uom_qty = move_line_id.reserved_uom_qty
|
||||
move_line_id.reserved_uom_qty = out.product_id.uom_id._compute_quantity(qty_to_link - assigned_amount, out.product_uom, rounding_method='HALF-UP')
|
||||
new_move_line.reserved_uom_qty -= out.product_id.uom_id._compute_quantity(move_line_id.reserved_qty, out.product_uom, rounding_method='HALF-UP')
|
||||
move_line_id.move_id = out
|
||||
assigned_amount += move_line_id.product_qty
|
||||
assigned_amount += move_line_id.reserved_qty
|
||||
if float_compare(assigned_amount, qty_to_link, precision_rounding=out.product_id.uom_id.rounding) == 0:
|
||||
break
|
||||
|
||||
@@ -282,10 +282,10 @@ class ReceptionReport(models.AbstractModel):
|
||||
for move_line_id in new_out.move_line_ids:
|
||||
if reserved_amount_to_remain <= 0:
|
||||
break
|
||||
if move_line_id.product_qty > reserved_amount_to_remain:
|
||||
new_move_line = move_line_id.copy({'product_uom_qty': 0, 'qty_done': 0})
|
||||
new_move_line.product_uom_qty = out.product_id.uom_id._compute_quantity(move_line_id.product_qty - reserved_amount_to_remain, move_line_id.product_uom_id, rounding_method='HALF-UP')
|
||||
move_line_id.product_uom_qty -= new_move_line.product_uom_qty
|
||||
if move_line_id.reserved_qty > reserved_amount_to_remain:
|
||||
new_move_line = move_line_id.copy({'reserved_uom_qty': 0, 'qty_done': 0})
|
||||
new_move_line.reserved_uom_qty = out.product_id.uom_id._compute_quantity(move_line_id.reserved_qty - reserved_amount_to_remain, move_line_id.product_uom_id, rounding_method='HALF-UP')
|
||||
move_line_id.reserved_uom_qty -= new_move_line.reserved_uom_qty
|
||||
new_move_line.move_id = out
|
||||
break
|
||||
else:
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
<span t-field="ml.product_id.description_picking"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-if="o.state != 'done'" t-field="ml.product_uom_qty"/>
|
||||
<span t-if="o.state != 'done'" t-field="ml.reserved_uom_qty"/>
|
||||
<span t-if="o.state == 'done'" t-field="ml.qty_done"/>
|
||||
<span t-field="ml.product_uom_id" groups="uom.group_uom"/>
|
||||
</td>
|
||||
|
||||
@@ -40,7 +40,7 @@ class StockGenerate(TransactionCase):
|
||||
move_lines_val.append({
|
||||
'product_id': self.product_serial.id,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'product_uom_qty': 1,
|
||||
'reserved_uom_qty': 1,
|
||||
'location_id': self.location.id,
|
||||
'location_dest_id': self.location_dest.id
|
||||
})
|
||||
|
||||
@@ -74,7 +74,7 @@ class StockMove(TransactionCase):
|
||||
|
||||
# fill the move line
|
||||
move_line = move1.move_line_ids[0]
|
||||
self.assertEqual(move_line.product_qty, 100.0)
|
||||
self.assertEqual(move_line.reserved_qty, 100.0)
|
||||
self.assertEqual(move_line.qty_done, 0.0)
|
||||
move_line.qty_done = 100.0
|
||||
|
||||
@@ -110,13 +110,13 @@ class StockMove(TransactionCase):
|
||||
self.assertEqual(move1.state, 'assigned')
|
||||
self.assertEqual(len(move1.move_line_ids), 1)
|
||||
move_line = move1.move_line_ids[0]
|
||||
self.assertEqual(move_line.product_qty, 5)
|
||||
self.assertEqual(move_line.reserved_qty, 5)
|
||||
move_line.lot_name = 'lot1'
|
||||
move_line.qty_done = 5.0
|
||||
self.assertEqual(move_line.product_qty, 5) # don't change reservation
|
||||
self.assertEqual(move_line.reserved_qty, 5) # don't change reservation
|
||||
|
||||
move1._action_done()
|
||||
self.assertEqual(move_line.product_qty, 0) # change reservation to 0 for done move
|
||||
self.assertEqual(move_line.reserved_qty, 0) # change reservation to 0 for done move
|
||||
self.assertEqual(move1.state, 'done')
|
||||
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product_lot, self.supplier_location), 0.0)
|
||||
@@ -213,7 +213,7 @@ class StockMove(TransactionCase):
|
||||
|
||||
# fill the move line
|
||||
move_line = move1.move_line_ids[0]
|
||||
self.assertEqual(move_line.product_qty, 100.0)
|
||||
self.assertEqual(move_line.reserved_qty, 100.0)
|
||||
self.assertEqual(move_line.qty_done, 0.0)
|
||||
move_line.qty_done = 100.0
|
||||
|
||||
@@ -258,7 +258,7 @@ class StockMove(TransactionCase):
|
||||
|
||||
# fill the move line
|
||||
move_line = move1.move_line_ids[0]
|
||||
self.assertEqual(move_line.product_qty, 100.0)
|
||||
self.assertEqual(move_line.reserved_qty, 100.0)
|
||||
self.assertEqual(move_line.qty_done, 0.0)
|
||||
move_line.qty_done = 100.0
|
||||
|
||||
@@ -333,7 +333,7 @@ class StockMove(TransactionCase):
|
||||
move1._action_assign()
|
||||
self.assertEqual(len(move1.move_line_ids), 4)
|
||||
for ml in move1.move_line_ids:
|
||||
self.assertEqual(ml.product_qty, 1.0)
|
||||
self.assertEqual(ml.reserved_qty, 1.0)
|
||||
|
||||
# assign lot3 and lot 4 to both untracked move lines
|
||||
lot3 = self.env['stock.lot'].create({
|
||||
@@ -350,7 +350,7 @@ class StockMove(TransactionCase):
|
||||
untracked_move_line[0].lot_id = lot3
|
||||
untracked_move_line[1].lot_id = lot4
|
||||
for ml in move1.move_line_ids:
|
||||
self.assertEqual(ml.product_qty, 1.0)
|
||||
self.assertEqual(ml.reserved_qty, 1.0)
|
||||
|
||||
# no changes on quants, even if i made some move lines with a lot id whom reserved on untracked quants
|
||||
self.assertEqual(len(self.gather_relevant(self.product_serial, self.stock_location, strict=True)), 1.0) # with a qty of 2
|
||||
@@ -559,9 +559,9 @@ class StockMove(TransactionCase):
|
||||
|
||||
move_line = move1.move_line_ids
|
||||
move_line.lot_id = lot1
|
||||
self.assertEqual(move_line.product_qty, 1.0)
|
||||
self.assertEqual(move_line.reserved_qty, 1.0)
|
||||
move_line.lot_id = lot2
|
||||
self.assertEqual(move_line.product_qty, 1.0)
|
||||
self.assertEqual(move_line.reserved_qty, 1.0)
|
||||
move_line.qty_done = 1
|
||||
|
||||
# validating the move line should move the lot, not create a negative quant in stock
|
||||
@@ -602,11 +602,11 @@ class StockMove(TransactionCase):
|
||||
move1._action_assign()
|
||||
self.assertEqual(len(move1.move_line_ids), 2)
|
||||
for ml in move1.move_line_ids:
|
||||
self.assertEqual(ml.product_qty, 1.0)
|
||||
self.assertEqual(ml.reserved_qty, 1.0)
|
||||
|
||||
untracked_move_line = move1.move_line_ids.filtered(lambda ml: not ml.lot_id).lot_id = lot2
|
||||
for ml in move1.move_line_ids:
|
||||
self.assertEqual(ml.product_qty, 1.0)
|
||||
self.assertEqual(ml.reserved_qty, 1.0)
|
||||
|
||||
move1.move_line_ids.write({'qty_done': 1.0})
|
||||
|
||||
@@ -1879,7 +1879,7 @@ class StockMove(TransactionCase):
|
||||
move_receipt.product_uom_qty = 3.0
|
||||
move_receipt._action_assign()
|
||||
self.assertEqual(move_receipt.state, 'assigned')
|
||||
self.assertEqual(move_receipt.move_line_ids.product_uom_qty, 3)
|
||||
self.assertEqual(move_receipt.move_line_ids.reserved_uom_qty, 3)
|
||||
|
||||
def test_unreserve_1(self):
|
||||
""" Check that unreserving a stock move sets the products reserved as available and
|
||||
@@ -2107,7 +2107,7 @@ class StockMove(TransactionCase):
|
||||
move1._action_assign()
|
||||
self.assertEqual(move1.state, 'assigned')
|
||||
self.assertEqual(len(move1.move_line_ids), 1)
|
||||
self.assertEqual(move1.move_line_ids.product_qty, 10)
|
||||
self.assertEqual(move1.move_line_ids.reserved_qty, 10)
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product, self.stock_location), 0.0)
|
||||
self.assertEqual(q2.reserved_quantity, 20)
|
||||
|
||||
@@ -2171,7 +2171,7 @@ class StockMove(TransactionCase):
|
||||
self.assertEqual(move1.state, 'confirmed')
|
||||
self.assertEqual(len(move1.move_line_ids), 2)
|
||||
self.assertEqual(move1.move_line_ids.mapped('qty_done'), [1, 1])
|
||||
self.assertEqual(move1.move_line_ids.mapped('product_uom_qty'), [0, 0])
|
||||
self.assertEqual(move1.move_line_ids.mapped('reserved_uom_qty'), [0, 0])
|
||||
|
||||
def test_link_assign_1(self):
|
||||
""" Test the assignment mechanism when two chained stock moves try to move one unit of an
|
||||
@@ -2330,7 +2330,7 @@ class StockMove(TransactionCase):
|
||||
move_line_1 = move_pack_cust.move_line_ids[0]
|
||||
self.assertEqual(move_line_1.location_id.id, self.pack_location.id)
|
||||
self.assertEqual(move_line_1.location_dest_id.id, self.customer_location.id)
|
||||
self.assertEqual(move_line_1.product_qty, 2.0)
|
||||
self.assertEqual(move_line_1.reserved_qty, 2.0)
|
||||
self.assertEqual(move_pack_cust.state, 'assigned')
|
||||
|
||||
def test_link_assign_4(self):
|
||||
@@ -2397,7 +2397,7 @@ class StockMove(TransactionCase):
|
||||
move_line_1 = move_pack_cust.move_line_ids[0]
|
||||
self.assertEqual(move_line_1.location_id.id, self.pack_location.id)
|
||||
self.assertEqual(move_line_1.location_dest_id.id, self.customer_location.id)
|
||||
self.assertEqual(move_line_1.product_qty, 2.0)
|
||||
self.assertEqual(move_line_1.reserved_qty, 2.0)
|
||||
self.assertEqual(move_line_1.lot_id.id, lot1.id)
|
||||
self.assertEqual(move_pack_cust.state, 'assigned')
|
||||
|
||||
@@ -2560,7 +2560,7 @@ class StockMove(TransactionCase):
|
||||
'product_id': self.product.id,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'qty_done': 6,
|
||||
'product_uom_qty': 0,
|
||||
'reserved_uom_qty': 0,
|
||||
'lot_id': False,
|
||||
'package_id': False,
|
||||
'result_package_id': False,
|
||||
@@ -2584,7 +2584,7 @@ class StockMove(TransactionCase):
|
||||
move_pack_cust._action_assign()
|
||||
self.assertEqual(move_pack_cust.state, 'partially_available')
|
||||
move_line_pack_cust = move_pack_cust.move_line_ids
|
||||
self.assertEqual(move_line_pack_cust.product_uom_qty, 6)
|
||||
self.assertEqual(move_line_pack_cust.reserved_uom_qty, 6)
|
||||
self.assertEqual(move_line_pack_cust.product_uom_id.id, self.uom_unit.id)
|
||||
|
||||
# move a dozen on the backorder to see how we handle the extra move
|
||||
@@ -2593,7 +2593,7 @@ class StockMove(TransactionCase):
|
||||
'product_id': self.product.id,
|
||||
'product_uom_id': self.uom_dozen.id,
|
||||
'qty_done': 1,
|
||||
'product_uom_qty': 0,
|
||||
'reserved_uom_qty': 0,
|
||||
'lot_id': False,
|
||||
'package_id': False,
|
||||
'result_package_id': False,
|
||||
@@ -2611,7 +2611,7 @@ class StockMove(TransactionCase):
|
||||
# the second move should now be reservable
|
||||
move_pack_cust._action_assign()
|
||||
self.assertEqual(move_pack_cust.state, 'assigned')
|
||||
self.assertEqual(move_line_pack_cust.product_uom_qty, 12)
|
||||
self.assertEqual(move_line_pack_cust.reserved_uom_qty, 12)
|
||||
self.assertEqual(move_line_pack_cust.product_uom_id.id, self.uom_unit.id)
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product, move_stock_pack.location_dest_id), 6)
|
||||
|
||||
@@ -2674,7 +2674,7 @@ class StockMove(TransactionCase):
|
||||
picking_stock_pack.button_validate()
|
||||
self.assertEqual(move_pack_cust.state, 'assigned')
|
||||
for ml in move_pack_cust.move_line_ids:
|
||||
self.assertEqual(ml.product_uom_qty, 1)
|
||||
self.assertEqual(ml.reserved_uom_qty, 1)
|
||||
self.assertEqual(ml.product_uom_id.id, self.uom_unit.id)
|
||||
self.assertTrue(bool(ml.lot_id.id))
|
||||
|
||||
@@ -2756,7 +2756,7 @@ class StockMove(TransactionCase):
|
||||
'product_id': self.product_serial.id,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'qty_done': 1,
|
||||
'product_uom_qty': 0,
|
||||
'reserved_uom_qty': 0,
|
||||
'lot_id': lot3.id,
|
||||
'package_id': False,
|
||||
'result_package_id': False,
|
||||
@@ -2943,7 +2943,7 @@ class StockMove(TransactionCase):
|
||||
'product_id': self.product.id,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'qty_done': 1,
|
||||
'product_uom_qty': 0,
|
||||
'reserved_uom_qty': 0,
|
||||
'lot_id': False,
|
||||
'package_id': False,
|
||||
'result_package_id': False,
|
||||
@@ -3001,7 +3001,7 @@ class StockMove(TransactionCase):
|
||||
'product_id': self.product.id,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'qty_done': 1,
|
||||
'product_uom_qty': 0,
|
||||
'reserved_uom_qty': 0,
|
||||
'lot_id': lot1.id,
|
||||
'package_id': False,
|
||||
'result_package_id': False,
|
||||
@@ -3038,7 +3038,7 @@ class StockMove(TransactionCase):
|
||||
'product_id': self.product.id,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'qty_done': 2,
|
||||
'product_uom_qty': 0,
|
||||
'reserved_uom_qty': 0,
|
||||
'lot_id': False,
|
||||
'package_id': False,
|
||||
'result_package_id': False,
|
||||
@@ -3378,14 +3378,14 @@ class StockMove(TransactionCase):
|
||||
self.assertEqual(move1.state, 'assigned')
|
||||
self.assertEqual(len(move1.move_line_ids), 1)
|
||||
move_line = move1.move_line_ids[0]
|
||||
self.assertEqual(move_line.product_qty, 5)
|
||||
self.assertEqual(move_line.reserved_qty, 5)
|
||||
move_line.qty_done = 5.0
|
||||
self.assertEqual(move_line.product_qty, 5) # don't change reservation
|
||||
self.assertEqual(move_line.reserved_qty, 5) # don't change reservation
|
||||
move_line.lot_id = lot1
|
||||
self.assertEqual(move_line.product_qty, 5) # don't change reservation when assgning a lot now
|
||||
self.assertEqual(move_line.reserved_qty, 5) # don't change reservation when assgning a lot now
|
||||
|
||||
move1._action_done()
|
||||
self.assertEqual(move_line.product_qty, 0) # change reservation to 0 for done move
|
||||
self.assertEqual(move_line.reserved_qty, 0) # change reservation to 0 for done move
|
||||
self.assertEqual(move1.state, 'done')
|
||||
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product_lot, self.stock_location), 0.0)
|
||||
@@ -3441,18 +3441,18 @@ class StockMove(TransactionCase):
|
||||
else:
|
||||
untracked_move_line = move_line
|
||||
|
||||
self.assertEqual(tracked_move_line.product_qty, 2)
|
||||
self.assertEqual(tracked_move_line.reserved_qty, 2)
|
||||
tracked_move_line.qty_done = 2
|
||||
|
||||
self.assertEqual(untracked_move_line.product_qty, 3)
|
||||
self.assertEqual(untracked_move_line.reserved_qty, 3)
|
||||
untracked_move_line.lot_id = lot2
|
||||
self.assertEqual(untracked_move_line.product_qty, 3) # don't change reservation
|
||||
self.assertEqual(untracked_move_line.reserved_qty, 3) # don't change reservation
|
||||
untracked_move_line.qty_done = 3
|
||||
self.assertEqual(untracked_move_line.product_qty, 3) # don't change reservation
|
||||
self.assertEqual(untracked_move_line.reserved_qty, 3) # don't change reservation
|
||||
|
||||
move1._action_done()
|
||||
self.assertEqual(untracked_move_line.product_qty, 0) # change reservation to 0 for done move
|
||||
self.assertEqual(tracked_move_line.product_qty, 0) # change reservation to 0 for done move
|
||||
self.assertEqual(untracked_move_line.reserved_qty, 0) # change reservation to 0 for done move
|
||||
self.assertEqual(tracked_move_line.reserved_qty, 0) # change reservation to 0 for done move
|
||||
self.assertEqual(move1.state, 'done')
|
||||
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product_lot, self.stock_location), 0.0)
|
||||
@@ -4233,7 +4233,7 @@ class StockMove(TransactionCase):
|
||||
picking.action_confirm()
|
||||
|
||||
for line in picking.move_line_ids:
|
||||
line.qty_done = line.product_uom_qty
|
||||
line.qty_done = line.reserved_uom_qty
|
||||
|
||||
return picking
|
||||
|
||||
@@ -5135,7 +5135,7 @@ class StockMove(TransactionCase):
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product, self.stock_location), 0)
|
||||
self.assertEqual(len(picking.move_line_ids), 2)
|
||||
unpacked_ml = picking.move_line_ids.filtered(lambda ml: not ml.result_package_id)
|
||||
self.assertEqual(unpacked_ml.product_qty, 1)
|
||||
self.assertEqual(unpacked_ml.reserved_qty, 1)
|
||||
unpacked_ml.qty_done = 1
|
||||
picking.action_put_in_pack()
|
||||
self.assertEqual(len(picking.move_line_ids), 2)
|
||||
|
||||
@@ -647,7 +647,7 @@ class TestPickShip(TestStockCommon):
|
||||
backorder_wizard.process()
|
||||
|
||||
self.assertTrue(picking_client.move_line_ids, 'A move line should be created.')
|
||||
self.assertEqual(picking_client.move_line_ids.product_uom_qty, 5, 'The move line should have 5 unit reserved.')
|
||||
self.assertEqual(picking_client.move_line_ids.reserved_uom_qty, 5, 'The move line should have 5 unit reserved.')
|
||||
|
||||
# Directly delete the move lines on the picking. (Use show detail operation on picking type)
|
||||
# Should do the same behavior than unreserve
|
||||
@@ -769,24 +769,24 @@ class TestPickShip(TestStockCommon):
|
||||
picking_pick.action_confirm()
|
||||
picking_pick.action_assign()
|
||||
for move_line in picking_pick.move_line_ids:
|
||||
move_line.qty_done = move_line.product_uom_qty
|
||||
move_line.qty_done = move_line.reserved_uom_qty
|
||||
picking_pick._action_done()
|
||||
picking_client.action_confirm()
|
||||
picking_client.action_assign()
|
||||
for move_line in picking_client.move_line_ids:
|
||||
move_line.qty_done = move_line.product_uom_qty
|
||||
move_line.qty_done = move_line.reserved_uom_qty
|
||||
picking_client._action_done()
|
||||
|
||||
picking_pick, picking_client = self.create_pick_ship()
|
||||
picking_pick.action_confirm()
|
||||
picking_pick.action_assign()
|
||||
for move_line in picking_pick.move_line_ids:
|
||||
move_line.qty_done = move_line.product_uom_qty
|
||||
move_line.qty_done = move_line.reserved_uom_qty
|
||||
picking_pick._action_done()
|
||||
picking_client.action_confirm()
|
||||
picking_client.action_assign()
|
||||
for move_line in picking_client.move_line_ids:
|
||||
move_line.qty_done = move_line.product_uom_qty
|
||||
move_line.qty_done = move_line.reserved_uom_qty
|
||||
picking_client._action_done()
|
||||
|
||||
# Following FIFO strategy, First picking should have empty lot1 and took 3 of lot2.
|
||||
@@ -804,9 +804,9 @@ class TestPickShip(TestStockCommon):
|
||||
|
||||
self.assertEqual(len(return_pick.move_line_ids), 2)
|
||||
self.assertEqual(return_pick.move_line_ids[0].lot_id, lot2)
|
||||
self.assertEqual(return_pick.move_line_ids[0].product_uom_qty, 4)
|
||||
self.assertEqual(return_pick.move_line_ids[0].reserved_uom_qty, 4)
|
||||
self.assertEqual(return_pick.move_line_ids[1].lot_id, lot3)
|
||||
self.assertEqual(return_pick.move_line_ids[1].product_uom_qty, 6)
|
||||
self.assertEqual(return_pick.move_line_ids[1].reserved_uom_qty, 6)
|
||||
self.assertEqual(return_pick.picking_type_id, picking_client.location_id.warehouse_id.return_type_id)
|
||||
|
||||
class TestSinglePicking(TestStockCommon):
|
||||
@@ -1021,7 +1021,7 @@ class TestSinglePicking(TestStockCommon):
|
||||
self.assertEqual(move1.product_qty, 2.0)
|
||||
self.assertEqual(move1.quantity_done, 2.0)
|
||||
self.assertEqual(move1.reserved_availability, 0.0)
|
||||
self.assertEqual(move1.move_line_ids.product_qty, 0.0) # change reservation to 0 for done move
|
||||
self.assertEqual(move1.move_line_ids.reserved_qty, 0.0) # change reservation to 0 for done move
|
||||
self.assertEqual(sum(move1.move_line_ids.mapped('qty_done')), 2.0)
|
||||
self.assertEqual(move1.state, 'done')
|
||||
|
||||
@@ -1066,7 +1066,7 @@ class TestSinglePicking(TestStockCommon):
|
||||
self.assertEqual(move1.product_qty, 3.0)
|
||||
self.assertEqual(move1.quantity_done, 3.0)
|
||||
self.assertEqual(move1.reserved_availability, 0.0)
|
||||
self.assertEqual(move1.move_line_ids.product_qty, 0.0) # change reservation to 0 for done move
|
||||
self.assertEqual(move1.move_line_ids.reserved_qty, 0.0) # change reservation to 0 for done move
|
||||
self.assertEqual(sum(move1.move_line_ids.mapped('qty_done')), 3.0)
|
||||
self.assertEqual(move1.state, 'done')
|
||||
|
||||
@@ -1103,7 +1103,7 @@ class TestSinglePicking(TestStockCommon):
|
||||
self.assertEqual(move1.product_qty, 2.0)
|
||||
self.assertEqual(move1.quantity_done, 2.0)
|
||||
self.assertEqual(move1.reserved_availability, 0.0)
|
||||
self.assertEqual(move1.move_line_ids.product_qty, 0.0) # change reservation to 0 for done move
|
||||
self.assertEqual(move1.move_line_ids.reserved_qty, 0.0) # change reservation to 0 for done move
|
||||
self.assertEqual(sum(move1.move_line_ids.mapped('qty_done')), 2.0)
|
||||
self.assertEqual(move1.state, 'done')
|
||||
|
||||
@@ -1212,7 +1212,7 @@ class TestSinglePicking(TestStockCommon):
|
||||
# Check reserved quantity
|
||||
self.assertEqual(move1.reserved_availability, 1.0)
|
||||
self.assertEqual(len(move1.move_line_ids), 1)
|
||||
self.assertEqual(move1.move_line_ids.product_qty, 1)
|
||||
self.assertEqual(move1.move_line_ids.reserved_qty, 1)
|
||||
|
||||
inventory_quant = self.env['stock.quant'].create({
|
||||
'location_id': self.stock_location,
|
||||
@@ -1227,7 +1227,7 @@ class TestSinglePicking(TestStockCommon):
|
||||
# Check reserved quantity
|
||||
self.assertEqual(move1.reserved_availability, 2.0)
|
||||
self.assertEqual(len(move1.move_line_ids), 1)
|
||||
self.assertEqual(move1.move_line_ids.product_qty, 2)
|
||||
self.assertEqual(move1.move_line_ids.reserved_qty, 2)
|
||||
|
||||
def test_recheck_availability_2(self):
|
||||
""" Same check than test_recheck_availability_1 but with lot this time.
|
||||
@@ -1266,7 +1266,7 @@ class TestSinglePicking(TestStockCommon):
|
||||
# Check reserved quantity
|
||||
self.assertEqual(move1.reserved_availability, 1.0)
|
||||
self.assertEqual(len(move1.move_line_ids), 1)
|
||||
self.assertEqual(move1.move_line_ids.product_qty, 1)
|
||||
self.assertEqual(move1.move_line_ids.reserved_qty, 1)
|
||||
|
||||
inventory_quant = self.env['stock.quant'].create({
|
||||
'location_id': self.stock_location,
|
||||
@@ -1283,7 +1283,7 @@ class TestSinglePicking(TestStockCommon):
|
||||
self.assertEqual(move1.reserved_availability, 2.0)
|
||||
self.assertEqual(len(move1.move_line_ids), 1)
|
||||
self.assertEqual(move1.move_line_ids.lot_id.id, lot1.id)
|
||||
self.assertEqual(move1.move_line_ids.product_qty, 2)
|
||||
self.assertEqual(move1.move_line_ids.reserved_qty, 2)
|
||||
|
||||
def test_recheck_availability_3(self):
|
||||
""" Same check than test_recheck_availability_2 but with different lots.
|
||||
@@ -1324,7 +1324,7 @@ class TestSinglePicking(TestStockCommon):
|
||||
# Check reserved quantity
|
||||
self.assertEqual(move1.reserved_availability, 1.0)
|
||||
self.assertEqual(len(move1.move_line_ids), 1)
|
||||
self.assertEqual(move1.move_line_ids.product_qty, 1)
|
||||
self.assertEqual(move1.move_line_ids.reserved_qty, 1)
|
||||
|
||||
inventory_quant = self.env['stock.quant'].create({
|
||||
'location_id': self.stock_location,
|
||||
@@ -1384,7 +1384,7 @@ class TestSinglePicking(TestStockCommon):
|
||||
# Check reserved quantity
|
||||
self.assertEqual(move1.reserved_availability, 1.0)
|
||||
self.assertEqual(len(move1.move_line_ids), 1)
|
||||
self.assertEqual(move1.move_line_ids.product_qty, 1)
|
||||
self.assertEqual(move1.move_line_ids.reserved_qty, 1)
|
||||
|
||||
inventory_quant = self.env['stock.quant'].create({
|
||||
'location_id': self.stock_location,
|
||||
@@ -2273,9 +2273,9 @@ class TestStockUOM(TestStockCommon):
|
||||
self.assertEqual(len(picking.move_line_ids), 1, 'One move line should exist for the picking.')
|
||||
move_line = picking.move_line_ids
|
||||
# check that we do not reserve more (in the same UOM) than the quantity in stock
|
||||
self.assertEqual(float_compare(move_line.product_qty, quant.quantity, precision_digits=precision_digits), -1, "We do not reserve more (in the same UOM) than the quantity in stock")
|
||||
self.assertEqual(float_compare(move_line.reserved_qty, quant.quantity, precision_digits=precision_digits), -1, "We do not reserve more (in the same UOM) than the quantity in stock")
|
||||
# check that we reserve the same quantity in the ml and the quant
|
||||
self.assertTrue(float_is_zero(move_line.product_qty - quant.reserved_quantity, precision_digits=precision_digits))
|
||||
self.assertTrue(float_is_zero(move_line.reserved_qty - quant.reserved_quantity, precision_digits=precision_digits))
|
||||
|
||||
def test_update_product_move_line_with_different_uom(self):
|
||||
""" Check that when the move line and corresponding
|
||||
@@ -2375,9 +2375,9 @@ class TestStockUOM(TestStockCommon):
|
||||
('lot_id', '=', quant_LtDA.lot_id.id),
|
||||
('package_id', '=', quant_LtDA.package_id.id),
|
||||
('owner_id', '=', quant_LtDA.owner_id.id),
|
||||
('product_qty', '!=', 0)
|
||||
('reserved_qty', '!=', 0)
|
||||
])
|
||||
reserved_on_move_lines_LtDA = sum(move_lines_LtDA.mapped('product_qty'))
|
||||
reserved_on_move_lines_LtDA = sum(move_lines_LtDA.mapped('reserved_qty'))
|
||||
|
||||
move_lines_GtDA = self.env["stock.move.line"].search([
|
||||
('product_id', '=', quant_GtDA.product_id.id),
|
||||
@@ -2385,9 +2385,9 @@ class TestStockUOM(TestStockCommon):
|
||||
('lot_id', '=', quant_GtDA.lot_id.id),
|
||||
('package_id', '=', quant_GtDA.package_id.id),
|
||||
('owner_id', '=', quant_GtDA.owner_id.id),
|
||||
('product_qty', '!=', 0)
|
||||
('reserved_qty', '!=', 0)
|
||||
])
|
||||
reserved_on_move_lines_GtDA = sum(move_lines_GtDA.mapped('product_qty'))
|
||||
reserved_on_move_lines_GtDA = sum(move_lines_GtDA.mapped('reserved_qty'))
|
||||
|
||||
# check that we do not reserve more (in the same UOM) than the quantity in stock
|
||||
self.assertEqual(float_compare(reserved_on_move_lines_LtDA, quant_LtDA.quantity, precision_digits=precision_digits), -1, "We do not reserve more (in the same UOM) than the quantity in stock")
|
||||
|
||||
@@ -240,7 +240,7 @@ class TestPacking(TestPackingCommon):
|
||||
picking.write({
|
||||
'move_line_ids': [(0, 0, {
|
||||
'product_id': self.productB.id,
|
||||
'product_uom_qty': 7.0,
|
||||
'reserved_uom_qty': 7.0,
|
||||
'qty_done': 7.0,
|
||||
'product_uom_id': self.productB.uom_id.id,
|
||||
'location_id': self.customer_location.id,
|
||||
@@ -252,7 +252,7 @@ class TestPacking(TestPackingCommon):
|
||||
picking.write({
|
||||
'move_line_ids': [(0, 0, {
|
||||
'product_id': self.productA.id,
|
||||
'product_uom_qty': 5.0,
|
||||
'reserved_uom_qty': 5.0,
|
||||
'qty_done': 5.0,
|
||||
'product_uom_id': self.productA.uom_id.id,
|
||||
'location_id': self.customer_location.id,
|
||||
|
||||
@@ -118,7 +118,7 @@ class TestPackingNeg(TransactionCase):
|
||||
|
||||
for rec in delivery_order_neg.move_line_ids:
|
||||
if rec.package_id.name == 'Palneg 1':
|
||||
rec.qty_done = rec.product_qty
|
||||
rec.qty_done = rec.reserved_qty
|
||||
rec.result_package_id = False
|
||||
elif rec.package_id.name == 'Palneg 2' and rec.lot_id.name == 'Lot neg':
|
||||
rec.write({
|
||||
|
||||
@@ -333,7 +333,7 @@ class TestStockFlow(TestStockCommon):
|
||||
# Replace pack operation (Back order of Incoming shipment)
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
packD = self.StockPackObj.search([('product_id', '=', self.productD.id), ('picking_id', '=', back_order_in.id)], order='product_qty')
|
||||
packD = self.StockPackObj.search([('product_id', '=', self.productD.id), ('picking_id', '=', back_order_in.id)], order='reserved_qty')
|
||||
self.assertEqual(len(packD), 1, 'Wrong number of pack operation.')
|
||||
packD[0].write({
|
||||
'qty_done': 8,
|
||||
@@ -511,7 +511,7 @@ class TestStockFlow(TestStockCommon):
|
||||
# ----------------------------------------------------
|
||||
|
||||
PackSdozAround = self.StockPackObj.search([('product_id', '=', self.SDozARound.id), ('picking_id', '=', picking_in_A.id)], limit=1)
|
||||
self.assertEqual(PackSdozAround.product_qty, 11, 'Wrong quantity in pack operation (%s found instead of 11)' % (PackSdozAround.product_qty))
|
||||
self.assertEqual(PackSdozAround.reserved_qty, 11, 'Wrong quantity in pack operation (%s found instead of 11)' % (PackSdozAround.reserved_qty))
|
||||
res_dict = picking_in_A.button_validate()
|
||||
wizard = Form(self.env[(res_dict.get('res_model'))].with_context(res_dict['context'])).save()
|
||||
wizard.process()
|
||||
@@ -610,25 +610,25 @@ class TestStockFlow(TestStockCommon):
|
||||
|
||||
# Check pack operation quantity and unit of measure for product DozA.
|
||||
PackdozA = self.StockPackObj.search([('product_id', '=', self.DozA.id), ('picking_id', '=', picking_in_B.id)], limit=1)
|
||||
self.assertEqual(PackdozA.product_uom_qty, 120, 'Wrong quantity in pack operation (%s found instead of 120)' % (PackdozA.product_uom_qty))
|
||||
self.assertEqual(PackdozA.product_qty, 10, 'Wrong real quantity in pack operation (%s found instead of 10)' % (PackdozA.product_qty))
|
||||
self.assertEqual(PackdozA.reserved_uom_qty, 120, 'Wrong quantity in pack operation (%s found instead of 120)' % (PackdozA.reserved_uom_qty))
|
||||
self.assertEqual(PackdozA.reserved_qty, 10, 'Wrong real quantity in pack operation (%s found instead of 10)' % (PackdozA.reserved_qty))
|
||||
self.assertEqual(PackdozA.product_uom_id.id, self.uom_unit.id, 'Wrong uom in pack operation for product DozA.')
|
||||
# Check pack operation quantity and unit of measure for product SDozA.
|
||||
PackSdozA = self.StockPackObj.search([('product_id', '=', self.SDozA.id), ('picking_id', '=', picking_in_B.id)], limit=1)
|
||||
self.assertEqual(PackSdozA.product_uom_qty, 1512, 'Wrong quantity in pack operation (%s found instead of 1512)' % (PackSdozA.product_uom_qty))
|
||||
self.assertEqual(PackSdozA.reserved_uom_qty, 1512, 'Wrong quantity in pack operation (%s found instead of 1512)' % (PackSdozA.reserved_uom_qty))
|
||||
self.assertEqual(PackSdozA.product_uom_id.id, self.uom_unit.id, 'Wrong uom in pack operation for product SDozA.')
|
||||
# Check pack operation quantity and unit of measure for product SDozARound.
|
||||
PackSdozAround = self.StockPackObj.search([('product_id', '=', self.SDozARound.id), ('picking_id', '=', picking_in_B.id)], limit=1)
|
||||
self.assertEqual(PackSdozAround.product_uom_qty, 1584, 'Wrong quantity in pack operation (%s found instead of 1584)' % (PackSdozAround.product_uom_qty))
|
||||
self.assertEqual(PackSdozAround.reserved_uom_qty, 1584, 'Wrong quantity in pack operation (%s found instead of 1584)' % (PackSdozAround.reserved_uom_qty))
|
||||
self.assertEqual(PackSdozAround.product_uom_id.id, self.uom_unit.id, 'Wrong uom in pack operation for product SDozARound.')
|
||||
# Check pack operation quantity and unit of measure for product gB.
|
||||
packgB = self.StockPackObj.search([('product_id', '=', self.gB.id), ('picking_id', '=', picking_in_B.id)], limit=1)
|
||||
self.assertEqual(packgB.product_uom_qty, 0.525, 'Wrong quantity in pack operation (%s found instead of 0.525)' % (packgB.product_uom_qty))
|
||||
self.assertEqual(packgB.product_qty, 525, 'Wrong real quantity in pack operation (%s found instead of 525)' % (packgB.product_qty))
|
||||
self.assertEqual(packgB.reserved_uom_qty, 0.525, 'Wrong quantity in pack operation (%s found instead of 0.525)' % (packgB.reserved_uom_qty))
|
||||
self.assertEqual(packgB.reserved_qty, 525, 'Wrong real quantity in pack operation (%s found instead of 525)' % (packgB.reserved_qty))
|
||||
self.assertEqual(packgB.product_uom_id.id, packgB.move_id.product_uom.id, 'Wrong uom in pack operation for product kgB.')
|
||||
# Check pack operation quantity and unit of measure for product kgB.
|
||||
packkgB = self.StockPackObj.search([('product_id', '=', self.kgB.id), ('picking_id', '=', picking_in_B.id)], limit=1)
|
||||
self.assertEqual(packkgB.product_uom_qty, 20.0, 'Wrong quantity in pack operation (%s found instead of 20)' % (packkgB.product_uom_qty))
|
||||
self.assertEqual(packkgB.reserved_uom_qty, 20.0, 'Wrong quantity in pack operation (%s found instead of 20)' % (packkgB.reserved_uom_qty))
|
||||
self.assertEqual(packkgB.product_uom_id.id, self.uom_gm.id, 'Wrong uom in pack operation for product kgB')
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
@@ -636,14 +636,14 @@ class TestStockFlow(TestStockCommon):
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
self.StockPackObj.search([('product_id', '=', self.kgB.id), ('picking_id', '=', picking_in_B.id)]).write({
|
||||
'product_uom_qty': 0.020, 'product_uom_id': self.uom_kg.id})
|
||||
'reserved_uom_qty': 0.020, 'product_uom_id': self.uom_kg.id})
|
||||
self.StockPackObj.search([('product_id', '=', self.gB.id), ('picking_id', '=', picking_in_B.id)]).write({
|
||||
'product_uom_qty': 526, 'product_uom_id': self.uom_gm.id})
|
||||
'reserved_uom_qty': 526, 'product_uom_id': self.uom_gm.id})
|
||||
self.StockPackObj.search([('product_id', '=', self.DozA.id), ('picking_id', '=', picking_in_B.id)]).write({
|
||||
'product_uom_qty': 4, 'product_uom_id': self.uom_dozen.id})
|
||||
'reserved_uom_qty': 4, 'product_uom_id': self.uom_dozen.id})
|
||||
self.StockPackObj.create({
|
||||
'product_id': self.DozA.id,
|
||||
'product_uom_qty': 48,
|
||||
'reserved_uom_qty': 48,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'location_id': self.supplier_location,
|
||||
'location_dest_id': self.stock_location,
|
||||
@@ -927,8 +927,8 @@ class TestStockFlow(TestStockCommon):
|
||||
self.assertEqual(move.state, 'assigned', 'Wrong state of move line.')
|
||||
# Check pack operation quantity.
|
||||
packKG = self.StockPackObj.search([('product_id', '=', productKG.id), ('picking_id', '=', picking_in.id)], limit=1)
|
||||
self.assertEqual(packKG.product_qty, 1000, 'Wrong product real quantity in pack operation (%s found instead of 1000)' % (packKG.product_qty))
|
||||
self.assertEqual(packKG.product_uom_qty, 1, 'Wrong product quantity in pack operation (%s found instead of 1)' % (packKG.product_uom_qty))
|
||||
self.assertEqual(packKG.reserved_qty, 1000, 'Wrong product real quantity in pack operation (%s found instead of 1000)' % (packKG.reserved_qty))
|
||||
self.assertEqual(packKG.reserved_uom_qty, 1, 'Wrong product quantity in pack operation (%s found instead of 1)' % (packKG.reserved_uom_qty))
|
||||
self.assertEqual(packKG.product_uom_id.id, self.uom_tone.id, 'Wrong product uom in pack operation.')
|
||||
# Transfer Incoming shipment.
|
||||
res_dict = picking_in.button_validate()
|
||||
@@ -966,7 +966,7 @@ class TestStockFlow(TestStockCommon):
|
||||
picking_out.action_confirm()
|
||||
picking_out.action_assign()
|
||||
pack_opt = self.StockPackObj.search([('product_id', '=', productKG.id), ('picking_id', '=', picking_out.id)], limit=1)
|
||||
pack_opt.write({'product_uom_qty': 0.5})
|
||||
pack_opt.write({'reserved_uom_qty': 0.5})
|
||||
res_dict = picking_out.button_validate()
|
||||
wizard = Form(self.env[(res_dict.get('res_model'))].with_context(res_dict['context'])).save()
|
||||
res_dict_for_back_order = wizard.process()
|
||||
@@ -990,7 +990,7 @@ class TestStockFlow(TestStockCommon):
|
||||
self.assertEqual(moves_KG.product_uom.id, self.uom_gm.id, 'Wrong uom in move for product KG.')
|
||||
bo_out_1.action_assign()
|
||||
pack_opt = self.StockPackObj.search([('product_id', '=', productKG.id), ('picking_id', '=', bo_out_1.id)], limit=1)
|
||||
pack_opt.write({'product_uom_qty': 0.5})
|
||||
pack_opt.write({'reserved_uom_qty': 0.5})
|
||||
res_dict = bo_out_1.button_validate()
|
||||
wizard = Form(self.env[(res_dict.get('res_model'))].with_context(res_dict['context'])).save()
|
||||
res_dict_for_back_order = wizard.process()
|
||||
@@ -1014,7 +1014,7 @@ class TestStockFlow(TestStockCommon):
|
||||
self.assertEqual(moves_KG.product_uom.id, self.uom_gm.id, 'Wrong uom in move for product KG.')
|
||||
bo_out_2.action_assign()
|
||||
pack_opt = self.StockPackObj.search([('product_id', '=', productKG.id), ('picking_id', '=', bo_out_2.id)], limit=1)
|
||||
pack_opt.write({'product_uom_qty': 0.5})
|
||||
pack_opt.write({'reserved_uom_qty': 0.5})
|
||||
res_dict = bo_out_2.button_validate()
|
||||
wizard = Form(self.env[(res_dict.get('res_model'))].with_context(res_dict['context'])).save()
|
||||
res_dict_for_back_order = wizard.process()
|
||||
@@ -1037,7 +1037,7 @@ class TestStockFlow(TestStockCommon):
|
||||
self.assertEqual(moves_KG.product_uom.id, self.uom_gm.id, 'Wrong uom in move for product KG.')
|
||||
bo_out_3.action_assign()
|
||||
pack_opt = self.StockPackObj.search([('product_id', '=', productKG.id), ('picking_id', '=', bo_out_3.id)], limit=1)
|
||||
pack_opt.write({'product_uom_qty': 0.5})
|
||||
pack_opt.write({'reserved_uom_qty': 0.5})
|
||||
res_dict = bo_out_3.button_validate()
|
||||
wizard = Form(self.env[(res_dict.get('res_model'))].with_context(res_dict['context'])).save()
|
||||
res_dict_for_back_order = wizard.process()
|
||||
@@ -1058,7 +1058,7 @@ class TestStockFlow(TestStockCommon):
|
||||
self.assertEqual(moves_KG.product_uom.id, self.uom_gm.id, 'Wrong uom in move for product KG.')
|
||||
bo_out_4.action_assign()
|
||||
pack_opt = self.StockPackObj.search([('product_id', '=', productKG.id), ('picking_id', '=', bo_out_4.id)], limit=1)
|
||||
pack_opt.write({'product_uom_qty': 0.5})
|
||||
pack_opt.write({'reserved_uom_qty': 0.5})
|
||||
res_dict = bo_out_4.button_validate()
|
||||
wizard = Form(self.env[(res_dict.get('res_model'))].with_context(res_dict['context'])).save()
|
||||
wizard.process()
|
||||
@@ -1327,7 +1327,7 @@ class TestStockFlow(TestStockCommon):
|
||||
pack2 = pack_obj.create({'name': 'PACKINOUTTEST2'})
|
||||
picking_in.move_line_ids[0].result_package_id = pack1
|
||||
picking_in.move_line_ids[0].qty_done = 4
|
||||
packop2 = picking_in.move_line_ids[0].with_context(bypass_reservation_update=True).copy({'product_uom_qty': 0})
|
||||
packop2 = picking_in.move_line_ids[0].with_context(bypass_reservation_update=True).copy({'reserved_uom_qty': 0})
|
||||
packop2.qty_done = 6
|
||||
packop2.result_package_id = pack2
|
||||
picking_in._action_done()
|
||||
@@ -1351,7 +1351,7 @@ class TestStockFlow(TestStockCommon):
|
||||
picking_out.action_confirm()
|
||||
picking_out.action_assign()
|
||||
packout1 = picking_out.move_line_ids[0]
|
||||
packout2 = picking_out.move_line_ids[0].with_context(bypass_reservation_update=True).copy({'product_uom_qty': 0})
|
||||
packout2 = picking_out.move_line_ids[0].with_context(bypass_reservation_update=True).copy({'reserved_uom_qty': 0})
|
||||
packout1.qty_done = 2
|
||||
packout1.package_id = pack1
|
||||
packout2.package_id = pack2
|
||||
@@ -1385,7 +1385,7 @@ class TestStockFlow(TestStockCommon):
|
||||
pack2 = pack_obj.create({'name': 'PACKINOUTTEST2'})
|
||||
picking_in.move_line_ids[0].result_package_id = pack1
|
||||
picking_in.move_line_ids[0].qty_done = 120
|
||||
packop2 = picking_in.move_line_ids[0].with_context(bypass_reservation_update=True).copy({'product_uom_qty': 0})
|
||||
packop2 = picking_in.move_line_ids[0].with_context(bypass_reservation_update=True).copy({'reserved_uom_qty': 0})
|
||||
packop2.qty_done = 80
|
||||
packop2.result_package_id = pack2
|
||||
picking_in._action_done()
|
||||
|
||||
@@ -145,10 +145,10 @@ class TestWiseOperator(TransactionCase):
|
||||
# put the move lines from delivery_order_wise2 into delivery_order_wise1
|
||||
for pack_id2 in pack_ids2:
|
||||
new_pack_id1 = pack_id2.copy(default={'picking_id': delivery_order_wise1.id, 'move_id': move1.id})
|
||||
new_pack_id1.qty_done = pack_id2.product_qty
|
||||
new_pack_id1.qty_done = pack_id2.reserved_qty
|
||||
|
||||
new_move_lines = delivery_order_wise1.move_line_ids.filtered(lambda p: p.qty_done)
|
||||
self.assertEqual(sum(new_move_lines.mapped('product_qty')), 0)
|
||||
self.assertEqual(sum(new_move_lines.mapped('reserved_qty')), 0)
|
||||
self.assertEqual(sum(new_move_lines.mapped('qty_done')), 5)
|
||||
self.assertEqual(set(new_move_lines.mapped('location_id.id')), set([
|
||||
self.shelf1.id,
|
||||
@@ -156,11 +156,11 @@ class TestWiseOperator(TransactionCase):
|
||||
|
||||
# put the move line from delivery_order_wise1 into delivery_order_wise2
|
||||
new_pack_id2 = pack_ids1.copy(default={'picking_id': delivery_order_wise2.id, 'move_id': move2.id})
|
||||
new_pack_id2.qty_done = pack_ids1.product_qty
|
||||
new_pack_id2.qty_done = pack_ids1.reserved_qty
|
||||
|
||||
new_move_lines = delivery_order_wise2.move_line_ids.filtered(lambda p: p.qty_done)
|
||||
self.assertEqual(len(new_move_lines), 1)
|
||||
self.assertEqual(sum(new_move_lines.mapped('product_qty')), 0)
|
||||
self.assertEqual(sum(new_move_lines.mapped('reserved_qty')), 0)
|
||||
self.assertEqual(sum(new_move_lines.mapped('qty_done')), 5)
|
||||
self.assertEqual(new_move_lines.location_id.id, self.shelf2.id)
|
||||
|
||||
|
||||
@@ -63,9 +63,9 @@
|
||||
<field name="location_dest_id" options="{'no_create': True}" groups="stock.group_stock_multi_locations"/>
|
||||
</group>
|
||||
<group>
|
||||
<label for="product_uom_qty" string="Quantity Reserved" attrs="{'invisible': [('state', '=', 'done')]}"/>
|
||||
<label for="reserved_uom_qty" string="Quantity Reserved" attrs="{'invisible': [('state', '=', 'done')]}"/>
|
||||
<div class="o_row" attrs="{'invisible': [('state', '=', 'done')]}">
|
||||
<field name="product_uom_qty" readonly="1"/>
|
||||
<field name="reserved_uom_qty" readonly="1"/>
|
||||
<field name="product_uom_id" options="{'no_create': True}" string="Unit of Measure" groups="uom.group_uom"/>
|
||||
</div>
|
||||
<label for="qty_done" string="Quantity Done"/>
|
||||
|
||||
@@ -207,7 +207,7 @@
|
||||
<field name="model">stock.move.line</field>
|
||||
<field name="priority">1000</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree editable="bottom" decoration-muted="state == 'done' and is_locked == True" decoration-success="product_uom_qty==qty_done" decoration-danger="qty_done > product_uom_qty and state != 'done' and picking_code != 'incoming'">
|
||||
<tree editable="bottom" decoration-muted="state == 'done' and is_locked == True" decoration-success="reserved_uom_qty==qty_done" decoration-danger="qty_done > reserved_uom_qty and state != 'done' and picking_code != 'incoming'">
|
||||
<field name="company_id" invisible="1" force_save="1"/>
|
||||
<field name="picking_id" invisible="1" force_save="1"/>
|
||||
<field name="move_id" invisible="1" force_save="1" />
|
||||
@@ -233,13 +233,13 @@
|
||||
<field name="package_id" attrs="{'readonly': ['&', ('package_level_id', '!=', False), ('parent.picking_type_entire_packs', '=', True)]}" invisible="not context.get('show_package')" groups="stock.group_tracking_lot"/>
|
||||
<field name="result_package_id" attrs="{'readonly': ['&', ('package_level_id', '!=', False), ('parent.picking_type_entire_packs', '=', True)]}" groups="stock.group_tracking_lot"/>
|
||||
<field name="owner_id" attrs="{'readonly': ['&', ('package_level_id', '!=', False), ('parent.picking_type_entire_packs', '=', True)]}" invisible="not context.get('show_owner')" groups="stock.group_tracking_owner"/>
|
||||
<field name="product_uom_qty" invisible="not context.get('show_reserved_quantity')" readonly="1"/>
|
||||
<field name="reserved_uom_qty" invisible="not context.get('show_reserved_quantity')" readonly="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="is_locked" invisible="1"/>
|
||||
<field name="picking_code" invisible="1"/>
|
||||
<field name="qty_done" attrs="{'readonly': ['|', '&', ('state', '=', 'done'), ('is_locked', '=', True), '&', ('package_level_id', '!=', False), ('parent.picking_type_entire_packs', '=', True)]}"/>
|
||||
<field name="product_uom_id" options="{'no_open': True, 'no_create': True}" string="Unit of Measure" groups="uom.group_uom"
|
||||
attrs="{'readonly': ['|', '|', ('product_uom_qty', '!=', 0.0),
|
||||
attrs="{'readonly': ['|', '|', ('reserved_uom_qty', '!=', 0.0),
|
||||
'&', ('package_level_id', '!=', False), ('parent.picking_type_entire_packs', '=', True),
|
||||
'&', ('state', '=', 'done'), ('id', '!=', False)]}"/>
|
||||
</tree>
|
||||
@@ -251,7 +251,7 @@
|
||||
<field name="model">stock.move.line</field>
|
||||
<field name="priority">1000</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree editable="bottom" decoration-muted="(state == 'done' and is_locked == True)" decoration-danger="qty_done>product_uom_qty and state!='done' and parent.picking_type_code != 'incoming'" decoration-success="qty_done==product_uom_qty and state!='done' and not result_package_id">
|
||||
<tree editable="bottom" decoration-muted="(state == 'done' and is_locked == True)" decoration-danger="qty_done>reserved_uom_qty and state!='done' and parent.picking_type_code != 'incoming'" decoration-success="qty_done==reserved_uom_qty and state!='done' and not result_package_id">
|
||||
<field name="product_id" required="1" context="{'default_detailed_type': 'product'}" attrs="{'readonly': ['|', ('state', '=', 'done'), ('move_id', '!=', False)]}"/>
|
||||
<field name="company_id" invisible="1"/>
|
||||
<field name="move_id" invisible="1"/>
|
||||
@@ -267,7 +267,7 @@
|
||||
<field name="lot_id" groups="stock.group_production_lot" attrs="{'column_invisible': [('parent.show_lots_text', '=', True)], 'invisible': [('lots_visible', '=', False)]}" context="{'default_product_id': product_id, 'default_company_id': company_id, 'active_picking_id': picking_id}" optional="show"/>
|
||||
<field name="lot_name" groups="stock.group_production_lot" attrs="{'column_invisible': [('parent.show_lots_text', '=', False)], 'invisible': [('lots_visible', '=', False)]}" context="{'default_product_id': product_id}"/>
|
||||
<field name="is_initial_demand_editable" invisible="1"/>
|
||||
<field name="product_uom_qty" readonly="1" attrs="{'column_invisible': ['|',('parent.immediate_transfer', '=', True),('parent.picking_type_code','=','incoming')]}" optional="show"/>
|
||||
<field name="reserved_uom_qty" readonly="1" attrs="{'column_invisible': ['|',('parent.immediate_transfer', '=', True),('parent.picking_type_code','=','incoming')]}" optional="show"/>
|
||||
<field name="is_locked" invisible="1"/>
|
||||
<field name="qty_done" attrs="{'readonly': [('state', 'in', ('done', 'cancel')), ('is_locked', '=', True)]}" force_save="1"/>
|
||||
<field name="product_uom_id" force_save="1" attrs="{'readonly': [('state', '!=', 'draft'), ('id', '!=', False)]}" groups="uom.group_uom"/>
|
||||
|
||||
@@ -35,9 +35,9 @@
|
||||
<field name="lot_id" attrs="{'column_invisible': [('parent.show_lots_m2o', '=', False)]}" groups="stock.group_production_lot"/>
|
||||
<field name="lot_name" attrs="{'column_invisible': [('parent.show_lots_text', '=', False)]}" groups="stock.group_production_lot"/>
|
||||
<field name="owner_id" groups="stock.group_tracking_owner"/>
|
||||
<field name="product_uom_qty"/>
|
||||
<field name="reserved_uom_qty"/>
|
||||
<field name="qty_done"/>
|
||||
<field name="product_uom_id" options="{'no_open': True, 'no_create': True}" attrs="{'readonly': [('product_uom_qty', '!=', 0.0)]}" string="Unit of Measure" groups="uom.group_uom"/>
|
||||
<field name="product_uom_id" options="{'no_open': True, 'no_create': True}" attrs="{'readonly': [('reserved_uom_qty', '!=', 0.0)]}" string="Unit of Measure" groups="uom.group_uom"/>
|
||||
<field name="state" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
||||
@@ -82,7 +82,7 @@ class ReturnPicking(models.TransientModel):
|
||||
if move.origin_returned_move_id and move.origin_returned_move_id != stock_move:
|
||||
continue
|
||||
if move.state in ('partially_available', 'assigned'):
|
||||
quantity -= sum(move.move_line_ids.mapped('product_qty'))
|
||||
quantity -= sum(move.move_line_ids.mapped('reserved_qty'))
|
||||
elif move.state in ('done'):
|
||||
quantity -= move.product_qty
|
||||
quantity = float_round(quantity, precision_rounding=stock_move.product_id.uom_id.rounding)
|
||||
|
||||
@@ -108,7 +108,7 @@ class ValuationReconciliationTestCommon(AccountTestInvoicingCommon):
|
||||
pickings.action_assign()
|
||||
for picking in pickings:
|
||||
for ml in picking.move_line_ids:
|
||||
ml.qty_done = quantity or ml.product_qty
|
||||
ml.qty_done = quantity or ml.reserved_qty
|
||||
pickings._action_done()
|
||||
self._change_pickings_date(pickings, date)
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ class StockMoveLine(models.Model):
|
||||
picking_to_wave_vals['move_ids'] += [Command.link(move.id)]
|
||||
continue
|
||||
# Split the move
|
||||
qty = sum(lines.mapped('product_qty'))
|
||||
qty = sum(lines.mapped('reserved_qty'))
|
||||
new_move = move._split(qty)
|
||||
new_move[0]['move_line_ids'] = [Command.set(move_lines.ids)]
|
||||
picking_to_wave_vals['move_ids'] += [Command.create(new_move[0])]
|
||||
|
||||
@@ -261,7 +261,7 @@ class StockPickingBatch(models.Model):
|
||||
and not ml.result_package_id
|
||||
)
|
||||
if not move_line_ids:
|
||||
move_line_ids = picking_move_lines.filtered(lambda ml: float_compare(ml.product_uom_qty, 0.0,
|
||||
move_line_ids = picking_move_lines.filtered(lambda ml: float_compare(ml.reserved_uom_qty, 0.0,
|
||||
precision_rounding=ml.product_uom_id.rounding) > 0 and float_compare(ml.qty_done, 0.0,
|
||||
precision_rounding=ml.product_uom_id.rounding) == 0)
|
||||
if move_line_ids:
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
<span t-esc="sum(move_operation.mapped('qty_done'))"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span t-esc="sum(move_operation.mapped('product_uom_qty'))"/>
|
||||
<span t-esc="sum(move_operation.mapped('reserved_uom_qty'))"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="has_package">
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
<field name="location_dest_id"/>
|
||||
<field name="package_id" groups="stock.group_tracking_lot"/>
|
||||
<field name="result_package_id" groups="stock.group_tracking_lot"/>
|
||||
<field name="product_uom_qty" readonly="1"/>
|
||||
<field name="reserved_uom_qty" readonly="1"/>
|
||||
<field name="product_uom_id" options="{'no_create': True}"
|
||||
groups="uom.group_uom" readonly="1" force_save="1"/>
|
||||
<field name="qty_done"/>
|
||||
|
||||
Reference in New Issue
Block a user