odoo-addon-stock-barcodes 16.0.1.1.0.10__py3-none-any.whl → 16.0.2.0.0__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 (79) hide show
  1. odoo/addons/stock_barcodes/README.rst +217 -12
  2. odoo/addons/stock_barcodes/__init__.py +1 -0
  3. odoo/addons/stock_barcodes/__manifest__.py +8 -3
  4. odoo/addons/stock_barcodes/data/stock_barcodes_action.xml +8 -0
  5. odoo/addons/stock_barcodes/data/stock_barcodes_option.xml +99 -1
  6. odoo/addons/stock_barcodes/i18n/stock_barcodes.pot +268 -79
  7. odoo/addons/stock_barcodes/models/__init__.py +1 -0
  8. odoo/addons/stock_barcodes/models/barcode_events_mixin.py +11 -0
  9. odoo/addons/stock_barcodes/models/stock_barcodes_action.py +137 -3
  10. odoo/addons/stock_barcodes/models/stock_picking.py +17 -2
  11. odoo/addons/stock_barcodes/models/stock_picking_type.py +35 -0
  12. odoo/addons/stock_barcodes/models/stock_quant.py +51 -1
  13. odoo/addons/stock_barcodes/readme/CONTRIBUTORS.rst +4 -0
  14. odoo/addons/stock_barcodes/readme/DESCRIPTION.rst +4 -0
  15. odoo/addons/stock_barcodes/readme/HISTORY.rst +12 -0
  16. odoo/addons/stock_barcodes/readme/USAGE.rst +191 -10
  17. odoo/addons/stock_barcodes/reports/__init__.py +1 -0
  18. odoo/addons/stock_barcodes/reports/barcode_actions_report.py +16 -0
  19. odoo/addons/stock_barcodes/reports/barcode_actions_report.xml +25 -0
  20. odoo/addons/stock_barcodes/reports/reports.xml +28 -0
  21. odoo/addons/stock_barcodes/static/description/index.html +189 -33
  22. odoo/addons/stock_barcodes/static/src/docs/barcodes_actions.pdf +0 -0
  23. odoo/addons/stock_barcodes/static/src/docs/barcodes_demo.pdf +0 -0
  24. odoo/addons/stock_barcodes/static/src/img/add_product.png +0 -0
  25. odoo/addons/stock_barcodes/static/src/img/apply_inventory.png +0 -0
  26. odoo/addons/stock_barcodes/static/src/img/apply_inventory_reason.png +0 -0
  27. odoo/addons/stock_barcodes/static/src/img/barcode_interface_picking.png +0 -0
  28. odoo/addons/stock_barcodes/static/src/img/confirm_all_quantity_items_picking.png +0 -0
  29. odoo/addons/stock_barcodes/static/src/img/confirm_items_picking.png +0 -0
  30. odoo/addons/stock_barcodes/static/src/img/create_barcode_action.png +0 -0
  31. odoo/addons/stock_barcodes/static/src/img/form_add_product.png +0 -0
  32. odoo/addons/stock_barcodes/static/src/img/form_add_product_quantity.png +0 -0
  33. odoo/addons/stock_barcodes/static/src/img/form_add_product_reset.png +0 -0
  34. odoo/addons/stock_barcodes/static/src/img/inventory_barcode_action.png +0 -0
  35. odoo/addons/stock_barcodes/static/src/img/list_action_items.png +0 -0
  36. odoo/addons/stock_barcodes/static/src/img/list_items.png +0 -0
  37. odoo/addons/stock_barcodes/static/src/img/list_items_picking.png +0 -0
  38. odoo/addons/stock_barcodes/static/src/img/list_items_picking_edit.png +0 -0
  39. odoo/addons/stock_barcodes/static/src/img/list_items_picking_quantity.png +0 -0
  40. odoo/addons/stock_barcodes/static/src/img/list_items_picking_scanned.png +0 -0
  41. odoo/addons/stock_barcodes/static/src/img/list_picking.png +0 -0
  42. odoo/addons/stock_barcodes/static/src/img/print_barcodes.png +0 -0
  43. odoo/addons/stock_barcodes/static/src/scss/barcode.scss +135 -0
  44. odoo/addons/stock_barcodes/static/src/scss/stock.scss +285 -0
  45. odoo/addons/stock_barcodes/static/src/utils/barcodes_models_utils.esm.js +1 -0
  46. odoo/addons/stock_barcodes/static/src/views/actions/stock_barcode_main_menu.esm.js +88 -0
  47. odoo/addons/stock_barcodes/static/src/views/actions/stock_barcode_main_menu.scss +74 -0
  48. odoo/addons/stock_barcodes/static/src/views/actions/stock_barcode_main_menu.xml +45 -0
  49. odoo/addons/stock_barcodes/static/src/views/form/form_controller.esm.js +71 -0
  50. odoo/addons/stock_barcodes/static/src/views/form/form_view.esm.js +14 -0
  51. odoo/addons/stock_barcodes/static/src/views/kanban/kanban_record.esm.js +27 -0
  52. odoo/addons/stock_barcodes/static/src/views/{kanban_renderer.esm.js → kanban/kanban_renderer.esm.js} +78 -27
  53. odoo/addons/stock_barcodes/static/src/views/kanban/kanban_view.esm.js +8 -0
  54. odoo/addons/stock_barcodes/static/src/views/kanban/stock_barcodes_kanban.xml +28 -0
  55. odoo/addons/stock_barcodes/static/src/views/views.esm.js +35 -7
  56. odoo/addons/stock_barcodes/static/src/widgets/boolean_toggle.esm.js +46 -0
  57. odoo/addons/stock_barcodes/tests/common.py +25 -0
  58. odoo/addons/stock_barcodes/tests/test_stock_barcodes.py +65 -1
  59. odoo/addons/stock_barcodes/tests/test_stock_barcodes_picking.py +97 -13
  60. odoo/addons/stock_barcodes/views/stock_barcodes_action_view.xml +83 -9
  61. odoo/addons/stock_barcodes/views/stock_barcodes_menu.xml +1 -1
  62. odoo/addons/stock_barcodes/views/stock_picking_views.xml +29 -10
  63. odoo/addons/stock_barcodes/wizard/__init__.py +1 -0
  64. odoo/addons/stock_barcodes/wizard/stock_barcodes_candidate_picking.py +148 -0
  65. odoo/addons/stock_barcodes/wizard/stock_barcodes_read.py +148 -55
  66. odoo/addons/stock_barcodes/wizard/stock_barcodes_read_inventory.py +30 -2
  67. odoo/addons/stock_barcodes/wizard/stock_barcodes_read_inventory_views.xml +101 -92
  68. odoo/addons/stock_barcodes/wizard/stock_barcodes_read_picking.py +77 -141
  69. odoo/addons/stock_barcodes/wizard/stock_barcodes_read_picking_views.xml +197 -219
  70. odoo/addons/stock_barcodes/wizard/stock_barcodes_read_todo.py +45 -0
  71. odoo/addons/stock_barcodes/wizard/stock_barcodes_read_views.xml +87 -170
  72. odoo_addon_stock_barcodes-16.0.2.0.0.dist-info/METADATA +435 -0
  73. odoo_addon_stock_barcodes-16.0.2.0.0.dist-info/RECORD +103 -0
  74. odoo/addons/stock_barcodes/static/src/css/stock.scss +0 -136
  75. odoo/addons/stock_barcodes/static/src/views/form_view.esm.js +0 -17
  76. odoo_addon_stock_barcodes-16.0.1.1.0.10.dist-info/METADATA +0 -230
  77. odoo_addon_stock_barcodes-16.0.1.1.0.10.dist-info/RECORD +0 -68
  78. {odoo_addon_stock_barcodes-16.0.1.1.0.10.dist-info → odoo_addon_stock_barcodes-16.0.2.0.0.dist-info}/WHEEL +0 -0
  79. {odoo_addon_stock_barcodes-16.0.1.1.0.10.dist-info → odoo_addon_stock_barcodes-16.0.2.0.0.dist-info}/top_level.txt +0 -0
