[IMP] product,stock{_picking_batch}: product labels revamp
This commit removes the pdf and zpl reports for product templates and variants. Instead, labels are printed via a new wizard allowing to specify the label quantity, format and optional text. There are a bunch of usual retail label sizes in pdf or zpl code Task : 2501730 closes odoo/odoo#69690 Related: odoo/enterprise#20246 Related: odoo/upgrade#2542 Signed-off-by: William Henrotin <Whenrow@users.noreply.github.com>
This commit is contained in:
@@ -4,3 +4,4 @@
|
||||
from . import models
|
||||
from . import report
|
||||
from . import populate
|
||||
from . import wizard
|
||||
|
||||
@@ -30,6 +30,7 @@ Print product labels with barcode.
|
||||
'data/product_data.xml',
|
||||
'security/product_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'wizard/product_label_layout_views.xml',
|
||||
'views/res_config_settings_views.xml',
|
||||
'views/product_attribute_views.xml',
|
||||
'views/product_views.xml',
|
||||
@@ -40,7 +41,7 @@ Print product labels with barcode.
|
||||
'report/product_product_templates.xml',
|
||||
'report/product_template_templates.xml',
|
||||
'report/product_packaging.xml',
|
||||
'report/product_pricelist_report_templates.xml'
|
||||
'report/product_pricelist_report_templates.xml',
|
||||
],
|
||||
'demo': [
|
||||
'data/product_demo.xml',
|
||||
@@ -51,6 +52,9 @@ Print product labels with barcode.
|
||||
'web.assets_backend': [
|
||||
'product/static/src/js/**/*',
|
||||
],
|
||||
'web.report_assets_common': [
|
||||
'product/static/src/scss/report_label_sheet.scss',
|
||||
],
|
||||
'web.qunit_suite_tests': [
|
||||
'product/static/tests/**/*',
|
||||
],
|
||||
|
||||
@@ -596,6 +596,11 @@ class ProductProduct(models.Model):
|
||||
)
|
||||
return super().view_header_get(view_id, view_type)
|
||||
|
||||
def action_open_label_layout(self):
|
||||
action = self.env['ir.actions.act_window']._for_xml_id('product.action_open_label_layout')
|
||||
action['context'] = {'default_product_ids': self.ids}
|
||||
return action
|
||||
|
||||
def open_pricelist_rules(self):
|
||||
self.ensure_one()
|
||||
domain = ['|',
|
||||
|
||||
@@ -528,6 +528,11 @@ class ProductTemplate(models.Model):
|
||||
'', args=[('id', 'in', list(searched_ids))],
|
||||
operator='ilike', limit=limit, name_get_uid=name_get_uid)
|
||||
|
||||
def action_open_label_layout(self):
|
||||
action = self.env['ir.actions.act_window']._for_xml_id('product.action_open_label_layout')
|
||||
action['context'] = {'default_product_tmpl_ids': self.ids}
|
||||
return action
|
||||
|
||||
def open_pricelist_rules(self):
|
||||
self.ensure_one()
|
||||
domain = ['|',
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import product_label_report
|
||||
from . import product_pricelist_report
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import _, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
def _prepare_data(env, data):
|
||||
# change product ids by actual product object to get access to fields in xml template
|
||||
# we needed to pass ids because reports only accepts native python types (int, float, strings, ...)
|
||||
if data.get('active_model') == 'product.template':
|
||||
quantity_by_product = {env['product.template'].with_context(display_default_code=False).browse(int(p)): q for p, q in data.get('quantity_by_product').items()}
|
||||
elif data.get('active_model') == 'product.product':
|
||||
quantity_by_product = {env['product.product'].with_context(display_default_code=False).browse(int(p)): q for p, q in data.get('quantity_by_product').items()}
|
||||
else:
|
||||
raise UserError(_('Product model not defined, Please contact your administrator.'))
|
||||
layout_wizard = env['product.label.layout'].browse(data.get('layout_wizard'))
|
||||
if not layout_wizard:
|
||||
return {}
|
||||
|
||||
return {
|
||||
'quantity': quantity_by_product,
|
||||
'rows': layout_wizard.rows,
|
||||
'columns': layout_wizard.columns,
|
||||
'page_numbers': (sum(quantity_by_product.values()) - 1) // (layout_wizard.rows * layout_wizard.columns) + 1,
|
||||
'price_included': data.get('price_included'),
|
||||
'extra_html': layout_wizard.extra_html,
|
||||
}
|
||||
|
||||
class ReportProductTemplateLabel(models.AbstractModel):
|
||||
_name = 'report.product.report_producttemplatelabel'
|
||||
_description = 'Product Label Report'
|
||||
|
||||
def _get_report_values(self, docids, data):
|
||||
return _prepare_data(self.env, data)
|
||||
|
||||
class ReportProductTemplateLabelDymo(models.AbstractModel):
|
||||
_name = 'report.product.report_producttemplatelabel_dymo'
|
||||
_description = 'Product Label Report'
|
||||
|
||||
def _get_report_values(self, docids, data):
|
||||
return _prepare_data(self.env, data)
|
||||
@@ -1,75 +1,168 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<template id="report_simple_label">
|
||||
<div style="width: 32%; display: inline-table; height:14rem;">
|
||||
<table class="table table-bordered mb-0" style="border: 2px solid black;">
|
||||
<tr>
|
||||
<th class="table-active text-left" style="height: 4rem;">
|
||||
<strong t-field="product.display_name"/>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="height: 2rem">
|
||||
<strong>Price:</strong>
|
||||
<strong t-field="product.lst_price" t-options="{'widget': 'monetary', 'display_currency': product.company_id.currency_id}"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center align-middle" style="height: 6rem">
|
||||
<template id="report_simple_label2x7">
|
||||
<t t-set="barcode_size" t-value="'width:33mm;height:14mm'"/>
|
||||
<t t-set="table_style" t-value="'width:97mm;height:37.1mm;' + table_style"/>
|
||||
<td t-att-style="make_invisible and 'visibility:hidden;'" >
|
||||
<div class="o_label_full" t-att-style="table_style">
|
||||
<div class="o_label_name">
|
||||
<strong t-field="product.display_name"/>
|
||||
</div>
|
||||
<div class="o_label_data">
|
||||
<div class="text-center o_label_left_column">
|
||||
<span class="text-nowrap" t-field="product.default_code"/>
|
||||
<t t-if="product.barcode">
|
||||
<div t-field="product.barcode" t-options="{'widget': 'barcode', 'symbology': 'auto', 'width': 600, 'height': 150, 'img_style': 'width:100%;height::4rem;'}"/>
|
||||
<span t-field="product.barcode"/>
|
||||
<div t-field="product.barcode" t-options="{'widget': 'barcode', 'symbology': 'auto', 'img_style': barcode_size}"/>
|
||||
<span class="text-center" t-field="product.barcode"/>
|
||||
</t>
|
||||
<t t-else=""><span class="text-muted">No barcode available</span></t>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="text-right" style="line-height:normal">
|
||||
<div class="o_label_extra_data">
|
||||
<t t-out="extra_html"/>
|
||||
</div>
|
||||
<strong class="o_label_price" t-field="product.lst_price" t-options="{'widget': 'monetary', 'label_price': True}"/>
|
||||
</div>
|
||||
<div class="o_label_clear"></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</template>
|
||||
|
||||
<template id="report_simple_label4x7">
|
||||
<t t-set="barcode_size" t-value="'width:33mm;height:8mm'"/>
|
||||
<t t-set="table_style" t-value="'width:47mm;height:37.1mm;' + table_style"/>
|
||||
<td t-att-style="make_invisible and 'visibility:hidden;'" >
|
||||
<div class="o_label_full" t-att-style="table_style">
|
||||
<div class="o_label_name">
|
||||
<strong t-field="product.display_name"/>
|
||||
</div>
|
||||
<div class="text-right" style="padding-top:0;padding-bottom:0">
|
||||
<strong class="o_label_price_medium" t-field="product.lst_price" t-options="{'widget': 'monetary', 'label_price': True}"/>
|
||||
</div>
|
||||
<div class= "text-center o_label_small_barcode">
|
||||
<span class="text-nowrap" t-field="product.default_code"/>
|
||||
<t t-if="product.barcode">
|
||||
<div t-field="product.barcode" style="padding:0" t-options="{'widget': 'barcode', 'symbology': 'auto', 'img_style': barcode_size}"/>
|
||||
<span class="text-center" t-field="product.barcode"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</template>
|
||||
|
||||
<template id="report_simple_label4x12">
|
||||
<t t-set="barcode_size" t-value="'width:33mm;height:4mm'"/>
|
||||
<t t-set="table_style" t-value="'width:43mm;height:19mm;' + table_style"/>
|
||||
<td t-att-style="make_invisible and 'visibility:hidden;'" >
|
||||
<div class="o_label_full o_label_small_text" t-att-style="table_style">
|
||||
<div class="o_label_name">
|
||||
<strong t-field="product.display_name"/>
|
||||
</div>
|
||||
<t t-if="price_included">
|
||||
<div class="o_label_left_column">
|
||||
<span class="text-nowrap" t-field="product.default_code"/>
|
||||
</div>
|
||||
<div class="o_label_price_medium text-right">
|
||||
<strong t-field="product.lst_price" t-options="{'widget': 'monetary', 'label_price': True}"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="o_label_left_column o_label_full_with">
|
||||
<span class="text-nowrap" t-field="product.default_code"/>
|
||||
</div>
|
||||
</t>
|
||||
<div class= "text-center o_label_small_barcode">
|
||||
<t t-if="product.barcode">
|
||||
<div t-field="product.barcode" style="padding:0" t-options="{'widget': 'barcode', 'symbology': 'auto', 'img_style': barcode_size}"/>
|
||||
<span class="text-center" t-field="product.barcode"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</template>
|
||||
|
||||
<template id="report_simple_label_dymo">
|
||||
<div class="o_label_sheet o_label_dymo" t-att-style="padding_page">
|
||||
<div class="o_label_full" t-att-style="table_style">
|
||||
<div class= "text-left o_label_small_barcode">
|
||||
<t t-if="product.barcode">
|
||||
<!-- `quiet=0` to remove the left and right margins on the barcode -->
|
||||
<div t-field="product.barcode" style="padding:0" t-options="{'widget': 'barcode', 'quiet': 0, 'symbology': 'auto', 'img_style': barcode_size}"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="o_label_name" style="line-height: 130%;height:2.7em;background-color: transparent;">
|
||||
<span t-field="product.display_name"/>
|
||||
</div>
|
||||
<div class="o_label_left_column">
|
||||
<small class="text-nowrap" t-field="product.default_code"/>
|
||||
</div>
|
||||
<div class="text-right" style="padding: 0 4px;">
|
||||
<strong class="o_label_price_small" t-field="product.lst_price" t-options="{'widget': 'monetary', 'label_price': True}"/>
|
||||
<div class="o_label_extra_data">
|
||||
<t t-out="extra_html"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="report_productlabel">
|
||||
<t t-call="web.basic_layout">
|
||||
<div class="page">
|
||||
<t t-foreach="docs" t-as="product">
|
||||
<t t-call="product.report_simple_label">
|
||||
<t t-set="product" t-value="product"/>
|
||||
</t>
|
||||
<t t-call="web.html_container">
|
||||
<t t-if="columns and rows">
|
||||
<t t-if="columns == 2 and rows == 7">
|
||||
<t t-set="padding_page" t-value="'padding: 14mm 3mm'"/>
|
||||
<t t-set="report_to_call" t-value="'product.report_simple_label2x7'"/>
|
||||
</t>
|
||||
</div>
|
||||
<t t-if="columns == 4 and rows == 7">
|
||||
<t t-set="padding_page" t-value="'padding: 14mm 3mm'"/>
|
||||
<t t-set="report_to_call" t-value="'product.report_simple_label4x7'"/>
|
||||
</t>
|
||||
<t t-if="columns == 4 and rows == 12">
|
||||
<t t-set="padding_page" t-value="'padding: 20mm 8mm'"/>
|
||||
<t t-set="report_to_call" t-value="'product.report_simple_label4x12'"/>
|
||||
</t>
|
||||
<t t-foreach="range(page_numbers)" t-as="page">
|
||||
<div class="o_label_sheet" t-att-style="padding_page">
|
||||
<table class="my-0 table table-sm table-borderless">
|
||||
<t t-foreach="range(rows)" t-as="row">
|
||||
<tr>
|
||||
<t t-foreach="range(columns)" t-as="column">
|
||||
<t t-if="not current_quantity and quantity">
|
||||
<t t-set="current_data" t-value="quantity.popitem()"/>
|
||||
<t t-set="product" t-value="current_data[0]"/>
|
||||
<t t-set="current_quantity" t-value="current_data[1]"/>
|
||||
</t>
|
||||
<t t-if="current_quantity">
|
||||
<t t-set="make_invisible" t-value="False"/>
|
||||
<t t-set="current_quantity" t-value="current_quantity - 1"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-set="make_invisible" t-value="True"/>
|
||||
</t>
|
||||
<t t-set="table_style" t-value="'border: 1px solid %s;' % (product.env.user.company_id.primary_color or 'black')"/>
|
||||
<t t-call="{{report_to_call}}"/>
|
||||
</t>
|
||||
</tr>
|
||||
</t>
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="report_simple_barcode">
|
||||
<div style="width: 32%; display: inline-table; height: 10rem;">
|
||||
<table class="table table-bordered mb-0" style="border: 2px solid black;">
|
||||
<tr>
|
||||
<th class="table-active text-left" style="height: 4rem;">
|
||||
<strong t-field="product.display_name"/>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center align-middle" style="height: 6rem;">
|
||||
<t t-if="product.barcode">
|
||||
<div t-field="product.barcode" t-options="{'widget': 'barcode', 'symbology': 'auto', 'width': 600, 'height': 150, 'img_style': 'width:100%;height:4rem'}"/>
|
||||
<span t-field="product.barcode"/>
|
||||
</t>
|
||||
<t t-else=""><span class="text-muted">No barcode available</span></t>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="report_productbarcode">
|
||||
<t t-call="web.basic_layout">
|
||||
<div class="page">
|
||||
<t t-foreach="docs" t-as="product">
|
||||
<t t-call="product.report_simple_barcode">
|
||||
<t t-set="product" t-value="product"/>
|
||||
</t>
|
||||
<template id="report_productlabel_dymo">
|
||||
<t t-call="web.html_container">
|
||||
<t t-set="barcode_size" t-value="'width:45.5mm;height:7.5mm'"/>
|
||||
<t t-set="table_style" t-value="'width:100%;height:32mm;'"/>
|
||||
<t t-set="padding_page" t-value="'padding: 2mm'"/>
|
||||
<t t-foreach="quantity.items()" t-as="qty_by_product">
|
||||
<t t-set="product" t-value="qty_by_product[0]"/>
|
||||
<t t-foreach="range(qty_by_product[1])" t-as="qty">
|
||||
<t t-call="product.report_simple_label_dymo"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
</data>
|
||||
|
||||
@@ -1,47 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="report_product_label" model="ir.actions.report">
|
||||
<field name="name">Product Label (PDF)</field>
|
||||
<field name="model">product.product</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">product.report_productlabel</field>
|
||||
<field name="report_file">product.report_productlabel</field>
|
||||
<field name="print_report_name">'Products Labels - %s' % (object.name)</field>
|
||||
<field name="binding_model_id" ref="product.model_product_product"/>
|
||||
<field name="binding_type">report</field>
|
||||
<record id="paperformat_label_sheet" model="report.paperformat">
|
||||
<field name="name">A4 Label Sheet</field>
|
||||
<field name="default" eval="True" />
|
||||
<field name="format">A4</field>
|
||||
<field name="page_height">0</field>
|
||||
<field name="page_width">0</field>
|
||||
<field name="orientation">Portrait</field>
|
||||
<field name="margin_top">0</field>
|
||||
<field name="margin_bottom">0</field>
|
||||
<field name="margin_left">0</field>
|
||||
<field name="margin_right">0</field>
|
||||
<field name="disable_shrinking" eval="True"/>
|
||||
<field name="dpi">96</field>
|
||||
</record>
|
||||
|
||||
<record id="report_product_template_label" model="ir.actions.report">
|
||||
<field name="name">Product Label (PDF)</field>
|
||||
<field name="model">product.template</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">product.report_producttemplatelabel</field>
|
||||
<field name="report_file">product.report_producttemplatelabel</field>
|
||||
<field name="paperformat_id" ref="product.paperformat_label_sheet"/>
|
||||
<field name="print_report_name">'Products Labels - %s' % (object.name)</field>
|
||||
<field name="binding_model_id" ref="product.model_product_template"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
|
||||
<record id="report_product_product_barcode" model="ir.actions.report">
|
||||
<field name="name">Product Barcode (PDF)</field>
|
||||
<field name="model">product.product</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">product.report_productbarcode</field>
|
||||
<field name="report_file">product.report_productbarcode</field>
|
||||
<field name="print_report_name">'Products barcode - %s' % (object.name)</field>
|
||||
<field name="binding_model_id" ref="product.model_product_product"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
|
||||
<record id="report_product_template_barcode" model="ir.actions.report">
|
||||
<field name="name">Product Barcode (PDF)</field>
|
||||
<field name="model">product.template</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">product.report_producttemplatebarcode</field>
|
||||
<field name="report_file">product.report_producttemplatebarcode</field>
|
||||
<field name="print_report_name">'Products barcode - %s' % (object.name)</field>
|
||||
<field name="binding_model_id" ref="product.model_product_template"/>
|
||||
<field name="binding_model_id" eval="False"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
|
||||
@@ -78,5 +60,16 @@
|
||||
<field name="disable_shrinking" eval="True"/>
|
||||
<field name="dpi">96</field>
|
||||
</record>
|
||||
|
||||
<record id="report_product_template_label_dymo" model="ir.actions.report">
|
||||
<field name="name">Product Label (PDF)</field>
|
||||
<field name="model">product.template</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">product.report_producttemplatelabel_dymo</field>
|
||||
<field name="report_file">product.report_producttemplatelabel_dymo</field>
|
||||
<field name="paperformat_id" ref="product.paperformat_label_sheet_dymo"/>
|
||||
<field name="print_report_name">'Products Labels - %s' % (object.name)</field>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -3,27 +3,21 @@
|
||||
<template id="report_producttemplatelabel">
|
||||
<t t-call="web.basic_layout">
|
||||
<div class="page">
|
||||
<t t-foreach="docs" t-as="template">
|
||||
<t t-foreach="template.product_variant_ids" t-as="product">
|
||||
<t t-call="product.report_simple_label">
|
||||
<t t-set="product" t-value="product"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-call="product.report_productlabel">
|
||||
<t t-set="products" t-value="products"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
<template id="report_producttemplatebarcode">
|
||||
|
||||
<template id="report_producttemplatelabel_dymo">
|
||||
<t t-call="web.basic_layout">
|
||||
<div class="page">
|
||||
<t t-foreach="docs" t-as="template">
|
||||
<t t-foreach="template.product_variant_ids" t-as="product">
|
||||
<t t-call="product.report_simple_barcode">
|
||||
<t t-set="product" t-value="product"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-call="product.report_productlabel_dymo">
|
||||
<t t-set="products" t-value="products"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -26,3 +26,4 @@ access_product_attribute_custom_value_manager,product.attribute.custom value man
|
||||
access_product_product_attribute_manager,product.template.attribute value manager,model_product_template_attribute_value,base.group_system,1,1,1,1
|
||||
access_product_template_attribute_exclusion_manager,product.template.attribute exclusion manager,model_product_template_attribute_exclusion,base.group_system,1,1,1,1
|
||||
access_product_template_attribute_line_manager,product.template.attribute line manager,model_product_template_attribute_line,base.group_system,1,1,1,1
|
||||
access_product_label_layout_user,product.label.layout.user,model_product_label_layout,base.group_system,1,1,1,1
|
||||
|
||||
|
@@ -0,0 +1,69 @@
|
||||
.o_label_sheet {
|
||||
margin-left: -4mm;
|
||||
margin-right: -4mm;
|
||||
overflow: hidden;
|
||||
width: 210mm;
|
||||
height: 297mm;
|
||||
page-break-before: always;
|
||||
&.o_label_dymo {
|
||||
font-size:90%;
|
||||
width: 57mm;
|
||||
height: 32mm;
|
||||
}
|
||||
div {
|
||||
padding: 2px 4px;
|
||||
}
|
||||
div.o_label_small_text {
|
||||
font-size: 60%;
|
||||
line-height: 130%;
|
||||
}
|
||||
div.o_label_name {
|
||||
background-color: ghostwhite;
|
||||
height: 3em;
|
||||
overflow: hidden;
|
||||
}
|
||||
div.o_label_full {
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
margin: auto;
|
||||
}
|
||||
div.o_label_left_column {
|
||||
float: left;
|
||||
font-size: .6em;
|
||||
overflow:hidden;
|
||||
width: 40%;
|
||||
&.o_label_full_with {
|
||||
width: 100%
|
||||
}
|
||||
}
|
||||
div.o_label_right_column {
|
||||
float: right;
|
||||
}
|
||||
div.o_label_small_barcode {
|
||||
font-size: .6em;
|
||||
padding: 0 4px;
|
||||
line-height: normal;
|
||||
}
|
||||
strong.o_label_price {
|
||||
font-size: 2em;
|
||||
}
|
||||
strong.o_label_price_medium {
|
||||
font-size: 1.3em;
|
||||
line-height: normal;
|
||||
padding: 0;
|
||||
padding-right: 2mm;
|
||||
}
|
||||
strong.o_label_price_small {
|
||||
font-size: 0.9em;
|
||||
padding: 0 4px;
|
||||
padding-right: 2mm;
|
||||
}
|
||||
div.o_label_extra_data {
|
||||
overflow: hidden;
|
||||
height: 2.5em;
|
||||
padding: 0;
|
||||
}
|
||||
div.o_label_clear {
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,9 @@
|
||||
<field name="model">product.template</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Product" multi_edit="1" sample="1">
|
||||
<header>
|
||||
<button string="Print Labels" type="object" name="action_open_label_layout"/>
|
||||
</header>
|
||||
<field name="product_variant_count" invisible="1"/>
|
||||
<field name="sale_ok" invisible="1"/>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
name="%(product_attribute_value_action)d"
|
||||
attrs="{'invisible': ['|', ('attribute_line_ids', '<=', 0), ('is_product_variant', '=', True)]}"
|
||||
groups="product.group_product_variant"/>
|
||||
<button string="Print Labels" type="object" name="action_open_label_layout"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<field name='product_variant_count' invisible='1'/>
|
||||
@@ -221,6 +222,9 @@
|
||||
<field name="mode">primary</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Variant Information" duplicate="false">
|
||||
<header>
|
||||
<button string="Print Labels" type="object" name="action_open_label_layout"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box"/>
|
||||
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
|
||||
@@ -305,6 +309,9 @@
|
||||
<field eval="7" name="priority"/>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Product Variants" multi_edit="1" duplicate="false" sample="1">
|
||||
<header>
|
||||
<button string="Print Labels" type="object" name="action_open_label_layout"/>
|
||||
</header>
|
||||
<field name="priority" widget="priority" nolabel="1" readonly="1"/>
|
||||
<field name="default_code" optional="show" readonly="1"/>
|
||||
<field name="barcode" optional="hide" readonly="1"/>
|
||||
@@ -726,5 +733,13 @@ action = {
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_open_label_layout" model="ir.actions.act_window">
|
||||
<field name="name">Choose Labels Layout</field>
|
||||
<field name="res_model">product.label.layout</field>
|
||||
<field name="view_ids"
|
||||
eval="[(5, 0, 0),
|
||||
(0, 0, {'view_mode': 'form', 'view_id': ref('product_label_layout_form')})]" />
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import product_label_layout
|
||||
@@ -0,0 +1,71 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class ProductLabelLayout(models.TransientModel):
|
||||
_name = 'product.label.layout'
|
||||
_description = 'Choose the sheet layout to print the labels'
|
||||
|
||||
print_format = fields.Selection([
|
||||
('dymo', 'Dymo'),
|
||||
('2x7xprice', '2 x 7 with price'),
|
||||
('4x7xprice', '4 x 7 with price'),
|
||||
('4x12', '4 x 12'),
|
||||
('4x12xprice', '4 x 12 with price')], string="Format", default='2x7xprice', required=True)
|
||||
custom_quantity = fields.Integer('Quantity', default=1, required=True)
|
||||
product_ids = fields.Many2many('product.product')
|
||||
product_tmpl_ids = fields.Many2many('product.template')
|
||||
extra_html = fields.Html('Extra Content', default='')
|
||||
rows = fields.Integer(compute='_compute_dimensions')
|
||||
columns = fields.Integer(compute='_compute_dimensions')
|
||||
|
||||
@api.depends('print_format')
|
||||
def _compute_dimensions(self):
|
||||
for wizard in self:
|
||||
if 'x' in wizard.print_format:
|
||||
columns, rows = wizard.print_format.split('x')[:2]
|
||||
wizard.columns = int(columns)
|
||||
wizard.rows = int(rows)
|
||||
else:
|
||||
wizard.columns, wizard.rows = 1, 1
|
||||
|
||||
def _prepare_report_data(self):
|
||||
if self.custom_quantity <= 0:
|
||||
raise UserError(_('You need to set a positive quantity.'))
|
||||
|
||||
# Get layout grid
|
||||
if self.print_format == 'dymo':
|
||||
xml_id = 'product.report_product_template_label_dymo'
|
||||
elif 'x' in self.print_format:
|
||||
xml_id = 'product.report_product_template_label'
|
||||
else:
|
||||
xml_id = ''
|
||||
|
||||
active_model = ''
|
||||
if self.product_tmpl_ids:
|
||||
products = self.product_tmpl_ids.ids
|
||||
active_model = 'product.template'
|
||||
elif self.product_ids:
|
||||
products = self.product_ids.ids
|
||||
active_model = 'product.product'
|
||||
|
||||
# Build data to pass to the report
|
||||
data = {
|
||||
'picking_quantity': self.picking_quantity,
|
||||
'active_model': active_model,
|
||||
'quantity_by_product': {p: self.custom_quantity for p in products},
|
||||
'layout_wizard': self.id,
|
||||
'price_included': 'xprice' in self.print_format,
|
||||
}
|
||||
return xml_id, data
|
||||
|
||||
def process(self):
|
||||
self.ensure_one()
|
||||
xml_id, data = self._prepare_report_data()
|
||||
if not xml_id:
|
||||
raise UserError(_('Unable to find report template for %s format', self.print_format))
|
||||
return self.env.ref(xml_id).report_action(None, data=data)
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="product_label_layout_form" model="ir.ui.view">
|
||||
<field name="name">product.label.layout.form</field>
|
||||
<field name="model">product.label.layout</field>
|
||||
<field name="mode">primary</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group>
|
||||
<group>
|
||||
<field name="product_ids" invisible="1"/>
|
||||
<field name="product_tmpl_ids" invisible="1"/>
|
||||
<field name="custom_quantity"/>
|
||||
<field name="print_format" widget="radio"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="extra_html" widget="html" attrs="{'invisible': [('print_format', 'not in', ('dymo', '2x7xprice'))]}"/>
|
||||
</group>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="process" string="Confirm" type="object" class="btn-primary"/>
|
||||
<button string="Discard" class="btn-secondary" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -59,6 +59,7 @@
|
||||
'wizard/stock_rules_report_views.xml',
|
||||
'wizard/stock_warn_insufficient_qty_views.xml',
|
||||
'wizard/product_replenish_views.xml',
|
||||
'wizard/product_label_layout_views.xml',
|
||||
'wizard/stock_track_confirmation_views.xml',
|
||||
'wizard/stock_orderpoint_snooze_views.xml',
|
||||
'wizard/stock_package_destination_views.xml',
|
||||
|
||||
@@ -1431,6 +1431,20 @@ class Picking(models.Model):
|
||||
def action_view_reception_report(self):
|
||||
return self.env["ir.actions.actions"]._for_xml_id("stock.stock_reception_action")
|
||||
|
||||
def action_open_label_layout(self):
|
||||
view = self.env.ref('stock.product_label_layout_form_picking')
|
||||
return {
|
||||
'name': _('Choose Labels Layout'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'product.label.layout',
|
||||
'views': [(view.id, 'form')],
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'default_product_ids': self.move_lines.product_id.ids,
|
||||
'default_move_line_ids': self.move_line_ids.ids,
|
||||
'default_picking_quantity': 'picking'},
|
||||
}
|
||||
|
||||
def _attach_sign(self):
|
||||
""" Render the delivery report in pdf and attach it to the picking in `self`. """
|
||||
self.ensure_one()
|
||||
|
||||
@@ -6,3 +6,4 @@ from . import report_stock_quantity
|
||||
from . import report_stock_reception
|
||||
from . import report_stock_rule
|
||||
from . import stock_traceability
|
||||
from . import product_label_report
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import _, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class ReportProductLabel(models.AbstractModel):
|
||||
_name = 'report.stock.label_product_product_view'
|
||||
_description = 'Product Label Report'
|
||||
|
||||
def _get_report_values(self, docids, data):
|
||||
if data.get('active_model') == 'product.template':
|
||||
data['quantity'] = {self.env['product.template'].browse(int(p)): q for p, q in data.get('quantity_by_product').items()}
|
||||
elif data.get('active_model') == 'product.product':
|
||||
data['quantity'] = {self.env['product.product'].browse(int(p)): q for p, q in data.get('quantity_by_product').items()}
|
||||
else:
|
||||
raise UserError(_('Product model not defined, Please contact your administrator.'))
|
||||
|
||||
return data
|
||||
@@ -1,82 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<template id="label_product_template_view">
|
||||
<t t-foreach="docs" t-as="product">
|
||||
<t t-translation="off">
|
||||
^XA
|
||||
^FO100,50
|
||||
^A0N,44,33^FD<t t-esc="product.display_name"/>^FS
|
||||
^FO100,100
|
||||
<t t-if="product.currency_id.position == 'after'">
|
||||
^CI28
|
||||
^A0N,44,33^FH^FDPrice: <t t-esc="product.list_price" t-options='{"widget": "float", "precision": 2}'/><t t-esc="product.currency_id.symbol"/>^FS
|
||||
</t>
|
||||
<t t-if="product.currency_id.position == 'before'">
|
||||
^CI28
|
||||
^A0N,44,33^FH^FDPrice: <t t-esc="product.currency_id.symbol"/><t t-esc="product.list_price" t-options='{"widget": "float", "precision": 2}'/>^FS
|
||||
</t>
|
||||
<t t-if="product.barcode">
|
||||
^FO100,150^BY3
|
||||
^BCN,100,Y,N,N
|
||||
^FD<t t-esc="product.barcode"/>^FS
|
||||
</t>
|
||||
^XZ
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
<template id="label_product_product_view">
|
||||
<t t-foreach="docs" t-as="product">
|
||||
<t t-translation="off">
|
||||
<t t-foreach="quantity.items()" t-as="qty_by_product">
|
||||
<t t-set="product" t-value="qty_by_product[0]"/>
|
||||
<t t-foreach="range(qty_by_product[1])" t-as="qty">
|
||||
<t t-translation="off">
|
||||
^XA
|
||||
^FO100,50
|
||||
^A0N,44,33^FD<t t-esc="product.display_name"/>^FS
|
||||
^FO100,100
|
||||
<t t-if="product.currency_id.position == 'after'">
|
||||
^FT100,80^A0N,40,30^FD<t t-esc="product.display_name"/>^FS
|
||||
<t t-if="product.default_code and len(product.default_code) > 15">
|
||||
^FT100,115^A0N,30,24^FD<t t-esc="product.default_code[:15]"/>^FS
|
||||
^FT100,150^A0N,30,24^FD<t t-esc="product.default_code[15:30]"/>^FS
|
||||
</t>
|
||||
<t t-else="">
|
||||
^FT100,150^A0N,30,24^FD<t t-esc="product.default_code"/>^FS
|
||||
</t>
|
||||
<t t-if="price_included">
|
||||
^FO600,100,1
|
||||
^CI28
|
||||
^A0N,44,33^FH^FDPrice: <t t-esc="product.lst_price" t-options='{"widget": "float", "precision": 2}'/><t t-esc="product.currency_id.symbol"/>^FS
|
||||
<t t-if="product.currency_id.position == 'after'">
|
||||
^A0N,66,48^FH^FD<t t-esc="product.list_price" t-options='{"widget": "float", "precision": 2}'/><t t-esc="product.currency_id.symbol"/>^FS
|
||||
</t>
|
||||
<t t-if="product.currency_id.position == 'before'">
|
||||
^CI28
|
||||
^A0N,44,33^FH^FDPrice: <t t-esc="product.currency_id.symbol"/><t t-esc="product.lst_price" t-options='{"widget": "float", "precision": 2}'/>^FS
|
||||
^A0N,66,48^FH^FD<t t-esc="product.currency_id.symbol"/><t t-esc="product.list_price" t-options='{"widget": "float", "precision": 2}'/>^FS
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="product.barcode">
|
||||
^FO100,150^BY3
|
||||
^FO100,160^BY3
|
||||
^BCN,100,Y,N,N
|
||||
^FD<t t-esc="product.barcode"/>^FS
|
||||
</t>
|
||||
^XZ
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
<template id="label_barcode_product_template_view">
|
||||
<t t-foreach="docs" t-as="product">
|
||||
<t t-translation="off">
|
||||
^XA
|
||||
^FO100,50
|
||||
^A0N,44,33^FD<t t-esc="product.display_name"/>^FS
|
||||
<t t-if="product.barcode ">
|
||||
^FO100,100^BY3
|
||||
^BCN,100,Y,N,N
|
||||
^FD<t t-esc="product.barcode"/>^FS
|
||||
</t>
|
||||
^XZ
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
<template id="label_barcode_product_product_view">
|
||||
<t t-foreach="docs" t-as="product">
|
||||
<t t-translation="off">
|
||||
^XA
|
||||
^FO100,50
|
||||
^A0N,44,33^FD<t t-esc="product.display_name"/>^FS
|
||||
<t t-if="product.barcode">
|
||||
^FO100,100^BY3
|
||||
^BCN,100,Y,N,N
|
||||
^FD<t t-esc="product.barcode"/>^FS
|
||||
</t>
|
||||
^XZ
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
<template id="label_lot_template_view">
|
||||
|
||||
@@ -86,40 +86,13 @@
|
||||
<field name="report_name">stock.report_stock_rule</field>
|
||||
<field name="report_file">stock.report_stock_rule</field>
|
||||
</record>
|
||||
<record id="label_product_template" model="ir.actions.report">
|
||||
<field name="name">Product Label (ZPL)</field>
|
||||
<field name="model">product.template</field>
|
||||
<field name="report_type">qweb-text</field>
|
||||
<field name="report_name">stock.label_product_template_view</field>
|
||||
<field name="report_file">stock.label_product_template_view</field>
|
||||
<field name="binding_model_id" ref="product.model_product_template"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
<record id="label_product_product" model="ir.actions.report">
|
||||
<field name="name">Product Label (ZPL)</field>
|
||||
<field name="model">product.product</field>
|
||||
<field name="report_type">qweb-text</field>
|
||||
<field name="report_name">stock.label_product_product_view</field>
|
||||
<field name="report_file">stock.label_product_product_view</field>
|
||||
<field name="binding_model_id" ref="product.model_product_product"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
<record id="label_barcode_product_template" model="ir.actions.report">
|
||||
<field name="name">Product Barcode (ZPL)</field>
|
||||
<field name="model">product.template</field>
|
||||
<field name="report_type">qweb-text</field>
|
||||
<field name="report_name">stock.label_barcode_product_template_view</field>
|
||||
<field name="report_file">stock.label_barcode_product_template_view</field>
|
||||
<field name="binding_model_id" ref="product.model_product_template"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
<record id="label_barcode_product_product" model="ir.actions.report">
|
||||
<field name="name">Product Barcode (ZPL)</field>
|
||||
<field name="model">product.product</field>
|
||||
<field name="report_type">qweb-text</field>
|
||||
<field name="report_name">stock.label_barcode_product_product_view</field>
|
||||
<field name="report_file">stock.label_barcode_product_product_view</field>
|
||||
<field name="binding_model_id" ref="product.model_product_product"/>
|
||||
<field name="binding_model_id" eval="False"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
<record id="label_lot_template" model="ir.actions.report">
|
||||
@@ -131,24 +104,6 @@
|
||||
<field name="binding_model_id" ref="model_stock_production_lot"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
<record id="action_label_transfer_template_zpl" model="ir.actions.report">
|
||||
<field name="name">Barcodes (ZPL)</field>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="report_type">qweb-text</field>
|
||||
<field name="report_name">stock.label_transfer_template_view_zpl</field>
|
||||
<field name="report_file">stock.label_transfer_template_view_zpl</field>
|
||||
<field name="binding_model_id" ref="model_stock_picking"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
<record id="action_label_transfer_template_pdf" model="ir.actions.report">
|
||||
<field name="name">Barcodes (PDF)</field>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">stock.label_transfer_template_view_pdf</field>
|
||||
<field name="report_file">stock.label_transfer_template_view_pdf</field>
|
||||
<field name="binding_model_id" ref="model_stock_picking"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
<record id="label_package_template" model="ir.actions.report">
|
||||
<field name="name">Package Barcode (ZPL)</field>
|
||||
<field name="model">stock.quant.package</field>
|
||||
|
||||
@@ -209,19 +209,17 @@
|
||||
<field name="model">product.product</field>
|
||||
<field name="inherit_id" ref="product.product_variant_easy_edit_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<sheet position="before">
|
||||
<header>
|
||||
<button string="Update Quantity" type="object"
|
||||
groups="stock.group_stock_manager"
|
||||
name="action_update_quantity_on_hand"
|
||||
attrs="{'invisible': [('type', '!=', 'product')]}"/>
|
||||
<button string="Replenish" type="action"
|
||||
name="%(action_product_replenish)d"
|
||||
context="{'default_product_id': id}"
|
||||
groups="stock.group_stock_user"
|
||||
attrs="{'invisible': [('type', '!=', 'product')]}"/>
|
||||
</header>
|
||||
</sheet>
|
||||
<header position="inside">
|
||||
<button string="Update Quantity" type="object"
|
||||
groups="stock.group_stock_manager"
|
||||
name="action_update_quantity_on_hand"
|
||||
attrs="{'invisible': [('type', '!=', 'product')]}"/>
|
||||
<button string="Replenish" type="action"
|
||||
name="%(action_product_replenish)d"
|
||||
context="{'default_product_id': id}"
|
||||
groups="stock.group_stock_user"
|
||||
attrs="{'invisible': [('type', '!=', 'product')]}"/>
|
||||
</header>
|
||||
<div name="button_box" position="inside">
|
||||
<button string="Putaway Rules" type="object"
|
||||
name="action_view_related_putaway_rules"
|
||||
|
||||
@@ -251,6 +251,7 @@
|
||||
attrs="{'invisible': ['|', '|', ('id', '=', False), ('picking_type_code', '!=', 'outgoing'), ('state', '=', 'done')]}"
|
||||
full_name="partner_id" groups="stock.group_stock_sign_delivery"/>
|
||||
<button name="do_print_picking" string="Print" groups="stock.group_stock_user" type="object" attrs="{'invisible': [('state', '!=', 'assigned')]}" data-hotkey="o"/>
|
||||
<button string="Print Labels" type="object" name="action_open_label_layout"/>
|
||||
<button name="%(action_report_delivery)d" string="Print" attrs="{'invisible': [('state', '!=', 'done')]}" type="action" groups="base.group_user" data-hotkey="o"/>
|
||||
<button name="%(act_stock_return_picking)d" string="Return" attrs="{'invisible': [('state', '!=', 'done')]}" type="action" groups="base.group_user" data-hotkey="k"/>
|
||||
<button name="do_unreserve" string="Unreserve" groups="base.group_user" type="object" attrs="{'invisible': ['|', '|', '|', ('picking_type_code', '=', 'incoming'), ('immediate_transfer', '=', True), '&', ('state', '!=', 'assigned'), ('move_type', '!=', 'one'), '&', ('state', 'not in', ('assigned', 'confirmed')), ('move_type', '=', 'one')]}" data-hotkey="w"/>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import product_label_layout
|
||||
from . import stock_assign_serial_numbers
|
||||
from . import stock_picking_return
|
||||
from . import stock_change_product_qty
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from collections import defaultdict
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ProductLabelLayout(models.TransientModel):
|
||||
_inherit = 'product.label.layout'
|
||||
|
||||
move_line_ids = fields.Many2many('stock.move.line')
|
||||
picking_quantity = fields.Selection([
|
||||
('picking', 'Transfer Quantities'),
|
||||
('custom', 'Custom')], string="Quantity to print", default='custom')
|
||||
print_format = fields.Selection(selection_add=[
|
||||
('zpl', 'ZPL Labels'),
|
||||
('zplxprice', 'ZPL Labels with price')
|
||||
], ondelete={'zpl': 'set default', 'zplxprice': 'set default'})
|
||||
|
||||
def _prepare_report_data(self):
|
||||
xml_id, data = super()._prepare_report_data()
|
||||
|
||||
if 'zpl' in self.print_format:
|
||||
xml_id = 'stock.label_product_product'
|
||||
|
||||
if self.picking_quantity == 'picking' and self.move_line_ids:
|
||||
qties = defaultdict(int)
|
||||
uom_unit = self.env.ref('uom.product_uom_categ_unit', raise_if_not_found=False)
|
||||
for line in self.move_line_ids:
|
||||
if line.product_uom_id.category_id == uom_unit:
|
||||
qties[line.product_id.id] += line.qty_done
|
||||
# Pass only products with some quantity done to the report
|
||||
data['quantity_by_product'] = {p: int(q) for p, q in qties.items() if q}
|
||||
return xml_id, data
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="product_label_layout_form_picking" model="ir.ui.view">
|
||||
<field name="name">product.label.layout.form</field>
|
||||
<field name="model">product.label.layout</field>
|
||||
<field name="mode">primary</field>
|
||||
<field name="priority">25</field>
|
||||
<field name="inherit_id" ref="product.product_label_layout_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr='//field[@name="custom_quantity"]' position="before">
|
||||
<field name="picking_quantity"/>
|
||||
</xpath>
|
||||
<xpath expr='//field[@name="custom_quantity"]' position="attributes">
|
||||
<attribute name="attrs">
|
||||
{'invisible': [('picking_quantity', '=', 'picking')]}
|
||||
</attribute>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -233,6 +233,22 @@ class StockPickingBatch(models.Model):
|
||||
action['context'] = {'default_picking_ids': self.picking_ids.ids}
|
||||
return action
|
||||
|
||||
def action_open_label_layout(self):
|
||||
view = self.env.ref('product.product_label_layout_form')
|
||||
return {
|
||||
'name': _('Choose Labels Layout'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'product.label.layout',
|
||||
'views': [(view.id, 'form')],
|
||||
'view_id': view.id,
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'default_product_ids': self.move_lines.product_id.ids,
|
||||
'default_move_line_ids': self.move_line_ids.ids,
|
||||
'default_picking_quantity': 'picking'},
|
||||
}
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Miscellaneous
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
('state', '!=', 'draft'),
|
||||
('show_check_availability', '=', False)]}"/>
|
||||
<button name="action_print" states="in_progress,done" string="Print" type="object"/>
|
||||
<button string="Print Labels" type="object" name="action_open_label_layout"/>
|
||||
<button name="action_cancel" string="Cancel" type="object" states="in_progress"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,in_progress,done"/>
|
||||
</header>
|
||||
|
||||
@@ -451,6 +451,12 @@ class MonetaryConverter(models.AbstractModel):
|
||||
else:
|
||||
post = '\N{NO-BREAK SPACE}{symbol}'.format(symbol=display_currency.symbol or '')
|
||||
|
||||
if options.get('label_price'):
|
||||
sep = lang.decimal_point
|
||||
integer_part, decimal_part = formatted_amount.split(sep)
|
||||
integer_part += sep
|
||||
return M('{pre}<span class="oe_currency_value">{0}</span><span class="oe_currency_value" style="font-size:0.5em">{1}</span>{post}').format(integer_part, decimal_part, pre=pre, post=post)
|
||||
|
||||
return M('{pre}<span class="oe_currency_value">{0}</span>{post}').format(formatted_amount, pre=pre, post=post)
|
||||
|
||||
@api.model
|
||||
|
||||
Reference in New Issue
Block a user