---
title: "openepcis_connector_stock: lots and serial numbers"
description: "The bridge to Inventory. A lot becomes /01/<gtin>/10/<lot>, a serial number /01/<gtin>/21/<serial>, each a document of its own in the catalog under the product's GTIN — with the instance-level Digital Link and its QR code on the lot form, where labels are actually printed."
canonical_url: "https://openepcis.io/docs/connectors/odoo/lots-and-serial-numbers"
last_updated: "2026-10-09T10:21:45.199Z"
---

A GTIN names the *model* of a thing. The batch it came from and the single unit in front of you are one level down, and GS1 keeps that level in the Digital Link path: `/01/<gtin>` is the model, `/01/<gtin>/10/<lot>` the batch, `/01/<gtin>/21/<serial>` the unit. The catalog stores a distinct document at each level, and this addon publishes Odoo's lots and serial numbers to those paths.

<table>
<thead>
  <tr>
    <th>
      
    </th>
    
    <th>
      
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <strong>
        Module
      </strong>
    </td>
    
    <td>
      <code>
        openepcis_connector_stock
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <strong>
        Depends on
      </strong>
    </td>
    
    <td>
      <code>
        openepcis_connector
      </code>
      
      , <code>
        stock
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <strong>
        Installs
      </strong>
    </td>
    
    <td>
      Automatically, once the connector and Inventory are both present
    </td>
  </tr>
  
  <tr>
    <td>
      <strong>
        Talks to
      </strong>
    </td>
    
    <td>
      The resolver's HTTP API
    </td>
  </tr>
  
  <tr>
    <td>
      <strong>
        Source
      </strong>
    </td>
    
    <td>
      <a href="https://github.com/openepcis/openepcis-odoo/tree/18.0/openepcis_connector_stock" rel="nofollow">
        openepcis-odoo
      </a>
      
       · LGPL-3
    </td>
  </tr>
</tbody>
</table>

## Why a bridge

The base connector depends on `product` only, and `stock.lot` lives in Inventory. Rather than make every installation carry Inventory, this addon installs itself wherever both are present and stays out of the way otherwise. Nothing to choose, nothing to configure beyond what the base connector already has.

## Batch or unit

A lot has no GS1 key of its own; it *qualifies* the product's GTIN. Which qualifier it gets follows the product's tracking setting:

<table>
<thead>
  <tr>
    <th>
      Product is tracked
    </th>
    
    <th>
      The lot becomes
    </th>
    
    <th>
      Path
    </th>
    
    <th>
      Level
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      By unique serial number
    </td>
    
    <td>
      A serial, AI 21
    </td>
    
    <td>
      <code>
        /01/<gtin>/21/<serial>
      </code>
    </td>
    
    <td>
      SGTIN — one unit
    </td>
  </tr>
  
  <tr>
    <td>
      By lots
    </td>
    
    <td>
      A batch, AI 10
    </td>
    
    <td>
      <code>
        /01/<gtin>/10/<lot>
      </code>
    </td>
    
    <td>
      LGTIN — a set
    </td>
  </tr>
  
  <tr>
    <td>
      Not at all, but a lot record was created on purpose
    </td>
    
    <td>
      A batch, AI 10
    </td>
    
    <td>
      <code>
        /01/<gtin>/10/<lot>
      </code>
    </td>
    
    <td>
      LGTIN
    </td>
  </tr>
</tbody>
</table>

The document carries the qualifier as a term of its own — `hasBatchLotNumber` or `hasSerialNumber` — so it says what its URI says. That is also what lets the resolver's linkset point at the instance rather than redirecting up to the GTIN: a scan of a lot label lands on the lot, not on the model.

## The product goes first

An instance document hangs off the product's GTIN, so an instance under a GTIN the catalog does not hold points at a model nobody can resolve. A lot whose product is not published yet is therefore **not an error**. It waits, says so on its form, and follows on its own the moment the product lands in the catalog.

The same rules as for products apply: publishing is opt-in per lot, a scheduled action delivers every five minutes, and *Publish now* does it at once. The instance-level Digital Link and its QR code appear on the lot form — the place where a warehouse actually prints labels.

## Fields on a lot

Instance fields are ordinary rows in the [field mapping](/docs/connectors/odoo/connector#the-field-mapping-is-data), on the `stock.lot` model, and an administrator edits them the same way. The dates that Odoo's Expiration Dates app keeps on a lot are added by a second, data-only bridge, [`openepcis_connector_product_expiry`](/docs/connectors/odoo/expiration-dates), so a database without that app never carries mapping rows pointing at fields it does not have.

## Events are a separate switch

Reporting what happens to a lot — that it arrived, was packed, shipped — is the job of [`openepcis_connector_events`](/docs/connectors/odoo/visibility-events), and it is a separate decision. An event names the lot whether or not an instance document exists for it; the repository stores and finds the event either way. What changes is what a phone pointed at the label reaches: something only if the instance document was published.