@@ -1,20 +1,18 @@
1
1
  <?xml version="1.0" encoding="utf-8" ?>
2
2
  <odoo>
3
- <!-- Main menu from scan wizard -->
4
- <record model="ir.actions.act_window" id="action_stock_barcodes_action">
5
- <field name="res_model">wiz.stock.barcodes.read.picking</field>
6
- <field name="name">Barcodes actions</field>
7
- <field name="view_mode">form</field>
8
- <field
9
- name="context"
10
- >{'control_panel_hidden': True, 'default_display_menu': True}</field>
11
- </record>
12
3
  <!-- Actions inside the menu -->
13
4
  <record id="view_stock_barcodes_action_tree" model="ir.ui.view">
14
5
  <field name="name">stock.barcodes.action.tree</field>
15
6
  <field name="model">stock.barcodes.action</field>
16
7
  <field name="arch" type="xml">
17
8
  <tree editable="top">
9
+ <header>
10
+ <button
11
+ string="Print barcodes"
12
+ type="object"
13
+ name="print_barcodes"
14
+ />
15
+ </header>
18
16
  <field name="sequence" widget="handle" />
19
17
  <field name="name" />
20
18
  <field name="action_window_id" />
@@ -22,15 +20,89 @@
22
20
  <field name="key_shortcut" />
