odoo-addon-stock-barcodes 15.0.3.1.5.2__py3-none-any.whl → 16.0.1.0.0.18__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. odoo/addons/stock_barcodes/README.rst +6 -6
  2. odoo/addons/stock_barcodes/__manifest__.py +8 -7
  3. odoo/addons/stock_barcodes/data/stock_barcodes_option.xml +1 -2
  4. odoo/addons/stock_barcodes/hooks.py +15 -13
  5. odoo/addons/stock_barcodes/i18n/es.po +2 -2
  6. odoo/addons/stock_barcodes/i18n/it.po +5 -5
  7. odoo/addons/stock_barcodes/i18n/stock_barcodes.pot +190 -160
  8. odoo/addons/stock_barcodes/models/__init__.py +1 -1
  9. odoo/addons/stock_barcodes/models/stock_barcodes_action.py +2 -1
  10. odoo/addons/stock_barcodes/models/stock_barcodes_option.py +2 -4
  11. odoo/addons/stock_barcodes/models/stock_move.py +37 -0
  12. odoo/addons/stock_barcodes/models/stock_move_line.py +8 -14
  13. odoo/addons/stock_barcodes/models/stock_picking.py +9 -36
  14. odoo/addons/stock_barcodes/models/stock_picking_type.py +5 -6
  15. odoo/addons/stock_barcodes/models/stock_quant.py +3 -4
  16. odoo/addons/stock_barcodes/security/ir.model.access.csv +0 -2
  17. odoo/addons/stock_barcodes/static/description/index.html +5 -4
  18. odoo/addons/stock_barcodes/static/src/css/stock.scss +41 -5
  19. odoo/addons/stock_barcodes/static/src/utils/barcode_handler_field.esm.js +36 -0
  20. odoo/addons/stock_barcodes/static/src/utils/barcodes_models_utils.esm.js +25 -0
  21. odoo/addons/stock_barcodes/static/src/views/form_view.esm.js +17 -0
  22. odoo/addons/stock_barcodes/static/src/views/kanban_renderer.esm.js +149 -0
  23. odoo/addons/stock_barcodes/static/src/views/view_compiler.esm.js +16 -0
  24. odoo/addons/stock_barcodes/static/src/views/views.esm.js +193 -0
  25. odoo/addons/stock_barcodes/static/src/widgets/boolean_toggle.esm.js +26 -0
  26. odoo/addons/stock_barcodes/static/src/widgets/numeric_step.esm.js +40 -0
  27. odoo/addons/stock_barcodes/static/src/widgets/numeric_step.xml +17 -0
  28. odoo/addons/stock_barcodes/static/src/widgets/view_button.esm.js +8 -0
  29. odoo/addons/stock_barcodes/static/src/widgets/view_button.xml +14 -0
  30. odoo/addons/stock_barcodes/tests/common.py +167 -0
  31. odoo/addons/stock_barcodes/tests/test_stock_barcodes.py +4 -172
  32. odoo/addons/stock_barcodes/tests/test_stock_barcodes_new_lot.py +2 -2
  33. odoo/addons/stock_barcodes/tests/test_stock_barcodes_picking.py +8 -8
  34. odoo/addons/stock_barcodes/views/stock_barcodes_option_view.xml +1 -1
  35. odoo/addons/stock_barcodes/views/stock_picking_views.xml +4 -3
  36. odoo/addons/stock_barcodes/wizard/stock_barcodes_read.py +56 -94
  37. odoo/addons/stock_barcodes/wizard/stock_barcodes_read_inventory.py +1 -4
  38. odoo/addons/stock_barcodes/wizard/stock_barcodes_read_inventory_views.xml +14 -15
  39. odoo/addons/stock_barcodes/wizard/stock_barcodes_read_picking.py +256 -92
  40. odoo/addons/stock_barcodes/wizard/stock_barcodes_read_picking_views.xml +59 -37
  41. odoo/addons/stock_barcodes/wizard/stock_barcodes_read_todo.py +33 -107
  42. odoo/addons/stock_barcodes/wizard/stock_barcodes_read_todo_view.xml +70 -28
  43. odoo/addons/stock_barcodes/wizard/stock_barcodes_read_views.xml +172 -189
  44. odoo/addons/stock_barcodes/wizard/stock_production_lot.py +2 -2
  45. odoo/addons/stock_barcodes/wizard/stock_production_lot_views.xml +6 -8
  46. {odoo_addon_stock_barcodes-15.0.3.1.5.2.dist-info → odoo_addon_stock_barcodes-16.0.1.0.0.18.dist-info}/METADATA +11 -11
  47. odoo_addon_stock_barcodes-16.0.1.0.0.18.dist-info/RECORD +66 -0
  48. {odoo_addon_stock_barcodes-15.0.3.1.5.2.dist-info → odoo_addon_stock_barcodes-16.0.1.0.0.18.dist-info}/WHEEL +1 -1
  49. odoo/addons/stock_barcodes/migrations/15.0.1.0.0/pre-migration.py +0 -14
  50. odoo/addons/stock_barcodes/models/stock_barcodes_read_log.py +0 -51
  51. odoo/addons/stock_barcodes/static/src/css/stock.css +0 -5
  52. odoo/addons/stock_barcodes/static/src/js/barcodes_models_mixin.js +0 -34
  53. odoo/addons/stock_barcodes/static/src/js/basic_controller.js +0 -412
  54. odoo/addons/stock_barcodes/static/src/js/basic_fields.js +0 -59
  55. odoo/addons/stock_barcodes/static/src/js/form_view.js +0 -24
  56. odoo/addons/stock_barcodes/static/src/js/kanban_renderer.js +0 -47
  57. odoo/addons/stock_barcodes/static/src/js/numeric_step.js +0 -43
  58. odoo_addon_stock_barcodes-15.0.3.1.5.2.dist-info/RECORD +0 -62
  59. {odoo_addon_stock_barcodes-15.0.3.1.5.2.dist-info → odoo_addon_stock_barcodes-16.0.1.0.0.18.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,193 @@
1
+ /** @odoo-module */
2
+ /* Copyright 2024 Akretion
3
+ /* Copyright 2024 Tecnativa
4
+ * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
5
+
6
+ import {getVisibleElements, isVisible} from "@web/core/utils/ui";
7
+ import {FormController} from "@web/views/form/form_controller";
8
+ import {KanbanController} from "@web/views/kanban/kanban_controller";
9
+ import {ListController} from "@web/views/list/list_controller";
10
+ import {isAllowedBarcodeModel} from "../utils/barcodes_models_utils.esm";
11
+ import {patch} from "@web/core/utils/patch";
12
+ import {useEffect} from "@odoo/owl";
13
+ import {useService} from "@web/core/utils/hooks";
14
+
15
+ let barcodeOverlaysVisible = false;
16
+
17
+ // This is necessary because the hotkey service does not make its API public for
18
+ // some reasons
19
+ export function barcodeRemoveHotkeyOverlays() {
20
+ for (const overlay of document.querySelectorAll(".o_barcode_web_hotkey_overlay")) {
21
+ overlay.remove();
22
+ }
23
+ barcodeOverlaysVisible = false;
24
+ }
25
+
26
+ // This is necessary because the hotkey service does not make its API public for
27
+ // some reasons
28
+ export function barcodeAddHotkeyOverlays(activeElement) {
29
+ for (const el of getVisibleElements(
30
+ activeElement,
31
+ "[data-hotkey]:not(:disabled)"
32
+ )) {
33
+ const hotkey = el.dataset.hotkey;
34
+ const overlay = document.createElement("div");
35
+ overlay.classList.add(
36
+ "o_barcode_web_hotkey_overlay",
37
+ "position-absolute",
38
+ "top-0",
39
+ "bottom-0",
40
+ "start-0",
41
+ "end-0",
42
+ "d-flex",
43
+ "justify-content-center",
44
+ "align-items-center",
45
+ "m-0",
46
+ "bg-black-50",
47
+ "h6"
48
+ );
49
+ const overlayKbd = document.createElement("kbd");
50
+ overlayKbd.className = "small";
51
+ overlayKbd.appendChild(document.createTextNode(hotkey.toUpperCase()));
52
+ overlay.appendChild(overlayKbd);
53
+
54
+ let overlayParent = null;
55
+ if (el.tagName.toUpperCase() === "INPUT") {
56
+ // Special case for the search input that has an access key
57
+ // defined. We cannot set the overlay on the input itself,
58
+ // only on its parent.
59
+ overlayParent = el.parentElement;
60
+ } else {
61
+ overlayParent = el;
62
+ }
63
+
64
+ if (overlayParent.style.position !== "absolute") {
65
+ overlayParent.style.position = "relative";
66
+ }
67
+ overlayParent.appendChild(overlay);
68
+ }
69
+ barcodeOverlaysVisible = true;
70
+ }
71
+
72
+ function setupView() {
73
+ const actionService = useService("action");
74
+ const uiService = useService("ui");
75
+ const busService = useService("bus_service");
76
+ const notification = useService("notification");
77
+
78
+ const handleKeys = async (ev) => {
79
+ if (ev.keyCode === 113) {
80
+ // F2
81
+ const {activeElement} = uiService;
82
+
83
+ if (barcodeOverlaysVisible) {
84
+ barcodeRemoveHotkeyOverlays();
85
+ } else {
86
+ barcodeAddHotkeyOverlays(activeElement);
87
+ }
88
+ } else if (ev.keyCode === 120) {
89
+ // F9
90
+ const button = document.querySelector("button[name='action_clean_values']");
91
+ if (isVisible(button)) {
92
+ button.click();
93
+ }
94
+ } else if (ev.keyCode === 123 || ev.keyCode === 115) {
95
+ // F12 or F4
96
+ await actionService.doAction(
97
+ "stock_barcodes.action_stock_barcodes_action",
98
+ {
99
+ name: "Barcode wizard menu",
100
+ res_model: "wiz.stock.barcodes.read.picking",
101
+ type: "ir.actions.act_window",
102
+ }
103
+ );
104
+ }
105
+ };
106
+
107
+ const handleNotification = ({detail: notifications}) => {
108
+ if (notifications && notifications.length > 0) {
109
+ notifications.forEach((notif) => {
110
+ const {payload, type} = notif;
111
+ if (
112
+ (this.model.root.resModel == payload.res_model) &
113
+ (this.model.root.resId == payload.res_id)
114
+ ) {
115
+ if (type === "stock_barcodes_sound") {
116
+ this.$sound_ok[0].play();
117
+ }
118
+ if (type === "stock_barcodes_focus") {
119
+ requestIdleCallback(() => {
120
+ const input = document.querySelector(
121
+ `[name=${payload.field_name}] input`
122
+ );
123
+ if (input) {
124
+ input.focus();
125
+ }
126
+ });
127
+ }
128
+ if (type === "stock_barcodes_notify") {
129
+ notification.add(notif.payload.message, {
130
+ title: notif.payload.title,
131
+ type: notif.payload.type,
132
+ sticky: notif.payload.sticky,
133
+ });
134
+ }
135
+ }
136
+ });
137
+ }
138
+ };
139
+
140
+ useEffect(() => {
141
+ document.body.addEventListener("keydown", handleKeys);
142
+
143
+ this.$sound_ok = $("<audio>", {
144
+ src: "/stock_barcodes/static/src/sounds/bell.wav",
145
+ preload: "auto",
146
+ });
147
+ this.$sound_ok.appendTo("body");
148
+ this.$sound_ko = $("<audio>", {
149
+ src: "/stock_barcodes/static/src/sounds/error.wav",
150
+ preload: "auto",
151
+ });
152
+ this.$sound_ko.appendTo("body");
153
+
154
+ busService.addChannel("stock_barcodes_scan");
155
+
156
+ busService.addEventListener("notification", handleNotification);
157
+
158
+ return () => {
159
+ this.$sound_ok.remove();
160
+ this.$sound_ko.remove();
161
+ document.body.removeEventListener("keydown", handleKeys);
162
+ busService.deleteChannel("stock_barcodes_scan");
163
+ busService.removeEventListener("notification", handleNotification);
164
+ };
165
+ });
166
+ }
167
+
168
+ patch(KanbanController.prototype, "add hotkeys to kanban", {
169
+ setup() {
170
+ this._super(...arguments);
171
+ if (isAllowedBarcodeModel(this.props.resModel)) {
172
+ setupView.call(this);
173
+ }
174
+ },
175
+ });
176
+
177
+ patch(FormController.prototype, "add hotkeys to form", {
178
+ setup() {
179
+ this._super(...arguments);
180
+ if (isAllowedBarcodeModel(this.props.resModel)) {
181
+ setupView.call(this);
182
+ }
183
+ },
184
+ });
185
+
186
+ patch(ListController.prototype, "add hotkeys to list", {
187
+ setup() {
188
+ this._super(...arguments);
189
+ if (isAllowedBarcodeModel(this.props.resModel)) {
190
+ setupView.call(this);
191
+ }
192
+ },
193
+ });
@@ -0,0 +1,26 @@
1
+ /** @odoo-module */
2
+ /* Copyright 2018-2019 Sergio Teruel <sergio.teruel@tecnativa.com>.
3
+ * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
4
+
5
+ import {BooleanToggleField} from "@web/views/fields/boolean_toggle/boolean_toggle_field";
6
+ import {registry} from "@web/core/registry";
7
+
8
+ class BarcodeBooleanToggleField extends BooleanToggleField {
9
+ /*
10
+ This is needed because, whenever we click the checkbox to enter data
11
+ manually, the checkbox will be focused causing that when we scan the
12
+ barcode afterwards, it will not perform the python on_barcode_scanned
13
+ function.
14
+ */
15
+ onChange(newValue) {
16
+ super.onChange(newValue);
17
+ // We can't blur an element on its onchange event
18
+ // we need to wait for the event to finish (thus
19
+ // requestIdleCallback)
20
+ requestIdleCallback(() => {
21
+ document.activeElement.blur();
22
+ });
23
+ }
24
+ }
25
+
26
+ registry.category("fields").add("barcode_boolean_toggle", BarcodeBooleanToggleField);
@@ -0,0 +1,40 @@
1
+ /** @odoo-module */
2
+ /* Copyright 2022 Tecnativa - Alexandre D. Díaz
3
+ * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
4
+
5
+ import {NumericStep} from "@web_widget_numeric_step/numeric_step.esm";
6
+ import {isAllowedBarcodeModel} from "../utils/barcodes_models_utils.esm";
7
+ import {patch} from "@web/core/utils/patch";
8
+
9
+ patch(NumericStep.prototype, "Adds barcode event handling and focus", {
10
+ _onFocus() {
11
+ if (isAllowedBarcodeModel(this.props.record.resModel)) {
12
+ // Auto select all content when user enters into fields with this
13
+ // widget.
14
+ this.inputRef.el.select();
15
+ }
16
+ },
17
+
18
+ _onKeyDown(ev) {
19
+ if (isAllowedBarcodeModel(this.props.record.resModel) && ev.keyCode === 13) {
20
+ const action_confirm = document.querySelector(
21
+ "button[name='action_confirm']"
22
+ );
23
+
24
+ if (action_confirm) {
25
+ action_confirm.click();
26
+ return;
27
+ }
28
+
29
+ const action_confirm_force = document.querySelector(
30
+ "button[name='action_force_done']"
31
+ );
32
+
33
+ if (action_confirm_force) {
34
+ action_confirm_force.click();
35
+ return;
36
+ }
37
+ }
38
+ this._super(...arguments);
39
+ },
40
+ });
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <!--
3
+ Copyright 2024 Akretion
4
+ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
5
+ -->
6
+ <template>
7
+ <t
8
+ t-name="barcode_web_widget_numeric_step"
9
+ t-inherit="web_widget_numeric_step.web_widget_numeric_step"
10
+ t-inherit-mode="extension"
11
+ owl="1"
12
+ >
13
+ <xpath expr="//input" position="attributes">
14
+ <attribute name="t-on-focus">_onFocus</attribute>
15
+ </xpath>
16
+ </t>
17
+ </template>
@@ -0,0 +1,8 @@
1
+ /** @odoo-module */
2
+
3
+ import {ViewButton} from "@web/views/view_button/view_button";
4
+ import {patch} from "@web/core/utils/patch";
5
+
6
+ patch(ViewButton, "Add hotkey to button", {
7
+ props: [...ViewButton.props, "hotkey?"],
8
+ });
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <templates xml:space="preserve">
3
+
4
+ <t
5
+ t-name="views.ViewButton"
6
+ t-inherit="web.views.ViewButton"
7
+ t-inherit-mode="extension"
8
+ owl="1"
9
+ >
10
+ <xpath expr="//t[@t-tag]" position="attributes">
11
+ <attribute name="t-att-data-hotkey">props.hotkey</attribute>
12
+ </xpath>
13
+ </t>
14
+ </templates>
@@ -0,0 +1,167 @@
1
+ # Copyright 2108-2019 Francois Poizat <francois.poizat@gmail.com>
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3
+
4
+ from odoo.tests.common import TransactionCase
5
+
6
+
7
+ class TestCommonStockBarcodes(TransactionCase):
8
+ @classmethod
9
+ def setUpClass(cls):
10
+ super().setUpClass()
11
+
12
+ # Active group_stock_packaging and group_production_lot for user
13
+ group_stock_packaging = cls.env.ref("product.group_stock_packaging")
14
+ group_production_lot = cls.env.ref("stock.group_production_lot")
15
+ cls.env.user.groups_id = [
16
+ (4, group_stock_packaging.id),
17
+ (4, group_production_lot.id),
18
+ ]
19
+ # models
20
+ cls.StockLocation = cls.env["stock.location"]
21
+ cls.Product = cls.env["product.product"]
22
+ cls.ProductPackaging = cls.env["product.packaging"]
23
+ cls.WizScanReadPicking = cls.env["wiz.stock.barcodes.read.picking"]
24
+ cls.StockProductionLot = cls.env["stock.lot"]
25
+ cls.StockPicking = cls.env["stock.picking"]
26
+ cls.StockQuant = cls.env["stock.quant"]
27
+
28
+ cls.company = cls.env.company
29
+
30
+ # Option groups for test
31
+ cls.option_group = cls._create_barcode_option_group()
32
+
33
+ # warehouse and locations
34
+ cls.warehouse = cls.env.ref("stock.warehouse0")
35
+ cls.stock_location = cls.env.ref("stock.stock_location_stock")
36
+ cls.location_1 = cls.StockLocation.create(
37
+ {
38
+ "name": "Test location 1",
39
+ "usage": "internal",
40
+ "location_id": cls.stock_location.id,
41
+ "barcode": "8411322222568",
42
+ }
43
+ )
44
+ cls.location_2 = cls.StockLocation.create(
45
+ {
46
+ "name": "Test location 2",
47
+ "usage": "internal",
48
+ "location_id": cls.stock_location.id,
49
+ "barcode": "8470001809032",
50
+ }
51
+ )
52
+
53
+ # products
54
+ cls.product_wo_tracking = cls.Product.create(
55
+ {
56
+ "name": "Product test wo lot tracking",
57
+ "type": "product",
58
+ "tracking": "none",
59
+ "barcode": "8480000723208",
60
+ "packaging_ids": [
61
+ (
62
+ 0,
63
+ 0,
64
+ {
65
+ "name": "Box 10 Units",
66
+ "qty": 10.0,
67
+ "barcode": "5099206074439",
68
+ },
69
+ )
70
+ ],
71
+ }
72
+ )
73
+ cls.product_tracking = cls.Product.create(
74
+ {
75
+ "name": "Product test with lot tracking",
76
+ "type": "product",
77
+ "tracking": "lot",
78
+ "barcode": "8433281006850",
79
+ "packaging_ids": [
80
+ (
81
+ 0,
82
+ 0,
83
+ {"name": "Box 5 Units", "qty": 5.0, "barcode": "5420008510489"},
84
+ )
85
+ ],
86
+ }
87
+ )
88
+ cls.lot_1 = cls.StockProductionLot.create(
89
+ {
90
+ "name": "8411822222568",
91
+ "product_id": cls.product_tracking.id,
92
+ "company_id": cls.company.id,
93
+ }
94
+ )
95
+ cls.quant_lot_1 = cls.StockQuant.create(
96
+ {
97
+ "product_id": cls.product_tracking.id,
98
+ "lot_id": cls.lot_1.id,
99
+ "location_id": cls.stock_location.id,
100
+ "quantity": 100.0,
101
+ }
102
+ )
103
+ cls.wiz_scan = cls.WizScanReadPicking.create(
104
+ {"option_group_id": cls.option_group.id, "step": 1}
105
+ )
106
+
107
+ @classmethod
108
+ def _create_barcode_option_group(cls):
109
+ return cls.env["stock.barcodes.option.group"].create(
110
+ {
111
+ "name": "option group for tests",
112
+ "create_lot": True,
113
+ "option_ids": [
114
+ (
115
+ 0,
116
+ 0,
117
+ {
118
+ "step": 1,
119
+ "name": "Location",
120
+ "field_name": "location_id",
121
+ "to_scan": True,
122
+ "required": True,
123
+ },
124
+ ),
125
+ (
126
+ 0,
127
+ 0,
128
+ {
129
+ "step": 2,
130
+ "name": "Product",
131
+ "field_name": "product_id",
132
+ "to_scan": True,
133
+ "required": True,
134
+ },
135
+ ),
136
+ (
137
+ 0,
138
+ 0,
139
+ {
140
+ "step": 2,
141
+ "name": "Packaging",
142
+ "field_name": "packaging_id",
143
+ "to_scan": True,
144
+ "required": False,
145
+ },
146
+ ),
147
+ (
148
+ 0,
149
+ 0,
150
+ {
151
+ "step": 2,
152
+ "name": "Lot / Serial",
153
+ "field_name": "lot_id",
154
+ "to_scan": True,
155
+ "required": True,
156
+ },
157
+ ),
158
+ ],
159
+ }
160
+ )
161
+
162
+ def action_barcode_scanned(self, wizard, barcode):
163
+ wizard._barcode_scanned = barcode
164
+ wizard._on_barcode_scanned()
165
+ # Method to call all methods outside of onchange environment for pickings read
166
+ if wizard._name != "wiz.stock.barcodes.new.lot":
167
+ wizard.dummy_on_barcode_scanned()
@@ -1,170 +1,13 @@
1
1
  # Copyright 2108-2019 Sergio Teruel <sergio.teruel@tecnativa.com>
