Skip to content

Commit

Permalink
[MIG][16.0] shopfloor_gs1
Browse files Browse the repository at this point in the history
  • Loading branch information
rousseldenis committed Jan 6, 2025
1 parent da3bc34 commit 949d8af
Show file tree
Hide file tree
Showing 14 changed files with 118 additions and 31 deletions.
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# generated from manifests external_dependencies
biip==2.3.0
biip
openupgradelib
6 changes: 4 additions & 2 deletions shopfloor_gs1/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ Add GS1 barcode support to Shopfloor.

Based on https://biip.readthedocs.io/

TODO....
This module allows to use the biip library to interpret a scanned GS1 barcode
and return the corresponding Odoo record for Shopfloor `find` method.

**Table of contents**

Expand All @@ -42,7 +43,7 @@ TODO....
Usage
=====

TODO
- You can use the `Scan` action in Shopfloor with a GS1 barcode. The

Bug Tracker
===========
Expand All @@ -67,6 +68,7 @@ Contributors

* Simone Orsi <[email protected]>
* Sébastien Alix <[email protected]>
* Denis Roussel <[email protected]>

Maintainers
~~~~~~~~~~~
Expand Down
5 changes: 2 additions & 3 deletions shopfloor_gs1/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{
"name": "Shopfloor GS1",
"summary": "Integrate GS1 barcode scan into Shopfloor app",
"version": "14.0.1.0.0",
"version": "16.0.1.0.0",
"development_status": "Beta",
"category": "Inventory",
"website": "https://github.com/OCA/wms",
Expand All @@ -18,8 +18,7 @@
# >= 2.3.0 required to use 'GS1Message.parse_hri' method
# and next version 3.0.0 has been refactored bringing
# incompatibility issues (to check later).
"biip==2.3.0"
"biip"
]
},
"data": [],
}
1 change: 1 addition & 0 deletions shopfloor_gs1/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
* Simone Orsi <[email protected]>
* Sébastien Alix <[email protected]>
* Denis Roussel <[email protected]>
3 changes: 2 additions & 1 deletion shopfloor_gs1/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ Add GS1 barcode support to Shopfloor.

Based on https://biip.readthedocs.io/

TODO....
This module allows to use the biip library to interpret a scanned GS1 barcode
and return the corresponding Odoo record for Shopfloor `find` method.
2 changes: 1 addition & 1 deletion shopfloor_gs1/readme/USAGE.rst
Original file line number Diff line number Diff line change
@@ -1 +1 @@
TODO
- You can use the `Scan` action in Shopfloor with a GS1 barcode. The
8 changes: 6 additions & 2 deletions shopfloor_gs1/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,8 @@ <h1 class="title">Shopfloor GS1</h1>
<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/wms/tree/16.0/shopfloor_gs1"><img alt="OCA/wms" src="https://img.shields.io/badge/github-OCA%2Fwms-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/wms-16-0/wms-16-0-shopfloor_gs1"><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/wms&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>Add GS1 barcode support to Shopfloor.</p>
<p>Based on <a class="reference external" href="https://biip.readthedocs.io/">https://biip.readthedocs.io/</a></p>
<p>TODO….</p>
<p>This module allows to use the biip library to interpret a scanned GS1 barcode
and return the corresponding Odoo record for Shopfloor <cite>find</cite> method.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
Expand All @@ -388,7 +389,9 @@ <h1 class="title">Shopfloor GS1</h1>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
<p>TODO</p>
<ul class="simple">
<li>You can use the <cite>Scan</cite> action in Shopfloor with a GS1 barcode. The</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
Expand All @@ -411,6 +414,7 @@ <h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<ul class="simple">
<li>Simone Orsi &lt;<a class="reference external" href="mailto:simone.orsi&#64;camptocamp.com">simone.orsi&#64;camptocamp.com</a>&gt;</li>
<li>Sébastien Alix &lt;<a class="reference external" href="mailto:sebastien.alix&#64;camptocamp.com">sebastien.alix&#64;camptocamp.com</a>&gt;</li>
<li>Denis Roussel &lt;<a class="reference external" href="mailto:denis.roussel&#64;acsone.eu">denis.roussel&#64;acsone.eu</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
Expand Down
1 change: 1 addition & 0 deletions shopfloor_gs1/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from . import test_utils
from . import test_action_search
from . import test_scan_anything
from . import test_action_search_hri
10 changes: 7 additions & 3 deletions shopfloor_gs1/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
DATE = "141231"
LOT1 = "1234AB"
LOT2 = "1234AC"
GS1_GTIN_BARCODE_1 = f"(01){PROD_BARCODE}(11){DATE}(10){LOT1}"
GS1_GTIN_BARCODE_2 = f"(01){PROD_BARCODE}(11){DATE}(10){LOT2}"
GS1_MANUF_BARCODE = f"(240){MANUF_CODE}(11){DATE}(10){LOT1}"
GS1_GTIN_BARCODE_1_HRI = f"(01){PROD_BARCODE}(11){DATE}(10){LOT1}"
GS1_GTIN_BARCODE_2_HRI = f"(01){PROD_BARCODE}(11){DATE}(10){LOT2}"
GS1_MANUF_BARCODE_HRI = f"(240){MANUF_CODE}(11){DATE}(10){LOT1}"