23
21
  <field name="key_char_shortcut" />
24
22
  <field name="active" widget="boolean_toggle" />
23
+ <field name="barcode" />
25
24
  <field name="icon_class" />
26
25
  </tree>
27
26
  </field>
28
27
  </record>
28
+
29
29
  <record model="ir.actions.act_window" id="action_stock_barcodes">
30
30
  <field name="res_model">stock.barcodes.action</field>
31
31
  <field name="name">Barcodes actions</field>
32
32
  <field name="view_mode">tree</field>
33
33
  </record>
34
+
35
+
36
+ <record id="view_stock_barcodes_action_kanban" model="ir.ui.view">
37
+ <field name="name">stock.barcodes.action.kanban</field>
38
+ <field name="model">stock.barcodes.action</field>
39
+ <field name="arch" type="xml">
40
+ <kanban
41
+ class="o_kanban_mobile stock_barcodes_action_kanban"
42
+ create="0"
43
+ edit="0"
44
+ delete="0"
45
+ action="open_action"
46
+ type="object"
47
+ >
48
+ <field name="name" />
49
+ <field name="action_window_id" />
50
+ <field name="key_shortcut" />
51
+ <field name="key_char_shortcut" />
52
+ <field name="icon_class" />
53
+ <templates>
54
+ <t t-name="kanban-box">
55
+ <div class="oe_kanban_card oe_kanban_content">
56
+ <t t-set="shortcut" t-value="record.key_char_shortcut" />
57
+ <t
58
+ t-set="hotkey"
59
+ t-value="context.context_display_menu &amp;&amp; record.key_char_shortcut.raw_value || ''"
60
+ />
61
+ <div class="d-flex justify-content-between">
62
+ <div>
63
+ <i
64
+ t-if="record.icon_class.raw_value != false"
65
+ t-attf-class="mx-2 #{record.icon_class.raw_value}"
66
+ />
67
+ <field name="name" />
68
+ </div>
69
+ <div class="rounded-circle count-elements">
70
+ <field name="count_elements" />
71
+ </div>
72
+ </div>
73
+ </div>
74
+ </t>
75
+ </templates>
76
+ </kanban>
77
+ </field>
78
+ </record>
79
+
80
+
81
+ <!-- Main menu from scan wizard -->
82
+ <record id="action_stock_barcodes_action_kanban" model="ir.actions.act_window">
83
+ <field name="res_model">stock.barcodes.action</field>
84
+ <field name="name">Barcodes</field>
85
+ <field name="view_mode">kanban</field>
86
+ <field name="view_id" ref="view_stock_barcodes_action_kanban" />
87
+ <field name="domain">[('action_window_id', '!=', False)]</field>
88
+ <field name="target">fullscreen</field>
89
+ </record>
90
+
91
+ <record id="action_stock_barcodes_action_client" model="ir.actions.client">
92
+ <field name="name">Barcodes</field>
93
+ <field name="tag">stock_barcodes_main_menu</field>
94
+ <field name="target">fullscreen</field>
95
+ </record>
96
+
97
+ <record model="ir.actions.act_window" id="action_stock_barcodes_action">
98
+ <field name="res_model">wiz.stock.barcodes.read.picking</field>
99
+ <field name="name">Barcodes actions</field>
100
+ <field name="view_mode">form</field>
101
+ <field
102
+ name="context"
103
+ >{'control_panel_hidden': True, 'default_display_menu': True}</field>
104
+ </record>
105
+
34
106
  <menuitem
