[REF] stock: create quants in every location
The purpose of this is to help stock manager in their quants analysis. An overview of quants can be accessed via inventory menu and for specific lot/SN via the locate button. This commit add quants in every location (only internal location previously) The purpose is to introduce a double entry for quant (add quants to a destination location will always remove quant from a source location). Quants in customers/suppliers location are shared between all customers/suppliers. In order to know the amount of product that come from a specific customer/supplier the tracability report should be used.
This commit is contained in:
@@ -117,9 +117,9 @@ class Location(models.Model):
|
||||
('view_location_id.parent_left', '<=', self.parent_left),
|
||||
('view_location_id.parent_right', '>=', self.parent_left)], limit=1)
|
||||
|
||||
def should_impact_quants(self):
|
||||
def should_bypass_reservation(self):
|
||||
self.ensure_one()
|
||||
return False if self.usage in ('supplier', 'inventory', 'production', 'customer') else True
|
||||
return self.usage in ('supplier', 'customer', 'inventory', 'production') or self.scrap_location
|
||||
|
||||
|
||||
class Route(models.Model):
|
||||
|
||||
@@ -96,10 +96,10 @@ class StockMoveLine(models.Model):
|
||||
vals['ordered_qty'] = vals.get('product_uom_qty')
|
||||
ml = super(StockMoveLine, self).create(vals)
|
||||
if ml.state == 'done':
|
||||
Quant = self.env['stock.quant']
|
||||
quantity = ml.product_uom_id._compute_quantity(ml.qty_done, ml.move_id.product_id.uom_id,rounding_method='HALF-UP')
|
||||
in_date = None
|
||||
if ml.location_id.should_impact_quants() and ml.product_id.type == 'product':
|
||||
if ml.product_id.type == 'product':
|
||||
Quant = self.env['stock.quant']
|
||||
quantity = ml.product_uom_id._compute_quantity(ml.qty_done, ml.move_id.product_id.uom_id,rounding_method='HALF-UP')
|
||||
in_date = None
|
||||
available_qty, in_date = Quant._update_available_quantity(ml.product_id, ml.location_id, -quantity, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id)
|
||||
if available_qty < 0 and ml.lot_id:
|
||||
# see if we can compensate the negative quants with some untracked quants
|
||||
@@ -108,7 +108,6 @@ class StockMoveLine(models.Model):
|
||||
taken_from_untracked_qty = min(untracked_qty, abs(quantity))
|
||||
Quant._update_available_quantity(ml.product_id, ml.location_id, -taken_from_untracked_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id)
|
||||
Quant._update_available_quantity(ml.product_id, ml.location_id, taken_from_untracked_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id)
|
||||
if ml.location_dest_id.should_impact_quants() and ml.product_id.type == 'product':
|
||||
Quant._update_available_quantity(ml.product_id, ml.location_dest_id, quantity, lot_id=ml.lot_id, package_id=ml.result_package_id, owner_id=ml.owner_id, in_date=in_date)
|
||||
next_moves = ml.move_id.move_dest_ids.filtered(lambda move: move.state not in ('done', 'cancel'))
|
||||
next_moves.do_unreserve()
|
||||
@@ -125,12 +124,13 @@ class StockMoveLine(models.Model):
|
||||
return super(StockMoveLine, self).write(vals)
|
||||
|
||||
Quant = self.env['stock.quant']
|
||||
precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
|
||||
# We forbid to change the reserved quantity in the interace, but it is needed in the
|
||||
# case of stock.move's split.
|
||||
# TODO Move me in the update
|
||||
if 'product_uom_qty' in vals:
|
||||
for ml in self.filtered(lambda m: m.state in ('partially_available', 'assigned')):
|
||||
if ml.location_id.should_impact_quants() and ml.product_id.type == 'product':
|
||||
for ml in self.filtered(lambda m: m.state in ('partially_available', 'assigned') and m.product_id.type == 'product'):
|
||||
if not ml.location_id.should_bypass_reservation():
|
||||
qty_to_decrease = ml.product_qty - ml.product_uom_id._compute_quantity(vals['product_uom_qty'], ml.product_id.uom_id, rounding_method='HALF-UP')
|
||||
try:
|
||||
Quant._update_reserved_quantity(ml.product_id, ml.location_id, -qty_to_decrease, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
|
||||
@@ -154,8 +154,8 @@ class StockMoveLine(models.Model):
|
||||
updates[key] = self.env[model].browse(vals[key])
|
||||
|
||||
if updates:
|
||||
for ml in self.filtered(lambda ml: ml.state in ['partially_available', 'assigned']):
|
||||
if ml.location_id.should_impact_quants() and ml.product_id.type == 'product':
|
||||
for ml in self.filtered(lambda ml: ml.state in ['partially_available', 'assigned'] and ml.product_id.type == 'product'):
|
||||
if not ml.location_id.should_bypass_reservation():
|
||||
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)
|
||||
except UserError:
|
||||
@@ -164,7 +164,7 @@ class StockMoveLine(models.Model):
|
||||
else:
|
||||
raise
|
||||
|
||||
if updates.get('location_id', ml.location_id).should_impact_quants() and ml.product_id.type == 'product':
|
||||
if not updates.get('location_id', ml.location_id).should_bypass_reservation():
|
||||
new_product_qty = 0
|
||||
try:
|
||||
q = Quant._update_reserved_quantity(ml.product_id, updates.get('location_id', ml.location_id), ml.product_qty, lot_id=updates.get('lot_id', ml.lot_id),
|
||||
@@ -186,18 +186,14 @@ class StockMoveLine(models.Model):
|
||||
# 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.
|
||||
next_moves = self.env['stock.move']
|
||||
if updates or 'qty_done' in vals:
|
||||
for ml in self.filtered(lambda ml: ml.move_id.state == 'done'):
|
||||
for ml in self.filtered(lambda ml: ml.move_id.state == 'done' and ml.product_id.type == 'product'):
|
||||
# undo the original move line
|
||||
in_date = None
|
||||
if ml.location_dest_id.should_impact_quants() and ml.product_id.type == 'product':
|
||||
in_date = Quant._update_available_quantity(ml.product_id, ml.location_dest_id, -ml.qty_done, lot_id=ml.lot_id,
|
||||
in_date = Quant._update_available_quantity(ml.product_id, ml.location_dest_id, -ml.qty_done, lot_id=ml.lot_id,
|
||||
package_id=ml.package_id, owner_id=ml.owner_id)[1]
|
||||
if ml.location_id.should_impact_quants() and ml.product_id.type == 'product':
|
||||
Quant._update_available_quantity(ml.product_id, ml.location_id, ml.qty_done, lot_id=ml.lot_id,
|
||||
Quant._update_available_quantity(ml.product_id, ml.location_id, ml.qty_done, lot_id=ml.lot_id,
|
||||
package_id=ml.package_id, owner_id=ml.owner_id, in_date=in_date)
|
||||
|
||||
# move what's been actually done
|
||||
in_date = None
|
||||
product_id = ml.product_id
|
||||
location_id = updates.get('location_id', ml.location_id)
|
||||
location_dest_id = updates.get('location_dest_id', ml.location_dest_id)
|
||||
@@ -207,8 +203,9 @@ class StockMoveLine(models.Model):
|
||||
result_package_id = updates.get('result_package_id', ml.result_package_id)
|
||||
owner_id = updates.get('owner_id', ml.owner_id)
|
||||
quantity = ml.move_id.product_uom._compute_quantity(qty_done, ml.move_id.product_id.uom_id, rounding_method='HALF-UP')
|
||||
if location_id.should_impact_quants() and ml.product_id.type == 'product':
|
||||
if not location_id.should_bypass_reservation():
|
||||
ml._free_reservation(product_id, location_id, quantity, lot_id=lot_id, package_id=package_id, owner_id=owner_id)
|
||||
if not float_is_zero(quantity, precision_digits=precision):
|
||||
available_qty, in_date = Quant._update_available_quantity(product_id, location_id, -quantity, lot_id=lot_id, package_id=package_id, owner_id=owner_id)
|
||||
if available_qty < 0 and lot_id:
|
||||
# see if we can compensate the negative quants with some untracked quants
|
||||
@@ -217,8 +214,8 @@ class StockMoveLine(models.Model):
|
||||
taken_from_untracked_qty = min(untracked_qty, abs(available_qty))
|
||||
Quant._update_available_quantity(product_id, location_id, -taken_from_untracked_qty, lot_id=False, package_id=package_id, owner_id=owner_id)
|
||||
Quant._update_available_quantity(product_id, location_id, taken_from_untracked_qty, lot_id=lot_id, package_id=package_id, owner_id=owner_id)
|
||||
ml._free_reservation(ml.product_id, location_id, untracked_qty, lot_id=False, package_id=package_id, owner_id=owner_id)
|
||||
if location_dest_id.should_impact_quants() and ml.product_id.type == 'product' and qty_done:
|
||||
if not location_id.should_bypass_reservation():
|
||||
ml._free_reservation(ml.product_id, location_id, untracked_qty, lot_id=False, package_id=package_id, owner_id=owner_id)
|
||||
Quant._update_available_quantity(product_id, location_dest_id, quantity, lot_id=lot_id, package_id=result_package_id, owner_id=owner_id, in_date=in_date)
|
||||
# Unreserve and reserve following move in order to have the real reserved quantity on move_line.
|
||||
next_moves |= ml.move_id.move_dest_ids.filtered(lambda move: move.state not in ('done', 'cancel'))
|
||||
@@ -233,8 +230,8 @@ class StockMoveLine(models.Model):
|
||||
for ml in self:
|
||||
if ml.state in ('done', 'cancel'):
|
||||
raise UserError(_('You can not delete pack operations of a done picking'))
|
||||
# Unlinking a pack operation should unreserve.
|
||||
if ml.location_id.should_impact_quants() and ml.product_id.type == 'product' and not float_is_zero(ml.product_qty, precision_digits=precision):
|
||||
# Unlinking a move line should unreserve.
|
||||
if ml.product_id.type == 'product' and not ml.location_id.should_bypass_reservation() and not float_is_zero(ml.product_qty, precision_digits=precision):
|
||||
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)
|
||||
return super(StockMoveLine, self).unlink()
|
||||
@@ -290,16 +287,16 @@ class StockMoveLine(models.Model):
|
||||
|
||||
# Now, we can actually move the quant.
|
||||
for ml in self - ml_to_delete:
|
||||
if ml.product_id.type != 'consu':
|
||||
if ml.product_id.type == 'product':
|
||||
Quant = self.env['stock.quant']
|
||||
rounding = ml.product_uom_id.rounding
|
||||
|
||||
# if this move line is force assigned, unreserve elsewhere if needed
|
||||
if ml.location_id.should_impact_quants() and float_compare(ml.qty_done, ml.product_qty, precision_rounding=rounding) > 0:
|
||||
if not ml.location_id.should_bypass_reservation() and float_compare(ml.qty_done, ml.product_qty, precision_rounding=rounding) > 0:
|
||||
extra_qty = ml.qty_done - ml.product_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)
|
||||
# unreserve what's been reserved
|
||||
if ml.location_id.should_impact_quants() and ml.product_id.type == 'product' and ml.product_qty:
|
||||
if not ml.location_id.should_bypass_reservation() and ml.product_id.type == 'product' and ml.product_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)
|
||||
except UserError:
|
||||
@@ -307,18 +304,15 @@ class StockMoveLine(models.Model):
|
||||
|
||||
# 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')
|
||||
in_date = None
|
||||
if ml.location_id.should_impact_quants() and ml.product_id.type == 'product':
|
||||
available_qty, in_date = Quant._update_available_quantity(ml.product_id, ml.location_id, -quantity, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id)
|
||||
if available_qty < 0 and ml.lot_id:
|
||||
# see if we can compensate the negative quants with some untracked quants
|
||||
untracked_qty = Quant._get_available_quantity(ml.product_id, ml.location_id, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
|
||||
if untracked_qty:
|
||||
taken_from_untracked_qty = min(untracked_qty, abs(quantity))
|
||||
Quant._update_available_quantity(ml.product_id, ml.location_id, -taken_from_untracked_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id)
|
||||
Quant._update_available_quantity(ml.product_id, ml.location_id, taken_from_untracked_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id)
|
||||
if ml.location_dest_id.should_impact_quants() and ml.product_id.type == 'product':
|
||||
Quant._update_available_quantity(ml.product_id, ml.location_dest_id, quantity, lot_id=ml.lot_id, package_id=ml.result_package_id, owner_id=ml.owner_id, in_date=in_date)
|
||||
available_qty, in_date = Quant._update_available_quantity(ml.product_id, ml.location_id, -quantity, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id)
|
||||
if available_qty < 0 and ml.lot_id:
|
||||
# see if we can compensate the negative quants with some untracked quants
|
||||
untracked_qty = Quant._get_available_quantity(ml.product_id, ml.location_id, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
|
||||
if untracked_qty:
|
||||
taken_from_untracked_qty = min(untracked_qty, abs(quantity))
|
||||
Quant._update_available_quantity(ml.product_id, ml.location_id, -taken_from_untracked_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id)
|
||||
Quant._update_available_quantity(ml.product_id, ml.location_id, taken_from_untracked_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id)
|
||||
Quant._update_available_quantity(ml.product_id, ml.location_dest_id, quantity, lot_id=ml.lot_id, package_id=ml.result_package_id, owner_id=ml.owner_id, in_date=in_date)
|
||||
|
||||
def _free_reservation(self, product_id, location_id, quantity, lot_id=None, package_id=None, owner_id=None):
|
||||
""" When editing a done move line or validating one with some forced quantities, it is
|
||||
|
||||
@@ -39,7 +39,9 @@ class ProductionLot(models.Model):
|
||||
|
||||
@api.one
|
||||
def _product_qty(self):
|
||||
self.product_qty = sum(self.quant_ids.mapped('quantity'))
|
||||
# We only care for the quants in internal or transit locations.
|
||||
quants = self.quant_ids.filtered(lambda q: q.location_id.usage in ['internal', 'transit'])
|
||||
self.product_qty = sum(quants.mapped('quantity'))
|
||||
|
||||
@api.multi
|
||||
def action_traceability(self):
|
||||
|
||||
@@ -90,6 +90,7 @@ class MrpStockReport(models.TransientModel):
|
||||
quant_ids = self.env['stock.quant'].search([
|
||||
('lot_id', '=', context.get('active_id')),
|
||||
('quantity', '<', 0),
|
||||
('location_id.usage', '=', 'internal'),
|
||||
])
|
||||
res += self._lines(line_id, model_id=model_id, model='stock.quant', level=level,
|
||||
parent_quant=parent_quant, stream=stream, obj_ids=quant_ids)
|
||||
@@ -104,6 +105,7 @@ class MrpStockReport(models.TransientModel):
|
||||
quant_ids = self.env['stock.quant'].search([
|
||||
('lot_id', '=', context.get('active_id')),
|
||||
('quantity', '>', 0),
|
||||
('location_id.usage', '=', 'internal'),
|
||||
])
|
||||
res += self._lines(line_id, model_id=model_id, model='stock.quant', level=level,
|
||||
parent_quant=parent_quant, stream=stream, obj_ids=quant_ids)
|
||||
|
||||
@@ -72,11 +72,12 @@
|
||||
!python {model: stock.picking, id: pick1}: |
|
||||
self.action_done()
|
||||
-
|
||||
Check the system created 3 quants one with 120 pieces on pallet 1, one with 120 pieces on pallet 2 with lot A and 60 pieces on pallet 3
|
||||
Check the system created 5 quants one with 120 pieces on pallet 1, one with 120 pieces on pallet 2 with lot A and 60 pieces on pallet 3 in stock
|
||||
and 1 with -180 pieces and another with -120 piece lot A in supplier
|
||||
-
|
||||
!python {model: stock.quant, id: False}: |
|
||||
quants = self.search([('product_id','=',ref('product1'))])
|
||||
assert len(quants.ids) == 3, "The number of quants created is not correct"
|
||||
assert len(quants.ids) == 5, "The number of quants created is not correct"
|
||||
for quant in quants:
|
||||
if quant.package_id.name == 'Pallet 1':
|
||||
assert quant.quantity == 120, "Should have 120 pieces on pallet 1"
|
||||
@@ -137,7 +138,7 @@
|
||||
elif rec.package_id.name == 'Pallet 3' and rec.location_id.id == ref('stock_location_stock'):
|
||||
assert rec.quantity == 50, "Should have 50 pieces in stock on pallet 3"
|
||||
else:
|
||||
assert False, "Unrecognized quant"
|
||||
assert rec.location_id.id != ref('stock_location_stock'), "Unrecognized quant in stock"
|
||||
-
|
||||
Check a backorder was created and on that backorder, prepare partial and process backorder
|
||||
-
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
elif rec.package_id.name == 'Palneg 3' and rec.location_id.id == ref('stock_location_stock'):
|
||||
pallet_3_stock_qty += rec.quantity
|
||||
else:
|
||||
assert False, "Unrecognized quant"
|
||||
assert rec.location_id.id != ref('stock_location_stock'), "Unrecognized quant in stock"
|
||||
assert pallet_3_stock_qty == 50, "Should have 50 pieces in stock on pallet 3"
|
||||
-
|
||||
Create a picking for reconciling the negative quant
|
||||
@@ -148,8 +148,9 @@
|
||||
Check the negative quant was reconciled
|
||||
-
|
||||
!python {model: stock.quant, id: False}: |
|
||||
neg_quants = self.search([('product_id','=', ref('product_neg')), ('quantity', '<', 0)])
|
||||
assert len(neg_quants.ids) == 0, "Negative quants should have been reconciled"
|
||||
neg_quants = self.search([('product_id','=', ref('product_neg')), ('quantity', '<', 0), ('location_id.id', '!=',
|
||||
ref('stock_location_suppliers'))])
|
||||
assert len(neg_quants) == 0, "Negative quants should have been reconciled"
|
||||
pick = self.env['stock.picking'].browse(ref('delivery_reconcile'))
|
||||
customer_quant = self.search([
|
||||
('product_id', '=', ref('product_neg')),
|
||||
|
||||
@@ -51,11 +51,11 @@
|
||||
!python {model: stock.picking, id: pick1_wise}: |
|
||||
self.do_transfer()
|
||||
-
|
||||
Check the system created 2 quants
|
||||
Check the system created 3 quants
|
||||
-
|
||||
!python {model: stock.quant, id: False}: |
|
||||
records = self.search([('product_id','=',ref('product_wise'))])
|
||||
assert len(records.ids) == 2, "The number of quants created is not correct"
|
||||
assert len(records.ids) == 3, "The number of quants created is not correct"
|
||||
-
|
||||
Make a delivery order of 5 pieces to the customer
|
||||
-
|
||||
@@ -138,7 +138,8 @@
|
||||
Check there was no negative quant created by this picking
|
||||
-
|
||||
!python {model: stock.quant, id: False}: |
|
||||
records = self.search([('product_id','=',ref('product_wise')), ('quantity', '<', 0.0)])
|
||||
records = self.search([('product_id','=',ref('product_wise')), ('quantity', '<', 0.0), ('location_id.id', '=',
|
||||
ref('stock_location_stock'))])
|
||||
assert len(records.ids) == 0, 'This should not have created a negative quant'
|
||||
-
|
||||
Check the other delivery order has changed its state back to partially available
|
||||
@@ -149,10 +150,10 @@
|
||||
Process the second picking
|
||||
-
|
||||
!python {model: stock.picking, id: delivery_order_wise2}: |
|
||||
self.do_transfer()
|
||||
self.action_done()
|
||||
-
|
||||
Check all quants are in Customers and there are no negative quants anymore
|
||||
-
|
||||
!python {model: stock.quant, id: False}: |
|
||||
records = self.search([('product_id','=',ref('product_wise'))])
|
||||
assert all([x.location_id.id==ref('stock_location_customers') and x.qty > 0.0 for x in records]), "Negative quant or wrong location detected"
|
||||
records = self.search([('product_id','=',ref('product_wise')), ('location_id', '!=', ref('stock_location_suppliers'))])
|
||||
assert all([x.location_id.id==ref('stock_location_customers') and x.quantity > 0.0 for x in records]), "Negative quant or wrong location detected"
|
||||
@@ -70,9 +70,9 @@ class StockMove(TransactionCase):
|
||||
move1.action_done()
|
||||
self.assertEqual(move1.state, 'done')
|
||||
# no quants are created in the supplier location
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.supplier_location), 0.0)
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.supplier_location), -100.0)
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 100.0)
|
||||
self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.supplier_location)), 0.0)
|
||||
self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.supplier_location)), 1.0)
|
||||
self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.stock_location)), 1.0)
|
||||
|
||||
def test_in_2(self):
|
||||
@@ -111,9 +111,9 @@ class StockMove(TransactionCase):
|
||||
self.assertEqual(move1.state, 'done')
|
||||
|
||||
# no quants are created in the supplier location
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product3, self.supplier_location), 0.0)
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product3, self.supplier_location), -5.0)
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product3, self.stock_location), 5.0)
|
||||
self.assertEqual(len(self.env['stock.quant']._gather(self.product3, self.supplier_location)), 0.0)
|
||||
self.assertEqual(len(self.env['stock.quant']._gather(self.product3, self.supplier_location)), 1.0)
|
||||
quants = self.env['stock.quant']._gather(self.product3, self.stock_location)
|
||||
self.assertEqual(len(quants), 1.0)
|
||||
for quant in quants:
|
||||
@@ -160,11 +160,11 @@ class StockMove(TransactionCase):
|
||||
self.assertEqual(move1.product_qty, 5) # don't change reservation
|
||||
self.assertEqual(move1.state, 'done')
|
||||
|
||||
# no quants are created in the supplier location
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.supplier_location), 0.0)
|
||||
# Quant balance should result with 5 quant in supplier and stock
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.supplier_location), -5.0)
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location), 5.0)
|
||||
|
||||
self.assertEqual(len(self.env['stock.quant']._gather(self.product2, self.supplier_location)), 0.0)
|
||||
self.assertEqual(len(self.env['stock.quant']._gather(self.product2, self.supplier_location)), 5.0)
|
||||
quants = self.env['stock.quant']._gather(self.product2, self.stock_location)
|
||||
self.assertEqual(len(quants), 5.0)
|
||||
for quant in quants:
|
||||
@@ -211,9 +211,9 @@ class StockMove(TransactionCase):
|
||||
# validation
|
||||
move1.action_done()
|
||||
self.assertEqual(move1.state, 'done')
|
||||
# # no quants are created in the customer location
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.customer_location), 0.0)
|
||||
self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.customer_location)), 0.0)
|
||||
# Check there is one quant in customer location
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.customer_location), 100.0)
|
||||
self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.customer_location)), 1.0)
|
||||
# there should be no quant amymore in the stock location
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 0.0)
|
||||
self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.stock_location)), 0.0)
|
||||
@@ -260,7 +260,7 @@ class StockMove(TransactionCase):
|
||||
# validation
|
||||
move1.action_done()
|
||||
self.assertEqual(move1.state, 'done')
|
||||
# # no quants are created in the customer location
|
||||
# no quants are created in the customer location since it's a consumable
|
||||
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.customer_location), 0.0)
|
||||
self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.customer_location)), 0.0)
|
||||
# there should be no quant amymore in the stock location
|
||||
@@ -2466,12 +2466,14 @@ class StockMove(TransactionCase):
|
||||
move2.action_done()
|
||||
|
||||
initial_in_date_lot2 = self.env['stock.quant'].search([
|
||||
('location_id', '=', self.stock_location.id),
|
||||
('product_id', '=', self.product3.id),
|
||||
('lot_id', '=', lot2.id),
|
||||
]).in_date
|
||||
|
||||
# Edit lot1's incoming date.
|
||||
quant_lot1 = self.env['stock.quant'].search([
|
||||
('location_id', '=', self.stock_location.id),
|
||||
('product_id', '=', self.product3.id),
|
||||
('lot_id', '=', lot1.id),
|
||||
])
|
||||
@@ -2508,6 +2510,7 @@ class StockMove(TransactionCase):
|
||||
|
||||
# Check that lot1 correctly is back to stock with its right in_date
|
||||
quant_lot1 = self.env['stock.quant'].search([
|
||||
('location_id.usage', '=', 'internal'),
|
||||
('product_id', '=', self.product3.id),
|
||||
('lot_id', '=', lot1.id),
|
||||
])
|
||||
@@ -2516,6 +2519,7 @@ class StockMove(TransactionCase):
|
||||
|
||||
# Check that lo2 is in pack with is right in_date
|
||||
quant_lot2 = self.env['stock.quant'].search([
|
||||
('location_id.usage', '=', 'internal'),
|
||||
('product_id', '=', self.product3.id),
|
||||
('lot_id', '=', lot2.id),
|
||||
])
|
||||
@@ -2567,12 +2571,14 @@ class StockMove(TransactionCase):
|
||||
move2.action_done()
|
||||
|
||||
initial_in_date_lot2 = self.env['stock.quant'].search([
|
||||
('location_id', '=', self.stock_location.id),
|
||||
('product_id', '=', self.product3.id),
|
||||
('lot_id', '=', lot2.id),
|
||||
]).in_date
|
||||
|
||||
# Edit lot1's incoming date.
|
||||
quant_lot1 = self.env['stock.quant'].search([
|
||||
('location_id.usage', '=', 'internal'),
|
||||
('product_id', '=', self.product3.id),
|
||||
('lot_id', '=', lot1.id),
|
||||
])
|
||||
@@ -2606,6 +2612,7 @@ class StockMove(TransactionCase):
|
||||
})
|
||||
|
||||
quants = self.env['stock.quant'].search([
|
||||
('location_id.usage', '=', 'internal'),
|
||||
('product_id', '=', self.product3.id),
|
||||
])
|
||||
self.assertEqual(len(quants), 2)
|
||||
|
||||
@@ -1415,9 +1415,9 @@ class TestStockFlow(TestStockCommon):
|
||||
# Check picking_in_package is in picking_pack_package
|
||||
self.assertEqual(picking_in_package.id, picking_pack_package.id, 'The package created in the picking in is not in the one created in picking pack')
|
||||
self.assertEqual(picking_pack_package.id, picking_out_package.id, 'The package created in the picking in is not in the one created in picking pack')
|
||||
# Check that we haven't quant in customer location.
|
||||
quant = self.StockQuantObj.search([('location_id', '=', self.customer_location)])
|
||||
self.assertEqual(len(quant), 0, 'There should be no package for customer location')
|
||||
# Check that we have one quant in customer location.
|
||||
quant = self.StockQuantObj.search([('product_id', '=', self.productA.id), ('location_id', '=', self.customer_location)])
|
||||
self.assertEqual(len(quant), 1, 'There should be one quant with package for customer location')
|
||||
# Check that the parent package of the quant is the picking_in_package
|
||||
|
||||
def test_50_create_in_out_with_product_pack_lines(self):
|
||||
@@ -1471,9 +1471,11 @@ class TestStockFlow(TestStockCommon):
|
||||
packout2.package_id = pack2
|
||||
packout2.qty_done = 1
|
||||
picking_out.action_done()
|
||||
# Check there are no negative quants
|
||||
# Should be only 1 negative quant in supplier location
|
||||
neg_quants = self.env['stock.quant'].search([('product_id', '=', self.productE.id), ('quantity', '<', 0.0)])
|
||||
self.assertEqual(len(neg_quants), 0, 'There are negative quants!')
|
||||
self.assertEqual(len(neg_quants), 1, 'There should be 1 negative quants for supplier!')
|
||||
self.assertEqual(neg_quants.location_id.id, self.supplier_location, 'There shoud be 1 negative quants for supplier!')
|
||||
|
||||
quants = self.env['stock.quant']._gather(self.productE, self.env['stock.location'].browse(self.stock_location))
|
||||
self.assertEqual(len(quants), 2, 'We should have exactly 2 quants in the end')
|
||||
|
||||
@@ -1538,9 +1540,10 @@ class TestStockFlow(TestStockCommon):
|
||||
'product_uom_id': self.productE.uom_id.id,
|
||||
})
|
||||
picking_out.action_done()
|
||||
# Check there are no negative quants
|
||||
# Should be only 1 negative quant in supplier location
|
||||
neg_quants = self.env['stock.quant'].search([('product_id', '=', self.productE.id), ('quantity', '<', 0.0)])
|
||||
self.assertEqual(len(neg_quants), 0, 'There are negative quants!')
|
||||
self.assertEqual(len(neg_quants), 1, 'There should be 1 negative quants for supplier!')
|
||||
self.assertEqual(neg_quants.location_id.id, self.supplier_location, 'There shoud be 1 negative quants for supplier!')
|
||||
# We should also make sure that when matching stock moves with pack operations, it takes the correct
|
||||
quants = self.env['stock.quant']._gather(self.productE, self.env['stock.location'].browse(self.stock_location))
|
||||
self.assertEqual(len(quants), 0, 'We should have no quants in the end')
|
||||
|
||||
@@ -37,7 +37,7 @@ class TestWarehouse(TestStockCommon):
|
||||
self.assertEqual(inventory.move_ids.location_dest_id, self.env.ref('stock.location_inventory')) # Inventory loss
|
||||
self.assertEqual(inventory.move_ids.state, 'done')
|
||||
quants = self.env['stock.quant']._gather(self.product_1, self.env.ref('stock.location_inventory'))
|
||||
self.assertEqual(len(quants), 0) # No quant created for inventory loss
|
||||
self.assertEqual(len(quants), 1) # One quant created for inventory loss
|
||||
|
||||
# Check quantity of product in various locations: current, its parent, brother and other
|
||||
self.assertEqual(self.env['stock.quant']._gather(self.product_1, self.warehouse_1.lot_stock_id).quantity, 35.0)
|
||||
@@ -67,9 +67,9 @@ class TestWarehouse(TestStockCommon):
|
||||
self.assertEqual(inventory.line_ids.product_id, self.product_1)
|
||||
self.assertEqual(inventory.line_ids.product_qty, 50.0)
|
||||
|
||||
# Check associated quants: 1 quant for the product and the quantity
|
||||
# Check associated quants: 2 quants for the product and the quantity (1 in stock, 1 in inventory adjustment)
|
||||
quant = self.env['stock.quant'].search([('id', 'not in', self.existing_quants.ids)])
|
||||
self.assertEqual(len(quant), 1)
|
||||
self.assertEqual(len(quant), 2)
|
||||
# print quant.name, quant.product_id, quant.location_id
|
||||
# TDE TODO: expand this test
|
||||
|
||||
@@ -225,9 +225,9 @@ class TestWarehouse(TestStockCommon):
|
||||
quants = self.env['stock.quant'].search([('product_id', '=', productA.id), ('location_id', '=', stock_location.id)])
|
||||
self.assertEqual(len(quants), 0)
|
||||
|
||||
# There should be no quant in the inventory loss location
|
||||
# There should be one quant in the inventory loss location
|
||||
quant = self.env['stock.quant'].search([('product_id', '=', productA.id), ('location_id', '=', location_loss.id)])
|
||||
self.assertEqual(len(quant), 0)
|
||||
self.assertEqual(len(quant), 1)
|
||||
|
||||
|
||||
class TestResupply(TestStockCommon):
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<field name="owner_id" groups="stock.group_tracking_owner"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="in_date"/>
|
||||
<field name="in_date" attrs="{'invisible': [('lot_id', '=', False)]}" groups="stock.group_production_lot"/>
|
||||
</group>
|
||||
</group>
|
||||
</form>
|
||||
@@ -68,7 +68,6 @@
|
||||
<field name="owner_id" groups="stock.group_tracking_owner"/>
|
||||
<field name="lot_id" groups="stock.group_production_lot"/>
|
||||
<field name="package_id" groups="stock.group_tracking_lot"/>
|
||||
<field name="in_date"/>
|
||||
<field name='company_id' groups="base.group_multi_company"/>
|
||||
</tree>
|
||||
</field>
|
||||
@@ -91,6 +90,7 @@
|
||||
<field name="res_model">stock.quant</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form,pivot</field>
|
||||
<field name="context">{'search_default_internal_loc': 1, 'search_default_transit_loc': 1}</field>
|
||||
<field name="help">This analysis gives you a fast overview on the current stock level of your products and their current inventory value.</field>
|
||||
</record>
|
||||
<record model="ir.actions.act_window" id="product_template_open_quants"> <!-- Not used -->
|
||||
|
||||
Reference in New Issue
Block a user