GS1_GTIN_BARCODE_1 = f"01{PROD_BARCODE}11{DATE}10{LOT1}"
GS1_GTIN_BARCODE_2 = f"01{PROD_BARCODE}11{DATE}10{LOT2}"
GS1_MANUF_BARCODE = f"01{PROD_BARCODE}11{DATE}10{LOT1}\x1d240{MANUF_CODE}"
14 changes: 3 additions & 11 deletions shopfloor_gs1/tests/test_action_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
class TestFind(TestSearchBaseCase):
@classmethod
def setUpClassBaseData(cls):
# pylint: disable=missing-return
super().setUpClassBaseData()
cls.product_a.barcode = PROD_BARCODE

Expand All @@ -25,7 +26,7 @@ def test_find_picking(self):

def test_find_location(self):
rec = self.customer_location
barcode = GS1_GTIN_BARCODE_1 + "(254)" + rec.name
barcode = GS1_GTIN_BARCODE_1 + "\x1d254" + rec.name
res = self.search.find(barcode, types=("location",))
self.assertEqual(res.record, rec)
res = self.search.find(rec.name, types=("location",))
Expand All @@ -46,7 +47,7 @@ def test_find_product(self):

def test_find_lot(self):
rec = (
self.env["stock.production.lot"]
self.env["stock.lot"]
.sudo()
.create(
{
Expand All @@ -62,12 +63,3 @@ def test_find_lot(self):
handler_kw=dict(lot=dict(products=self.product_a)),
)
self.assertEqual(res.record, rec)

def test_find_generic_packaging(self):
rec = (
self.env["product.packaging"]
.sudo()
.create({"name": "TEST PKG", "barcode": "1234"})
)
res = self.search.find(rec.barcode, types=("delivery_packaging",))
self.assertEqual(res.record, rec)
65 changes: 65 additions & 0 deletions shopfloor_gs1/tests/test_action_search_hri.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Copyright 2022 Camptocamp SA (http://www.camptocamp.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo.addons.shopfloor.tests.test_actions_search import TestSearchBaseCase

from .common import (
GS1_GTIN_BARCODE_1_HRI,
GS1_MANUF_BARCODE_HRI,
LOT1,
MANUF_CODE,
PROD_BARCODE,
)


class TestFindHri(TestSearchBaseCase):
@classmethod
def setUpClassBaseData(cls):
# pylint: disable=missing-return
super().setUpClassBaseData()
cls.product_a.barcode = PROD_BARCODE

def test_find_picking(self):
ptype = self.env.ref("shopfloor.picking_type_single_pallet_transfer_demo")
rec = self._create_picking(picking_type=ptype)
res = self.search.find(rec.name, types=("picking",))
self.assertEqual(res.record, rec)

def test_find_location(self):
rec = self.customer_location
barcode = GS1_GTIN_BARCODE_1_HRI + "(254)" + rec.name
res = self.search.find(barcode, types=("location",))
self.assertEqual(res.record, rec)
res = self.search.find(rec.name, types=("location",))
self.assertEqual(res.record, rec)

def test_find_package(self):
rec = self.env["stock.quant.package"].sudo().create({"name": "ABC1234"})
res = self.search.find(rec.name, types=("package",))
self.assertEqual(res.record, rec)

def test_find_product(self):
rec = self.product_a
res = self.search.find(GS1_GTIN_BARCODE_1_HRI, types=("product",))
self.assertEqual(res.record, rec)
rec.barcode = MANUF_CODE
res = self.search.find(GS1_MANUF_BARCODE_HRI, types=("product",))
self.assertEqual(res.record, rec)

def test_find_lot(self):
rec = (
self.env["stock.lot"]
.sudo()
.create(
{
"product_id": self.product_a.id,
"company_id": self.env.company.id,
"name": LOT1,
}
)
)
res = self.search.find(
GS1_GTIN_BARCODE_1_HRI,
types=("lot",),
handler_kw=dict(lot=dict(products=self.product_a)),
)
self.assertEqual(res.record, rec)
4 changes: 2 additions & 2 deletions shopfloor_gs1/tests/test_scan_anything.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def test_scan_product(self):
def test_find_location(self):
record = self.stock_location
rec_type = "location"
gs1_barcode = GS1_GTIN_BARCODE_1 + "(254)" + record.name
gs1_barcode = GS1_GTIN_BARCODE_1 + "\x1d254" + record.name
data = self.data_detail.location_detail(record)
for identifier in (gs1_barcode, record.name):
self._test_response_ok(rec_type, data, identifier)
Expand All @@ -47,7 +47,7 @@ def test_scan_package(self):

def test_scan_lot(self):
record = (
self.env["stock.production.lot"]
self.env["stock.lot"]
.sudo()
.create(
{
Expand Down
15 changes: 15 additions & 0 deletions shopfloor_gs1/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,18 @@ def test_parse_order(self):
self.assertEqual(res[0].ai, "01")
self.assertEqual(res[1].ai, "11")
self.assertEqual(res[2].ai, "10")

def test_barcode(self):
code = "(01)09506000117843(11)141231(10)1234AB"
res = GS1Barcode.parse(code)
res_2 = GS1Barcode.parse(code)

self.assertTrue(res[0] == res_2[0])

self.assertFalse(res[0] == res_2[1])
self.assertFalse(res[0] == list())

self.assertTrue(res[0])
self.assertFalse(GS1Barcode())

self.assertEqual(str(res[0]), "<GS1Barcode: ai=01>")
13 changes: 8 additions & 5 deletions shopfloor_gs1/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def __repr__(self) -> str:
return f"<{self.__class__.__name__}: ai={self.ai}>"

def __bool__(self):
return self.type != "none" or bool(self.record)
return bool(self.ai)

def __eq__(self, other):
for k in self.__slots__:
Expand All @@ -41,16 +41,19 @@ def parse(cls, barcode, ai_whitelist=None, safe=True):
:param ai_whitelist: ordered list of AI to look for
:param safe: break or not if barcode is invalid
:return: an instance of `GS1Barcode`.
:return: a list of `GS1Barcode` instances.
"""
res = []
try:
# TODO: we might not get an HRI...
parsed = GS1Message.parse_hri(barcode)
except ParseError:
if not safe:
raise
parsed = None
try:
parsed = GS1Message.parse(barcode)
except ParseError:
if not safe:
raise

Check warning on line 55 in shopfloor_gs1/utils.py

View check run for this annotation

Codecov / codecov/patch

shopfloor_gs1/utils.py#L55

Added line #L55 was not covered by tests
parsed = None
if not parsed:
return res
# Use whitelist if given, to respect a specific order
Expand Down

0 comments on commit 949d8af

Please sign in to comment.