35
107
  action="action_stock_barcodes"
36
108
  id="menu_action_stock_barcodes"
@@ -39,4 +111,6 @@
39
111
  parent="stock.menu_product_in_config_stock"
40
112
  sequence="100"
41
113
  />
114
+
115
+
42
116
  </odoo>
@@ -4,7 +4,7 @@
4
4
  id="stock_barcodes_root"
5
5
  name="Barcodes"
6
6
  web_icon="stock_barcodes,static/description/icon.png"
7
- action="stock_barcodes.action_stock_barcodes_action"
7
+ action="stock_barcodes.action_stock_barcodes_action_client"
8
8
  groups="stock.group_stock_user"
9
9
  />
10
10
  </odoo>
@@ -24,16 +24,14 @@
24
24
  <field name="model">stock.picking</field>
25
25
  <field name="inherit_id" ref="stock.stock_picking_kanban" />
26
26
  <field name="arch" type="xml">
27
- <xpath expr="//t[@t-name='kanban-box']/div" position="inside">
28
- <button
29
- name="action_barcode_scan"
30
- class="btn btn-secondary"
31
- type="object"
32
- help="Start barcode interface"
33
- states="assigned"
34
- >
35
- <i class="fa fa-barcode fa-2x" title="Start barcode interface" />
36
- </button>
27
+ <xpath expr="//kanban" position="attributes">
28
+ <attribute name="type">object</attribute>
29
+ </xpath>
30
+ <xpath expr="//kanban" position="attributes">
31
+ <attribute name="action">action_barcode_scan</attribute>
32
+ </xpath>
33
+ <xpath expr="//kanban" position="attributes">
34
+ <attribute name="js_class">stock_barcodes_kanban</attribute>
37
35
  </xpath>
38
36
  </field>
39
37
  </record>
@@ -109,4 +107,25 @@
109
107
  </field>
110
108
  </field>
111
109
  </record>
110
+
111
+
112
+ <record id="stock_barcodes_action_picking_tree_ready" model="ir.actions.act_window">
113
+ <field name="name">Operations</field>
114
+ <field name="res_model">stock.picking</field>
115
+ <field name="type">ir.actions.act_window</field>
116
+ <field name="view_mode">kanban</field>
117
+ <field
118
+ name="context"
119
+ >{'contact_display': 'partner_address', 'search_default_available': 1}
120
+ </field>
121
+ <field name="search_view_id" ref="stock.view_picking_internal_search" />
122
+ <field name="help" type="html">
123
+ <p class="o_view_nocontent_smiling_face">
124
+ No transfer found. Let's create one!
125
+ </p>
126
+ <p>
127
+ Transfers allow you to move products from one location to another.
128
+ </p>
129
+ </field>
130
+ </record>
112
131
  </odoo>
@@ -1,5 +1,6 @@
1
1
  from . import stock_barcodes_read
2
2
  from . import stock_barcodes_read_inventory
3
+ from . import stock_barcodes_candidate_picking
3
4
  from . import stock_barcodes_read_picking
4
5
  from . import stock_barcodes_read_todo
5
6
  from . import stock_production_lot
