Skip to content

Commit d8e9f46

Browse files
[18.0][MIG] product_label_image: Migration to v18.0
1 parent 30a2052 commit d8e9f46

File tree

9 files changed

+229
-0
lines changed

9 files changed

+229
-0
lines changed

product_label_image/README.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
===================
2+
Product Label Image
3+
===================
4+
5+
Product barcode print with product image

product_label_image/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import reports, wizard
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "Product Label Image",
3+
"category": "other",
4+
"version": "18.0.1.0.1",
5+
"summary": """Prints product barcode along with product image""",
6+
"author": "Nitrokey GmbH, Odoo Community Association (OCA)",
7+
"website": "https://github.com/Nitrokey/odoo-modules",
8+
"license": "AGPL-3",
9+
"depends": ["product"],
10+
"data": [
11+
"reports/product_template_report.xml",
12+
],
13+
"assets": {
14+
"web.report_assets_common": [
15+
"product_label_image/static/src/scss/product_label_image.scss"
16+
],
17+
},
18+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import product_label_report
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from collections import defaultdict
2+
3+
from odoo import _, models
4+
from odoo.exceptions import UserError
5+
6+
7+
def _prepare_data(env, data):
8+
# change product ids by actual product object to get access to fields in xml
9+
# template we needed to pass ids because reports only accepts native python
10+
# types (int, float, strings, ...)
11+
if data.get("active_model") == "product.template":
12+
Product = env["product.template"].with_context(display_default_code=False)
13+
elif data.get("active_model") == "product.product":
14+
Product = env["product.product"].with_context(display_default_code=False)
15+
else:
16+
raise UserError(
17+
_("Product model not defined, Please contact your administrator.")
18+
)
19+
20+
total, quantity_by_product = 0, defaultdict(list)
21+
for p, q in data.get("quantity_by_product", {}).items():
22+
product = Product.browse(int(p))
23+
quantity_by_product[product].append((product.barcode, q))
24+
total += q
25+
if data.get("custom_barcodes"):
26+
# we expect custom barcodes format as: {product: [(barcode, qty_of_barcode)]}
27+
for product, barcodes_qtys in data.get("custom_barcodes").items():
28+
quantity_by_product[Product.browse(int(product))] += barcodes_qtys
29+
total += sum(qty for _, qty in barcodes_qtys)
30+
31+
layout_wizard = env["product.label.layout"].browse(data.get("layout_wizard"))
32+
if not layout_wizard:
33+
return {}
34+
35+
return {
36+
"quantity": quantity_by_product,
37+
"rows": layout_wizard.rows,
38+
"columns": layout_wizard.columns,
39+
"page_numbers": (total - 1) // (layout_wizard.rows * layout_wizard.columns) + 1,
40+
"price_included": data.get("price_included"),
41+
"extra_html": layout_wizard.extra_html,
42+
}
43+
44+
45+
class ReportProductTemplateLabelImage4x6(models.AbstractModel):
46+
_name = "report.product_label_image.producttemplatelabel_image_4x6"
47+
_description = "Product Label Report"
48+
49+
def _get_report_values(self, docids, data):
50+
return _prepare_data(self.env, data)
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<odoo>
3+
<template id="report_simple_label_image_4x6">
4+
<tr>
5+
<td t-att-style="make_invisible and 'visibility:hidden;'">
6+
<div class="row o_firstdiv">
7+
<div class="o_seconddiv">
8+
<div class="o_thirddiv">
9+
<strong t-field="product.display_name" />
10+
</div>
11+
<div class="text-center">
12+
<t t-if="barcode">
13+
<div
14+
class="o_barcode"
15+
t-out="barcode"
16+
t-options="{'widget': 'barcode', 'symbology': 'auto', 'img_style': 'width:71mm; height:15mm;'}"
17+
/>
18+
<span class="text-center" t-out="barcode" />
19+
</t>
20+
</div>
21+
</div>
22+
<t t-if="product and product.image_512">
23+
<div class="o_product_img_div1">
24+
<div class="text-center align-middle img_div2">
25+
<img
26+
class="o_product_picture"
27+
t-att-src="'data:image/png;base64,' + (product.image_512.decode('utf-8') if isinstance(product.image_512, bytes) else product.image_512 or '')"
28+
t-attf-style="max-width: 100%; max-height: 100%; object-fit: contain;"
29+
/>
30+
</div>
31+
</div>
32+
</t>
33+
</div>
34+
</td>
35+
</tr>
36+
</template>
37+
38+
<template id="report_productlabel_image_4x6">
39+
<t t-call="web.html_container">
40+
<t t-foreach="quantity.items()" t-as="barcode_and_qty_by_product">
41+
<t t-set="product" t-value="barcode_and_qty_by_product[0]" />
42+
<t t-foreach="barcode_and_qty_by_product[1]" t-as="barcode_and_qty">
43+
<t t-set="barcode" t-value="barcode_and_qty[0]" />
44+
<t t-foreach="range(barcode_and_qty[1])" t-as="qty">
45+
<t t-call="product_label_image.report_simple_label_image_4x6" />
46+
</t>
47+
</t>
48+
</t>
49+
</t>
50+
</template>
51+
52+
<template id="producttemplatelabel_image_4x6">
53+
<t t-call="web.basic_layout">
54+
<div class="page">
55+
<t t-call="product_label_image.report_productlabel_image_4x6">
56+
<t t-set="products" t-value="products" />
57+
</t>
58+
</div>
59+
</t>
60+
</template>
61+
62+
<record id="report_product_label_image_4x6" model="ir.actions.report">
63+
<field name="name">Product Label (PDF)</field>
64+
<field name="model">product.template</field>
65+
<field name="report_type">qweb-pdf</field>
66+
<field
67+
name="report_name"
68+
>product_label_image.producttemplatelabel_image_4x6</field>
69+
<field
70+
name="report_file"
71+
>product_label_image.producttemplatelabel_image_4x6</field>
72+
<field name="paperformat_id" ref="product.paperformat_label_sheet" />
73+
<field name="print_report_name">'Products Labels - %s' % (object.name)</field>
74+
<field name="binding_type">report</field>
75+
</record>
76+
</odoo>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
div {
2+
&.o_firstdiv {
3+
width: 100%;
4+
margin-bottom: 200px;
5+
}
6+
&.o_seconddiv {
7+
width: 310px;
8+
height: 210px;
9+
border: 2px solid #555555 !important;
10+
padding: 2px 4px;
11+
}
12+
&.o_thirddiv {
13+
height: 86px;
14+
margin-bottom: 18px;
15+
overflow: hidden;
16+
background-color: ghostwhite;
17+
& > strong {
18+
font-size: 16px;
19+
}
20+
}
21+
&.o_barcode {
22+
padding: 5px;
23+
}
24+
&.o_product_img_div1 {
25+
width: 310px;
26+
height: 210px;
27+
border: 2px solid #555555;
28+
border-left: 1px;
29+
}
30+
&.img_div2 {
31+
height: 10rem;
32+
}
33+
& > img.o_product_picture {
34+
height: 190px;
35+
width: auto;
36+
margin-top: 8%;
37+
}
38+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import product_label_layout
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from odoo import _, fields, models
2+
from odoo.exceptions import UserError
3+
4+
5+
class ProductLabelLayout(models.TransientModel):
6+
_inherit = "product.label.layout"
7+
8+
print_format = fields.Selection(
9+
selection_add=[("4x6", "4x6")],
10+
default="4x6",
11+
ondelete={"4x6": "set default"},
12+
)
13+
14+
def _prepare_report_data(self):
15+
if self.custom_quantity <= 0:
16+
raise UserError(_("You need to set a positive quantity."))
17+
18+
# Get layout grid
19+
if self.print_format != "4x6":
20+
return super()._prepare_report_data()
21+
22+
xml_id = "product_label_image.report_product_label_image_4x6"
23+
24+
active_model = ""
25+
if self.product_tmpl_ids:
26+
products = self.product_tmpl_ids.ids
27+
active_model = "product.template"
28+
elif self.product_ids:
29+
products = self.product_ids.ids
30+
active_model = "product.product"
31+
32+
# Build data to pass to the report
33+
data = {
34+
"active_model": active_model,
35+
"quantity_by_product": {p: self.custom_quantity for p in products},
36+
"layout_wizard": self.id,
37+
"price_included": "xprice" in self.print_format,
38+
}
39+
return xml_id, data

0 commit comments

Comments
 (0)