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
@@ -1,6 +1,6 @@
1
1
  from . import stock_barcodes_action
2
2
  from . import stock_barcodes_option
3
- from . import stock_barcodes_read_log
3
+ from . import stock_move
4
4
  from . import stock_move_line
5
5
  from . import stock_picking
6
6
  from . import stock_picking_type
@@ -40,10 +40,11 @@ class StockBarcodesAction(models.Model):
40
40
  vals = {
41
41
  "option_group_id": option_group.id,
42
42
  "manual_entry": option_group.manual_entry,
43
+ "display_read_quant": option_group.display_read_quant,
43
44
  }
44
45
  if option_group.get_option_value("location_id", "filled_default"):
45
46
  vals["location_id"] = (
46
- self.env["stock.warehouse"].search([])[:1].lot_stock_id.id
47
+ self.env["stock.warehouse"].search([], limit=1).lot_stock_id.id
47
48
  )
48
49
  wiz = self.env["wiz.stock.barcodes.read.inventory"].create(vals)
49
50
  action = self.env["ir.actions.actions"]._for_xml_id(
@@ -35,13 +35,10 @@ class StockBarcodesOptionGroup(models.Model):
35
35
  string="Show pending moves", help="Shows a list of movements to process"
36
36
  )
37
37
  source_pending_moves = fields.Selection(
38
- [("move_line_ids", "Detailed operations"), ("move_lines", "Operations")],
38
+ [("move_line_ids", "Detailed operations"), ("move_ids", "Operations")],
39
39
  default="move_line_ids",
40
40
  help="Origin of the data to generate the movements to process",
41
41
  )
42
- show_scan_log = fields.Boolean(
43
- string="Show scan log", help="Displays a log of the scans processed"
44
- )
45
42
  ignore_filled_fields = fields.Boolean(
46
43
  string="Ignore filled fields",
47
44
  )
@@ -103,6 +100,7 @@ class StockBarcodesOptionGroup(models.Model):
103
100
  ("location_dest_id", "Destination Location"),
104
101
  ]
105
102
  )
103
+ display_read_quant = fields.Boolean(string="Read items on inventory mode")
106
104
 
107
105
  def get_option_value(self, field_name, attribute):
108
106
  option = self.option_ids.filtered(lambda op: op.field_name == field_name)[:1]
@@ -0,0 +1,37 @@
1
+ # Copyright 2024 Tecnativa - Sergio Teruel
2
+ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
3
+
4
+ from odoo import fields, models
5
+
6
+
7
+ class StockMove(models.Model):
8
+ _inherit = "stock.move"
9
+
10
+ barcode_backorder_action = fields.Selection(
11
+ [
12
+ ("pending", "Pending"),
13
+ ("create_backorder", "Create Backorder"),
14
+ ("skip_backorder", "No Backorder"),
15
+ ],
16
+ string="Backorder action",
17
+ default="pending",
18
+ )
19
+
20
+ def _action_done(self, cancel_backorder=False):
21
+ moves_cancel_backorder = self.browse()
22
+ if not cancel_backorder:
23
+ moves_cancel_backorder = self.filtered(
24
+ lambda sm: sm.barcode_backorder_action == "skip_backorder"
25
+ )
26
+ super(StockMove, moves_cancel_backorder)._action_done(cancel_backorder=True)
27
+ moves_backorder = self - moves_cancel_backorder
28
+ moves_backorder.barcode_backorder_action = "pending"
29
+ return super(StockMove, moves_backorder)._action_done(
30
+ cancel_backorder=cancel_backorder
31
+ )
32
+
33
+ def copy_data(self, default=None):
34
+ vals_list = super().copy_data(default=default)
35
+ for vals in vals_list:
36
+ vals.pop("barcode_backorder_action", None)
37
+ return vals_list
@@ -15,10 +15,10 @@ class StockMoveLine(models.Model):
15
15
  store=True,
