summaryrefslogtreecommitdiff
path: root/addons/stock/tests/test_packing_neg.py
blob: a42d33ed5349df27ed1b2b6f1811c044c046ad0a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# -*- 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):
        res_partner_2 = self.env['res.partner'].create({
            'name': 'Deco Addict',
            'email': 'deco.addict82@example.com',
        })

        res_partner_4 = self.env['res.partner'].create({
            'name': 'Ready Mat',
            'email': 'ready.mat28@example.com',
        })

        # 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': res_partner_2.id,
                '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': res_partner_2.id,
            '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, 'company_id': self.env.company.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': res_partner_4.id,
            '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': res_partner_4.id,
            '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")