[IMP] product_expiry, stock: print GS1 datamatrices for Lot/SNs
When printing Lot/SNs barcodes, it's sometimes desired that we print a GS1 compliant datamatrix with the following info (when applicable): Product barcode, Lot/SN barcode, Best By Date, Expiration Date For flexibility, a setting has been added for when the GS1 datamatrix should print instead of 1D barcode. Note that datamatrix will automatically exclude invalid product barcodes (i.e. non-EAN compliant) and datamatrix size can vary based on amount of data in datamatrix (so size has been set to accomodate expected largest gs1 compliant datamatrix possible). If it appears that datamatrix cannot be created, then default to standard 1D barcode. Note that zpl printer has built in datamatrix creation command, so we can always assume they will print correctly. Part of Task: 2494740 Part-of: odoo/odoo#82389
This commit is contained in:
@@ -11,46 +11,60 @@
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
<xpath expr="//t[@name='gs1_datamatrix_lot']" position="before">
|
||||
<t t-if="o.use_expiration_date">
|
||||
<t t-if="o.use_date" t-set="final_barcode" t-value="(final_barcode or '') + '15' + o.use_date.strftime('%y%m%d')"/>
|
||||
<t t-if="o.expiration_date" t-set="final_barcode" t-value="(final_barcode or '') + '17' + o.expiration_date.strftime('%y%m%d')"/>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="label_lot_template_view_expiry" inherit_id="stock.label_lot_template_view">
|
||||
<xpath expr="//t" position="replace">
|
||||
<t t-foreach="docs" t-as="lot">
|
||||
<t t-translation="off">
|
||||
^XA
|
||||
^FO100,50
|
||||
^A0N,44,33^FD<t t-esc="lot.product_id.display_name"/>^FS
|
||||
^FO100,100
|
||||
^A0N,44,33^FDLN/SN: <t t-esc="lot.name"/>^FS
|
||||
<t t-if="lot.use_expiration_date and lot.use_date">
|
||||
<xpath expr="//t[@name='datamatrix_lot']" position="before">
|
||||
<t t-if="lot.use_expiration_date">
|
||||
<t t-if="lot.use_date">
|
||||
<t t-set="final_barcode" t-value="(final_barcode or '') + '15' + lot.use_date.strftime('%y%m%d')"/>
|
||||
^FO100,150
|
||||
^A0N,44,33^FDBest before: <t t-esc="lot.use_date" t-options='{"widget": "date"}'/>^FS
|
||||
<t t-if="lot.expiration_date">
|
||||
^A0N,44,33^FDBest before: <t t-out="lot.use_date" t-options='{"widget": "date"}'/>^FS
|
||||
</t>
|
||||
<t t-if="lot.expiration_date">
|
||||
<t t-set="final_barcode" t-value="(final_barcode or '') + '17' + lot.expiration_date.strftime('%y%m%d')"/>
|
||||
<t t-if="not lot.use_date">
|
||||
^FO100,150
|
||||
</t>
|
||||
<t t-else="">
|
||||
^FO100,200
|
||||
^A0N,44,33^FDUse by: <t t-esc="lot.expiration_date" t-options='{"widget": "date"}'/>^FS
|
||||
^FO100,250^BY3
|
||||
^BCN,100,Y,N,N
|
||||
^FD<t t-esc="lot.name"/>^FS
|
||||
</t>
|
||||
<t t-else="">
|
||||
^FO100,200^BY3
|
||||
^BCN,100,Y,N,N
|
||||
^FD<t t-esc="lot.name"/>^FS
|
||||
</t>
|
||||
</t>
|
||||
<t t-elif="lot.use_expiration_date and lot.expiration_date">
|
||||
</t>
|
||||
^A0N,44,33^FDUse by: <t t-out="lot.expiration_date" t-options='{"widget": "date"}'/>^FS
|
||||
</t>
|
||||
</t>
|
||||
</xpath>
|
||||
<xpath expr="//t[@name='code128_barcode']" position="before">
|
||||
<t t-elif="lot.use_expiration_date and (lot.use_date or lot.expiration_date)">
|
||||
^FO100,50
|
||||
^A0N,44,33^FD<t t-out="lot.product_id.display_name"/>^FS
|
||||
^FO100,100
|
||||
^A0N,44,33^FDLN/SN: <t t-out="lot.name"/>^FS
|
||||
<t t-if="lot.use_date">
|
||||
^FO100,150
|
||||
^A0N,44,33^FDUse by: <t t-esc="lot.expiration_date" t-options='{"widget": "date"}'/>^FS
|
||||
^A0N,44,33^FDBest before: <t t-out="lot.use_date" t-options='{"widget": "date"}'/>^FS
|
||||
<t t-if="lot.expiration_date">
|
||||
^FO100,200
|
||||
^A0N,44,33^FDUse by: <t t-out="lot.expiration_date" t-options='{"widget": "date"}'/>^FS
|
||||
^FO100,250^BY3
|
||||
</t>
|
||||
<t t-else="">
|
||||
^FO100,200^BY3
|
||||
</t>
|
||||
^BCN,100,Y,N,N
|
||||
^FD<t t-out="lot.name"/>^FS
|
||||
</t>
|
||||
<t t-elif="lot.expiration_date">
|
||||
^FO100,150
|
||||
^A0N,44,33^FDUse by: <t t-out="lot.expiration_date" t-options='{"widget": "date"}'/>^FS
|
||||
^FO100,200^BY3
|
||||
^BCN,100,Y,N,N
|
||||
^FD<t t-esc="lot.name"/>^FS
|
||||
</t>
|
||||
<t t-else="">
|
||||
^FO100,150^BY3
|
||||
^BCN,100,Y,N,N
|
||||
^FD<t t-esc="lot.name"/>^FS
|
||||
</t>
|
||||
^XZ
|
||||
^FD<t t-out="lot.name"/>^FS
|
||||
</t>
|
||||
</t>
|
||||
</xpath>
|
||||
|
||||
@@ -12,6 +12,8 @@ class ResConfigSettings(models.TransientModel):
|
||||
help="Track following dates on lots & serial numbers: best before, removal, end of life, alert. \n Such dates are set automatically at lot/serial number creation based on values set on the product (in days).")
|
||||
group_stock_production_lot = fields.Boolean("Lots & Serial Numbers",
|
||||
implied_group='stock.group_production_lot')
|
||||
group_stock_lot_print_gs1 = fields.Boolean("Print GS1 Barcodes for Lots & Serial Numbers",
|
||||
implied_group='stock.group_stock_lot_print_gs1')
|
||||
group_lot_on_delivery_slip = fields.Boolean("Display Lots & Serial Numbers on Delivery Slips",
|
||||
implied_group='stock.group_lot_on_delivery_slip', group="base.group_user,base.group_portal")
|
||||
group_stock_tracking_lot = fields.Boolean("Packages",
|
||||
|
||||
@@ -38,17 +38,29 @@
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="label_lot_template_view">
|
||||
<t t-foreach="docs" t-as="lot">
|
||||
<t t-translation="off">
|
||||
^XA
|
||||
^FO100,50
|
||||
^A0N,44,33^FD<t t-esc="lot.product_id.display_name"/>^FS
|
||||
^A0N,44,33^FD<t t-out="lot.product_id.display_name"/>^FS
|
||||
^FO100,100
|
||||
^A0N,44,33^FDLN/SN: <t t-esc="lot.name"/>^FS
|
||||
^A0N,44,33^FDLN/SN: <t t-out="lot.name"/>^FS
|
||||
<t t-if="env.user.has_group('stock.group_stock_lot_print_gs1')">
|
||||
<t t-if="lot.product_id.valid_ean" t-set="final_barcode" t-value="'01' + '0' * (14 - len(lot.product_id.barcode)) + lot.product_id.barcode"/>
|
||||
<!-- TODO: must keep lot/sn as last value in barcode because we cannot pad '0's without changing lot/sn name until we can scan in FNC1. -->
|
||||
<t t-if="lot.product_id.tracking == 'lot'" name="datamatrix_lot" t-set="final_barcode" t-value="(final_barcode or '') + '10' + lot.name"/>
|
||||
<t t-elif="lot.product_id.tracking == 'serial'" t-set="final_barcode" t-value="(final_barcode or '') + '21' + lot.name"/>
|
||||
^FO425,150^BY3
|
||||
^BXN,8,200
|
||||
^FD<t t-out="final_barcode"/>^FS
|
||||
</t>
|
||||
<t t-else="" name="code128_barcode">
|
||||
^FO100,150^BY3
|
||||
^BCN,100,Y,N,N
|
||||
^FD<t t-esc="lot.name"/>^FS
|
||||
^FD<t t-out="lot.name"/>^FS
|
||||
</t>
|
||||
^XZ
|
||||
</t>
|
||||
</t>
|
||||
|
||||
@@ -18,12 +18,22 @@
|
||||
<t t-set="o" t-value="page_docs[0]"/>
|
||||
</t>
|
||||
<td t-att-style="barcode_index >= len(page_docs) and 'visibility:hidden'">
|
||||
<div t-att-style="'width:43mm; height:19mm; border: 1px solid %s;' % (o.env.user.company_id.primary_color or 'black')">
|
||||
<div t-att-style="'position:relative; width:43mm; height:19mm; border: 1px solid %s;' % (o.env.user.company_id.primary_color or 'black')">
|
||||
<div class="o_label_4x12" t-field="o.product_id.display_name"/>
|
||||
<div class="o_label_4x12" name="lot_name">
|
||||
LN/SN: <span t-field="o.name"/>
|
||||
</div>
|
||||
<div t-field="o.name" t-options="{'widget': 'barcode', 'img_style': 'width:100%; height:35%'}"/>
|
||||
<t t-if="env.user.has_group('stock.group_stock_lot_print_gs1') and env['ir.actions.report'].datamatrix_available()">
|
||||
<!-- ensure we clear barcode string when multi-record print -->
|
||||
<t t-set="final_barcode" t-value="''"/>
|
||||
<t t-if="o.product_id.valid_ean" t-set="final_barcode" t-value="'01' + '0' * (14 - len(o.product_id.barcode)) + o.product_id.barcode"/>
|
||||
<t name="gs1_datamatrix_lot" t-if="o.product_id.tracking == 'lot'" t-set="final_barcode" t-value="(final_barcode or '') + '10' + o.name"/>
|
||||
<t t-elif="o.product_id.tracking == 'serial'" t-set="final_barcode" t-value="(final_barcode or '') + '21' + o.name"/>
|
||||
<div t-if="final_barcode" t-att-style="'position:absolute; right:.5px; bottom:.5px'" t-out="final_barcode" t-options="{'widget': 'barcode', 'symbology': 'DataMatrix', 'width': 45, 'height': 45}"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div t-field="o.name" t-options="{'widget': 'barcode', 'img_style': 'width:100%; height:35%'}"/>
|
||||
</t>
|
||||
</div>
|
||||
</td>
|
||||
</t>
|
||||
|
||||
@@ -34,6 +34,11 @@
|
||||
<field name="category_id" ref="base.module_category_hidden"/>
|
||||
</record>
|
||||
|
||||
<record id="group_stock_lot_print_gs1" model="res.groups">
|
||||
<field name="name">Print GS1 Barcodes for Lot & Serial Numbers</field>
|
||||
<field name="category_id" ref="base.module_category_hidden"/>
|
||||
</record>
|
||||
|
||||
<record id="group_lot_on_delivery_slip" model="res.groups">
|
||||
<field name="name">Display Serial & Lot Number in Delivery Slips</field>
|
||||
<field name="category_id" ref="base.module_category_hidden"/>
|
||||
|
||||
@@ -335,6 +335,13 @@
|
||||
<div class="text-muted">
|
||||
Get a full traceability from vendors to customers
|
||||
</div>
|
||||
<div class="row mt-2" attrs="{'invisible': [('group_stock_production_lot','=',False)]}">
|
||||
<field name="group_stock_lot_print_gs1" class="col-lg-1 ml16 mr0"/>
|
||||
<div class="col pl-0">
|
||||
<label for="group_stock_lot_print_gs1"/>
|
||||
<div class="text-muted">Use GS1 nomenclature datamatrix whenever barcodes are printed for lots and serial numbers. Printing datamatrix requires extra software. If software can't be found then 1D barcodes will be printed.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 o_setting_box"
|
||||
|
||||
Reference in New Issue
Block a user