16
16
  )
17
17
 
18
- @api.depends("qty_done", "product_uom_qty")
18
+ @api.depends("qty_done", "reserved_uom_qty")
19
19
  def _compute_barcode_scan_state(self):
20
20
  for line in self:
21
- if line.qty_done >= line.product_uom_qty:
21
+ if line.qty_done >= line.reserved_uom_qty:
22
22
  line.barcode_scan_state = "done"
23
23
  else:
24
24
  line.barcode_scan_state = "pending"
@@ -28,19 +28,13 @@ class StockMoveLine(models.Model):
28
28
 
29
29
  def action_barcode_detailed_operation_unlink(self):
30
30
  for sml in self:
31
- if sml.product_uom_qty:
32
- sml._barcodes_process_line_to_unlink()
33
- else:
34
- sml.unlink()
31
+ stock_move = sml.move_id
32
+ stock_move.barcode_backorder_action = "pending"
33
+ sml.unlink()
35
34
  # HACK: To force refresh wizard values
36
35
  wiz_barcode = self.env["wiz.stock.barcodes.read.picking"].browse(
37
36
  self.env.context.get("wiz_barcode_id", False)
38
37
  )
39
- if wiz_barcode.option_group_id.barcode_guided_mode == "guided":
40
- wiz_barcode.todo_line_id.line_ids = wiz_barcode.todo_line_id.line_ids
41
- if not any(wiz_barcode.todo_line_id.line_ids.mapped("qty_done")):
42
- wiz_barcode.fill_todo_records()
43
- wiz_barcode.determine_todo_action()
44
- else:
45
- wiz_barcode.fill_todo_records()
46
- wiz_barcode.todo_line_id.line_ids = wiz_barcode.todo_line_id.line_ids
38
+ stock_move._action_assign()
39
+ wiz_barcode.fill_todo_records()
40
+ wiz_barcode.determine_todo_action()
@@ -1,7 +1,6 @@
1
1
  # Copyright 2019 Sergio Teruel <sergio.teruel@tecnativa.com>
2
2
  # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
3
3
  from odoo import models
4
- from odoo.tools.float_utils import float_compare
5
4
 
6
5
 
7
6
  class StockPicking(models.Model):
@@ -19,7 +18,7 @@ class StockPicking(models.Model):
19
18
  }
20
19
  if self.picking_type_id.code == "outgoing":
21
20
  vals["location_dest_id"] = self.location_dest_id.id
22
- if self.picking_type_id.code == "incoming":
21
+ elif self.picking_type_id.code == "incoming":
23
22
  vals["location_id"] = self.location_id.id
24
23
 
25
24
  if option_group.get_option_value("location_id", "filled_default"):
@@ -33,8 +32,8 @@ class StockPicking(models.Model):
33
32
  wiz = self.env["wiz.stock.barcodes.read.picking"].create(
34
33
  self._prepare_barcode_wiz_vals(option_group)
35
34
  )
36
- wiz.determine_todo_action()
37
35
  wiz.fill_pending_moves()
36
+ wiz.determine_todo_action()
38
37
  action = self.env["ir.actions.actions"]._for_xml_id(
39
38
  "stock_barcodes.action_stock_barcodes_read_picking"
40
39
  )
@@ -42,41 +41,15 @@ class StockPicking(models.Model):
42
41
  return action
43
42
 
44
43
  def button_validate(self):
45
- if (
46
- self.picking_type_id.barcode_option_group_id.auto_put_in_pack
47
- and not self.move_line_ids.mapped("result_package_id")
48
- ):
49
- self.action_put_in_pack()
50
- create_backorder = False
51
- # Variable initialized as True to optimize break loop
52
- skip_backorder = True
44
+ put_in_pack_picks = self.filtered(
45
+ lambda p: p.picking_type_id.barcode_option_group_id.auto_put_in_pack
46
+ and not p.move_line_ids.result_package_id
47
+ )
48
+ if put_in_pack_picks:
49
+ put_in_pack_picks.action_put_in_pack()
53
50
  if self.env.context.get("stock_barcodes_validate_picking", False):
