Metadata-Version: 2.1
Name: odoo-addon-barcode_gs1
Version: 18.0.1.0.0.4
Requires-Python: >=3.10
Requires-Dist: odoo-addon-barcode_scanner==18.0.*
Requires-Dist: odoo==18.0.*
Summary: GS1 barcode parsing (GS1-128, application identifiers)
Home-page: https://github.com/OCA/barcode-interface
License: AGPL-3
Author: Binhex, Odoo Community Association (OCA)
Author-email: support@odoo-community.org
Classifier: Programming Language :: Python
Classifier: Framework :: Odoo
Classifier: Framework :: Odoo :: 18.0
Classifier: License :: OSI Approved :: GNU Affero General Public License v3
Description-Content-Type: text/x-rst

.. image:: https://odoo-community.org/readme-banner-image
   :target: https://odoo-community.org/get-involved?utm_source=readme
   :alt: Odoo Community Association

===========
Barcode GS1
===========

.. 
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   !! This file is generated by oca-gen-addon-readme !!
   !! changes will be overwritten.                   !!
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   !! source digest: sha256:7b6424f4b2b745e0e0bdeb5ac492b6dfaad961cb4e7e9424bdbc03d38f1c09d9
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
    :target: https://odoo-community.org/page/development-status
    :alt: Beta
.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png
    :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
    :alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fbarcode--interface-lightgray.png?logo=github
    :target: https://github.com/OCA/barcode-interface/tree/18.0/barcode_gs1
    :alt: OCA/barcode-interface
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
    :target: https://translation.odoo-community.org/projects/barcode-interface-18-0/barcode-interface-18-0-barcode_gs1
    :alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
    :target: https://runboat.odoo-community.org/builds?repo=OCA/barcode-interface&target_branch=18.0
    :alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module adds **GS1 barcode parsing** to the Barcode suite.

It registers a GS1 parser into the ``barcode_scanner`` base — through
the ``barcode_parsers`` registry, without patching the base. Scanned
GS1-128 barcodes, whether written with parenthesised application
identifiers (``(01)...(10)...``) or as raw FNC1-separated data, are
decoded into structured fields: GTIN (AI 01), batch/lot (10), serial
(21), production/pack/best-before/ expiry dates (11/13/15/16/17), count
(30/37), net weight and other measures (310n–360n), amounts payable
(390n–393n), SSCC (00) and location GLNs (410/413/414).

What each application identifier means is read from **Odoo's own GS1
nomenclature** (``barcode.nomenclature`` and its rules, as shipped by
the standard *Barcode - GS1 Nomenclature* module), so a rule added or
adapted in Settings applies to the scanner too. Identifiers the
nomenclature does not define fall back to the ones built into this
module, so an unknown AI in the middle of a barcode never cuts the rest
of the scan short.

Numeric identifiers — GTIN, SSCC, GLN — are only accepted when their
**check digit** matches, so a misread is reported instead of quietly
resolving to the wrong product.

Every screen then receives the parsed data alongside the raw scan, so a
single GS1 scan can identify the product and fill lot, expiry and
quantity at once. Non-GS1 codes fall through to the base EAN13 parser,
so the module is safe to install next to the rest of the suite.

**Table of contents**

.. contents::
   :local:

Configuration
=============

No configuration is needed: once installed, GS1 barcodes are parsed
wherever the app reads a scan. Two things can be adjusted.

Application identifiers
-----------------------

The application identifiers are read from a GS1
``barcode.nomenclature``: the one set on the company when it is a GS1
nomenclature, otherwise the first GS1 nomenclature found (the *Default
GS1 Nomenclature* Odoo ships). Its GS1-128 rules are fetched once, when
the barcode app opens.

To teach the scanner a new application identifier, add a rule under
*Inventory → Configuration → Barcode Nomenclatures* — no code change. A
rule whose *Type* is one the app understands (product, lot, quantity,
weighted product, priced product, package, package type, expiration
date, best before date, pack date, location, destination location) lands
on the matching field of the parsed scan (see Usage); the value of any
other rule is still available in ``ais``.

Identifiers the nomenclature does not define keep working through the
ones built into the module, and if the nomenclature cannot be read at
all the module falls back to them entirely.

Scanners that cannot send FNC1
------------------------------