2
2
  # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3
3
 
4
- from odoo.tests.common import TransactionCase, tagged
4
+ from odoo.tests.common import tagged
5
5
 
6
+ from .common import TestCommonStockBarcodes
6
7
 
7
- @tagged("post_install", "-at_install")
8
- class TestStockBarcodes(TransactionCase):
9
- @classmethod
10
- def setUpClass(cls):
11
- super().setUpClass()
12
-
13
- # Active group_stock_packaging and group_production_lot for user
14
- group_stock_packaging = cls.env.ref("product.group_stock_packaging")
15
- group_production_lot = cls.env.ref("stock.group_production_lot")
16
- cls.env.user.groups_id = [
17
- (4, group_stock_packaging.id),
18
- (4, group_production_lot.id),
19
- ]
20
- # models
21
- cls.StockLocation = cls.env["stock.location"]
22
- cls.Product = cls.env["product.product"]
23
- cls.ProductPackaging = cls.env["product.packaging"]
24
- cls.WizScanReadPicking = cls.env["wiz.stock.barcodes.read.picking"]
25
- cls.StockProductionLot = cls.env["stock.production.lot"]
26
- cls.StockPicking = cls.env["stock.picking"]
27
- cls.StockQuant = cls.env["stock.quant"]
28
-
29
- cls.company = cls.env.company
30
-
31
- # Option groups for test
32
- cls.option_group = cls._create_barcode_option_group()
33
-
34
- # warehouse and locations
35
- cls.warehouse = cls.env.ref("stock.warehouse0")
36
- cls.stock_location = cls.env.ref("stock.stock_location_stock")
37
- cls.location_1 = cls.StockLocation.create(
38
- {
39
- "name": "Test location 1",
40
- "usage": "internal",
41
- "location_id": cls.stock_location.id,
42
- "barcode": "8411322222568",
43
- }
44
- )
45
- cls.location_2 = cls.StockLocation.create(
46
- {
47
- "name": "Test location 2",
48
- "usage": "internal",
49
- "location_id": cls.stock_location.id,
50
- "barcode": "8470001809032",
51
- }
52
- )
53
-
54
- # products
55
- cls.product_wo_tracking = cls.Product.create(
56
- {
57
- "name": "Product test wo lot tracking",
58
- "type": "product",
59
- "tracking": "none",
60
- "barcode": "8480000723208",
61
- "packaging_ids": [
62
- (
63
- 0,
64
- 0,
65
- {
66
- "name": "Box 10 Units",
67
- "qty": 10.0,
68
- "barcode": "5099206074439",
69
- },
70
- )
71
- ],
72
- }
73
- )
74
- cls.product_tracking = cls.Product.create(
75
- {
76
- "name": "Product test with lot tracking",
77
- "type": "product",
78
- "tracking": "lot",
79
- "barcode": "8433281006850",
80
- "packaging_ids": [
81
- (
82
- 0,
83
- 0,
84
- {"name": "Box 5 Units", "qty": 5.0, "barcode": "5420008510489"},
85
- )
86
- ],
87
- }
88
- )
89
- cls.lot_1 = cls.StockProductionLot.create(
90
- {
91
- "name": "8411822222568",
92
- "product_id": cls.product_tracking.id,
93
- "company_id": cls.company.id,
94
- }
95
- )
96
- cls.quant_lot_1 = cls.StockQuant.create(
97
- {
98
- "product_id": cls.product_tracking.id,
99
- "lot_id": cls.lot_1.id,
100
- "location_id": cls.stock_location.id,
101
- "quantity": 100.0,
102
- }
103
- )
104
- cls.wiz_scan = cls.WizScanReadPicking.create(
105
- {"option_group_id": cls.option_group.id, "step": 1}
106
- )
107
-
108
- @classmethod
109
- def _create_barcode_option_group(cls):
110
- return cls.env["stock.barcodes.option.group"].create(
111
- {
112
- "name": "option group for tests",
113
- "show_scan_log": True,
114
- "create_lot": True,
115
- "option_ids": [
116
- (
117
- 0,
118
- 0,
119
- {
120
- "step": 1,
121
- "name": "Location",
122
- "field_name": "location_id",
123
- "to_scan": True,
124
- "required": True,
125
- },
126
- ),
127
- (
128
- 0,
129
- 0,
130
- {
131
- "step": 2,
132
- "name": "Product",
133
- "field_name": "product_id",
134
- "to_scan": True,
135
- "required": True,
136
- },
137
- ),
138
- (
139
- 0,
140
- 0,
141
- {
142
- "step": 2,
143
- "name": "Packaging",
144
- "field_name": "packaging_id",
145
- "to_scan": True,
146
- "required": False,
147
- },
148
- ),
149
- (
150
- 0,
151
- 0,
152
- {
153
- "step": 2,
154
- "name": "Lot / Serial",
155
- "field_name": "lot_id",
156
- "to_scan": True,
157
- "required": True,
158
- },
159
- ),
160
- ],
161
- }
162
- )
163
-
164
- def action_barcode_scanned(self, wizard, barcode):
165
- wizard._barcode_scanned = barcode
166
- wizard._on_barcode_scanned()
167
8
 