54
- # Avoid backorder when all move lines are processed (done or done_forced)
55
- prec = self.env["decimal.precision"].precision_get(
56
- "Product Unit of Measure"
57
- )
58
- for move in self.move_lines.filtered(lambda sm: sm.state != "cancel"):
59
- if (
60
- float_compare(
61
- move.quantity_done, move.product_uom_qty, precision_digits=prec
62
- )
63
- < 0
64
- ):
65
- # In normal conditions backorder will be created
66
- create_backorder = True
67
- if not move.move_line_ids or any(
68
- sml.barcode_scan_state in ["pending"]
69
- for sml in move.move_line_ids
70
- ):
71
- # If any move are not processed we can not skip backorder
72
- skip_backorder = False
73
- break
74
- if create_backorder and skip_backorder:
75
51
  res = super(
76
- StockPicking,
77
- self.with_context(
78
- picking_ids_not_to_backorder=self.ids, skip_backorder=True
79
- ),
52
+ StockPicking, self.with_context(skip_backorder=True)
80
53
  ).button_validate()
81
54
  else:
82
55
  res = super().button_validate()
@@ -26,17 +26,15 @@ class StockPickingType(models.Model):
26
26
  "picking_mode": "picking",
27
27
  }
28
28
  if self.code == "outgoing":
29
- location_dest_id = (
29
+ vals["location_dest_id"] = (
30
30
  self.default_location_dest_id.id
31
31
  or self.env.ref("stock.stock_location_customers").id
32
32
  )
33
- vals["location_dest_id"] = location_dest_id
34
- if self.code == "incoming":
35
- location_src_id = (
33
+ elif self.code == "incoming":
34
+ vals["location_id"] = (
36
35
  self.default_location_src_id.id
37
36
  or self.env.ref("stock.stock_location_suppliers").id
38
37
  )
39
- vals["location_id"] = location_src_id
40
38
  if self.barcode_option_group_id.get_option_value(
41
39
  "location_id", "filled_default"
42
40
  ):
@@ -46,8 +44,8 @@ class StockPickingType(models.Model):
46
44
  ):
47
45
  vals["location_dest_id"] = self.default_location_dest_id.id
48
46
  wiz = self.env["wiz.stock.barcodes.read.picking"].create(vals)
49
- wiz.determine_todo_action()
50
47
  wiz.fill_pending_moves()
48
+ wiz.determine_todo_action()
51
49
  action = self.env["ir.actions.actions"]._for_xml_id(
52
50
  "stock_barcodes.action_stock_barcodes_read_picking"
53
51
  )
@@ -55,6 +53,7 @@ class StockPickingType(models.Model):
55
53
  return action
56
54
 
57
55
  def action_barcode_new_picking(self):
56
+ self.ensure_one()
58
57
  picking = (
59
58
  self.env["stock.picking"]
60
59
  .with_context(default_immediate_transfer=True)
@@ -16,7 +16,6 @@ class StockQuant(models.Model):
16
16
  "product_uom_id",
17
17
  "lot_id",
18
18
  "package_id",
19
- "product_qty",
20
19
  ]
21
20
 
22
21
  def action_barcode_inventory_quant_edit(self):
@@ -25,7 +24,7 @@ class StockQuant(models.Model):
25
24
  wiz_barcode_id
26
25
  )
27
26
  for quant in self:
28
- for fname in quant._fields:
29
- if fname in self._get_fields_to_edit():
30
- wiz_barcode[fname] = quant[fname]
27
+ # Try to assign fields with the same name between quant and the scan wizard
28
+ for fname in self._get_fields_to_edit():
29
+ wiz_barcode[fname] = quant[fname]
31
30
  wiz_barcode.product_qty = quant.inventory_quantity
