[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:
Simon Lejeune
2017-08-07 12:10:13 +02:00
parent f55a2aa9df
commit e1cea2640f
11 changed files with 88 additions and 77 deletions
+2 -2
View File
@@ -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):
+31 -37
View File
@@ -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
+3 -1
View File
@@ -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)
+4 -3
View File
@@ -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
-
+4 -3
View File
@@ -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')),
+7 -6
View File
@@ -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"
+18 -11
View File
@@ -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)
+10 -7
View File
@@ -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')
+5 -5
View File
@@ -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):
+2 -2
View File
@@ -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 -->