Initial commit
This commit is contained in:
2
garazd_product_label/wizard/__init__.py
Normal file
2
garazd_product_label/wizard/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from . import print_product_label_line
|
||||
from . import print_product_label
|
||||
184
garazd_product_label/wizard/print_product_label.py
Normal file
184
garazd_product_label/wizard/print_product_label.py
Normal file
@@ -0,0 +1,184 @@
|
||||
# Copyright © 2018 Garazd Creation (<https://garazd.biz>)
|
||||
# @author: Yurii Razumovskyi (<support@garazd.biz>)
|
||||
# @author: Iryna Razumovska (<support@garazd.biz>)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.html).
|
||||
|
||||
import base64
|
||||
from typing import List
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.addons.base.models.res_partner import _lang_get
|
||||
|
||||
|
||||
class PrintProductLabel(models.TransientModel):
|
||||
_name = "print.product.label"
|
||||
_description = 'Wizard to print Product Labels'
|
||||
|
||||
@api.model
|
||||
def _complete_label_fields(self, label_ids: List[int]) -> List[int]:
|
||||
"""Set additional fields for product labels. Method to override."""
|
||||
# Increase a label sequence
|
||||
labels = self.env['print.product.label.line'].browse(label_ids)
|
||||
for seq, label in enumerate(labels):
|
||||
label.sequence = 1000 + seq
|
||||
return label_ids
|
||||
|
||||
@api.model
|
||||
def _get_product_label_ids(self):
|
||||
res = []
|
||||
# flake8: noqa: E501
|
||||
if self._context.get('active_model') == 'product.template':
|
||||
products = self.env[self._context.get('active_model')].browse(
|
||||
self._context.get('default_product_template_ids')
|
||||
)
|
||||
for product in products:
|
||||
label = self.env['print.product.label.line'].create({
|
||||
'product_id': product.product_variant_id.id,
|
||||
})
|
||||
res.append(label.id)
|
||||
elif self._context.get('active_model') == 'product.product':
|
||||
products = self.env[self._context.get('active_model')].browse(
|
||||
self._context.get('default_product_product_ids')
|
||||
)
|
||||
for product in products:
|
||||
label = self.env['print.product.label.line'].create({'product_id': product.id})
|
||||
res.append(label.id)
|
||||
res = self._complete_label_fields(res)
|
||||
return res
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
default_vals = super(PrintProductLabel, self).default_get(fields_list)
|
||||
if 'label_type_id' in fields_list and not default_vals.get('label_type_id'):
|
||||
default_vals['label_type_id'] = self.env.ref('garazd_product_label.type_product').id
|
||||
return default_vals
|
||||
|
||||
name = fields.Char(default='Print Product Labels')
|
||||
message = fields.Char(readonly=True)
|
||||
output = fields.Selection(selection=[('pdf', 'PDF')], string='Print to', default='pdf')
|
||||
mode = fields.Selection(
|
||||
selection=[('product.product', 'Products')],
|
||||
help='Technical field to specify the mode of the label printing wizard.',
|
||||
default='product.product',
|
||||
)
|
||||
label_type_id = fields.Many2one(comodel_name='print.label.type', string='Label Type')
|
||||
label_ids = fields.One2many(
|
||||
comodel_name='print.product.label.line',
|
||||
inverse_name='wizard_id',
|
||||
string='Labels for Products',
|
||||
default=_get_product_label_ids,
|
||||
)
|
||||
report_id = fields.Many2one(
|
||||
comodel_name='ir.actions.report',
|
||||
string='Label',
|
||||
domain=[('model', '=', 'print.product.label.line')],
|
||||
)
|
||||
is_template_report = fields.Boolean(compute='_compute_is_template_report')
|
||||
qty_per_product = fields.Integer(
|
||||
string='Label quantity per product',
|
||||
default=1,
|
||||
)
|
||||
# Options
|
||||
humanreadable = fields.Boolean(
|
||||
string='Human readable barcode',
|
||||
help='Print digital code of barcode.',
|
||||
default=False,
|
||||
)
|
||||
border_width = fields.Integer(
|
||||
string='Border',
|
||||
help='Border width for labels (in pixels). Set "0" for no border.'
|
||||
)
|
||||
lang = fields.Selection(
|
||||
selection=_lang_get,
|
||||
string='Language',
|
||||
help="The language that will be used to translate label names.",
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
comodel_name='res.company',
|
||||
help='Specify a company for product labels.'
|
||||
)
|
||||
|
||||
@api.depends('report_id')
|
||||
def _compute_is_template_report(self):
|
||||
for wizard in self:
|
||||
# flake8: noqa: E501
|
||||
wizard.is_template_report = self.report_id == self.env.ref('garazd_product_label.action_report_product_label_from_template')
|
||||
|
||||
def get_labels_to_print(self):
|
||||
self.ensure_one()
|
||||
labels = self.label_ids.filtered(lambda l: l.selected and l.qty)
|
||||
if not labels:
|
||||
raise UserError(_('Nothing to print, set the quantity of labels in the table.'))
|
||||
return labels
|
||||
|
||||
def _get_report_action_params(self):
|
||||
"""Return two params for a report action: record "ids" and "data"."""
|
||||
self.ensure_one()
|
||||
return self.get_labels_to_print().ids, None
|
||||
|
||||
def _prepare_report(self):
|
||||
self.ensure_one()
|
||||
output_mode = self._context.get('print_mode', 'pdf')
|
||||
if not self.report_id:
|
||||
raise UserError(_('Please select a label type.'))
|
||||
report = self.report_id.with_context(discard_logo_check=True, lang=self.lang)
|
||||
report.sudo().write({'report_type': f'qweb-{output_mode}'})
|
||||
return report
|
||||
|
||||
def action_print(self):
|
||||
"""Print labels."""
|
||||
self.ensure_one()
|
||||
report = self._prepare_report()
|
||||
return report.report_action(*self._get_report_action_params())
|
||||
|
||||
def action_set_qty(self):
|
||||
"""Set a specific number of labels for all lines."""
|
||||
self.ensure_one()
|
||||
self.label_ids.write({'qty': self.qty_per_product})
|
||||
|
||||
def action_restore_initial_qty(self):
|
||||
"""Restore the initial number of labels for all lines."""
|
||||
self.ensure_one()
|
||||
for label in self.label_ids:
|
||||
if label.qty_initial:
|
||||
label.update({'qty': label.qty_initial})
|
||||
|
||||
@api.model
|
||||
def get_quick_report_action(
|
||||
self, model_name: str, ids: List[int], qty: int = None, template=None, force_direct: bool = False,
|
||||
):
|
||||
""" Allow to get a report action for custom labels. Method to override. """
|
||||
wizard = self.with_context(
|
||||
**{'active_model': model_name, f'default_{model_name.replace(".", "_")}_ids': ids}
|
||||
).create({'report_id': self.env.ref('garazd_product_label.action_report_product_label_50x38').id})
|
||||
return wizard.action_print()
|
||||
|
||||
@api.model
|
||||
def _set_sequence(self, lbl, seq, processed):
|
||||
if lbl in processed:
|
||||
return seq, processed
|
||||
lbl.sequence = seq
|
||||
seq += 1
|
||||
processed += lbl
|
||||
return seq, processed
|
||||
|
||||
def action_sort_by_product(self):
|
||||
self.ensure_one()
|
||||
sequence = 1000
|
||||
processed_labels = self.env['print.product.label.line'].browse()
|
||||
# flake8: noqa: E501
|
||||
for label in self.label_ids:
|
||||
sequence, processed_labels = self._set_sequence(label, sequence, processed_labels)
|
||||
tmpl_labels = self.label_ids.filtered(lambda l: l.product_id.product_tmpl_id == label.product_id.product_tmpl_id).sorted(lambda l: l.product_id.id, reverse=True) - label
|
||||
for tmpl_label in tmpl_labels:
|
||||
sequence, processed_labels = self._set_sequence(tmpl_label, sequence, processed_labels)
|
||||
product_labels = tmpl_labels.filtered(lambda l: l.product_id == label.product_id) - tmpl_label
|
||||
for product_label in product_labels:
|
||||
sequence, processed_labels = self._set_sequence(product_label, sequence, processed_labels)
|
||||
|
||||
def get_pdf(self):
|
||||
self.ensure_one()
|
||||
report = self.with_context(print_mode='pdf')._prepare_report()
|
||||
pdf_data = report._render_qweb_pdf(report, *self._get_report_action_params())
|
||||
return base64.b64encode(pdf_data[0])
|
||||
48
garazd_product_label/wizard/print_product_label_line.py
Normal file
48
garazd_product_label/wizard/print_product_label_line.py
Normal file
@@ -0,0 +1,48 @@
|
||||
# Copyright © 2018 Garazd Creation (<https://garazd.biz>)
|
||||
# @author: Yurii Razumovskyi (<support@garazd.biz>)
|
||||
# @author: Iryna Razumovska (<support@garazd.biz>)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.html).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class PrintProductLabelLine(models.TransientModel):
|
||||
_name = "print.product.label.line"
|
||||
_description = 'Line with a Product Label Data'
|
||||
_order = 'sequence'
|
||||
|
||||
sequence = fields.Integer(default=900)
|
||||
selected = fields.Boolean(string='Print', default=True)
|
||||
wizard_id = fields.Many2one(comodel_name='print.product.label') # Do not make required
|
||||
product_id = fields.Many2one(comodel_name='product.product', required=True)
|
||||
barcode = fields.Char(compute='_compute_barcode')
|
||||
qty_initial = fields.Integer(string='Initial Qty', default=1)
|
||||
qty = fields.Integer(string='Label Qty', default=1)
|
||||
custom_value = fields.Char(help="This field can be filled manually to use in label templates.")
|
||||
company_id = fields.Many2one(comodel_name='res.company', compute='_compute_company_id')
|
||||
# Allow users to specify a partner to use it on label templates
|
||||
partner_id = fields.Many2one(comodel_name='res.partner', readonly=False)
|
||||
|
||||
@api.depends('wizard_id.company_id')
|
||||
def _compute_company_id(self):
|
||||
for label in self:
|
||||
label.company_id = label.wizard_id.company_id.id \
|
||||
if label.wizard_id.company_id else self.env.user.company_id.id
|
||||
|
||||
@api.depends('product_id')
|
||||
def _compute_barcode(self):
|
||||
for label in self:
|
||||
label.barcode = label.product_id.barcode
|
||||
|
||||
def action_plus_qty(self):
|
||||
self.ensure_one()
|
||||
if not self.qty:
|
||||
self.update({'selected': True})
|
||||
self.update({'qty': self.qty + 1})
|
||||
|
||||
def action_minus_qty(self):
|
||||
self.ensure_one()
|
||||
if self.qty > 0:
|
||||
self.update({'qty': self.qty - 1})
|
||||
if not self.qty:
|
||||
self.update({'selected': False})
|
||||
108
garazd_product_label/wizard/print_product_label_views.xml
Normal file
108
garazd_product_label/wizard/print_product_label_views.xml
Normal file
@@ -0,0 +1,108 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="print_product_label_view_form" model="ir.ui.view">
|
||||
<field name="name">print.product.label.view.form</field>
|
||||
<field name="model">print.product.label</field>
|
||||
<field name="arch" type="xml">
|
||||
<form create="false" string="Print Product Labels">
|
||||
<header>
|
||||
<button name="action_print"
|
||||
string="Print"
|
||||
help="Print product labels"
|
||||
type="object"
|
||||
icon="fa-print"
|
||||
class="btn-primary mr8"/>
|
||||
<button name="action_print"
|
||||
string="Preview"
|
||||
context="{'print_mode': 'html'}"
|
||||
help="Preview product labels"
|
||||
type="object"
|
||||
icon="fa-search"
|
||||
class="border btn-light mr8"/>
|
||||
<field name="label_type_id" widget="selection_badge" invisible="1"/> <!-- Technical field to specify the label type -->
|
||||
</header>
|
||||
<div class="oe_button_box" name="button_box"/>
|
||||
<field name="mode" invisible="1"/> <!-- Technical field to specify the mode of the label printing wizard -->
|
||||
<field name="is_template_report" invisible="1"/> <!-- Technical field to specify if the custom label template is selected -->
|
||||
<div class="alert alert-info text-center mb-3" invisible="not message" role="alert">
|
||||
<field name="message"/>
|
||||
</div>
|
||||
<group col="6" colspan="2" name="top_group">
|
||||
<group name="output_format" col="2" colspan="1">
|
||||
<field name="output" widget="badge"/>
|
||||
</group>
|
||||
<group name="label_report" col="2" colspan="2">
|
||||
<field name="report_id" string="Label" widget="radio" />
|
||||
</group>
|
||||
<group name="label_template" col="2" colspan="2" invisible="not is_template_report">
|
||||
<label for="report_id" string="Template"/>
|
||||
<div class="o_row">
|
||||
<a name="label_builder_link" invisible="not is_template_report" href="https://garazd.biz/r/kb3" title="How to get Product Label Builder" target="_blank" rel="noopener noreferrer">
|
||||
<span>Get the Label Builder to create your own labels</span>
|
||||
</a>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
<div name="extra_action" class="oe_row">
|
||||
<button name="action_sort_by_product" title="Sort labels by a product" icon="fa-sort-amount-desc" type="object" class="btn-xs btn-light"/>
|
||||
<span class="text-muted px-3">|</span>
|
||||
<field name="qty_per_product" class="mr-2 mt-1 text-right" help="Label quantity per product" style="width: 40px !important;"/>
|
||||
<button name="action_set_qty" string="Set quantity" help="Set a certain quantity for each line." type="object" class="btn-xs btn-light mr-2"/>
|
||||
<button name="action_restore_initial_qty" title="Restore initial quantity" help="Restore initial quantity" icon="fa-undo" type="object" class="btn-xs btn-light"/>
|
||||
</div>
|
||||
<notebook>
|
||||
<page string="Labels" name="labels">
|
||||
<field name="label_ids" mode="list">
|
||||
<list editable="top" decoration-muted="qty==0">
|
||||
<field name="sequence" widget="handle" width="0.5"/>
|
||||
<field name="selected" widget="boolean_toggle"/>
|
||||
<field name="partner_id" optional="hide"/>
|
||||
<field name="product_id"/>
|
||||
<field name="barcode" optional="show"/>
|
||||
<field name="custom_value" optional="hide"/>
|
||||
<field name="company_id" groups="base.group_multi_company" optional="hide"/>
|
||||
<button name="action_minus_qty" type="object" title="Decrease Qty" icon="fa-minus" class="btn-light"/>
|
||||
<field name="qty" sum="Total" width="0.6" class="text-center font-weight-bold"/>
|
||||
<button name="action_plus_qty" type="object" title="Increase Qty" icon="fa-plus" class="btn-light"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Options" name="options">
|
||||
<group name="general_options" class="o_label_nowrap">
|
||||
<group>
|
||||
<field name="lang" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="humanreadable" widget="boolean_toggle" />
|
||||
<field name="border_width" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="company_id" widget="radio" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_print_label_from_template" model="ir.actions.act_window">
|
||||
<field name="name">Custom Product Labels</field>
|
||||
<field name="res_model">print.product.label</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">current</field>
|
||||
<field name="context">{'default_product_template_ids': context.get('active_ids', [])}</field>
|
||||
<field name="binding_model_id" ref="product.model_product_template"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
|
||||
<record id="action_print_label_from_product" model="ir.actions.act_window">
|
||||
<field name="name">Custom Product Labels</field>
|
||||
<field name="res_model">print.product.label</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">current</field>
|
||||
<field name="context">{'default_product_product_ids': context.get('active_ids', [])}</field>
|
||||
<field name="binding_model_id" ref="product.model_product_product"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user