|
4 | 4 | from odoo.tests.common import TransactionCase
|
5 | 5 |
|
6 | 6 |
|
7 |
| -class TestStockException(TransactionCase): |
8 |
| - @classmethod |
9 |
| - def setUpClass(cls): |
10 |
| - super().setUpClass() |
11 |
| - cls.res_users_model = cls.env["res.users"] |
12 |
| - cls.product_model = cls.env["product.product"] |
13 |
| - cls.exception_rule = cls.env["exception.rule"] |
14 |
| - |
15 |
| - cls.uom_unit = cls.env.ref("uom.product_uom_unit") |
16 |
| - cls.picking_type_id = cls.env.ref("stock.picking_type_out") |
17 |
| - cls.stock_location = cls.env.ref("stock.stock_location_stock") |
18 |
| - cls.customer_location = cls.env.ref("stock.stock_location_customers") |
19 |
| - |
20 |
| - # Create a product: |
21 |
| - cls.product_1 = cls.product_model.create( |
22 |
| - { |
23 |
| - "name": "Test Product 1", |
24 |
| - "type": "product", |
25 |
| - "default_code": "PROD1", |
26 |
| - "uom_id": cls.uom_unit.id, |
27 |
| - } |
28 |
| - ) |
29 |
| - |
30 |
| - # Create a Picking: |
31 |
| - cls.picking = cls.env["stock.picking"].create( |
| 7 | +class TestStockPicking(TransactionCase): |
| 8 | + def setUp(self): |
| 9 | + super().setUp() |
| 10 | + stock_location = self.env.ref("stock.stock_location_stock") |
| 11 | + customer_location = self.env.ref("stock.stock_location_customers") |
| 12 | + product = self.env.ref("product.product_product_4") |
| 13 | + picking_type = self.env.ref("stock.picking_type_out") |
| 14 | + # Create a picking in 'assigned' state with exceptions |
| 15 | + self.picking_with_exceptions = self.env["stock.picking"].create( |
32 | 16 | {
|
33 |
| - "location_id": cls.stock_location.id, |
34 |
| - "location_dest_id": cls.customer_location.id, |
35 |
| - "picking_type_id": cls.picking_type_id.id, |
| 17 | + "name": "Test Picking With Exceptions 2", |
| 18 | + "state": "assigned", |
| 19 | + "location_id": stock_location.id, |
| 20 | + "location_dest_id": customer_location.id, |
| 21 | + "picking_type_id": picking_type.id, |
36 | 22 | "move_ids": [
|
37 | 23 | (
|
38 | 24 | 0,
|
39 | 25 | 0,
|
40 | 26 | {
|
41 |
| - "name": cls.product_1.name, |
42 |
| - "product_id": cls.product_1.id, |
| 27 | + "name": "Test Move With Exceptions", |
| 28 | + "product_id": product.id, |
43 | 29 | "product_uom_qty": 1,
|
44 |
| - "product_uom": cls.product_1.uom_id.id, |
45 |
| - "location_id": cls.stock_location.id, |
46 |
| - "location_dest_id": cls.customer_location.id, |
| 30 | + "quantity": 1, |
| 31 | + "product_uom": self.env.ref("uom.product_uom_unit").id, |
| 32 | + "location_id": stock_location.id, |
| 33 | + "location_dest_id": customer_location.id, |
47 | 34 | },
|
48 | 35 | )
|
49 | 36 | ],
|
| 37 | + "ignore_exception": False, |
50 | 38 | }
|
51 | 39 | )
|
52 | 40 |
|
53 |
| - def test01_confirm_picking_fail_by_py(self): |
54 |
| - self.stock_exception = self.exception_rule.create( |
| 41 | + self.exception = self.env["exception.rule"].create( |
55 | 42 | {
|
56 |
| - "name": "No Partner", |
57 |
| - "sequence": 10, |
58 |
| - "model": "stock.picking", |
59 |
| - "exception_type": "by_py_code", |
60 |
| - "code": "if not self.partner_id: failed=True", |
| 43 | + "name": "Demand Quantity not positive", |
| 44 | + "description": "Demand Quantity not positive", |
| 45 | + "sequence": 50, |
| 46 | + "model": "stock.move", |
| 47 | + "code": "if self.product_uom_qty == 0: failed=True", |
| 48 | + "active": True, |
61 | 49 | }
|
62 | 50 | )
|
63 |
| - exception_action = self.picking.action_confirm() |
64 |
| - self.assertEqual(exception_action.get("res_model"), "stock.exception.confirm") |
65 |
| - self.assertTrue(self.picking.exceptions_summary) |
66 |
| - self.assertTrue(self.picking.exception_ids) |
67 |
| - rules = self.env["exception.rule"].browse(self.picking.exception_ids.ids) |
68 |
| - self.assertIn(self.picking.id, rules.mapped("picking_ids.id")) |
69 | 51 |
|
70 |
| - self.picking.button_validate() |
71 |
| - self.assertTrue(self.picking.exceptions_summary) |
| 52 | + def test_detect_exceptions(self): |
| 53 | + # Test that exceptions are detected for the picking with exceptions |
| 54 | + exceptions = self.picking_with_exceptions.detect_exceptions() |
| 55 | + self.assertFalse(exceptions, "Exceptions shouldn't be detected") |
| 56 | + move = self.picking_with_exceptions.move_ids[0] |
| 57 | + move._reverse_field() |
| 58 | + move.write({"product_uom_qty": 0}) |
| 59 | + exceptions = self.picking_with_exceptions.detect_exceptions() |
| 60 | + self.assertTrue(exceptions, "Exceptions should be detected") |
72 | 61 |
|
73 |
| - # Test ignore exception make possible for the picking to validate |
74 |
| - self.assertEqual(self.picking.state, "draft") |
75 |
| - self.picking.action_ignore_exceptions() |
76 |
| - self.assertTrue(self.picking.ignore_exception) |
77 |
| - self.assertFalse(self.picking.exceptions_summary) |
78 |
| - self.picking.action_confirm() |
79 |
| - self.assertEqual(self.picking.state, "confirmed") |
| 62 | + def test_button_validate_with_exceptions(self): |
| 63 | + move = self.picking_with_exceptions.move_ids[0] |
| 64 | + move.write({"product_uom_qty": 0}) |
| 65 | + move.write({"quantity": 1}) |
| 66 | + # Result returns a dict in case it detects an exception, |
| 67 | + # otherwise it returns 'True' |
| 68 | + result = self.picking_with_exceptions.button_validate() |
80 | 69 |
|
81 |
| - def test02_confirm_picking_fail_by_domain(self): |
82 |
| - self.exception_method = self.env["exception.rule"].create( |
| 70 | + # Verify the result of the button_validate action |
| 71 | + # If exceptions detected, the result should be different from 'True' |
| 72 | + self.assertNotEqual( |
| 73 | + result, True, f"Expected result not to be True, but got {type(result)}" |
| 74 | + ) |
| 75 | + |
| 76 | + def test_onchange_ignore_exception(self): |
| 77 | + # Change state and verify onchange behavior for picking |
| 78 | + self.picking_with_exceptions.onchange_ignore_exception() |
| 79 | + self.picking_with_exceptions._reverse_field() |
| 80 | + self.picking_with_exceptions.write( |
| 81 | + {"state": "waiting", "ignore_exception": True} |
| 82 | + ) |
| 83 | + self.assertTrue(self.picking_with_exceptions.ignore_exception) |
| 84 | + |
| 85 | + def test_confirm_picking(self): |
| 86 | + self.stock_exception = self.env["exception.rule"].create( |
83 | 87 | {
|
84 | 88 | "name": "No Partner",
|
85 |
| - "sequence": 11, |
| 89 | + "description": "No Partner", |
| 90 | + "sequence": 10, |
86 | 91 | "model": "stock.picking",
|
87 |
| - "domain": "[('partner_id', '=', False)]", |
88 |
| - "exception_type": "by_domain", |
| 92 | + "exception_type": "by_py_code", |
| 93 | + "code": "if not self.partner_id: failed=True", |
89 | 94 | }
|
90 | 95 | )
|
91 |
| - exception_action = self.picking.action_confirm() |
| 96 | + exception_action = self.picking_with_exceptions.action_confirm() |
92 | 97 | self.assertEqual(exception_action.get("res_model"), "stock.exception.confirm")
|
93 |
| - self.assertTrue(self.picking.exceptions_summary) |
94 |
| - self.assertTrue(self.picking.exception_ids) |
95 | 98 | exception_form = Form(
|
96 | 99 | self.env["stock.exception.confirm"].with_context(
|
97 | 100 | **exception_action.get("context")
|
98 | 101 | ),
|
99 | 102 | )
|
100 | 103 | stock_exception = exception_form.save()
|
101 | 104 | stock_exception.ignore = True
|
| 105 | + self.picking_with_exceptions.test_all_draft_pickings() |
102 | 106 | stock_exception.action_confirm()
|
103 |
| - |
104 |
| - def test03_call_picking_method(self): |
105 |
| - self.env["stock.picking"].test_all_draft_pickings() |
106 |
| - self.env["stock.picking"]._reverse_field() |
107 |
| - self.picking.move_ids._get_main_records() |
108 |
| - self.picking.move_ids._reverse_field() |
109 |
| - |
110 |
| - def test_confirm_picking(self): |
111 |
| - self.assertEqual(self.picking.state, "draft") |
112 |
| - self.picking.action_confirm() |
113 |
| - self.assertEqual(self.picking.state, "confirmed") |
0 commit comments