@@ -1,6 +1,4 @@
1
1
  id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
2
- access_stock_barcodes_read_log,access_stock_barcodes_read_log,model_stock_barcodes_read_log,base.group_user,1,1,1,1
3
- access_stock_barcodes_read_log_line,access_stock_barcodes_read_log_line,model_stock_barcodes_read_log_line,base.group_user,1,1,1,1
4
2
  access_wiz_stock_barcodes_read_picking,access_wiz_stock_barcodes_read_picking,model_wiz_stock_barcodes_read_picking,base.group_user,1,1,1,1
5
3
  access_wiz_candidate_picking,access_wiz_candidate_picking,model_wiz_candidate_picking,base.group_user,1,1,1,1
6
4
  access_wiz_stock_barcodes_new_lot,access_wiz_stock_barcodes_new_lot,model_wiz_stock_barcodes_new_lot,base.group_user,1,1,1,1
@@ -1,3 +1,4 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
1
2
  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
3
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
3
4
  <head>
@@ -366,9 +367,9 @@ ul.auto-toc {
366
367
  !! This file is generated by oca-gen-addon-readme !!
367
368
  !! changes will be overwritten. !!
368
369
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
369
- !! source digest: sha256:2cb108800d4184b951795fa6c906ec0d63a06035061daad42aca10893c49a5be
370
+ !! source digest: sha256:f6453112d1afcb3f171e5f468a06e4927c98ed93493c10c8af4e4aef077de7fd
370
371
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
371
- <p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/stock-logistics-barcode/tree/15.0/stock_barcodes"><img alt="OCA/stock-logistics-barcode" src="https://img.shields.io/badge/github-OCA%2Fstock--logistics--barcode-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/stock-logistics-barcode-15-0/stock-logistics-barcode-15-0-stock_barcodes"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/stock-logistics-barcode&amp;target_branch=15.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
372
+ <p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/stock-logistics-barcode/tree/16.0/stock_barcodes"><img alt="OCA/stock-logistics-barcode" src="https://img.shields.io/badge/github-OCA%2Fstock--logistics--barcode-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/stock-logistics-barcode-16-0/stock-logistics-barcode-16-0-stock_barcodes"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/stock-logistics-barcode&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
372
373
  <p>This module provides a barcode reader interface for stock module.</p>
373
374
  <p>This module contains a base wizard read barcode that can be extended by
374
375
  other modules.</p>
@@ -517,7 +518,7 @@ Add security for users.</li>
517
518
  <p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/stock-logistics-barcode/issues">GitHub Issues</a>.
518
519
  In case of trouble, please check there if your issue has already been reported.
519
520
  If you spotted it first, help us to smash it by providing a detailed and welcomed
520
- <a class="reference external" href="https://github.com/OCA/stock-logistics-barcode/issues/new?body=module:%20stock_barcodes%0Aversion:%2015.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
521
+ <a class="reference external" href="https://github.com/OCA/stock-logistics-barcode/issues/new?body=module:%20stock_barcodes%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
521
522
  <p>Do not contact contributors directly about support or help with technical issues.</p>
522
523
  </div>
523
524
  <div class="section" id="credits">
@@ -560,7 +561,7 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
560
561
  <p>OCA, or the Odoo Community Association, is a nonprofit organization whose
561
562
  mission is to support the collaborative development of Odoo features and
562
563
  promote its widespread use.</p>
563
- <p>This module is part of the <a class="reference external" href="https://github.com/OCA/stock-logistics-barcode/tree/15.0/stock_barcodes">OCA/stock-logistics-barcode</a> project on GitHub.</p>
564
+ <p>This module is part of the <a class="reference external" href="https://github.com/OCA/stock-logistics-barcode/tree/16.0/stock_barcodes">OCA/stock-logistics-barcode</a> project on GitHub.</p>
564
565
  <p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
565
566
  </div>
566
567
  </div>
@@ -12,15 +12,29 @@
12
12
  border-width: 1px 0 0 0;
13
13
  }
