Compare commits
41 Commits
14-fix-mig
...
14.0-stock
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61818437b3 | ||
|
|
f2172a5f06 | ||
|
|
e81e8e5a93 | ||
|
|
a7b0210a90 | ||
|
|
cd30298f88 | ||
|
|
5039e56417 | ||
|
|
3c338c9c78 | ||
|
|
2c87670281 | ||
|
|
59e34d0166 | ||
|
|
0e87b385d4 | ||
|
|
4a434d69f9 | ||
|
|
bade674c41 | ||
|
|
def89c0a5d | ||
|
|
88b12d86a2 | ||
|
|
e3c55047b3 | ||
|
|
b701586edc | ||
|
|
aae3ac2898 | ||
|
|
8a2e23cff5 | ||
|
|
0781cb7ba7 | ||
|
|
a7022e899f | ||
|
|
068509066d | ||
|
|
e594d15417 | ||
|
|
4121d8466d | ||
|
|
6df9756479 | ||
|
|
0331cc8eda | ||
|
|
54bc3d8af8 | ||
|
|
15edfe5603 | ||
|
|
8bf2116630 | ||
|
|
6b5282994a | ||
|
|
993aab7d18 | ||
|
|
73137ee1fb | ||
|
|
c4ec388380 | ||
|
|
8afcd49bc3 | ||
|
|
1e8f00d4e1 | ||
|
|
061efb2197 | ||
|
|
e698746dd1 | ||
|
|
d2bc7be9fe | ||
|
|
5f6b731e50 | ||
|
|
6c81ade7d0 | ||
|
|
209de4f6db | ||
|
|
2d3a792ce8 |
@@ -6,7 +6,7 @@ from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.osv import expression
|
||||
from odoo.tools import float_is_zero
|
||||
from odoo.tools.misc import format_date
|
||||
@@ -40,6 +40,34 @@ class AccountMove(models.Model):
|
||||
compute="_compute_sales_dates", readonly=True,
|
||||
help="This information appear on invoice qweb report "
|
||||
"(you may use it for your own report)")
|
||||
# There is a native "blocked" field (bool) on account.move.line
|
||||
# We want to have that field on invoices to improve usability
|
||||
# while keeping compatibility with the standard Odoo datamodel
|
||||
blocked = fields.Boolean(
|
||||
compute="_compute_blocked",
|
||||
inverse="_inverse_blocked",
|
||||
store=True,
|
||||
string="Dispute",
|
||||
tracking=True,
|
||||
)
|
||||
|
||||
@api.depends("line_ids", "line_ids.blocked")
|
||||
def _compute_blocked(self):
|
||||
for move in self:
|
||||
move.blocked = any(
|
||||
[
|
||||
l.blocked
|
||||
for l in move.line_ids
|
||||
if l.account_id.internal_type in ("payable", "receivable")
|
||||
]
|
||||
)
|
||||
|
||||
def _inverse_blocked(self):
|
||||
for move in self:
|
||||
for line in move.line_ids.filtered(
|
||||
lambda l: l.account_id.internal_type in ("payable", "receivable")
|
||||
):
|
||||
line.blocked = move.blocked
|
||||
|
||||
def _compute_has_discount(self):
|
||||
prec = self.env['decimal.precision'].precision_get('Discount')
|
||||
@@ -235,6 +263,40 @@ class AccountMove(models.Model):
|
||||
date = invoice_date
|
||||
return date
|
||||
|
||||
# I don't use account_invoice_supplier_ref_unique because it adds
|
||||
# a field supplier_invoice_number on account.move instead of using the native field
|
||||
# cf https://github.com/OCA/account-invoicing/issues/1484
|
||||
# So I take inspiration from the code of account_invoice_supplier_ref_unique
|
||||
# but I use the native "ref" field
|
||||
@api.constrains("ref", "partner_id")
|
||||
def _check_in_invoice_ref_unique_insensitive(self):
|
||||
for move in self:
|
||||
if move.ref and move.is_purchase_document(
|
||||
include_receipts=True
|
||||
):
|
||||
in_invoice_same_ref = self.search(
|
||||
[
|
||||
("commercial_partner_id", "=", move.commercial_partner_id.id),
|
||||
("move_type", "in", ("in_invoice", "in_refund")),
|
||||
("company_id", "=", move.company_id.id),
|
||||
("ref", "=ilike", move.ref),
|
||||
("id", "!=", move.id),
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
if in_invoice_same_ref:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"An invoice already exists in Odoo with the same "
|
||||
"bill reference '%s' for the same supplier '%s': %s."
|
||||
)
|
||||
% (
|
||||
in_invoice_same_ref.ref,
|
||||
in_invoice_same_ref.partner_id.display_name,
|
||||
in_invoice_same_ref.display_name,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class AccountMoveLine(models.Model):
|
||||
_inherit = 'account.move.line'
|
||||
|
||||
@@ -47,6 +47,16 @@
|
||||
<xpath expr="//field[@name='invoice_line_ids']/tree/field[@name='product_id']" position="after">
|
||||
<field name="product_barcode" optional="hide"/>
|
||||
</xpath>
|
||||
<field name="auto_post" position="before">
|
||||
<field name="blocked"/>
|
||||
</field>
|
||||
<div role="alert" position="after">
|
||||
<div id="warn_blocked" groups="account.group_account_invoice,account.group_account_readonly"
|
||||
class="alert alert-warning" role="alert" style="margin-bottom:0px;"
|
||||
attrs="{'invisible': ['|', ('move_type', 'not in', ('in_invoice', 'in_refund', 'out_invoice', 'out_refund')), ('blocked', '=', False)]}">
|
||||
This <field name="move_type"/> is marked as <b>disputed</b>.
|
||||
</div>
|
||||
</div>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -71,6 +81,8 @@
|
||||
<filter name="sent" string="Sent" domain="[('is_move_sent', '=', True), ('move_type', 'in', ('out_invoice', 'out_refund'))]"/>
|
||||
<separator/>
|
||||
<filter name="no_attachment" string="Missing Attachment" domain="[('has_attachment', '=', False)]"/>
|
||||
<separator/>
|
||||
<filter name="dispute" string="Dispute" domain="[('blocked', '=', True)]"/>
|
||||
</filter>
|
||||
<filter name="salesperson" position="before">
|
||||
<filter name="commercial_partner_groupby" string="Commercial Partner" context="{'group_by': 'commercial_partner_id'}"/>
|
||||
@@ -81,6 +93,23 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_move_line_form" model="ir.ui.view">
|
||||
<field name="model">account.move.line</field>
|
||||
<field name="inherit_id" ref="account.view_move_line_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<!-- The field 'blocked' is alone in it's block
|
||||
We don't want to display an empty block, so we put the attrs on the group
|
||||
The drawback of this is that, if someone added a field in that group,
|
||||
he won't see the field when internal_type is not payable/receivable -->
|
||||
<xpath expr="//field[@name='blocked']/.." position="attributes">
|
||||
<attribute name="attrs">{'invisible': [('account_internal_type', 'not in', ('payable', 'receivable'))]}</attribute>
|
||||
</xpath>
|
||||
<field name="company_id" position="after">
|
||||
<field name="account_internal_type" invisible="1"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_move_line_tree" model="ir.ui.view">
|
||||
<field name="model">account.move.line</field>
|
||||
<field name="inherit_id" ref="account.view_move_line_tree"/>
|
||||
@@ -126,6 +155,18 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_move_line_pivot" model="ir.ui.view">
|
||||
<field name="model">account.move.line</field>
|
||||
<field name="inherit_id" ref="account.view_move_line_pivot"/>
|
||||
<field name="arch" type="xml">
|
||||
<!-- By default, date is split by month... but if you've been using Odoo for several years,
|
||||
the pivot table becomes very big by default: so we split by year -->
|
||||
<field name="date" position="attributes">
|
||||
<attribute name="interval">year</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="account.action_move_journal_line" model="ir.actions.act_window">
|
||||
<field name="context">{'default_move_type': 'entry', 'view_no_maturity': True}</field>
|
||||
<!-- Remove 'search_default_misc_filter': 1 -->
|
||||
|
||||
@@ -15,6 +15,7 @@ class ResPartnerPhone(models.Model):
|
||||
_name = 'res.partner.phone'
|
||||
_order = 'partner_id, type'
|
||||
_phone_name_sequence = 8
|
||||
_phone_name_fields = ["phone"]
|
||||
_inherit = ['phone.validation.mixin']
|
||||
_description = 'Multiple emails and phones for partners'
|
||||
|
||||
@@ -73,7 +74,7 @@ class ResPartnerPhone(models.Model):
|
||||
if self._context.get('callerid'):
|
||||
name = pphone.partner_id.display_name
|
||||
else:
|
||||
name = u'%s (%s)' % (pphone.phone, pphone.partner_id.name)
|
||||
name = '%s (%s)' % (pphone.phone, pphone.partner_id.name)
|
||||
else:
|
||||
name = pphone.phone
|
||||
res.append((pphone.id, name))
|
||||
@@ -104,6 +105,7 @@ class ResPartnerPhone(models.Model):
|
||||
|
||||
class ResPartner(models.Model):
|
||||
_inherit = 'res.partner'
|
||||
_phone_name_fields = []
|
||||
|
||||
# in v10, we are supposed to have in DB E.164 format
|
||||
# with the current implementation, we have:
|
||||
@@ -147,6 +149,8 @@ class ResPartner(models.Model):
|
||||
if vals.get(partner_field):
|
||||
vals['phone_ids'].append(
|
||||
(0, 0, {'type': type, partner_phone_field: vals[partner_field]}))
|
||||
if partner_field in vals:
|
||||
vals.pop(partner_field)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
@@ -155,7 +159,6 @@ class ResPartner(models.Model):
|
||||
self._update_create_vals(vals, '1_email_primary', 'email', 'email')
|
||||
self._update_create_vals(vals, '3_phone_primary', 'phone', 'phone')
|
||||
self._update_create_vals(vals, '5_mobile_primary', 'mobile', 'phone')
|
||||
# self._update_create_vals(vals, '7_fax_primary', 'fax', 'phone')
|
||||
return super().create(vals)
|
||||
|
||||
def _update_write_vals(
|
||||
@@ -178,16 +181,16 @@ class ResPartner(models.Model):
|
||||
else:
|
||||
if pphone:
|
||||
vals['phone_ids'].append((2, pphone.id))
|
||||
vals.pop(partner_field)
|
||||
|
||||
def write(self, vals):
|
||||
if 'phone_ids' not in vals:
|
||||
for rec in self:
|
||||
vals['phone_ids'] = []
|
||||
rec._update_write_vals(vals, '1_email_primary', 'email', 'email')
|
||||
rec._update_write_vals(vals, '3_phone_primary', 'phone', 'phone')
|
||||
rec._update_write_vals(vals, '5_mobile_primary', 'mobile', 'phone')
|
||||
rec._update_write_vals(vals, '7_fax_primary', 'fax', 'phone')
|
||||
super(ResPartner, rec).write(vals)
|
||||
cvals = dict(vals, phone_ids=[])
|
||||
rec._update_write_vals(cvals, '1_email_primary', 'email', 'email')
|
||||
rec._update_write_vals(cvals, '3_phone_primary', 'phone', 'phone')
|
||||
rec._update_write_vals(cvals, '5_mobile_primary', 'mobile', 'phone')
|
||||
super(ResPartner, rec).write(cvals)
|
||||
return True
|
||||
else:
|
||||
return super().write(vals)
|
||||
|
||||
@@ -161,6 +161,12 @@
|
||||
<field name="name" position="attributes">
|
||||
<attribute name="filter_domain">['|', '|', ('display_name', 'ilike', self), ('ref', '=ilike', self + '%'), ('phone_ids.email', 'ilike', self)]</attribute>
|
||||
</field>
|
||||
<field name="email" position="attributes">
|
||||
<attribute name="filter_domain">[('phone_ids.email', 'ilike', self)]</attribute>
|
||||
</field>
|
||||
<field name="phone" position="attributes">
|
||||
<attribute name="filter_domain">[('phone_ids.phone', 'ilike', self)]</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
'summary': 'Better usability in base module',
|
||||
'author': 'Akretion',
|
||||
'website': 'http://www.akretion.com',
|
||||
'depends': ['base'],
|
||||
'depends': ['web'],
|
||||
'data': [
|
||||
'security/group.xml',
|
||||
'security/ir.model.access.csv',
|
||||
@@ -21,6 +21,7 @@
|
||||
'views/ir_module.xml',
|
||||
'views/ir_sequence.xml',
|
||||
'views/ir_property.xml',
|
||||
'views/assets.xml',
|
||||
],
|
||||
'installable': True,
|
||||
}
|
||||
|
||||
10
base_usability/static/src/scss/form_view.scss
Normal file
10
base_usability/static/src/scss/form_view.scss
Normal file
@@ -0,0 +1,10 @@
|
||||
.o_form_view {
|
||||
.o_address_format {
|
||||
.o_address_state {
|
||||
margin-right: 0;
|
||||
}
|
||||
.o_address_zip {
|
||||
margin-right: 2%;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
base_usability/views/assets.xml
Normal file
15
base_usability/views/assets.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<template
|
||||
id="assets_backend"
|
||||
name="web_sheet_full_width"
|
||||
inherit_id="web.assets_backend"
|
||||
>
|
||||
<xpath expr="." position="inside">
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="/base_usability/static/src/scss/form_view.scss"
|
||||
/>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
||||
@@ -20,6 +20,10 @@
|
||||
<div attrs="{'invisible': [('same_vat_partner_id', '=', False)]}" position="attributes">
|
||||
<attribute name="class">alert alert-warning</attribute>
|
||||
</div>
|
||||
<!-- Native order: city / state_id / zip. New order: zip / city / state_id -->
|
||||
<xpath expr="//div[hasclass('o_address_format')]/field[@name='city']" position="before">
|
||||
<field name="zip" position="move"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
28
base_usability/web-advanced_search_startswith.diff
Normal file
28
base_usability/web-advanced_search_startswith.diff
Normal file
@@ -0,0 +1,28 @@
|
||||
diff --git a/addons/web/static/src/js/control_panel/custom_filter_item.js b/addons/web/static/src/js/control_panel/custom_filter_item.js
|
||||
index 6682b660b78..b2ff23344d9 100644
|
||||
--- a/addons/web/static/src/js/control_panel/custom_filter_item.js
|
||||
+++ b/addons/web/static/src/js/control_panel/custom_filter_item.js
|
||||
@@ -180,6 +180,10 @@ odoo.define('web.CustomFilterItem', function (require) {
|
||||
[field.name, '>=', domainValue[0]],
|
||||
[field.name, '<=', domainValue[1]]
|
||||
);
|
||||
+ } else if (operator.symbol === 'startswith') {
|
||||
+ domainArray.push([field.name, '=ilike', domainValue[0] + '%']);
|
||||
+ } else if (operator.symbol === 'endswith') {
|
||||
+ domainArray.push([field.name, '=ilike', '%' + domainValue[0]]);
|
||||
} else {
|
||||
domainArray.push([field.name, operator.symbol, domainValue[0]]);
|
||||
}
|
||||
diff --git a/addons/web/static/src/js/control_panel/search_utils.js b/addons/web/static/src/js/control_panel/search_utils.js
|
||||
index 8fce5b23ef6..d240d2e1fb2 100644
|
||||
--- a/addons/web/static/src/js/control_panel/search_utils.js
|
||||
+++ b/addons/web/static/src/js/control_panel/search_utils.js
|
||||
@@ -18,6 +18,8 @@ odoo.define('web.searchUtils', function (require) {
|
||||
char: [
|
||||
{ symbol: "ilike", description: _lt("contains") },
|
||||
{ symbol: "not ilike", description: _lt("doesn't contain") },
|
||||
+ { symbol: "startswith", description: _lt("starts with") },
|
||||
+ { symbol: "endswith", description: _lt("ends with") },
|
||||
{ symbol: "=", description: _lt("is equal to") },
|
||||
{ symbol: "!=", description: _lt("is not equal to") },
|
||||
{ symbol: "!=", description: _lt("is set"), value: false },
|
||||
@@ -1,4 +1 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import intrastat_product_type
|
||||
from .post_install import set_intrastat_type_on_products
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
{
|
||||
'name': 'Intrastat Product Type',
|
||||
'version': '12.0.1.0.0',
|
||||
'version': '14.0.1.0.0',
|
||||
'category': 'Accounting',
|
||||
'license': 'AGPL-3',
|
||||
'summary': 'Adds a special field Intrastat Type on Products',
|
||||
@@ -19,9 +19,8 @@ This module adds a field *Intrastat Type* on the Product Form with 2 possible op
|
||||
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
|
||||
""",
|
||||
'author': 'Akretion',
|
||||
'website': 'http://www.akretion.com',
|
||||
'website': 'https://github.com/akretion/odoo-usability',
|
||||
'depends': ['intrastat_product', 'l10n_fr_intrastat_service'],
|
||||
'data': ['product_view.xml'],
|
||||
'post_init_hook': 'set_intrastat_type_on_products',
|
||||
'installable': False,
|
||||
'installable': True,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016-2019 Akretion (http://www.akretion.com)
|
||||
# Copyright 2016-2023 Akretion (http://www.akretion.com)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
|
||||
@@ -14,50 +13,36 @@ class ProductTemplate(models.Model):
|
||||
intrastat_type = fields.Selection([
|
||||
('product', 'Product'),
|
||||
('service', 'Service'),
|
||||
], string='Intrastat Type', default='product', required=True,
|
||||
],
|
||||
compute='_compute_intrastat_type', readonly=False, store=True,
|
||||
required=True, string='Intrastat Type',
|
||||
help="Type of product used for the intrastat declarations. "
|
||||
"For example, you can configure a product with "
|
||||
"'Product Type' = 'Consumable' and 'Intrastat Type' = 'Service'.")
|
||||
|
||||
@api.multi
|
||||
@api.constrains('type', 'intrastat_type')
|
||||
def check_intrastat_type(self):
|
||||
for pt in self:
|
||||
if pt.intrastat_type == 'product' and pt.type == 'service':
|
||||
raise ValidationError(_(
|
||||
"On the product %s, you cannot set Product Type to "
|
||||
"'Service' and Intrastat Type to 'Product'.") % pt.name)
|
||||
"On the product '%s', you cannot set Product Type to "
|
||||
"'Service' and Intrastat Type to 'Product'.")
|
||||
% pt.display_name)
|
||||
if pt.intrastat_type == 'service' and pt.type == 'product':
|
||||
raise ValidationError(_(
|
||||
"On the product %s, you cannot set Intrastat Type to "
|
||||
"On the product '%s', you cannot set Intrastat Type to "
|
||||
"'Service' and Product Type to 'Stockable product' "
|
||||
"(but you can set Product Type to 'Consumable' or "
|
||||
"'Service').") % pt.name)
|
||||
"'Service').") % pt.display_name)
|
||||
|
||||
@api.onchange('type')
|
||||
def intrastat_type_onchange(self):
|
||||
if self.type in ('product', 'consu'):
|
||||
self.intrastat_type = 'product'
|
||||
elif self.type == 'service':
|
||||
self.intrastat_type = 'service'
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if vals.get('type'):
|
||||
if not vals.get('intrastat_type'):
|
||||
if vals['type'] in ('product', 'consu'):
|
||||
vals['intrastat_type'] = 'product'
|
||||
elif vals['type'] == 'service':
|
||||
vals['intrastat_type'] = 'service'
|
||||
elif (
|
||||
vals.get('intrastat_type') == 'product' and
|
||||
vals['type'] == 'service'):
|
||||
# usefull because intrastat_type = 'product' by default and
|
||||
# wizards in other modules that don't depend on this module
|
||||
# (e.g. sale_rental) may create a product with only
|
||||
# {'type': 'service'} and no 'intrastat_type'
|
||||
vals['intrastat_type'] = 'service'
|
||||
return super(ProductTemplate, self).create(vals)
|
||||
@api.depends('type')
|
||||
def _compute_intrastat_type(self):
|
||||
for pt in self:
|
||||
if pt.type in ('product', 'consu'):
|
||||
intrastat_type = 'product'
|
||||
else:
|
||||
intrastat_type = 'service'
|
||||
pt.intrastat_type = intrastat_type
|
||||
|
||||
|
||||
class L10nFrIntrastatServiceDeclaration(models.Model):
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016-2019 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
|
||||
def set_intrastat_type_on_products(cr, registry):
|
||||
cr.execute(
|
||||
"UPDATE product_template SET intrastat_type='service' "
|
||||
"WHERE type='service'")
|
||||
return
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2016-2019 Akretion (http://www.akretion.com/)
|
||||
Copyright 2016-2023 Akretion France (http://www.akretion.com/)
|
||||
@author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
|
||||
0
mrp_subcontracting_usability/__init__.py
Normal file
0
mrp_subcontracting_usability/__init__.py
Normal file
18
mrp_subcontracting_usability/__manifest__.py
Normal file
18
mrp_subcontracting_usability/__manifest__.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Copyright 2023 Akretion (http://www.akretion.com)
|
||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
{
|
||||
'name': 'MRP Subcontracting Usability',
|
||||
'version': '14.0.1.0.0',
|
||||
'category': 'Manufacturing',
|
||||
'license': 'AGPL-3',
|
||||
'summary': 'Usability improvements on mrp_subcontracting',
|
||||
'author': 'Akretion',
|
||||
'website': 'https://github.com/akretion/odoo-usability',
|
||||
'depends': ['mrp_subcontracting'],
|
||||
'data': [
|
||||
'views/mrp_bom.xml',
|
||||
],
|
||||
'installable': True,
|
||||
}
|
||||
22
mrp_subcontracting_usability/views/mrp_bom.xml
Normal file
22
mrp_subcontracting_usability/views/mrp_bom.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
|
||||
<record id="view_mrp_bom_filter" model="ir.ui.view">
|
||||
<field name="model">mrp.bom</field>
|
||||
<field name="inherit_id" ref="mrp.view_mrp_bom_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<filter name="phantom" position="after">
|
||||
<filter name="subcontract" domain="[('type', '=', 'subcontract')]" string="Subcontracting"/>
|
||||
</filter>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
</odoo>
|
||||
@@ -31,7 +31,10 @@ Akretion:
|
||||
"views/report_pos_order.xml",
|
||||
"views/pos_category.xml",
|
||||
"views/pos_session.xml",
|
||||
"views/pos_order.xml",
|
||||
"views/pos_config.xml",
|
||||
"views/product.xml",
|
||||
"views/pos_payment_method.xml",
|
||||
],
|
||||
"installable": True,
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from . import product
|
||||
from . import pos_category
|
||||
from . import pos_config
|
||||
from . import pos_payment_method
|
||||
|
||||
12
pos_usability/models/pos_config.py
Normal file
12
pos_usability/models/pos_config.py
Normal file
@@ -0,0 +1,12 @@
|
||||
# Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class PosConfig(models.Model):
|
||||
_inherit = 'pos.config'
|
||||
_order = 'sequence, id'
|
||||
|
||||
sequence = fields.Integer(default=10)
|
||||
@@ -8,5 +8,7 @@ from odoo import fields, models
|
||||
class PosPaymentMethod(models.Model):
|
||||
_inherit = 'pos.payment.method'
|
||||
_check_company_auto = True
|
||||
_order = 'sequence, id'
|
||||
|
||||
cash_journal_id = fields.Many2one(check_company=True)
|
||||
sequence = fields.Integer(default=10)
|
||||
|
||||
35
pos_usability/pos-payment_terminal-auto_validate.diff
Normal file
35
pos_usability/pos-payment_terminal-auto_validate.diff
Normal file
@@ -0,0 +1,35 @@
|
||||
diff --git a/addons/point_of_sale/static/src/js/Screens/PaymentScreen/PaymentScreen.js b/addons/point_of_sale/static/src/js/Screens/PaymentScreen/PaymentScreen.js
|
||||
index 55aa635aa10..d91ea933a71 100644
|
||||
--- a/addons/point_of_sale/static/src/js/Screens/PaymentScreen/PaymentScreen.js
|
||||
+++ b/addons/point_of_sale/static/src/js/Screens/PaymentScreen/PaymentScreen.js
|
||||
@@ -8,6 +8,7 @@ odoo.define('point_of_sale.PaymentScreen', function (require) {
|
||||
const { useListener } = require('web.custom_hooks');
|
||||
const Registries = require('point_of_sale.Registries');
|
||||
const { onChangeOrder } = require('point_of_sale.custom_hooks');
|
||||
+ const utils = require('web.utils');
|
||||
|
||||
class PaymentScreen extends PosComponent {
|
||||
constructor() {
|
||||
@@ -20,6 +21,7 @@ odoo.define('point_of_sale.PaymentScreen', function (require) {
|
||||
useListener('send-payment-cancel', this._sendPaymentCancel);
|
||||
useListener('send-payment-reverse', this._sendPaymentReverse);
|
||||
useListener('send-force-done', this._sendForceDone);
|
||||
+ useListener('validate-order', () => this.validateOrder(false));
|
||||
this.lockedValidateOrder = useAsyncLockedMethod(this.validateOrder);
|
||||
NumberBuffer.use(this._getNumberBufferConfig);
|
||||
onChangeOrder(this._onPrevOrder, this._onNewOrder);
|
||||
@@ -333,6 +335,14 @@ odoo.define('point_of_sale.PaymentScreen', function (require) {
|
||||
if (isPaymentSuccessful) {
|
||||
line.set_payment_status('done');
|
||||
line.can_be_reversed = payment_terminal.supports_reversals;
|
||||
+ // Automatically validate the order if, after an electronic payment,
|
||||
+ // the current order is fully paid (BACKPORT FROM v16)
|
||||
+ if (
|
||||
+ this.currentOrder.is_paid() &&
|
||||
+ utils.float_is_zero(this.currentOrder.get_due(), this.env.pos.currency.decimals)
|
||||
+ ) {
|
||||
+ this.trigger('validate-order');
|
||||
+ }
|
||||
} else {
|
||||
line.set_payment_status('retry');
|
||||
}
|
||||
22
pos_usability/pos_payment_method-sort_by_sequence.diff
Normal file
22
pos_usability/pos_payment_method-sort_by_sequence.diff
Normal file
@@ -0,0 +1,22 @@
|
||||
diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js
|
||||
index 86a7b44bcfb..06b46ba5645 100644
|
||||
--- a/addons/point_of_sale/static/src/js/models.js
|
||||
+++ b/addons/point_of_sale/static/src/js/models.js
|
||||
@@ -514,16 +514,7 @@ exports.PosModel = Backbone.Model.extend({
|
||||
fields: ['name', 'is_cash_count', 'use_payment_terminal'],
|
||||
domain: function(self){return ['|',['active', '=', false], ['active', '=', true]]; },
|
||||
loaded: function(self, payment_methods) {
|
||||
- self.payment_methods = payment_methods.sort(function(a,b){
|
||||
- // prefer cash payment_method to be first in the list
|
||||
- if (a.is_cash_count && !b.is_cash_count) {
|
||||
- return -1;
|
||||
- } else if (!a.is_cash_count && b.is_cash_count) {
|
||||
- return 1;
|
||||
- } else {
|
||||
- return a.id - b.id;
|
||||
- }
|
||||
- });
|
||||
+ self.payment_methods = payment_methods;
|
||||
self.payment_methods_by_id = {};
|
||||
_.each(self.payment_methods, function(payment_method) {
|
||||
self.payment_methods_by_id[payment_method.id] = payment_method;
|
||||
21
pos_usability/views/pos_config.xml
Normal file
21
pos_usability/views/pos_config.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<record id="view_pos_config_tree" model="ir.ui.view">
|
||||
<field name="model">pos.config</field>
|
||||
<field name="inherit_id" ref="point_of_sale.view_pos_config_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="name" position="before">
|
||||
<field name="sequence" widget="handle"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
||||
21
pos_usability/views/pos_order.xml
Normal file
21
pos_usability/views/pos_order.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<record id="view_pos_pos_form" model="ir.ui.view">
|
||||
<field name="model">pos.order</field>
|
||||
<field name="inherit_id" ref="point_of_sale.view_pos_pos_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='lines']/form//field[@name='full_product_name']" position="before">
|
||||
<field name="product_id"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
20
pos_usability/views/pos_payment_method.xml
Normal file
20
pos_usability/views/pos_payment_method.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<record id="pos_payment_method_view_tree" model="ir.ui.view">
|
||||
<field name="model">pos.payment.method</field>
|
||||
<field name="inherit_id" ref="point_of_sale.pos_payment_method_view_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="name" position="before">
|
||||
<field name="sequence" widget="handle"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -1,20 +1,50 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * product_category_tax
|
||||
# * product_category_tax
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 8.0-20150727\n"
|
||||
"Project-Id-Version: Odoo Server 14.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-12-04 17:16+0000\n"
|
||||
"PO-Revision-Date: 2015-12-04 17:16+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"POT-Creation-Date: 2023-10-16 20:34+0000\n"
|
||||
"PO-Revision-Date: 2023-10-16 20:34+0000\n"
|
||||
"Last-Translator: Alexis de Lattre <alexis.delattre@akretion.com>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: fr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: product_category_tax
|
||||
#: model:ir.model,name:product_category_tax.model_product_categ_tax_mixin
|
||||
msgid "Common code for taxes on product categories"
|
||||
msgstr "Code commun pour les taxes sur les catégories d'articles"
|
||||
|
||||
#. module: product_category_tax
|
||||
#: model:ir.model.fields,field_description:product_category_tax.field_product_categ_tax_mixin__display_name
|
||||
#: model:ir.model.fields,field_description:product_category_tax.field_product_category__display_name
|
||||
#: model:ir.model.fields,field_description:product_category_tax.field_product_product__display_name
|
||||
#: model:ir.model.fields,field_description:product_category_tax.field_product_template__display_name
|
||||
msgid "Display Name"
|
||||
msgstr "Nom affiché"
|
||||
|
||||
#. module: product_category_tax
|
||||
#: model:ir.model.fields,field_description:product_category_tax.field_product_categ_tax_mixin__id
|
||||
#: model:ir.model.fields,field_description:product_category_tax.field_product_category__id
|
||||
#: model:ir.model.fields,field_description:product_category_tax.field_product_product__id
|
||||
#: model:ir.model.fields,field_description:product_category_tax.field_product_template__id
|
||||
msgid "ID"
|
||||
msgstr "ID"
|
||||
|
||||
#. module: product_category_tax
|
||||
#: model:ir.model.fields,field_description:product_category_tax.field_product_categ_tax_mixin____last_update
|
||||
#: model:ir.model.fields,field_description:product_category_tax.field_product_category____last_update
|
||||
#: model:ir.model.fields,field_description:product_category_tax.field_product_product____last_update
|
||||
#: model:ir.model.fields,field_description:product_category_tax.field_product_template____last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr "Dernière modification le"
|
||||
|
||||
#. module: product_category_tax
|
||||
#: model:ir.model,name:product_category_tax.model_product_product
|
||||
msgid "Product"
|
||||
@@ -23,7 +53,7 @@ msgstr "Article"
|
||||
#. module: product_category_tax
|
||||
#: model:ir.model,name:product_category_tax.model_product_category
|
||||
msgid "Product Category"
|
||||
msgstr "Catégorie d'articles"
|
||||
msgstr "Catégorie d'article"
|
||||
|
||||
#. module: product_category_tax
|
||||
#: model:ir.model,name:product_category_tax.model_product_template
|
||||
@@ -31,23 +61,31 @@ msgid "Product Template"
|
||||
msgstr "Modèle d'article"
|
||||
|
||||
#. module: product_category_tax
|
||||
#: field:product.category,purchase_tax_ids:0
|
||||
#: model:ir.model.fields,field_description:product_category_tax.field_product_category__purchase_tax_ids
|
||||
msgid "Purchase Taxes"
|
||||
msgstr "Taxes fournisseurs"
|
||||
msgstr "Taxes à l'achat"
|
||||
|
||||
#. module: product_category_tax
|
||||
#: field:product.category,sale_tax_ids:0
|
||||
#: model:ir.model.fields,field_description:product_category_tax.field_product_category__sale_tax_ids
|
||||
msgid "Sale Taxes"
|
||||
msgstr "Taxes à la vente"
|
||||
|
||||
#. module: product_category_tax
|
||||
#: code:addons/product_category_tax/product.py:57
|
||||
#: code:addons/product_category_tax/product.py:0
|
||||
#, python-format
|
||||
msgid "The purchase taxes configured on the product '%s' are not the same as the purchase taxes configured on it's related product category '%s'."
|
||||
msgstr "Les taxes fournisseurs paramétrées sur l'article '%s' ne sont pas les mêmes que les taxes fournisseurs paramétrées sur la catégorie interne '%s'."
|
||||
msgid ""
|
||||
"The purchase taxes configured on the product '%s' are not the same as the "
|
||||
"purchase taxes configured on it's related internal category '%s'."
|
||||
msgstr ""
|
||||
"Les taxes à l'achat configurées sur l'article '%s' ne sont pas les mêmes que "
|
||||
"les taxes à l'achat configurées sur sa catégorie interne '%s'."
|
||||
|
||||
#. module: product_category_tax
|
||||
#: code:addons/product_category_tax/product.py:49
|
||||
#: code:addons/product_category_tax/product.py:0
|
||||
#, python-format
|
||||
msgid "The sale taxes configured on the product '%s' are not the same as the sale taxes configured on it's related product category '%s'."
|
||||
msgstr "Les taxes à la vente paramétrées sur l'article '%s' ne sont pas les mêmes que les taxes à la vente paramétrées sur la catégorie interne '%s'."
|
||||
msgid ""
|
||||
"The sale taxes configured on the product '%s' are not the same as the sale "
|
||||
"taxes configured on it's related internal category '%s'."
|
||||
msgstr ""
|
||||
"Les taxes à la vente configurées sur l'article '%s' ne sont pas les mêmes que "
|
||||
"les taxes à la vente configurées sur sa catégorie interne '%s'."
|
||||
|
||||
@@ -32,7 +32,7 @@ This module has been written by Alexis de Lattre from Akretion
|
||||
<alexis.delattre@akretion.com>.
|
||||
""",
|
||||
'author': 'Akretion',
|
||||
'website': 'http://www.akretion.com',
|
||||
'website': 'https://github.com/akretion/odoo-usability',
|
||||
# We depend on point_of_sale and not only 'product'
|
||||
# because the price barcode rule is added by the point_of_sale module
|
||||
# (the weight barcode rule is added by the stock module)
|
||||
@@ -46,6 +46,7 @@ This module has been written by Alexis de Lattre from Akretion
|
||||
'security/ir.model.access.csv',
|
||||
'wizard/product_print_zpl_barcode_view.xml',
|
||||
'views/product.xml',
|
||||
'views/stock_picking.xml',
|
||||
'data/barcode_sequence.xml',
|
||||
],
|
||||
'installable': True,
|
||||
|
||||
412
product_print_zpl_barcode/i18n/fr.po
Normal file
412
product_print_zpl_barcode/i18n/fr.po
Normal file
@@ -0,0 +1,412 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * product_print_zpl_barcode
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 16.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-07-15 13:39+0000\n"
|
||||
"PO-Revision-Date: 2023-07-15 13:39+0000\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__copies
|
||||
msgid "# Labels"
|
||||
msgstr "Nb étiquettes"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields.selection,name:product_print_zpl_barcode.selection__product_print_zpl_barcode__label_size__38x25
|
||||
msgid "38x25 mm"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__barcode
|
||||
msgid "Barcode"
|
||||
msgstr "Code-barres"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__nomenclature_id
|
||||
msgid "Barcode Nomenclature"
|
||||
msgstr "Nomenclature des codes-barres"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__rule_id
|
||||
msgid "Barcode Rule"
|
||||
msgstr "Règle de codes-barres"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__barcode_type
|
||||
msgid "Barcode Type"
|
||||
msgstr "Type de code-barres"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_print_zpl_barcode_form
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_print_zpl_barcode_form
|
||||
msgid "Close"
|
||||
msgstr "Fermer"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__company_id
|
||||
msgid "Company"
|
||||
msgstr "Société"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__create_uid
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__create_uid
|
||||
msgid "Created by"
|
||||
msgstr "Créé par"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__create_date
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__create_date
|
||||
msgid "Created on"
|
||||
msgstr "Créé le"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__currency_id
|
||||
msgid "Currency"
|
||||
msgstr "Devise"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,help:product_print_zpl_barcode.field_product_print_zpl_barcode_line__uom_id
|
||||
msgid "Default unit of measure used for all stock operations."
|
||||
msgstr ""
|
||||
"Unité de mesure par défaut utilisée pour toutes les opérations de stock."
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__display_name
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__display_name
|
||||
msgid "Display Name"
|
||||
msgstr "Nom affiché"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,help:product_print_zpl_barcode.field_product_product__must_print_barcode
|
||||
#: model:ir.model.fields,help:product_print_zpl_barcode.field_product_template__must_print_barcode
|
||||
msgid ""
|
||||
"Enable that option for products for which you must print a barcode upon "
|
||||
"reception in stock."
|
||||
msgstr ""
|
||||
"Activez cette option sur les articles pour lesquels vous devez imprimer un "
|
||||
"code-barres dès leur réception en stock."
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.actions.act_window,name:product_print_zpl_barcode.product_print_zpl_barcode_action
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_normal_form_view
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_template_only_form_view
|
||||
msgid "Generate Barcode"
|
||||
msgstr "Générer un code-barres"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_print_zpl_barcode_form
|
||||
msgid "Generate Labels"
|
||||
msgstr "Générer les étiquettes"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model,name:product_print_zpl_barcode.model_product_print_zpl_barcode
|
||||
msgid "Generate and print product barcodes in ZPL"
|
||||
msgstr "Générer et imprimer des codes-barres d'articles en ZPL"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__id
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__id
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__label_size
|
||||
msgid "Label Size"
|
||||
msgstr "Taille de l'étiquette"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode____last_update
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line____last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr "Dernière modification le"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__write_uid
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__write_uid
|
||||
msgid "Last Updated by"
|
||||
msgstr "Dernière mise à jour par"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__write_date
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__write_date
|
||||
msgid "Last Updated on"
|
||||
msgstr "Dernière mise à jour le"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Line '%s': barcode '%s' has %d digits. This wizard only supports EAN8 and "
|
||||
"EAN13 for the moment."
|
||||
msgstr ""
|
||||
"Ligne '%s' : le code-barres '%s' comporte %d chiffres. Cet assistant ne "
|
||||
"prend en charge que les EAN8 et EAN13 pour le moment."
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid "Line '%s': barcode type '%s' is not supported for the moment"
|
||||
msgstr ""
|
||||
"Ligne '%s' : le type de code-barres '%s' n'est pas supporté pour le moment"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Line '%s': the barcode '%s' is not a valid EAN barcode (wrong checksum)."
|
||||
msgstr ""
|
||||
"Ligne '%s' : le code-barres '%s' n'est pas un code-barres EAN valide "
|
||||
"(mauvaise somme de contrôle)."
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model,name:product_print_zpl_barcode.model_product_print_zpl_barcode_line
|
||||
msgid "Line of the print ZPL barcode wizard"
|
||||
msgstr "Ligne de l'assistant d'impression du code-barres ZPL"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__line_ids
|
||||
msgid "Lines"
|
||||
msgstr "Lignes"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid "Missing Products"
|
||||
msgstr "Produits manquants"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_product__must_print_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_template__must_print_barcode
|
||||
msgid "Must Print Barcode"
|
||||
msgstr "Code-barres à imprimer"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid "On line '%s', the number of copies must be strictly positive."
|
||||
msgstr ""
|
||||
"Sur la ligne '%s', le nombre d'étiquettes doit être strictement positif."
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_product__barcode_image_png
|
||||
msgid "PNG Barcode Image"
|
||||
msgstr "Image PNG du code-barres"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__parent_id
|
||||
msgid "Parent"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__price
|
||||
msgid "Price"
|
||||
msgstr "Prix"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__price_uom
|
||||
msgid "Price/UoM"
|
||||
msgstr "Prix/unité"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__pricelist_id
|
||||
msgid "Pricelist"
|
||||
msgstr "Liste de prix"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_print_zpl_barcode_form
|
||||
msgid "Print"
|
||||
msgstr "Imprimer"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_normal_form_view
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_template_only_form_view
|
||||
msgid "Print Barcode"
|
||||
msgstr "Imprimer le code-barres"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_product_tree_view
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_template_tree_view
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.view_picking_form
|
||||
msgid "Print Barcodes"
|
||||
msgstr "Imprimer les code-barres"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model,name:product_print_zpl_barcode.model_product_template
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__product_id
|
||||
msgid "Product"
|
||||
msgstr "Article"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__product_name
|
||||
msgid "Product Label"
|
||||
msgstr "Étiquette de l'article"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model,name:product_print_zpl_barcode.model_product_product
|
||||
msgid "Product Variant"
|
||||
msgstr "Variante d'article"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__quantity
|
||||
msgid "Qty"
|
||||
msgstr "Qté"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_product__barcode_image_svg
|
||||
msgid "SVG Barcode Image"
|
||||
msgstr "Image SVG du code-barres"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_stock_picking__show_print_zpl_barcode
|
||||
msgid "Show Print Zpl Barcode"
|
||||
msgstr "Afficher le bouton imprimer le code-barres ZPL"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__state
|
||||
msgid "State"
|
||||
msgstr "État"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields.selection,name:product_print_zpl_barcode.selection__product_print_zpl_barcode__state__step1
|
||||
msgid "Step1"
|
||||
msgstr "Étape 1"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields.selection,name:product_print_zpl_barcode.selection__product_print_zpl_barcode__state__step2
|
||||
msgid "Step2"
|
||||
msgstr "Étape 2"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The barcode of the product (%s) has %d characters, which is smaller than the"
|
||||
" %d characters of the prefix of the barcode pattern (%s)."
|
||||
msgstr ""
|
||||
"Le code-barres de l'article (%s) comporte %d caractères, ce qui est plus "
|
||||
"petit que les %d caractères du préfixe du modèle de code-barres (%s)."
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The barcode rule '%s' has a pattern '%s' which doesn't contain a integer and"
|
||||
" decimal part between '{}'."
|
||||
msgstr ""
|
||||
"La règle de code-barres '%s' a un motif '%s' qui ne contient pas de partie "
|
||||
"entière et décimale entre '{}'."
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/models/product.py:0
|
||||
#, python-format
|
||||
msgid "The product '%s' already has a barcode."
|
||||
msgstr "L'article '%s' a déjà un code-barres."
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid "The quantity (%s) must be positive !"
|
||||
msgstr "La quantité (%s) doit être positive !"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/models/product.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The sequence 'private.product.barcode' is not properly configured. The "
|
||||
"generated sequence should have 7 digits (for EAN-8) or 12 digits (for "
|
||||
"EAN-13). It currently has %d digits."
|
||||
msgstr ""
|
||||
"La séquence 'private.product.barcode' n'est pas correctement configurée. La "
|
||||
"séquence générée devrait avoir 7 chiffres (pour EAN-8) ou 12 chiffres (pour "
|
||||
"EAN-13). Elle comporte actuellement %d chiffres."
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The value to encode in the barcode (%s) is superior to the maximum value "
|
||||
"allowed by the barcode pattern (%s)."
|
||||
msgstr ""
|
||||
"La valeur à encoder dans le code-barres (%s) est supérieure à la valeur "
|
||||
"maximale autorisée par le motif du code-barres (%s)."
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid "There are no pricelist in company '%s'."
|
||||
msgstr "Il n'y a pas de liste de prix dans la société '%s'."
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model,name:product_print_zpl_barcode.model_stock_picking
|
||||
msgid "Transfer"
|
||||
msgstr "Transfert"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__uom_id
|
||||
msgid "UoM"
|
||||
msgstr "Unité"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid "Wrong active_model in context (%s)."
|
||||
msgstr "Mauvais active_model dans le contexte (%s)."
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/models/product.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You cannot call the method generate_barcode_from_product_template on product"
|
||||
" '%s' because it has %d variants and not just one."
|
||||
msgstr ""
|
||||
"Vous ne pouvez pas appeler la méthode generate_barcode_from_product_template"
|
||||
" sur l'article '%s' parce qu'il a %d variantes et non une seule."
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid "You must select a ZPL Printer."
|
||||
msgstr "Vous devez sélectionner une imprimante ZPL."
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__zpl_file
|
||||
msgid "ZPL File"
|
||||
msgstr "Fichier ZPL"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__zpl_filename
|
||||
msgid "ZPL Filename"
|
||||
msgstr "Nom du fichier ZPL"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__zpl_printer_id
|
||||
msgid "ZPL Printer"
|
||||
msgstr "Imprimante ZPL"
|
||||
392
product_print_zpl_barcode/i18n/product_print_zpl_barcode.pot
Normal file
392
product_print_zpl_barcode/i18n/product_print_zpl_barcode.pot
Normal file
@@ -0,0 +1,392 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * product_print_zpl_barcode
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 16.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-07-15 13:39+0000\n"
|
||||
"PO-Revision-Date: 2023-07-15 13:39+0000\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__copies
|
||||
msgid "# Labels"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields.selection,name:product_print_zpl_barcode.selection__product_print_zpl_barcode__label_size__38x25
|
||||
msgid "38x25 mm"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__barcode
|
||||
msgid "Barcode"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__nomenclature_id
|
||||
msgid "Barcode Nomenclature"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__rule_id
|
||||
msgid "Barcode Rule"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__barcode_type
|
||||
msgid "Barcode Type"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_print_zpl_barcode_form
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_print_zpl_barcode_form
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__company_id
|
||||
msgid "Company"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__create_uid
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__create_uid
|
||||
msgid "Created by"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__create_date
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__create_date
|
||||
msgid "Created on"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__currency_id
|
||||
msgid "Currency"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,help:product_print_zpl_barcode.field_product_print_zpl_barcode_line__uom_id
|
||||
msgid "Default unit of measure used for all stock operations."
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__display_name
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__display_name
|
||||
msgid "Display Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,help:product_print_zpl_barcode.field_product_product__must_print_barcode
|
||||
#: model:ir.model.fields,help:product_print_zpl_barcode.field_product_template__must_print_barcode
|
||||
msgid ""
|
||||
"Enable that option for products for which you must print a barcode upon "
|
||||
"reception in stock."
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.actions.act_window,name:product_print_zpl_barcode.product_print_zpl_barcode_action
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_normal_form_view
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_template_only_form_view
|
||||
msgid "Generate Barcode"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_print_zpl_barcode_form
|
||||
msgid "Generate Labels"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model,name:product_print_zpl_barcode.model_product_print_zpl_barcode
|
||||
msgid "Generate and print product barcodes in ZPL"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__id
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__id
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__label_size
|
||||
msgid "Label Size"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode____last_update
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line____last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__write_uid
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__write_uid
|
||||
msgid "Last Updated by"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__write_date
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__write_date
|
||||
msgid "Last Updated on"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Line '%s': barcode '%s' has %d digits. This wizard only supports EAN8 and "
|
||||
"EAN13 for the moment."
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid "Line '%s': barcode type '%s' is not supported for the moment"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Line '%s': the barcode '%s' is not a valid EAN barcode (wrong checksum)."
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model,name:product_print_zpl_barcode.model_product_print_zpl_barcode_line
|
||||
msgid "Line of the print ZPL barcode wizard"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__line_ids
|
||||
msgid "Lines"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid "Missing Products"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_product__must_print_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_template__must_print_barcode
|
||||
msgid "Must Print Barcode"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid "On line '%s', the number of copies must be strictly positive."
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_product__barcode_image_png
|
||||
msgid "PNG Barcode Image"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__parent_id
|
||||
msgid "Parent"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__price
|
||||
msgid "Price"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__price_uom
|
||||
msgid "Price/UoM"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__pricelist_id
|
||||
msgid "Pricelist"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_print_zpl_barcode_form
|
||||
msgid "Print"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_normal_form_view
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_template_only_form_view
|
||||
msgid "Print Barcode"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_product_tree_view
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.product_template_tree_view
|
||||
#: model_terms:ir.ui.view,arch_db:product_print_zpl_barcode.view_picking_form
|
||||
msgid "Print Barcodes"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model,name:product_print_zpl_barcode.model_product_template
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__product_id
|
||||
msgid "Product"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__product_name
|
||||
msgid "Product Label"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model,name:product_print_zpl_barcode.model_product_product
|
||||
msgid "Product Variant"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__quantity
|
||||
msgid "Qty"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_product__barcode_image_svg
|
||||
msgid "SVG Barcode Image"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_stock_picking__show_print_zpl_barcode
|
||||
msgid "Show Print Zpl Barcode"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__state
|
||||
msgid "State"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields.selection,name:product_print_zpl_barcode.selection__product_print_zpl_barcode__state__step1
|
||||
msgid "Step1"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields.selection,name:product_print_zpl_barcode.selection__product_print_zpl_barcode__state__step2
|
||||
msgid "Step2"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The barcode of the product (%s) has %d characters, which is smaller than the"
|
||||
" %d characters of the prefix of the barcode pattern (%s)."
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The barcode rule '%s' has a pattern '%s' which doesn't contain a integer and"
|
||||
" decimal part between '{}'."
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/models/product.py:0
|
||||
#, python-format
|
||||
msgid "The product '%s' already has a barcode."
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid "The quantity (%s) must be positive !"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/models/product.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The sequence 'private.product.barcode' is not properly configured. The "
|
||||
"generated sequence should have 7 digits (for EAN-8) or 12 digits (for "
|
||||
"EAN-13). It currently has %d digits."
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The value to encode in the barcode (%s) is superior to the maximum value "
|
||||
"allowed by the barcode pattern (%s)."
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid "There are no pricelist in company '%s'."
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model,name:product_print_zpl_barcode.model_stock_picking
|
||||
msgid "Transfer"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode_line__uom_id
|
||||
msgid "UoM"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid "Wrong active_model in context (%s)."
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/models/product.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You cannot call the method generate_barcode_from_product_template on product"
|
||||
" '%s' because it has %d variants and not just one."
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#. odoo-python
|
||||
#: code:addons/product_print_zpl_barcode/wizard/product_print_zpl_barcode.py:0
|
||||
#, python-format
|
||||
msgid "You must select a ZPL Printer."
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__zpl_file
|
||||
msgid "ZPL File"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__zpl_filename
|
||||
msgid "ZPL Filename"
|
||||
msgstr ""
|
||||
|
||||
#. module: product_print_zpl_barcode
|
||||
#: model:ir.model.fields,field_description:product_print_zpl_barcode.field_product_print_zpl_barcode__zpl_printer_id
|
||||
msgid "ZPL Printer"
|
||||
msgstr ""
|
||||
@@ -1 +1,2 @@
|
||||
from . import product
|
||||
from . import stock_picking
|
||||
|
||||
@@ -29,22 +29,6 @@ class ProductTemplate(models.Model):
|
||||
% (self.display_name, self.product_variant_count))
|
||||
return self.product_variant_ids[0].generate_barcode_from_product_product()
|
||||
|
||||
def print_zpl_barcode_from_product_template(self):
|
||||
self.ensure_one()
|
||||
if self.product_variant_count != 1:
|
||||
raise UserError(_(
|
||||
"You cannot call the method "
|
||||
"print_zpl_barcode_from_product_template on product '%s' "
|
||||
"because it has %d variants and not just one.")
|
||||
% (self.display_name, self.product_variant_count))
|
||||
action = self.env["ir.actions.actions"]._for_xml_id(
|
||||
'product_print_zpl_barcode.product_print_zpl_barcode_action')
|
||||
action['context'] = {
|
||||
'active_id': self.product_variant_ids[0].id,
|
||||
'active_model': 'product.product',
|
||||
}
|
||||
return action
|
||||
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = 'product.product'
|
||||
|
||||
25
product_print_zpl_barcode/models/stock_picking.py
Normal file
25
product_print_zpl_barcode/models/stock_picking.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.tools import float_compare
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
_inherit = "stock.picking"
|
||||
|
||||
show_print_zpl_barcode = fields.Boolean(compute='_compute_show_print_zpl_barcode')
|
||||
|
||||
@api.depends('state')
|
||||
def _compute_show_print_zpl_barcode(self):
|
||||
prec = self.env['decimal.precision'].precision_get('Product Unit of Measure')
|
||||
for picking in self:
|
||||
show = False
|
||||
if picking.state == 'done' and picking.picking_type_code != 'outgoing':
|
||||
for line in picking.move_line_ids:
|
||||
if (
|
||||
line.product_id.must_print_barcode and
|
||||
float_compare(line.qty_done, 0, precision_digits=prec) > 0):
|
||||
show = True
|
||||
picking.show_print_zpl_barcode = show
|
||||
@@ -1,2 +1,3 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_product_print_zpl_barcode,Full access to product.print.zpl.barcode wizard,model_product_print_zpl_barcode,base_report_to_printer.printing_group_user,1,1,1,1
|
||||
access_product_print_zpl_barcode_line,Full access to product.print.zpl.barcode.line wizard,model_product_print_zpl_barcode_line,base_report_to_printer.printing_group_user,1,1,1,1
|
||||
|
||||
|
@@ -27,11 +27,23 @@
|
||||
<field name="arch" type="xml">
|
||||
<header position="inside">
|
||||
<button name="generate_barcode_from_product_template" type="object" string="Generate Barcode" attrs="{'invisible': ['|', ('product_variant_count', '>', 1), ('barcode', '!=', False)]}"/>
|
||||
<button name="print_zpl_barcode_from_product_template" type="object" string="Print Barcode" groups="base_report_to_printer.printing_group_user" attrs="{'invisible': ['|', ('product_variant_count', '>', 1), ('barcode', '=', False)]}"/>
|
||||
<button name="%(product_print_zpl_barcode.product_print_zpl_barcode_action)d" type="action" string="Print Barcode" groups="base_report_to_printer.printing_group_user" attrs="{'invisible': ['|', ('product_variant_count', '>', 1), ('barcode', '=', False)]}"/>
|
||||
</header>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_template_tree_view" model="ir.ui.view">
|
||||
<field name="model">product.template</field>
|
||||
<field name="inherit_id" ref="product.product_template_tree_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="product_variant_count" position="before">
|
||||
<header>
|
||||
<button name="%(product_print_zpl_barcode.product_print_zpl_barcode_action)d" type="action" string="Print Barcodes" groups="base_report_to_printer.printing_group_user"/>
|
||||
</header>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="product_normal_form_view" model="ir.ui.view">
|
||||
<field name="model">product.product</field>
|
||||
@@ -44,5 +56,16 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_product_tree_view" model="ir.ui.view">
|
||||
<field name="model">product.product</field>
|
||||
<field name="inherit_id" ref="product.product_product_tree_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="default_code" position="before">
|
||||
<header>
|
||||
<button name="%(product_print_zpl_barcode.product_print_zpl_barcode_action)d" type="action" string="Print Barcodes" groups="base_report_to_printer.printing_group_user"/>
|
||||
</header>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
||||
21
product_print_zpl_barcode/views/stock_picking.xml
Normal file
21
product_print_zpl_barcode/views/stock_picking.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
@author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<record id="view_picking_form" model="ir.ui.view">
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<button name="action_toggle_is_locked" position="after">
|
||||
<button name="%(product_print_zpl_barcode.product_print_zpl_barcode_action)d" type="action" string="Print Barcodes" attrs="{'invisible': [('show_print_zpl_barcode', '=', False)]}"/>
|
||||
<field name="show_print_zpl_barcode" invisible="1"/>
|
||||
</button>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright 2016-2020 Akretion France (http://www.akretion.com/)
|
||||
# Copyright 2016-2023 Akretion France (http://www.akretion.com/)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
@@ -9,23 +9,18 @@ from stdnum.ean import is_valid, calc_check_digit
|
||||
import base64
|
||||
import re
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ProductPrintZplBarcode(models.TransientModel):
|
||||
_name = 'product.print.zpl.barcode'
|
||||
_description = 'Generate and print product barcodes in ZPL'
|
||||
_check_company_auto = True
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
res = super().default_get(fields_list)
|
||||
assert self._context.get('active_model') == 'product.product',\
|
||||
'wrong active_model, should be product.product'
|
||||
product_id = self._context.get('active_id')
|
||||
product = self.env['product.product'].browse(product_id)
|
||||
if not product:
|
||||
raise UserError(_('Missing Product'))
|
||||
if not product.barcode:
|
||||
raise UserError(_(
|
||||
"Product '%s' doesn't have a barcode") % product.display_name)
|
||||
nomenclature = self.env.ref('barcodes.default_barcode_nomenclature')
|
||||
company = self.env.company
|
||||
posconfig = self.env['pos.config'].sudo().search(
|
||||
@@ -39,82 +34,200 @@ class ProductPrintZplBarcode(models.TransientModel):
|
||||
], limit=1)
|
||||
if not pricelist:
|
||||
raise UserError(_(
|
||||
"There are no pricelist in company %s ?") % company.name)
|
||||
"There are no pricelist in company '%s'.") % company.name)
|
||||
|
||||
printer = self.env['printing.printer'].get_default()
|
||||
|
||||
line_ids = []
|
||||
if self._context.get('active_model') == 'product.product':
|
||||
product_ids = self._context.get('active_ids')
|
||||
products = self.env['product.product'].browse(product_ids)
|
||||
if not products:
|
||||
raise UserError(_('Missing Products'))
|
||||
for product in products:
|
||||
self._update_line_ids(line_ids, product)
|
||||
elif self._context.get('active_model') == 'product.template':
|
||||
product_tmpl_ids = self._context.get('active_ids')
|
||||
product_tmpls = self.env['product.template'].browse(product_tmpl_ids)
|
||||
for product_tmpl in product_tmpls:
|
||||
for product in product_tmpl.product_variant_ids:
|
||||
self._update_line_ids(line_ids, product)
|
||||
elif self._context.get('active_model') == 'stock.picking':
|
||||
prec = self.env['decimal.precision'].precision_get(
|
||||
'Product Unit of Measure')
|
||||
picking = self.env['stock.picking'].browse(self._context['active_id'])
|
||||
for ml in picking.move_line_ids:
|
||||
if (
|
||||
ml.product_id and
|
||||
ml.product_id.must_print_barcode and
|
||||
float_compare(ml.qty_done, 0, precision_digits=prec) > 0):
|
||||
self._update_line_ids(
|
||||
line_ids, ml.product_id, int(round(ml.qty_done)))
|
||||
else:
|
||||
raise UserError(_(
|
||||
"Wrong active_model in context (%s).")
|
||||
% self._context.get('active_model'))
|
||||
res.update({
|
||||
'company_id': company.id,
|
||||
'nomenclature_id': nomenclature.id,
|
||||
'pricelist_id': pricelist.id,
|
||||
'currency_id': pricelist.currency_id.id,
|
||||
'barcode': product.barcode,
|
||||
'product_name': product.name,
|
||||
'product_id': product_id,
|
||||
'zpl_printer_id': printer and printer.id or False,
|
||||
'line_ids': line_ids,
|
||||
})
|
||||
return res
|
||||
|
||||
product_id = fields.Many2one(
|
||||
'product.product', string='Product', required=True, readonly=True)
|
||||
uom_id = fields.Many2one(related='product_id.uom_id')
|
||||
# 1 line = un peu moins de 30
|
||||
product_name = fields.Char('Product Label', required=True, size=56)
|
||||
@api.model
|
||||
def _update_line_ids(self, line_ids, product, copies=1):
|
||||
if product.barcode:
|
||||
line_ids.append((0, 0, {
|
||||
'barcode': product.barcode,
|
||||
'product_name': product.name,
|
||||
'product_id': product.id,
|
||||
'copies': copies,
|
||||
}))
|
||||
else:
|
||||
logger.warning("Product '%s' doesn't have a barcode", product.display_name)
|
||||
|
||||
company_id = fields.Many2one( # default value set by default_get
|
||||
'res.company', required=True, ondelete='cascade')
|
||||
nomenclature_id = fields.Many2one(
|
||||
'barcode.nomenclature', 'Barcode Nomenclature', required=True)
|
||||
rule_id = fields.Many2one(
|
||||
'barcode.rule', string='Barcode Rule', readonly=True,
|
||||
compute='_compute_rule_id')
|
||||
barcode_type = fields.Selection(related='rule_id.type', string="Barcode Type")
|
||||
'barcode.nomenclature', 'Barcode Nomenclature', required=True,
|
||||
states={'step2': [('readonly', True)]})
|
||||
# label_size: remove readonly=True when we will support more labels
|
||||
label_size = fields.Selection([
|
||||
('38x25', '38x25 mm'),
|
||||
], required=True, default='38x25')
|
||||
], required=True, default='38x25', readonly=True)
|
||||
pricelist_id = fields.Many2one(
|
||||
'product.pricelist', string='Pricelist', required=True)
|
||||
currency_id = fields.Many2one(related='pricelist_id.currency_id')
|
||||
# TODO: for the moment, we only support weight, but...
|
||||
quantity = fields.Float(digits='Stock Weight')
|
||||
price_uom = fields.Monetary(
|
||||
readonly=True, string="Price per Unit of Measure",
|
||||
compute='_compute_price') # given by pricelist
|
||||
price = fields.Monetary(compute='_compute_price', readonly=True)
|
||||
currency_id = fields.Many2one('res.currency', string='Currency')
|
||||
'product.pricelist', string='Pricelist', required=True,
|
||||
states={'step2': [('readonly', True)]}, check_company=True,
|
||||
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]"
|
||||
)
|
||||
state = fields.Selection([
|
||||
('step1', 'Step1'),
|
||||
('step2', 'Step2'),
|
||||
], default='step1', readonly=True)
|
||||
zpl_file = fields.Binary(string='ZPL File', readonly=True)
|
||||
zpl_filename = fields.Char('ZPL Filename')
|
||||
barcode = fields.Char(readonly=True)
|
||||
copies = fields.Integer(
|
||||
string='Number of Labels', default=1, required=True)
|
||||
zpl_printer_id = fields.Many2one(
|
||||
'printing.printer', string='ZPL Printer')
|
||||
line_ids = fields.One2many(
|
||||
'product.print.zpl.barcode.line', 'parent_id',
|
||||
string='Lines', states={'step2': [('readonly', True)]})
|
||||
|
||||
@api.depends('pricelist_id', 'quantity', 'product_id')
|
||||
def generate(self):
|
||||
"""Called by button for the wizard, 1st step"""
|
||||
self.ensure_one()
|
||||
zpl_strings = []
|
||||
for line in self.line_ids:
|
||||
barcode = line.barcode
|
||||
product_name = line.product_name
|
||||
assert barcode
|
||||
barcode_len = len(barcode)
|
||||
if barcode_len not in (8, 13):
|
||||
raise UserError(_(
|
||||
"Line '%s': barcode '%s' has %d digits. "
|
||||
"This wizard only supports EAN8 and EAN13 for the moment.")
|
||||
% (product_name, barcode, barcode_len))
|
||||
if not is_valid(barcode):
|
||||
raise UserError(_(
|
||||
"Line '%s': the barcode '%s' is not a valid EAN barcode "
|
||||
"(wrong checksum).") % (product_name, barcode))
|
||||
if line.copies <= 0:
|
||||
raise UserError(_(
|
||||
"On line '%s', the number of copies must be strictly positive."
|
||||
) % product_name)
|
||||
if line.barcode_type in ('price', 'weight'):
|
||||
barcode, zpl_str = line._prepare_price_weight_barcode_type()
|
||||
elif line.barcode_type == 'product':
|
||||
barcode, zpl_str = line._prepare_product_barcode_type()
|
||||
else:
|
||||
raise UserError(_(
|
||||
"Line '%s': barcode type '%s' is not supported for the moment")
|
||||
% (product_name, line.barcode_type))
|
||||
line.write({'barcode': barcode})
|
||||
zpl_strings.append(zpl_str)
|
||||
|
||||
zpl_filename = "barcodes.zpl"
|
||||
if len(self.line_ids) == 1:
|
||||
zpl_filename = "barcode_%s.zpl" % self.line_ids[0].barcode
|
||||
|
||||
zpl_str = '\n'.join(zpl_strings)
|
||||
zpl_bytes = zpl_str.encode('utf-8')
|
||||
vals = {
|
||||
'zpl_file': base64.encodebytes(zpl_bytes),
|
||||
'state': 'step2',
|
||||
'zpl_filename': zpl_filename,
|
||||
}
|
||||
self.write(vals)
|
||||
action = self.env["ir.actions.actions"]._for_xml_id(
|
||||
'product_print_zpl_barcode.product_print_zpl_barcode_action')
|
||||
action.update({
|
||||
'res_id': self.id,
|
||||
'context': self._context,
|
||||
'views': False})
|
||||
return action
|
||||
|
||||
def print_zpl(self):
|
||||
if not self.zpl_printer_id:
|
||||
raise UserError(_(
|
||||
"You must select a ZPL Printer."))
|
||||
self.zpl_printer_id.print_document(
|
||||
self.zpl_filename, base64.decodebytes(self.zpl_file), format='raw')
|
||||
|
||||
|
||||
class ProductPrintZplBarcodeLine(models.TransientModel):
|
||||
_name = 'product.print.zpl.barcode.line'
|
||||
_description = 'Line of the print ZPL barcode wizard'
|
||||
|
||||
parent_id = fields.Many2one(
|
||||
'product.print.zpl.barcode', ondelete='cascade')
|
||||
product_id = fields.Many2one(
|
||||
'product.product', string='Product', readonly=True)
|
||||
uom_id = fields.Many2one(related='product_id.uom_id', string='UoM')
|
||||
# 1 line = a bit less than 30
|
||||
# I don't make product_name a stored computed field because I'm afraid
|
||||
# that we may not take the lang of the user
|
||||
product_name = fields.Char('Product Label', required=True, size=56)
|
||||
rule_id = fields.Many2one(
|
||||
'barcode.rule', string='Barcode Rule', compute='_compute_rule_id')
|
||||
barcode_type = fields.Selection(related='rule_id.type', string="Barcode Type")
|
||||
currency_id = fields.Many2one(related='parent_id.pricelist_id.currency_id')
|
||||
# TODO: for the moment, we only support weight, but...
|
||||
quantity = fields.Float(digits='Stock Weight', string='Qty')
|
||||
price_uom = fields.Monetary(
|
||||
string="Price/UoM", compute='_compute_price') # given by pricelist
|
||||
price = fields.Monetary(compute='_compute_price')
|
||||
barcode = fields.Char(readonly=True)
|
||||
copies = fields.Integer(string='# Labels', default=1, required=True)
|
||||
|
||||
@api.depends('parent_id.pricelist_id', 'quantity', 'product_id')
|
||||
def _compute_price(self):
|
||||
# for regular barcodes
|
||||
for wiz in self:
|
||||
if wiz.pricelist_id and wiz.product_id:
|
||||
price_uom = wiz.pricelist_id.get_product_price(
|
||||
wiz.product_id, 1, False)
|
||||
wiz.price_uom = price_uom
|
||||
wiz.price = price_uom * wiz.quantity
|
||||
for line in self:
|
||||
pricelist = line.parent_id.pricelist_id
|
||||
price_uom = price = 0.0
|
||||
if pricelist and line.product_id:
|
||||
price_uom = pricelist.get_product_price(line.product_id, 1, False)
|
||||
price = price_uom * line.quantity
|
||||
line.price_uom = price_uom
|
||||
line.price = price
|
||||
|
||||
@api.depends('nomenclature_id')
|
||||
@api.depends('parent_id.nomenclature_id')
|
||||
def _compute_rule_id(self):
|
||||
for wiz in self:
|
||||
for line in self:
|
||||
nomenclature = line.parent_id.nomenclature_id
|
||||
match_rule = False
|
||||
if wiz.nomenclature_id and wiz.barcode:
|
||||
for rule in wiz.nomenclature_id.rule_ids:
|
||||
match = wiz.nomenclature_id.match_pattern(
|
||||
wiz.barcode, rule.pattern)
|
||||
if nomenclature and line.barcode:
|
||||
for rule in nomenclature.rule_ids:
|
||||
match = nomenclature.match_pattern(
|
||||
line.barcode, rule.pattern)
|
||||
if match.get('match'):
|
||||
match_rule = rule.id
|
||||
break
|
||||
wiz.rule_id = match_rule
|
||||
line.rule_id = match_rule
|
||||
|
||||
def _prepare_price_weight_barcode_type(self):
|
||||
dpo = self.env['decimal.precision']
|
||||
bno = self.env['barcode.nomenclature']
|
||||
prec = dpo.precision_get('Stock Weight')
|
||||
value = self.quantity
|
||||
pbarcode = self.barcode
|
||||
@@ -139,7 +252,7 @@ class ProductPrintZplBarcode(models.TransientModel):
|
||||
barcode = pbarcode[0:len(prefix)]
|
||||
# print("barcode=", barcode)
|
||||
# print("pattern=", pattern)
|
||||
m = re.search('\{N+D+\}', pattern)
|
||||
m = re.search(r'\{N+D+\}', pattern)
|
||||
# print("m=", m)
|
||||
assert m
|
||||
pattern_val = m.group(0)
|
||||
@@ -172,7 +285,7 @@ class ProductPrintZplBarcode(models.TransientModel):
|
||||
assert len(barcode) == 13
|
||||
assert is_valid(barcode)
|
||||
# print("barcode FINAL=", barcode)
|
||||
zpl_unicode = self._price_weight_barcode_type_zpl() % {
|
||||
zpl_str = self._price_weight_barcode_type_zpl() % {
|
||||
'product_name': self.product_name,
|
||||
'ean_zpl_command': len(self.barcode) == 8 and 'B8' or 'BE',
|
||||
'ean_no_checksum': barcode[:-1],
|
||||
@@ -183,12 +296,7 @@ class ProductPrintZplBarcode(models.TransientModel):
|
||||
'quantity': value,
|
||||
'uom_name': self.uom_id.name,
|
||||
}
|
||||
zpl_bytes = zpl_unicode.encode('utf-8')
|
||||
vals = {
|
||||
'zpl_file': base64.encodebytes(zpl_bytes),
|
||||
'barcode': barcode,
|
||||
}
|
||||
return vals
|
||||
return (barcode, zpl_str)
|
||||
|
||||
@api.model
|
||||
def _price_weight_barcode_type_zpl(self):
|
||||
@@ -229,7 +337,7 @@ class ProductPrintZplBarcode(models.TransientModel):
|
||||
return label
|
||||
|
||||
def _prepare_product_barcode_type(self):
|
||||
zpl_unicode = self._product_barcode_type_zpl() % {
|
||||
zpl_str = self._product_barcode_type_zpl() % {
|
||||
'product_name': self.product_name,
|
||||
'ean_zpl_command': len(self.barcode) == 8 and 'B8' or 'BE',
|
||||
'ean_no_checksum': self.barcode[:-1],
|
||||
@@ -237,60 +345,4 @@ class ProductPrintZplBarcode(models.TransientModel):
|
||||
'currency_symbol': self.currency_id.symbol, # symbol is a required field
|
||||
'copies': self.copies,
|
||||
}
|
||||
zpl_bytes = zpl_unicode.encode('utf-8')
|
||||
vals = {
|
||||
'zpl_file': base64.encodebytes(zpl_bytes),
|
||||
'barcode': self.barcode, # unchanged
|
||||
}
|
||||
return vals
|
||||
|
||||
def generate(self):
|
||||
assert self.barcode
|
||||
if len(self.barcode) not in (8, 13):
|
||||
raise UserError(_(
|
||||
"This wizard only supports EAN8 and EAN13 for the moment. "
|
||||
"Barcode '%s' has %d digits.") % (
|
||||
self.barcode,
|
||||
len(self.barcode)))
|
||||
if not is_valid(self.barcode):
|
||||
raise UserError(_(
|
||||
"The barcode '%s' is not a valid EAN barcode "
|
||||
"(wrong checksum).") % self.barcode)
|
||||
if not self.copies:
|
||||
raise UserError(_("The number of copies cannot be 0"))
|
||||
if self.barcode_type in ('price', 'weight'):
|
||||
vals = self._prepare_price_weight_barcode_type()
|
||||
elif self.barcode_type == 'product':
|
||||
vals = self._prepare_product_barcode_type()
|
||||
else:
|
||||
raise UserError(_(
|
||||
"Barcode Type %s is not supported for the moment")
|
||||
% self.barcode_type)
|
||||
vals.update({
|
||||
'state': 'step2',
|
||||
'zpl_filename': 'barcode_%s.zpl' % vals['barcode'],
|
||||
})
|
||||
self.write(vals)
|
||||
action = self.env["ir.actions.actions"]._for_xml_id(
|
||||
'product_print_zpl_barcode.product_print_zpl_barcode_action')
|
||||
action.update({
|
||||
'res_id': self.id,
|
||||
'context': self._context,
|
||||
'views': False})
|
||||
return action
|
||||
|
||||
def print_zpl(self):
|
||||
if not self.zpl_printer_id:
|
||||
raise UserError(_(
|
||||
"You must select a ZPL Printer."))
|
||||
self.zpl_printer_id.print_document(
|
||||
self.zpl_filename, base64.decodebytes(self.zpl_file), format='raw')
|
||||
action = True
|
||||
if self._context.get('print_and_new'):
|
||||
action = self.env["ir.actions.actions"]._for_xml_id(
|
||||
'product_print_zpl_barcode.product_print_zpl_barcode_action')
|
||||
action.update({
|
||||
'views': False,
|
||||
'context': self._context,
|
||||
})
|
||||
return action
|
||||
return (self.barcode, zpl_str)
|
||||
|
||||
@@ -11,38 +11,41 @@
|
||||
<field name="name">product_print_zpl_barcode.form</field>
|
||||
<field name="model">product.print.zpl.barcode</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Generate and Print Product Barcode">
|
||||
<group name="step1" string="Configuration">
|
||||
<form>
|
||||
<group name="step1">
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
<field name="product_id"/>
|
||||
<field name="product_name" attrs="{'readonly': [('state', '=', 'step2')]}"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<field name="company_id" invisible="1"/>
|
||||
<field name="pricelist_id" attrs="{'readonly': [('state', '=', 'step2')]}"/>
|
||||
<field name="price_uom"/>
|
||||
<field name="label_size" attrs="{'readonly': [('state', '=', 'step2')]}"/>
|
||||
<field name="nomenclature_id" attrs="{'readonly': [('state', '=', 'step2')]}"/>
|
||||
<field name="rule_id"/>
|
||||
<field name="barcode_type"/>
|
||||
<field name="barcode"/>
|
||||
<field name="copies" attrs="{'readonly': [('state', '=', 'step2')]}"/>
|
||||
</group>
|
||||
<group string="Enter Quantity" attrs="{'invisible': [('barcode_type', '=', 'product')]}">
|
||||
<div name="qty_uom">
|
||||
<field name="quantity" attrs="{'readonly': [('state', '=', 'step2')]}" class="oe_inline"/>
|
||||
<field name="uom_id" class="oe_inline"/>
|
||||
</div>
|
||||
</group>
|
||||
<group name="step2" states="step2" string="Label">
|
||||
<field name="price" attrs="{'invisible': [('barcode_type', 'not in', ('price', 'weight'))]}"/>
|
||||
<group name="step2" states="step2">
|
||||
<field name="zpl_file" filename="zpl_filename" />
|
||||
<field name="zpl_filename" invisible="1"/>
|
||||
<field name="zpl_printer_id" attrs="{'required': [('state', '=', 'step2')]}"/>
|
||||
</group>
|
||||
<group name="lines">
|
||||
<field name="line_ids" colspan="2" nolabel="1">
|
||||
<tree editable="bottom">
|
||||
<field name="currency_id" invisible="1"/>
|
||||
<field name="product_id" optional="hide" force_save="1"/>
|
||||
<field name="product_name"/>
|
||||
<field name="price_uom"/>
|
||||
<field name="rule_id" optional="show"/>
|
||||
<field name="barcode_type" optional="hide"/>
|
||||
<field name="barcode" force_save="1"/>
|
||||
<field name="price" attrs="{'invisible': [('barcode_type', 'not in', ('price', 'weight'))]}"/>
|
||||
<field name="quantity" attrs="{'invisible': [('barcode_type', '=', 'product')]}" optional="show"/>
|
||||
<field name="uom_id" attrs="{'invisible': [('barcode_type', '=', 'product')]}" optional="show"/>
|
||||
<field name="copies" />
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="generate" type="object" string="Generate Label" class="btn-primary" states="step1"/>
|
||||
<button name="generate" type="object" string="Generate Labels" class="btn-primary" states="step1"/>
|
||||
<button special="cancel" string="Cancel" class="btn-default" states="step1"/>
|
||||
<button name="print_zpl" type="object" string="Print" class="btn-primary" states="step2"/>
|
||||
<button name="print_zpl" type="object" string="Print and New" class="btn-primary" context="{'print_and_new': True}" attrs="{'invisible': ['|', ('state', '!=', 'step2'), ('barcode_type', '=', 'product')]}"/>
|
||||
<button special="cancel" string="Close" class="btn-default" states="step2"/>
|
||||
</footer>
|
||||
</form>
|
||||
|
||||
@@ -15,6 +15,8 @@ Product Priority Star
|
||||
|
||||
This module adds a priority star on products (like on pickings and manufacturing order). If the star is yellow, the product will be displayed at the top.
|
||||
|
||||
This feature is native in Odoo 16.0.
|
||||
|
||||
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
|
||||
""",
|
||||
'author': 'Akretion',
|
||||
|
||||
@@ -37,6 +37,7 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
|
||||
'views/product_product.xml',
|
||||
'views/product_config_menu.xml',
|
||||
'views/product_category_view.xml',
|
||||
'views/product_attribute_view.xml',
|
||||
],
|
||||
'installable': True,
|
||||
}
|
||||
|
||||
@@ -3,3 +3,4 @@ from . import product_template
|
||||
from . import product_supplierinfo
|
||||
from . import product_pricelist
|
||||
from . import product_category
|
||||
from . import product_attribute
|
||||
|
||||
27
product_usability/models/product_attribute.py
Normal file
27
product_usability/models/product_attribute.py
Normal file
@@ -0,0 +1,27 @@
|
||||
# Copyright (C) 2022 Akretion (<http://www.akretion.com>).
|
||||
# @author Kévin Roche <kevin.roche@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
class ProductAttribute(models.Model):
|
||||
_inherit = "product.attribute"
|
||||
|
||||
values_count = fields.Integer(compute="_compute_values_count")
|
||||
|
||||
@api.depends("value_ids")
|
||||
def _compute_values_count(self):
|
||||
for attr in self:
|
||||
attr.values_count = len(attr.value_ids)
|
||||
|
||||
def show_values_ids(self):
|
||||
return {
|
||||
"name": "Attributes Lines",
|
||||
"type": "ir.actions.act_window",
|
||||
"res_id": self.id,
|
||||
"view_mode": "tree",
|
||||
"res_model": "product.attribute.value",
|
||||
"view_id":self.env.ref("product_usability.product_attribute_value_view_tree").id,
|
||||
"target": "current",
|
||||
"domain": [("id", "in", self.value_ids.ids)],
|
||||
}
|
||||
38
product_usability/views/product_attribute_view.xml
Normal file
38
product_usability/views/product_attribute_view.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="product_attribute_values_button" model="ir.ui.view">
|
||||
<field name="model">product.attribute</field>
|
||||
<field name="inherit_id" ref="product.product_attribute_view_form" />
|
||||
<field name="arch" type="xml">
|
||||
<group name="main_fields" position='before'>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button
|
||||
name="show_values_ids"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-tasks"
|
||||
>
|
||||
<field
|
||||
name="values_count"
|
||||
widget="statinfo"
|
||||
string="Attribute Values"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="product_attribute_value_view_tree">
|
||||
<field name="name">product.attribute.value.view.tree</field>
|
||||
<field name="model">product.attribute.value</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Attributes Values">
|
||||
<field name="name"/>
|
||||
<field name="is_custom"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -32,11 +32,13 @@
|
||||
<field name="model">product.pricelist.item</field>
|
||||
<field name="inherit_id" ref="product.product_pricelist_item_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="applied_on" position="before">
|
||||
<field name="pricelist_id" position="move"/>
|
||||
</field>
|
||||
<field name="pricelist_id" position="attributes">
|
||||
<attribute name="invisible">not context.get('product_pricelist_item_main_view')</attribute>
|
||||
<attribute name="invisible">context.get('from_product_pricelist_view')</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<field name="res_model">product.pricelist.item</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[('pricelist_id', '=', active_id)]</field>
|
||||
<field name="context">{'product_pricelist_item_main_view': True}</field>
|
||||
<field name="context">{'product_pricelist_item_main_view': True, 'default_pricelist_id': active_id}</field>
|
||||
</record>
|
||||
|
||||
<record id="product_pricelist_view" model="ir.ui.view">
|
||||
@@ -34,6 +34,10 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<field name="item_ids" position="attributes">
|
||||
<attribute name="context">{'from_product_pricelist_view': True, 'default_base': 'list_price'}</attribute>
|
||||
</field>
|
||||
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -32,5 +32,16 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_product_tree_view" model="ir.ui.view">
|
||||
<field name="name">usability.product.product.tree</field>
|
||||
<field name="model">product.product</field>
|
||||
<field name="inherit_id" ref="product.product_product_tree_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="company_id" position="before">
|
||||
<field name="seller_id" optional="hide"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<field name="inherit_id" ref="product.product_template_search_view" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="categ_id" position="after">
|
||||
<field name="seller_ids" string="Supplier" filter_domain="[('seller_ids.name', 'ilike', self)]"/>
|
||||
<field name="seller_id" string="Main Supplier"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
@@ -32,4 +32,14 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_template_tree_view" model="ir.ui.view">
|
||||
<field name="model">product.template</field>
|
||||
<field name="inherit_id" ref="product.product_template_tree_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="barcode" position="after">
|
||||
<field name="seller_id" optional="hide"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
||||
0
project_usability/__init__.py
Normal file
0
project_usability/__init__.py
Normal file
20
project_usability/__manifest__.py
Normal file
20
project_usability/__manifest__.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# Copyright 2023 Akretion France (http://www.akretion.com)
|
||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
{
|
||||
'name': 'Project Usability',
|
||||
'version': '14.0.1.0.0',
|
||||
'category': 'Services/Project',
|
||||
'license': 'AGPL-3',
|
||||
'summary': 'Usability improvements on project module',
|
||||
'author': 'Akretion',
|
||||
'website': 'https://github.com/akretion/odoo-usability',
|
||||
'depends': [
|
||||
'project',
|
||||
],
|
||||
'data': [
|
||||
'views/project_project.xml',
|
||||
],
|
||||
'installable': True,
|
||||
}
|
||||
26
project_usability/views/project_project.xml
Normal file
26
project_usability/views/project_project.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<!-- user_id is not displayed by default in project kanban view (it is native in v16) -->
|
||||
<record id="view_project_kanban" model="ir.ui.view">
|
||||
<field name="model">project.project</field>
|
||||
<field name="inherit_id" ref="project.view_project_kanban"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="name" position="after">
|
||||
<field name="user_id"/>
|
||||
</field>
|
||||
<xpath expr="//div[hasclass('o_project_kanban_boxes')]" position="inside">
|
||||
<a t-if="record.user_id.raw_value" class="o_project_kanban_box">
|
||||
<field name="user_id" widget="many2one_avatar_user"/>
|
||||
</a>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -23,7 +23,9 @@ Please contact Alexis de Lattre from Akretion <alexis.delattre@akretion.com> for
|
||||
'purchase_usability',
|
||||
],
|
||||
'data': [
|
||||
'views/purchase_order.xml',
|
||||
'views/stock_picking.xml',
|
||||
'views/stock_warehouse_orderpoint.xml',
|
||||
],
|
||||
'installable': True,
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
from . import purchase
|
||||
from . import stock_warehouse_orderpoint
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# Copyright 2015-2020 Akretion (http://www.akretion.com)
|
||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class StockWarehouseOrderpoint(models.Model):
|
||||
_inherit = 'stock.warehouse.orderpoint'
|
||||
|
||||
# Field needed to be able to search on supplier in the "Replenish" tree view
|
||||
# I put it in purchase_stock_usability and not stock_usability
|
||||
# because I wanted to use the field 'show_supplier' defined in purchase_stock
|
||||
# (but I don't use it in the end because its computation returns False even
|
||||
# on products with a Buy route) and I may also
|
||||
# one day interact with supplier_id (M2O product.supplierinfo) defined in
|
||||
# purchase_stock
|
||||
seller_id = fields.Many2one(
|
||||
related='product_id.product_tmpl_id.seller_ids.name',
|
||||
store=True, string='Supplier',
|
||||
)
|
||||
43
purchase_stock_usability/views/purchase_order.xml
Normal file
43
purchase_stock_usability/views/purchase_order.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2023 Akretion (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
|
||||
<record id="purchase_order_tree" model="ir.ui.view">
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="inherit_id" ref="purchase.purchase_order_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="date_planned" position="after">
|
||||
<field name="picking_type_id" optional="hide"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="purchase_order_view_tree" model="ir.ui.view">
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="inherit_id" ref="purchase.purchase_order_view_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="date_planned" position="after">
|
||||
<field name="picking_type_id" optional="hide"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="purchase_order_kpis_tree" model="ir.ui.view">
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="inherit_id" ref="purchase.purchase_order_kpis_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="date_planned" position="after">
|
||||
<field name="picking_type_id" optional="hide"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
</odoo>
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2014-2020 Akretion (http://www.akretion.com/)
|
||||
@author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
|
||||
<record id="view_warehouse_orderpoint_tree_editable" model="ir.ui.view">
|
||||
<field name="model">stock.warehouse.orderpoint</field>
|
||||
<field name="inherit_id" ref="stock.view_warehouse_orderpoint_tree_editable" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="product_id" position="after">
|
||||
<field name="seller_id" optional="hide"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_warehouse_orderpoint_tree_editable_config" model="ir.ui.view">
|
||||
<field name="model">stock.warehouse.orderpoint</field>
|
||||
<field name="inherit_id" ref="stock.view_warehouse_orderpoint_tree_editable_config" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="product_id" position="after">
|
||||
<field name="seller_id" optional="hide"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="stock_reorder_report_search" model="ir.ui.view">
|
||||
<field name="model">stock.warehouse.orderpoint</field>
|
||||
<field name="inherit_id" ref="stock.stock_reorder_report_search"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="product_id" position="after">
|
||||
<field name="seller_id" domain="[('parent_id', '=', False)]"/>
|
||||
</field>
|
||||
<filter name="groupby_category" position="after">
|
||||
<filter string="Supplier" name="seller_id_groupby" context="{'group_by': 'seller_id'}"/>
|
||||
</filter>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
</odoo>
|
||||
@@ -68,6 +68,13 @@ class PurchaseOrder(models.Model):
|
||||
# ]
|
||||
return res
|
||||
|
||||
def _prepare_invoice(self):
|
||||
# Don't write self.partner_ref on 'ref' of invoice... ref is for the
|
||||
# supplier invoice number !
|
||||
vals = super()._prepare_invoice()
|
||||
vals["ref"] = ''
|
||||
return vals
|
||||
|
||||
|
||||
class PurchaseOrderLine(models.Model):
|
||||
_inherit = 'purchase.order.line'
|
||||
|
||||
@@ -7,6 +7,7 @@ from odoo import api, models
|
||||
class CrmLead(models.Model):
|
||||
_inherit = 'crm.lead'
|
||||
|
||||
# not needed in v16 because it has been fixed in sale_crm
|
||||
def action_view_sale_quotation(self):
|
||||
action = super().action_view_sale_quotation()
|
||||
if 'search_default_partner_id' in action['context']:
|
||||
|
||||
@@ -16,7 +16,7 @@ This module has been written by Alexis de Lattre from Akretion
|
||||
""",
|
||||
'author': 'Akretion',
|
||||
'website': 'http://www.akretion.com',
|
||||
'depends': ['sale_stock'],
|
||||
'depends': ['sale_stock', 'base_view_inheritance_extension'],
|
||||
'data': ['views/sale_order.xml'],
|
||||
'installable': True,
|
||||
}
|
||||
|
||||
@@ -15,6 +15,11 @@
|
||||
<field name="partner_shipping_id" position="after">
|
||||
<field name="route_id" options="{'no_create_edit': True}"/>
|
||||
</field>
|
||||
<!-- propagate route_id to lines: it's important when you add an order line AFTER
|
||||
order confirmation -->
|
||||
<field name="order_line" position="attributes">
|
||||
<attribute name="context" operation="python_dict" key="default_route_id">route_id</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -399,11 +399,6 @@ msgstr ""
|
||||
"Sélectionner l'option 'Avertissement' informera l'utilisateur du Message. Sélectionner 'Message Bloquant' lancera une "
|
||||
"exception avec le message et bloquera le flux. Le message doit être écrit dans le champ suivant."
|
||||
|
||||
#. module: sale_usability
|
||||
#: model_terms:ir.ui.view,arch_db:sale_usability.view_order_form
|
||||
msgid "Send Order Acknowledgement"
|
||||
msgstr "Confirmation de commande"
|
||||
|
||||
#. module: sale_usability
|
||||
#: model_terms:ir.ui.view,arch_db:sale_usability.view_sales_order_filter
|
||||
msgid "State"
|
||||
|
||||
@@ -32,9 +32,6 @@
|
||||
<xpath expr="//field[@name='order_line']/tree/field[@name='product_template_id']" position="after">
|
||||
<field name="product_barcode" optional="hide"/>
|
||||
</xpath>
|
||||
<button name="action_quotation_send" attrs="{'invisible': ['|', ('state', '=', 'draft'), ('invoice_count','>=',1)]}" position="before">
|
||||
<button name="action_quotation_send" type="object" string="Send Order Acknowledgement" attrs="{'invisible': ['|', ('state', 'not in', ('sale', 'done')), ('invoice_count','>=',1)]}"/>
|
||||
</button>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ class StockQuant(models.Model):
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"picking_id": picking_id,
|
||||
"product_id": product_id,
|
||||
"product_uom_id": uom_id,
|
||||
"qty_done": qty,
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
from . import stock_move
|
||||
|
||||
from . import stock_picking
|
||||
from . import stock_picking_type
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# @author Kévin Roche <kevin.roche@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from collections import defaultdict
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
@@ -9,28 +10,35 @@ class StockMove(models.Model):
|
||||
_inherit = "stock.move"
|
||||
|
||||
location_dest_list = fields.Text(
|
||||
string="Locations", compute="_compute_locations_dest_list"
|
||||
string="Dest. Locations", compute="_compute_locations_list"
|
||||
)
|
||||
|
||||
location_src_list = fields.Text(
|
||||
string="Src. Locations", compute="_compute_locations_list"
|
||||
)
|
||||
|
||||
@api.depends(
|
||||
"move_line_ids", "move_line_ids.location_dest_id", "move_line_ids.qty_done"
|
||||
"move_line_ids.location_dest_id",
|
||||
"move_line_ids.location_id",
|
||||
"move_line_ids.qty_done",
|
||||
)
|
||||
def _compute_locations_dest_list(self):
|
||||
def _compute_locations_list(self):
|
||||
def format_loc(data):
|
||||
return "\n ".join([
|
||||
f"{int(qty) if qty.is_integer() else qty}: {location.name}"
|
||||
for location, qty in data.items()
|
||||
])
|
||||
for move in self:
|
||||
data = []
|
||||
separator = ", "
|
||||
dest_list = move.move_line_ids.location_dest_id
|
||||
for dest in dest_list:
|
||||
lines_qty = move.move_line_ids.search(
|
||||
[("move_id", "=", move.id), ("location_dest_id", "=", dest.id)]
|
||||
).mapped("qty_done")
|
||||
quantity = int(sum(lines_qty))
|
||||
location = dest.name
|
||||
data.append("{}: {}".format(quantity, location))
|
||||
move.location_dest_list = separator.join(data)
|
||||
dest = defaultdict(int)
|
||||
src = defaultdict(int)
|
||||
for line in move.move_line_ids:
|
||||
dest[line.location_dest_id] += line.qty_done
|
||||
src[line.location_id] += line.qty_done
|
||||
move.location_src_list = format_loc(src)
|
||||
move.location_dest_list = format_loc(dest)
|
||||
|
||||
def _compute_is_quantity_done_editable(self):
|
||||
super()._compute_is_quantity_done_editable()
|
||||
for move in self:
|
||||
if len(move.move_line_ids) == 1 and move.show_details_visible:
|
||||
if len(move.move_line_ids) <= 1:
|
||||
move.is_quantity_done_editable = True
|
||||
|
||||
26
stock_reception_usability/models/stock_picking.py
Normal file
26
stock_reception_usability/models/stock_picking.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# Copyright 2024 Akretion (https://www.akretion.com).
|
||||
# @author Sébastien BEAU <sebastien.beau@akretion.com>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
_inherit = 'stock.picking'
|
||||
|
||||
show_src_location = fields.Boolean(compute="_compute_show_location")
|
||||
show_dest_location = fields.Boolean(compute="_compute_show_location")
|
||||
|
||||
@api.depends("picking_type_id.code", "location_id", "location_dest_id")
|
||||
def _compute_show_location(self):
|
||||
for picking in self:
|
||||
picking.show_src_location = (
|
||||
picking.picking_type_id.code != "incoming"
|
||||
and picking.location_id.child_ids
|
||||
)
|
||||
picking.show_dest_location = (
|
||||
picking.picking_type_id.code != "outgoing"
|
||||
and picking.location_dest_id.child_ids
|
||||
)
|
||||
17
stock_reception_usability/models/stock_picking_type.py
Normal file
17
stock_reception_usability/models/stock_picking_type.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Copyright 2024 Akretion (https://www.akretion.com).
|
||||
# @author Sébastien BEAU <sebastien.beau@akretion.com>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
|
||||
|
||||
class StockPickingType(models.Model):
|
||||
_inherit = 'stock.picking.type'
|
||||
|
||||
def _default_show_operations(self):
|
||||
# super is not called as we want to always force the value to False
|
||||
# super()._default_show_operations()
|
||||
return False
|
||||
|
||||
show_operations = fields.Boolean(default=lambda s: s._default_show_operations())
|
||||
@@ -4,8 +4,13 @@
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_form" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="picking_type_code" position="after">
|
||||
<field name="show_src_location" invisible="1"/>
|
||||
<field name="show_dest_location" invisible="1"/>
|
||||
</field>
|
||||
<xpath expr="//field[@name='product_uom']" position="after">
|
||||
<field name="location_dest_list" />
|
||||
<field name="location_src_list" attrs="{'column_invisible': [('parent.show_src_location', '=', False)]}"/>
|
||||
<field name="location_dest_list" attrs="{'column_invisible': [('parent.show_dest_location', '=', False)]}"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='product_uom_qty']" position="attributes">
|
||||
<attribute
|
||||
|
||||
@@ -31,6 +31,7 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
|
||||
'views/stock_location.xml',
|
||||
'views/stock_move.xml',
|
||||
'views/stock_picking.xml',
|
||||
'views/stock_picking_type.xml',
|
||||
'views/stock_warehouse.xml',
|
||||
'views/stock_warehouse_orderpoint.xml',
|
||||
'views/product.xml',
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from . import stock_move
|
||||
from . import stock_picking
|
||||
from . import stock_picking_type
|
||||
from . import stock_location
|
||||
from . import stock_location_route
|
||||
from . import stock_warehouse_orderpoint
|
||||
from . import stock_quant
|
||||
|
||||
14
stock_usability/models/stock_location.py
Normal file
14
stock_usability/models/stock_location.py
Normal file
@@ -0,0 +1,14 @@
|
||||
# Copyright 2023 Akretion France (http://www.akretion.com)
|
||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class StockLocation(models.Model):
|
||||
_inherit = 'stock.location'
|
||||
|
||||
def action_show_quants(self):
|
||||
self.ensure_one()
|
||||
action = self.env['stock.quant']._get_quants_action(domain=[('location_id', 'child_of', self.id)])
|
||||
return action
|
||||
@@ -3,9 +3,6 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models, _
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
@@ -24,9 +21,3 @@ class StockPicking(models.Model):
|
||||
for pick in self:
|
||||
pick.message_post(body=_("Picking <b>unreserved</b>."))
|
||||
return res
|
||||
|
||||
|
||||
class StockPickingType(models.Model):
|
||||
_inherit = 'stock.picking.type'
|
||||
|
||||
name = fields.Char(translate=False)
|
||||
|
||||
27
stock_usability/models/stock_picking_type.py
Normal file
27
stock_usability/models/stock_picking_type.py
Normal file
@@ -0,0 +1,27 @@
|
||||
# Copyright 2014-2020 Akretion (http://www.akretion.com)
|
||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class StockPickingType(models.Model):
|
||||
_inherit = 'stock.picking.type'
|
||||
|
||||
name = fields.Char(translate=False)
|
||||
is_dropship = fields.Boolean(compute="_compute_is_dropship", store=True)
|
||||
|
||||
@api.depends("code", "warehouse_id", "default_location_src_id", "default_location_dest_id")
|
||||
def _compute_is_dropship(self):
|
||||
supplier_loc_id = self.env.ref("stock.stock_location_suppliers").id
|
||||
customer_loc_id = self.env.ref("stock.stock_location_customers").id
|
||||
for picktype in self:
|
||||
is_dropship = False
|
||||
if (
|
||||
picktype.code == 'incoming'
|
||||
and not picktype.warehouse_id
|
||||
and picktype.default_location_src_id.id == supplier_loc_id
|
||||
and picktype.default_location_dest_id.id == customer_loc_id
|
||||
):
|
||||
is_dropship = True
|
||||
picktype.is_dropship = is_dropship
|
||||
@@ -24,5 +24,5 @@ class StockQuant(models.Model):
|
||||
('package_id', '=', self.package_id.id or False),
|
||||
('result_package_id', '=', self.package_id.id or False),
|
||||
]
|
||||
action['context'] = {'create': 0}
|
||||
action['context'] = {'create': 0, 'stock_move_line_main_view': True}
|
||||
return action
|
||||
|
||||
@@ -40,6 +40,10 @@
|
||||
string="Reordering Rules"
|
||||
class="oe_stat_button" icon="fa-refresh"/>
|
||||
</div>
|
||||
<button name="%(stock.location_open_quants)d" position="attributes">
|
||||
<attribute name="type">object</attribute>
|
||||
<attribute name="name">action_show_quants</attribute>
|
||||
</button>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -61,6 +61,10 @@
|
||||
<field name="product_id" position="after">
|
||||
<field name="product_barcode" optional="hide"/>
|
||||
</field>
|
||||
<field name="reference" position="after">
|
||||
<field name="origin" optional="hide"/>
|
||||
<field name="partner_id" optional="hide"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -69,6 +73,18 @@
|
||||
<field name="context">{'search_default_done': 1}</field>
|
||||
</record>
|
||||
|
||||
<record id="view_move_line_form" model="ir.ui.view">
|
||||
<field name="name">stock_usability.stock.move.line.form</field>
|
||||
<field name="model">stock.move.line</field>
|
||||
<field name="inherit_id" ref="stock.view_move_line_form" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="reference" position="before">
|
||||
<field name="picking_id" attrs="{'invisible': [('picking_id', '=', False)]}"/>
|
||||
<field name="production_id" attrs="{'invisible': [('production_id', '=', False)]}"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_move_line_tree" model="ir.ui.view">
|
||||
<field name="name">stock_usability.stock.move.line.tree</field>
|
||||
<field name="model">stock.move.line</field>
|
||||
|
||||
22
stock_usability/views/stock_picking_type.xml
Normal file
22
stock_usability/views/stock_picking_type.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2023 Akretion (http://www.akretion.com/)
|
||||
@author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
|
||||
<record id="view_picking_type_form" model="ir.ui.view">
|
||||
<field name="model">stock.picking.type</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_type_form" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="code" position="after">
|
||||
<field name="is_dropship"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
</odoo>
|
||||
@@ -25,6 +25,14 @@
|
||||
<field name="trigger" position="attributes">
|
||||
<attribute name="optional">show</attribute>
|
||||
</field>
|
||||
<field name="route_id" position="attributes">
|
||||
<attribute name="optional">show</attribute>
|
||||
</field>
|
||||
<!-- Button 'Automate Orders' is not needed because the user
|
||||
can manually change the 'Trigger' field. And it takes a
|
||||
lot of room in the tree view -->
|
||||
<!-- TODO I tried many things to avoid a replace... but it didn't work -->
|
||||
<button name="action_replenish_auto" position="replace"/>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -39,5 +47,4 @@
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -27,10 +27,10 @@ class StockValuationXlsx(models.TransientModel):
|
||||
required=True)
|
||||
warehouse_id = fields.Many2one(
|
||||
'stock.warehouse', string='Warehouse', check_company=True,
|
||||
domain="[('company_id', '=', company_id)]")
|
||||
domain="[('company_id', 'in', [False, company_id])]")
|
||||
location_id = fields.Many2one(
|
||||
'stock.location', string='Root Stock Location', required=True,
|
||||
domain="[('usage', 'in', ('view', 'internal')), ('company_id', '=', company_id)]",
|
||||
domain="[('usage', 'in', ('view', 'internal')), ('company_id', 'in', [False, company_id])]",
|
||||
default=lambda self: self._default_location(), check_company=True,
|
||||
help="The childen locations of the selected locations will "
|
||||
"be taken in the valuation.")
|
||||
@@ -75,7 +75,7 @@ class StockValuationXlsx(models.TransientModel):
|
||||
|
||||
@api.model
|
||||
def _default_location(self):
|
||||
wh = self.env.ref('stock.warehouse0')
|
||||
wh = self.env["stock.warehouse"].search([], limit=1)
|
||||
return wh.lot_stock_id
|
||||
|
||||
@api.onchange('warehouse_id')
|
||||
|
||||
@@ -25,10 +25,10 @@ class StockVariationXlsx(models.TransientModel):
|
||||
required=True)
|
||||
warehouse_id = fields.Many2one(
|
||||
'stock.warehouse', string='Warehouse', check_company=True,
|
||||
domain="[('company_id', '=', company_id)]")
|
||||
domain="[('company_id', 'in', [False, company_id])]")
|
||||
location_id = fields.Many2one(
|
||||
'stock.location', string='Root Stock Location', required=True,
|
||||
domain="[('usage', 'in', ('view', 'internal')), ('company_id', '=', company_id)]",
|
||||
domain="[('usage', 'in', ('view', 'internal')), ('company_id', 'in', [False, company_id])]",
|
||||
default=lambda self: self._default_location(), check_company=True,
|
||||
help="The childen locations of the selected locations will "
|
||||
"be taken in the valuation.")
|
||||
@@ -58,7 +58,7 @@ class StockVariationXlsx(models.TransientModel):
|
||||
|
||||
@api.model
|
||||
def _default_location(self):
|
||||
wh = self.env.ref('stock.warehouse0')
|
||||
wh = self.env["stock.warehouse"].search([], limit=1)
|
||||
return wh.lot_stock_id
|
||||
|
||||
@api.onchange('warehouse_id')
|
||||
|
||||
Reference in New Issue
Block a user