Files
odoo_source/addons/stock/tests/test_packing_neg.py
T
Arnold Moyaux c0d7a05730 [REF] stock: _action_done and cache invalidation
`_action_done` could unlink a quant. This happens when moving a product from a
location to another one and makes null the quantity of this product in one of
theses locations. In this case, we unlink the quant because it is now useless
and could be confusing on reports based on quants.

The unwanted side effect is that unlinking a record will invalidate the cache. In
some pathologic cases, like making an inventory adjustment of 600 products
and reseting their quantity back to 0, the time of the operation is around 15
minutes. With this patch that tries to work carefully with the cache invalidation,
the same operations takes around 15 secondes.

This commit do not unlink quant anymore, instead it use a 'garbage
collector' on quants without quantity. The garbage collector is trigger
on the scheduler and when the user open the inventory view.
2018-09-18 14:53:03 +02:00

175 lines
8.2 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.tests.common import TransactionCase
class TestPackingNeg(TransactionCase):
def test_packing_neg(self):
# Create a new "negative" storable product
product_neg = self.env['product.product'].create({
'name': 'Negative product',
'type': 'product',
'categ_id': self.ref('product.product_category_1'),
'list_price': 100.0,
'standard_price': 70.0,
'seller_ids': [(0, 0, {
'delay': 1,
'name': self.ref('base.res_partner_2'),
'min_qty': 2.0,})],
'uom_id': self.ref('uom.product_uom_unit'),
'uom_po_id': self.ref('uom.product_uom_unit'),
})
# Create an incoming picking for this product of 300 PCE from suppliers to stock
vals = {
'name': 'Incoming picking (negative product)',
'partner_id': self.ref('base.res_partner_2'),
'picking_type_id': self.ref('stock.picking_type_in'),
'location_id': self.ref('stock.stock_location_suppliers'),
'location_dest_id': self.ref('stock.stock_location_stock'),
'move_lines': [(0, 0, {
'name': 'NEG',
'product_id': product_neg.id,
'product_uom': product_neg.uom_id.id,
'product_uom_qty': 300.00,
'location_id': self.ref('stock.stock_location_suppliers'),
'location_dest_id': self.ref('stock.stock_location_stock'),
})],
}
pick_neg = self.env['stock.picking'].create(vals)
pick_neg.onchange_picking_type()
pick_neg.move_lines.onchange_product_id()
# Confirm and assign picking
pick_neg.action_confirm()
pick_neg.action_assign()
# Put 120 pieces on Palneg 1 (package), 120 pieces on Palneg 2 with lot A and 60 pieces on Palneg 3
# create lot A
lot_a = self.env['stock.production.lot'].create({'name': 'Lot neg', 'product_id': product_neg.id})
# create package
package1 = self.env['stock.quant.package'].create({'name': 'Palneg 1'})
package2 = self.env['stock.quant.package'].create({'name': 'Palneg 2'})
package3 = self.env['stock.quant.package'].create({'name': 'Palneg 3'})
# Create package for each line and assign it as result_package_id
# create pack operation
pick_neg.move_line_ids[0].write({'result_package_id': package1.id, 'qty_done': 120})
new_pack1 = self.env['stock.move.line'].create({
'product_id': product_neg.id,
'product_uom_id': self.ref('uom.product_uom_unit'),
'picking_id': pick_neg.id,
'lot_id': lot_a.id,
'qty_done': 120,
'result_package_id': package2.id,
'location_id': self.ref('stock.stock_location_suppliers'),
'location_dest_id': self.ref('stock.stock_location_stock')
})
new_pack2 = self.env['stock.move.line'].create({
'product_id': product_neg.id,
'product_uom_id': self.ref('uom.product_uom_unit'),
'picking_id': pick_neg.id,
'result_package_id': package3.id,
'qty_done': 60,
'location_id': self.ref('stock.stock_location_suppliers'),
'location_dest_id': self.ref('stock.stock_location_stock')
})
# Transfer the receipt
pick_neg.action_done()
# Make a delivery order of 300 pieces to the customer
vals = {
'name': 'outgoing picking (negative product)',
'partner_id': self.ref('base.res_partner_4'),
'picking_type_id': self.ref('stock.picking_type_out'),
'location_id': self.ref('stock.stock_location_stock'),
'location_dest_id': self.ref('stock.stock_location_customers'),
'move_lines': [(0, 0, {
'name': 'NEG',
'product_id': product_neg.id,
'product_uom': product_neg.uom_id.id,
'product_uom_qty': 300.00,
'location_id': self.ref('stock.stock_location_stock'),
'location_dest_id': self.ref('stock.stock_location_customers'),
})],
}
delivery_order_neg = self.env['stock.picking'].create(vals)
delivery_order_neg.onchange_picking_type()
delivery_order_neg.move_lines.onchange_product_id()
# Assign and confirm
delivery_order_neg.action_confirm()
delivery_order_neg.action_assign()
# Instead of doing the 300 pieces, you decide to take pallet 1 (do not mention
# product in operation here) and 140 pieces from lot A/pallet 2 and 10 pieces from pallet 3
for rec in delivery_order_neg.move_line_ids:
if rec.package_id.name == 'Palneg 1':
rec.qty_done = rec.product_qty
rec.result_package_id = False
elif rec.package_id.name == 'Palneg 2' and rec.lot_id.name == 'Lot neg':
rec.write({
'qty_done': 140,
'result_package_id': False,
})
elif rec.package_id.name == 'Palneg 3':
rec.qty_done = 10
rec.result_package_id = False
# Process this picking
delivery_order_neg.action_done()
# Check the quants that you have -20 pieces pallet 2 in stock, and a total quantity
# of 50 in stock from pallet 3 (should be 20+30, as it has been split by reservation)
records = self.env['stock.quant'].search([('product_id', '=', product_neg.id), ('quantity', '!=', '0')])
pallet_3_stock_qty = 0
for rec in records:
if rec.package_id.name == 'Palneg 2' and rec.location_id.id == self.ref('stock.stock_location_stock'):
self.assertTrue(rec.quantity == -20, "Should have -20 pieces in stock on pallet 2. Got " + str(rec.quantity))
self.assertTrue(rec.lot_id.name == 'Lot neg', "It should have kept its Lot")
elif rec.package_id.name == 'Palneg 3' and rec.location_id.id == self.ref('stock.stock_location_stock'):
pallet_3_stock_qty += rec.quantity
else:
self.assertTrue(rec.location_id.id != self.ref('stock.stock_location_stock'), "Unrecognized quant in stock")
self.assertEqual(pallet_3_stock_qty, 50, "Should have 50 pieces in stock on pallet 3")
# Create a picking for reconciling the negative quant
vals = {
'name': 'reconciling_delivery',
'partner_id': self.ref('base.res_partner_4'),
'picking_type_id': self.ref('stock.picking_type_in'),
'location_id': self.ref('stock.stock_location_suppliers'),
'location_dest_id': self.ref('stock.stock_location_stock'),
'move_lines': [(0, 0, {
'name': 'NEG',
'product_id': product_neg.id,
'product_uom': product_neg.uom_id.id,
'product_uom_qty': 20.0,
'location_id': self.ref('stock.stock_location_suppliers'),
'location_dest_id': self.ref('stock.stock_location_stock'),
})],
}
delivery_reconcile = self.env['stock.picking'].create(vals)
delivery_reconcile.onchange_picking_type()
delivery_reconcile.move_lines.onchange_product_id()
# Receive 20 products with lot neg in stock with a new incoming shipment that should be on pallet 2
delivery_reconcile.action_confirm()
lot = self.env["stock.production.lot"].search([
('product_id', '=', product_neg.id),
('name', '=', 'Lot neg')], limit=1)
pack = self.env["stock.quant.package"].search([('name', '=', 'Palneg 2')], limit=1)
delivery_reconcile.move_line_ids[0].write({'lot_id': lot.id, 'qty_done': 20.0, 'result_package_id': pack.id})
delivery_reconcile.action_done()
# Check the negative quant was reconciled
neg_quants = self.env['stock.quant'].search([
('product_id', '=', product_neg.id),
('quantity', '<', 0),
('location_id.id', '!=', self.ref('stock.stock_location_suppliers'))])
self.assertTrue(len(neg_quants) == 0, "Negative quants should have been reconciled")