9
+ @tagged("post_install", "-at_install")
10
+ class TestStockBarcodes(TestCommonStockBarcodes):
168
11
  def test_wizard_scan_location(self):
169
12
  self.action_barcode_scanned(self.wiz_scan, "8411322222568")
170
13
  self.assertEqual(self.wiz_scan.location_id, self.location_1)
@@ -205,14 +48,6 @@ class TestStockBarcodes(TransactionCase):
205
48
  self.assertEqual(self.wiz_scan.product_qty, 15.0)
206
49
  self.wiz_scan.manual_entry = False
207
50
 
208
- # Force more than one package with the same lot
209
- self.product_wo_tracking.packaging_ids.barcode = "5420008510489"
210
- self.action_barcode_scanned(self.wiz_scan, "5420008510489")
211
- self.assertEqual(
212
- self.wiz_scan.message,
213
- "5420008510489 (More than one package found)",
214
- )
215
-
216
51
  def test_wizard_scan_lot(self):
217
52
  self.wiz_scan.location_id = self.location_1.id
218
53
  self.wiz_scan.action_show_step()
@@ -233,9 +68,6 @@ class TestStockBarcodes(TransactionCase):
233
68
  "84118xxx22568 (Barcode not found with this screen values)",
234
69
  )
235
70
 
236
- def test_wizard_remove_last_scan(self):
237
- self.assertTrue(self.wiz_scan.action_undo_last_scan())
238
-
239
71
  def test_wiz_clean_lot(self):
240
72
  self.wiz_scan.location_id = self.location_1.id
241
73
  self.wiz_scan.action_show_step()
@@ -2,11 +2,11 @@
2
2
  # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3
3
  from odoo.tests.common import tagged
4
4
 
5
- from .test_stock_barcodes_picking import TestStockBarcodesPicking
5
+ from .common import TestCommonStockBarcodes
6
6
 
7
7
 
8
8
  @tagged("post_install", "-at_install")
9
- class TestStockBarcodesNewLot(TestStockBarcodesPicking):
9
+ class TestStockBarcodesNewLot(TestCommonStockBarcodes):
10
10
  @classmethod
11
11
  def setUpClass(cls):
12
12
  super().setUpClass()