@@ -0,0 +1,148 @@
1
+ # Copyright 2019 Sergio Teruel <sergio.teruel@tecnativa.com>
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).f
3
+ from odoo import api, fields, models
4
+
5
+
6
+ class WizCandidatePicking(models.TransientModel):
7
+
8
+ _name = "wiz.candidate.picking"
9
+ _description = "Candidate pickings for barcode interface"
10
+ # To prevent remove the record wizard until 2 days old
11
+ _transient_max_hours = 48
12
+
13
+ wiz_barcode_id = fields.Many2one(
14
+ comodel_name="wiz.stock.barcodes.read.picking", readonly=True
15
+ )
16
+ picking_id = fields.Many2one(
17
+ comodel_name="stock.picking", string="Picking", readonly=True
18
+ )
19
+ wiz_picking_id = fields.Many2one(
20
+ comodel_name="stock.picking",
21
+ related="wiz_barcode_id.picking_id",
22
+ string="Wizard Picking",
23
+ readonly=True,
24
+ )
25
+ name = fields.Char(
26
+ related="picking_id.name", readonly=True, string="Candidate Picking"
27
+ )
28
+ partner_id = fields.Many2one(
29
+ comodel_name="res.partner",
30
+ related="picking_id.partner_id",
31
+ readonly=True,
32
+ string="Partner",
33
+ )
34
+ state = fields.Selection(related="picking_id.state", readonly=True)
35
+ date = fields.Datetime(
36
+ related="picking_id.date", readonly=True, string="Creation Date"
37
+ )
38
+ product_qty_reserved = fields.Float(
39
+ "Reserved",
40
+ compute="_compute_picking_quantity",
41
+ digits="Product Unit of Measure",
42
+ readonly=True,
43
+ )
44
+ product_uom_qty = fields.Float(
45
+ "Demand",
46
+ compute="_compute_picking_quantity",
47
+ digits="Product Unit of Measure",
48
+ readonly=True,
49
+ )
50
+ product_qty_done = fields.Float(
51
+ "Done",
52
+ compute="_compute_picking_quantity",
53
+ digits="Product Unit of Measure",
54
+ readonly=True,
55
+ )
56
+ # For reload kanban view
57
+ scan_count = fields.Integer()
58
+ is_pending = fields.Boolean(compute="_compute_is_pending")
59
+ note = fields.Html(related="picking_id.note")
60
+
61
+ @api.depends("scan_count")
62
+ def _compute_picking_quantity(self):
63
+ for candidate in self:
64
+ qty_reserved = 0
65
+ qty_demand = 0
66
+ qty_done = 0
67
+ candidate.product_qty_reserved = sum(
68
+ candidate.picking_id.mapped("move_ids.reserved_availability")
69
+ )
70
+ for move in candidate.picking_id.move_ids:
71
+ qty_reserved += move.reserved_availability
72
+ qty_demand += move.product_uom_qty
73
+ qty_done += move.quantity_done
74
+ candidate.update(
75
+ {
76
+ "product_qty_reserved": qty_reserved,
77
+ "product_uom_qty": qty_demand,
78
+ "product_qty_done": qty_done,
79
+ }
80
+ )
81
+
82
+ @api.depends("scan_count")
83
+ def _compute_is_pending(self):
84
+ for rec in self:
85
+ rec.is_pending = bool(rec.wiz_barcode_id.pending_move_ids)
86
+
87
+ def _get_wizard_barcode_read(self):
88
+ return self.env["wiz.stock.barcodes.read.picking"].browse(
89
+ self.env.context["wiz_barcode_id"]
90
+ )
91
+
92
+ def action_lock_picking(self):
93
+ wiz = self._get_wizard_barcode_read()
94
+ picking_id = self.env.context["picking_id"]
95
+ wiz.picking_id = picking_id
96
+ wiz._set_candidate_pickings(wiz.picking_id)
97
+ return wiz.action_confirm()
98
+
99
+ def action_unlock_picking(self):
100
+ wiz = self._get_wizard_barcode_read()
101
+ wiz.update(
102
+ {
103
+ "picking_id": False,
104
+ "candidate_picking_ids": False,
105
+ "message_type": False,
106
+ "message": False,
107
+ }
108
+ )
109
+ return wiz.action_cancel()
110
+
111
+ def _get_picking_to_validate(self):
112
+ """Inject context show_picking_type_action_tree to redirect to picking list
113
+ after validate picking in barcodes environment.
114
+ The stock_barcodes_validate_picking key allows to know when a picking has been
115
+ validated from stock barcodes interface.
116
+ """
117
+ return (
118
+ self.env["stock.picking"]
119
+ .browse(self.env.context.get("picking_id", False))
120
+ .with_context(
121
+ show_picking_type_action_tree=True, stock_barcodes_validate_picking=True
122
+ )
123
+ )
124
+
125
+ def action_validate_picking(self):
126
+ context = dict(self.env.context)
127
+ picking = self._get_picking_to_validate()
128
+ if picking._check_immediate():
129
+ return False, picking.with_context(
130
+ button_validate_picking_ids=picking.ids, operations_mode=True
131
+ )._action_generate_immediate_wizard(
132
+ show_transfers=picking._should_show_transfers()
133
+ )
134
+ return (
135
+ True,
136
+ picking.with_context(
137
+ skip_sms=context.get("skip_sms", False)
138
+ ).button_validate(),
139
+ )
140
+
141
+ def action_open_picking(self):
142
+ picking = self.env["stock.picking"].browse(
143
+ self.env.context.get("picking_id", False)
144
+ )
145
+ return picking.with_context(control_panel_hidden=False).get_formview_action()
146
+
147
+ def action_put_in_pack(self):
148
+ self.picking_id.action_put_in_pack()
@@ -6,6 +6,8 @@ from odoo import _, api, fields, models
6
6
 