GS1 ends a variable-length value with FNC1 unless it is the last element
of the barcode, and a keyboard-wedge scanner often sends nothing in its
place. Odoo has a field for exactly that — *FNC1 Separator* on the
nomenclature — so configure the scanner to send one of those characters
(``#`` out of the box) and the scan is read as printed.

Usage
=====

Install ``barcode_gs1`` alongside ``barcode_scanner`` (and a feature
module such as ``barcode_stock``). Once installed, GS1 barcodes are
parsed automatically wherever the app reads a scan.

A scanned GS1 barcode produces a parsed object such as:

::

   {
       type: "gs1",
       value: "<product code>",  // GTIN (AI 01), in the form products store
       gtin: "<GTIN>",           // the GTIN exactly as scanned (14 digits)
       productCodes: [...],      // every form the GTIN may be stored as
       lot: "<batch/lot>",       // AI 10 (falls back to the serial, AI 21)
       serial: "<serial>",       // AI 21
       expiry: "YYYY-MM-DD",     // AI 17, or 15/16 when no 17 is present
       useDate: "YYYY-MM-DD",    // AI 15 / 16 (best before, sell by)
       packDate: "YYYY-MM-DD",   // AI 13
       productionDate: "...",    // AI 11
       qty: <number>,            // AI 30 / 37; null when the label states no count
       count: <number>,          // AI 30 / 37 (pieces), kept next to the weight
       weight: <number>,         // AI 31xx–36xx, the measure of the goods
       weightUom: {id, name},    // the unit that measure is in, per the rule
       measures: [{ai, value, uom}, ...], // every measure, gross weight included
       price: <number>,          // AI 390n–393n (amount payable)
       currency: "<ISO 4217>",   // the numeric code AI 391n / 393n carries
       sscc: "<SSCC>",           // AI 00 (logistic unit)
       location: "<GLN>",        // AI 414
       locationDest: "<GLN>",    // AI 410 / 413
       ais: {"01": "...", "10": "...", ...},
       errors: [...],            // what could not be read, e.g. a bad check digit
   }

Both parenthesised barcodes — ``(01)09501101020917(10)LOT123(17)261231``
— and raw FNC1-separated scans are supported.

GS1 always carries the GTIN zero-padded to 14 digits, while a product
stores the short code printed on the item. ``value`` therefore holds the
padding-free form Odoo stores (13 digits, as ``sanitize_ean`` produces),
which is what the screens match the product against; ``productCodes``
lists the other lengths a barcode may have been stored as,
longest-standing form first.

Variable-length values
----------------------

GS1 ends a variable-length value (a lot, a serial…) with FNC1, except
when it is the last element of the barcode, where none is needed. The
parser reads it that way: up to the next separator, or to the end of the
barcode (see Configuration for scanners that cannot send FNC1).

Only when that reading is impossible — a value longer than its rule
allows — was a separator clearly dropped. The value then ends at the
next element that reads cleanly: a specific numeric identifier (never an
alphanumeric one, nor a catch-all range) with a value, a real date or a
right check digit. Anything short of that is ambiguous — ``21 5830192``
is the serial 5830192, or the serial 58 followed by a count of 192 — and
is read as GS1 says, as one value.

Misreads are refused
--------------------

A GTIN, SSCC or GLN is only accepted when its check digit (GS1 modulo
10) matches. A misread identifier is left empty and reported in
``errors`` instead of resolving to the wrong product or pallet.

In the warehouse app
--------------------

What the warehouse app does with it (with ``barcode_stock`` installed):

- the quantity picked is the piece count the label states (AI 30/37). A
  label without one picks a single unit, or the pack's quantity when its
  GTIN is a packaging barcode. A measure such as a net weight is decoded
  but not taken as the quantity: that depends on the unit the product is
  stocked in;
- the lot or serial is looked up for the scanned product and preselected
  in the move wizard; on a receipt an unknown lot opens the create-lot
  flow with the name and, when ``product_expiry`` is installed, the
  expiry date prefilled;
- on a delivery or an internal transfer, a lot that is not available is
  reported instead of silently picking another one.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/barcode-interface/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/barcode-interface/issues/new?body=module:%20barcode_gs1%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* Binhex

Contributors
------------

- `Antonio David Ruban Espinal <https://github.com/antoniodavid>`__
- `Zuzanna Elzbieta Szalaty
  Szalaty <https://github.com/szalatyzuzanna>`__

Maintainers
-----------

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
   :alt: Odoo Community Association
   :target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

.. |maintainer-szalatyzuzanna| image:: https://github.com/szalatyzuzanna.png?size=40px
    :target: https://github.com/szalatyzuzanna
    :alt: szalatyzuzanna

Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-szalatyzuzanna| 

This module is part of the `OCA/barcode-interface <https://github.com/OCA/barcode-interface/tree/18.0/barcode_gs1>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