14
14
 
15
+ // Avoid too big small buttons from core
16
+ .o_web_client.o_touch_device {
17
+ .oe_stock_barcordes_form {
18
+ .btn {
19
+ &,
20
+ .btn-sm {
21
+ padding: 0.25rem 0.5rem;
22
+ }
23
+ }
24
+ }
25
+ }
26
+
15
27
  .oe_stock_barcordes_form {
16
28
  padding: 0 !important;
17
29
  height: 100%;
18
-
19
- .o_group {
30
+ // Recover useless space
31
+ div[name="_barcode_scanned"] {
32
+ min-height: 0 !important;
33
+ }
34
+ .o_group .scan_fields {
20
35
  &.o_inner_group {
21
36
  margin-bottom: 0 !important;
22
37
  }
23
-
24
38
  margin: 0 !important;
25
39
  }
26
40
 
@@ -32,12 +46,27 @@
32
46
  border: 0 !important;
33
47
  }
34
48
 
49
+ // In Odoo 16 the flat input styling lacks proper usability
35
50
  .o_field_widget {
36
- margin-bottom: 0 !important;
51
+ margin-bottom: 1px !important;
52
+ .o_input {
53
+ border-radius: 3px;
54
+ border-width: 1px;
55
+ background-color: white;
56
+ }
57
+ .o_x2m_control_panel {
58
+ margin: 0px !important;
59
+ }
37
60
  }
38
61
 
39
62
  .o_kanban_record {
40
- padding: 0.3em;
63
+ flex-basis: 100%;
64
+
65
+ .btn-full-width {
66
+ margin: -9px;
67
+ width: calc(100% + 18px);
68
+ height: calc(100% + 18px);
69
+ }
41
70
 
42
71
  &.o_kanban_ghost {
43
72
  display: none;
@@ -82,6 +111,13 @@
82
111
  width: 100% !important;
83
112
  }
84
113
 
114
+ // The kanban view adds some pre-styles that we want to be able to tweak
115
+ div[name="menu_actions"] {
116
+ div[role="article"] {
117
+ margin-top: 10px !important;
118
+ }
119
+ }
120
+
85
121
  // Dropdown that is desactivated at lg width
86
122
  @media (min-width: 992px) {
87
123
  .d-lg-flex-no-dropdown {
@@ -0,0 +1,36 @@
1
+ /** @odoo-module **/
2
+ import {BarcodeHandlerField} from "@barcodes/barcode_handler_field";
3
+ import {patch} from "@web/core/utils/patch";
4
+ import {useService} from "@web/core/utils/hooks";
5
+ const {useEffect} = owl;
6
+
7
+ patch(BarcodeHandlerField.prototype, "stock_barcodes.BarcodeHandlerField", {
8
+ /* eslint-disable no-unused-vars */
9
+ setup() {
10
+ this._super(...arguments);
11
+ const busService = useService("bus_service");
12
+ this.orm = useService("orm");
13
+ const notifyChanges = async ({detail: notifications}) => {
14
+ for (const {payload, type} of notifications) {
15
+ if (type === "stock_barcodes_refresh_data") {
16
+ await this.env.model.root.load();
17
+ this.env.model.notify();
18
+ }
19
+ }
20
+ };
21
+ useEffect(() => {
22
+ busService.addChannel("barcode_reload");
23
+ busService.addEventListener("notification", notifyChanges);
24
+ return () => {
25
+ busService.deleteChannel("barcode_reload");
26
+ busService.removeEventListener("notification", notifyChanges);
27
+ };
28
+ });
29
+ },
30
+ onBarcodeScanned(event) {
31
+ this._super(...arguments);
32
+ if (this.props.record.resModel.includes("wiz.stock.barcodes.read")) {
33
+ $("#dummy_on_barcode_scanned").click();
34
+ }
35
+ },
36
+ });
@@ -0,0 +1,25 @@
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
+ // Models allowed to have extra keybinding features
6
+ export const barcodeModels = [
7
+ "stock.barcodes.action",
8
+ "stock.picking",
9
+ "stock.picking.type",
10
+ "wiz.candidate.picking",
11
+ "wiz.stock.barcodes.new.lot",
12
+ "wiz.stock.barcodes.read",
13
+ "wiz.stock.barcodes.read.inventory",
14
+ "wiz.stock.barcodes.read.picking",
15
+ "wiz.stock.barcodes.read.todo",
16
+ ];
17
+
18
+ /**
19
+ * Helper to know if the given model is allowed
20
+ *
21
+ * @returns {Boolean}
22
+ */
23
+ export function isAllowedBarcodeModel(modelName) {
24
+ return barcodeModels.includes(modelName);
25
+ }
@@ -0,0 +1,17 @@
1
+ /** @odoo-module */
2
+ /* Copyright 2021 Tecnativa - Alexandre D. Díaz
3
+ * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
4
+
5
+ import {FormController} from "@web/views/form/form_controller";
6
+ import {patch} from "@web/core/utils/patch";
7
+
8
+ patch(FormController.prototype, "Allow display.controlPanel overriding", {
9
+ setup() {
10
+ this._super(...arguments);
11
+ // Adds support to use control_pannel_hidden from the
12
+ // context to disable the control panel
13
+ if (this.props.context.control_panel_hidden) {
14
+ this.display.controlPanel = false;
15
+ }
16
+ },
17
+ });
@@ -0,0 +1,149 @@
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 {KanbanRenderer} from "@web/views/kanban/kanban_renderer";
6
+ import {isAllowedBarcodeModel} from "../utils/barcodes_models_utils.esm";
7
+ import {patch} from "@web/core/utils/patch";
8
+ import {useBus} from "@web/core/utils/hooks";
9
+ import {useHotkey} from "@web/core/hotkeys/hotkey_hook";
10
+ import {useRef} from "@odoo/owl";
11
+
12
+ patch(KanbanRenderer.prototype, "add hotkey", {
13
+ setup() {
14
+ const rootRef = useRef("root");
15
+ useHotkey(
16
+ "Enter",
17
+ ({target}) => {
18
+ if (!target.classList.contains("o_kanban_record")) {
19
+ return;
20
+ }
21
+
22
+ // Open first link
23
+ let firstLink = null;
24
+ if (isAllowedBarcodeModel(this.props.list.resModel)) {
25
+ firstLink = target.querySelector(
26
+ ".oe_kanban_action_button,.oe_btn_quick_action"
27
+ );
28
+ }
29
+ if (!firstLink) {
30
+ firstLink = target.querySelector(
31
+ ".oe_kanban_global_click, a, button"
32
+ );
33
+ }
34
+ if (firstLink && firstLink instanceof HTMLElement) {
35
+ firstLink.click();
36
+ }
37
+ return;
38
+ },
39
+ {area: () => rootRef.el}
40
+ );
41
+
42
+ this._super(...arguments);
43
+
44
+ if (isAllowedBarcodeModel(this.props.list.resModel)) {
45
+ if (this.env.searchModel) {
46
+ useBus(this.env.searchModel, "focus-view", () => {
47
+ const {model} = this.props.list;
48
+ if (model.useSampleModel || !model.hasData()) {
49
+ return;
50
+ }
51
+ const cards = Array.from(
52
+ rootRef.el.querySelectorAll(".o_kanban_record")
53
+ );
54
+ const firstCard = cards.find(
55
+ (card) =>
56
+ card.querySelectorAll("button[name='action_barcode_scan']")
57
+ .length > 0
58
+ );
59
+ if (firstCard) {
60
+ // Focus first kanban card
61
+ firstCard.focus();
62
+ }
63
+ });
64
+ }
65
+ }
66
+ },
67
+
68
+ // eslint-disable-next-line complexity
69
+ // This is copied from the base kanban_renderer.
70
+ // We want to only focus card with barcode when isAllowedBarcodeModel returns true
71
+ // Since there is no way to hook and change the candidate cards that are selectable
72
+ // (cards line 84) we cannot inherit and change the result. And even if we called
73
+ // super it would not respect inheritability
74
+ /**
75
+ * Redefines focusNextCard to select only kanban card with a barcode
76
+ * when isAllowBarcodeModel returns true for the current model
77
+ *
78
+ * @param {Node} area
79
+ * @param {String} direction
80
+ */
81
+ focusNextCard(area, direction) {
82
+ const {isGrouped} = this.props.list;
83
+ const closestCard = document.activeElement.closest(".o_kanban_record");
84
+ if (!closestCard) {
85
+ return;
86
+ }
87
+ const groups = isGrouped
88
+ ? [...area.querySelectorAll(".o_kanban_group")]
89
+ : [area];
90
+ let cards = [...groups]
91
+ .map((group) => [...group.querySelectorAll(".o_kanban_record")])
92
+ .filter((group) => group.length);
93
+
94
+ if (isAllowedBarcodeModel(this.props.list.resModel)) {
95
+ cards = cards.map((group) => {
96
+ const result = group.filter((card) => {
97
+ return (
98
+ card.querySelectorAll('button[name="action_barcode_scan"]')
99
+ .length > 0
100
+ );
101
+ });
102
+ return result;
103
+ });
104
+ }
105
+
106
+ let iGroup = null;
107
+ let iCard = null;
108
+ for (iGroup = 0; iGroup < cards.length; iGroup++) {
109
+ const i = cards[iGroup].indexOf(closestCard);
110
+ if (i !== -1) {
111
+ iCard = i;
112
+ break;
113
+ }
114
+ }
115
+ if (iCard === undefined) {
116
+ iCard = 0;
117
+ iGroup = 0;
118
+ }
119
+ // Find next card to focus
120
+ let nextCard = null;
121
+ switch (direction) {
122
+ case "down":
123
+ nextCard = iCard < cards[iGroup].length - 1 && cards[iGroup][iCard + 1];
124
+ break;
125
+ case "up":
126
+ nextCard = iCard > 0 && cards[iGroup][iCard - 1];
127
+ break;
128
+ case "right":
129
+ if (isGrouped) {
130
+ nextCard = iGroup < cards.length - 1 && cards[iGroup + 1][0];
131
+ } else {
132
+ nextCard = iCard < cards[0].length - 1 && cards[0][iCard + 1];
133
+ }
134
+ break;
135
+ case "left":
136
+ if (isGrouped) {
137
+ nextCard = iGroup > 0 && cards[iGroup - 1][0];
138
+ } else {
139
+ nextCard = iCard > 0 && cards[0][iCard - 1];
140
+ }
141
+ break;
142
+ }
143
+
144
+ if (nextCard && nextCard instanceof HTMLElement) {
145
+ nextCard.focus();
146
+ return true;
147
+ }
148
+ },
149
+ });
@@ -0,0 +1,16 @@
1
+ /** @odoo-module */
2
+
3
+ import {ViewCompiler} from "@web/views/view_compiler";
4
+ import {patch} from "@web/core/utils/patch";
5
+
6
+ patch(ViewCompiler.prototype, "Add hotkey props to button tag", {
7
+ compileButton(el, params) {
8
+ const hotkey = el.getAttribute("data-hotkey");
9
+ el.removeAttribute("data-hotkey");
10
+ const button = this._super(el, params);
11
+ if (hotkey) {
12
+ button.setAttribute("hotkey", hotkey);
13
+ }
14
+ return button;
15
+ },
16
+ });