7
7
  _logger = logging.getLogger(__name__)
8
8
 
9
+ TYPE_ERROR = ["more_match", "not_found"]
10
+
9
11
 
10
12
  class WizStockBarcodesRead(models.AbstractModel):
11
13
  _name = "wiz.stock.barcodes.read"
@@ -14,6 +16,7 @@ class WizStockBarcodesRead(models.AbstractModel):
14
16
  # To prevent remove the record wizard until 2 days old
15
17
  _transient_max_hours = 48
16
18
  _allowed_product_types = ["product", "consu"]
19
+ _rec_name = "barcode"
17
20
 
18
21
  barcode = fields.Char()
19
22
  res_model_id = fields.Many2one(comodel_name="ir.model", index=True)
@@ -48,6 +51,7 @@ class WizStockBarcodesRead(models.AbstractModel):
48
51
  message_type = fields.Selection(
49
52
  [
50
53
  ("info", "Barcode read with additional info"),
54
+ ("info_page", "Info page"),
51
55
  ("not_found", "No barcode found"),
52
56
  ("more_match", "More than one matches found"),
53
57
  ("success", "Barcode read correctly"),
@@ -92,9 +96,13 @@ class WizStockBarcodesRead(models.AbstractModel):
92
96
  string="Product Qty. Done", digits="Product Unit of Measure", store=False
93
97
  )
94
98
 
99
+ enable_add_product = fields.Boolean(default=True)
100
+
95
101
  @api.depends("res_id")
96
102
  def _compute_action_ids(self):
97
- actions = self.env["stock.barcodes.action"].search([])
103
+ actions = self.env["stock.barcodes.action"].search(
104
+ [("action_window_id", "!=", False)]
105
+ )
98
106
  self.action_ids = actions
99
107
 
100
108
  @api.depends("option_group_id")
@@ -146,14 +154,36 @@ class WizStockBarcodesRead(models.AbstractModel):
146
154
  For manual entry mode barcode is not set so is not displayed
147
155
  """
148
156
  self.message_type = message_type
149
- # TODO: Uncomment this line when the tests of all modules have been adapted
150
157
  # if self.barcode and self.message_type in ["more_match", "not_found"]:
151
158
  if self.barcode:
152
159
  self.message = _(
153
160
  "%(barcode)s (%(message)s)", barcode=self.barcode, message=message
154
161
  )
155
162
  else:
156
- self.message = "%s" % message
163
+ if message_type in TYPE_ERROR:
164
+ self.manual_entry = True
165
+ self.send_bus_done(
166
+ "stock_barcodes_scan",
167
+ "actions_barcode_notification",
168
+ {
169
+ "message": message,
170
+ "sticky": True,
171
+ "message_type": "danger"
172
+ if message_type in TYPE_ERROR
173
+ else message_type,
174
+ },
175
+ )
176
+ elif message_type != "info_page":
177
+ self.send_bus_done(
178
+ "stock_barcodes_scan",
179
+ "actions_barcode_notification",
180
+ {
181
+ "message": message,
182
+ "message_type": message_type,
183
+ },
184
+ )
185
+ else:
186
+ self.message = "%s" % message
157
187
 
158
188
  def process_barcode_location_id(self):
159
189
  location = self.env["stock.location"].search(self._barcode_domain(self.barcode))
@@ -361,52 +391,73 @@ class WizStockBarcodesRead(models.AbstractModel):
361
391
  return False
362
392
 
363
393
  def process_barcode(self, barcode):
364
- self._set_messagge_info("success", _("OK"))
365
- options = self.option_group_id.option_ids
366
- barcode_found = False
367
- options_to_scan = options.filtered("to_scan")
368
- options_required = options.filtered("required")
369
- options_to_scan = options_to_scan.filtered(lambda op: op.step == self.step)
370
- for option in options_to_scan:
371
- if (
372
- self.option_group_id.ignore_filled_fields
373
- and option in options_required
374
- and getattr(self, option.field_name, False)
375
- ):
376
- continue
377
- option_func = getattr(self, "process_barcode_%s" % option.field_name, False)
378
- if option_func:
379
- res = option_func()
380
- if res:
381
- barcode_found = True
382
- self.play_sounds(barcode_found)
383
- break
384
- elif self.message_type != "success":
385
- self.play_sounds(False)
386
- return False
387
- if not barcode_found:
388
- self.play_sounds(barcode_found)
389
- if self.option_group_id.ignore_filled_fields:
390
- self._set_messagge_info(
391
- "info", _("Barcode not found or field already filled")
394
+ if not self:
395
+ barcode_action = self.env["stock.barcodes.action"].search(
396
+ [
397
+ ("action_window_id", "!=", False),
398
+ ("barcode", "=", barcode),
399
+ ],
400
+ limit=1,
401
+ )
402
+
403
+ self.env["bus.bus"]._sendone(
404
+ "stock_barcodes_scan",
405
+ "actions_main_menu_barcode",
406
+ {
407
+ "action_ok": len(barcode_action) > 0,
408
+ "action": barcode_action.open_action() if barcode_action else "",
409
+ "barcode": barcode,
410
+ },
411
+ )
412
+ else:
413
+ self._set_messagge_info("success", _("OK"))
414
+ options = self.option_group_id.option_ids
415
+ barcode_found = False
416
+ options_to_scan = options.filtered("to_scan")
417
+ options_required = options.filtered("required")
418
+ options_to_scan = options_to_scan.filtered(lambda op: op.step == self.step)
419
+ for option in options_to_scan:
420
+ if (
421
+ self.option_group_id.ignore_filled_fields
422
+ and option in options_required
423
+ and getattr(self, option.field_name, False)
424
+ ):
425
+ continue
426
+ option_func = getattr(
427
+ self, "process_barcode_%s" % option.field_name, False
392
428
  )
393
- else:
394
- self._set_messagge_info(
395
- "not_found", _("Barcode not found with this screen values")
429
+ if option_func:
430
+ res = option_func()
431
+ if res:
432
+ barcode_found = True
433
+ self.play_sounds(barcode_found)
434
+ break
435
+ elif self.message_type != "success":
436
+ self.play_sounds(False)
437
+ return False
438
+ if not barcode_found:
439
+ self.play_sounds(barcode_found)
440
+ if self.option_group_id.ignore_filled_fields:
441
+ self._set_messagge_info(
442
+ "not_found", _("Barcode not found or field already filled")
443
+ )
444
+ else:
445
+ self._set_messagge_info(
446
+ "not_found", _("Barcode not found with this screen values")
447
+ )
448
+ self.display_notification(
449
+ self.barcode,
450
+ message_type="danger",
451
+ title=_("Barcode not found"),
452
+ sticky=False,
396
453
  )
397
- self.display_notification(
398
- self.barcode,
399
- message_type="danger",
400
- title=_("Barcode not found"),
401
- sticky=False,
402
- )
403
- return False
404
- if not self.check_option_required():
405
- return False
406
- if self.is_manual_confirm or self.manual_entry:
407
- self._set_messagge_info("info", _("Review and confirm"))
408
- return False
409
- return self.action_confirm()
454
+ return False
455
+ if not self.check_option_required():
456
+ return False
457
+ if self.is_manual_confirm or self.manual_entry:
458
+ self._set_messagge_info("info", _("Review and confirm"))
459
+ return False
460
+ return self.action_confirm()
410
461
 
411
462
  def check_option_required(self):
412
463
  options = self.option_group_id.option_ids
@@ -626,16 +677,18 @@ class WizStockBarcodesRead(models.AbstractModel):
626
677
  def action_manual_entry(self):
627
678
  return True
628
679
 
629
- # TODO: To remove when stock_move_location uses action_clean_values
630
680
  def reset_qty(self):
631
681
  self.product_qty = 0
632
682
  self.packaging_qty = 0
633
683
 
634
684
  def open_actions(self):
635
685
  self.display_menu = True
686
+ return self.env.ref(
687
+ "stock_barcodes.action_stock_barcodes_action_client"
688
+ ).read()[0]
636
689
 
637
690
  def action_back(self):
638
- self.display_menu = False
691
+ return self.env.ref("stock.stock_picking_type_action").read()[0]
639
692
 
640
693
  def open_records(self):
641
694
  action = self.action_ids
@@ -688,7 +741,7 @@ class WizStockBarcodesRead(models.AbstractModel):
688
741
  lambda op: op.step == self.step and op.to_scan
689
742
  )
690
743
  self._set_messagge_info(
691
- "info", _("Scan {}").format(", ".join(options.mapped("name")))
744
+ "info_page", _("Scan {}").format(", ".join(options.mapped("name")))
692
745
  )
693
746
 
694
747
  @api.onchange("package_id")
@@ -704,12 +757,50 @@ class WizStockBarcodesRead(models.AbstractModel):
704
757
  record = self.browse(self.ids)
705
758
  record.write(self._convert_to_write(self._cache))
706
759
  self = record
707
- res = self.action_done()
760
+ no_increase_qty_done, force_create_move = False, False
761
+ context = dict(self.env.context)
762
+ if self._name == "wiz.stock.barcodes.read.picking":
763
+ no_increase_qty_done = (
764
+ context.get("no_increase_qty_done", False) or self.manual_entry
765
+ )
766
+ force_create_move = context.get("force_create_move", False)
767
+ res = self.with_context(
768
+ no_increase_qty_done=no_increase_qty_done,
769
+ force_create_move=force_create_move,
770
+ ).action_done()
708
771
  self.invalidate_recordset()
709
772
  self.play_sounds(res)
710
773
  self._set_focus_on_qty_input()
774
+
775
+ if force_create_move:
776
+ # Hide Form Edit
777
+ self.manual_entry = False
778
+ self.send_bus_done(
779
+ "stock_barcodes_scan",
780
+ "stock_barcodes_edit_manual",
781
+ {
782
+ "manual_entry": False,
783
+ },
784
+ )
785
+
786
+ # Count elements for apply in inventory
787
+ if self._name == "wiz.stock.barcodes.read.inventory":
788
+ self.display_read_quant = True
789
+ self._compute_count_inventory_quants()
790
+ self.send_bus_done(
791
+ "stock_barcodes_form_update",
792
+ "count_apply_inventory",
793
+ {"count": self.count_inventory_quants},
794
+ )
795
+
711
796
  return res
712
797
 
798
+ def action_add_scan_manual(self):
799
+ self.manual_entry = True
800
+ self.send_bus_done(
801
+ "stock_barcodes_scan", "stock_barcodes_edit_manual", {"manual_entry": True}
802
+ )
803
+
713
804
  def process_lot_before_done(self):
714
805
  if (
715
806
  not self.lot_id
@@ -723,13 +814,14 @@ class WizStockBarcodesRead(models.AbstractModel):
723
814
 
724
815
  def play_sounds(self, res):
725
816
  if res:
726
- self.env["bus.bus"]._sendone(
817
+ self.send_bus_done(
727
818
  "stock_barcodes_scan",
728
819
  "stock_barcodes_sound",
729
820
  {"sound": "ok", "res_model": self._name, "res_id": self.ids[0]},
730
821
  )
822
+
731
823
  else:
732
- self.env["bus.bus"]._sendone(
824
+ self.send_bus_done(
733
825
  "stock_barcodes_scan",
734
826
  "stock_barcodes_sound",
735
827
  {"sound": "ko", "res_model": self._name, "res_id": self.ids[0]},
@@ -740,7 +832,8 @@ class WizStockBarcodesRead(models.AbstractModel):
740
832
  field_name = "product_qty"
741
833
  if field_name == "product_qty" and self.packaging_id:
742
834
  field_name = "packaging_qty"
743
- self.env["bus.bus"]._sendone(
835
+
836
+ self.send_bus_done(
744
837
  "stock_barcodes_scan",
745
838
  "stock_barcodes_focus",
746
839
  {
@@ -805,7 +898,7 @@ class WizStockBarcodesRead(models.AbstractModel):
805
898
  }
806
899
  if title:
807
900
  message["title"] = title
808
- self.env["bus.bus"]._sendone(
901
+ self.send_bus_done(
809
902
  "stock_barcodes-{}".format(self.ids[0]),
810
903
  "stock_barcodes_notify-{}".format(self.ids[0]),
811
904
  message,