Compare commits
1 Commits
14-adapt-u
...
16.0-no_de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b0f12eb27 |
@@ -18,10 +18,9 @@
|
|||||||
'views/account_account.xml',
|
'views/account_account.xml',
|
||||||
'views/account_group.xml',
|
'views/account_group.xml',
|
||||||
# 'views/account_bank_statement.xml',
|
# 'views/account_bank_statement.xml',
|
||||||
'views/account_invoice_report.xml',
|
# 'views/account_invoice_report.xml',
|
||||||
'views/account_journal.xml',
|
'views/account_journal.xml',
|
||||||
'views/account_move.xml',
|
'views/account_move.xml',
|
||||||
'views/account_analytic_line.xml',
|
|
||||||
'views/account_menu.xml',
|
'views/account_menu.xml',
|
||||||
'views/account_tax.xml',
|
'views/account_tax.xml',
|
||||||
# 'views/product.xml', # TODO
|
# 'views/product.xml', # TODO
|
||||||
|
|||||||
@@ -36,34 +36,6 @@ class AccountMove(models.Model):
|
|||||||
compute="_compute_sales_dates",
|
compute="_compute_sales_dates",
|
||||||
help="This information appear on invoice qweb report "
|
help="This information appear on invoice qweb report "
|
||||||
"(you may use it for your own 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.account_type in ("liability_payable", "asset_receivable")
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def _inverse_blocked(self):
|
|
||||||
for move in self:
|
|
||||||
for line in move.line_ids.filtered(
|
|
||||||
lambda l: l.account_id.account_type in ("liability_payable", "asset_receivable")
|
|
||||||
):
|
|
||||||
line.blocked = move.blocked
|
|
||||||
|
|
||||||
def _compute_has_discount(self):
|
def _compute_has_discount(self):
|
||||||
prec = self.env['decimal.precision'].precision_get('Discount')
|
prec = self.env['decimal.precision'].precision_get('Discount')
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright 2024 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_account_analytic_line_tree_inherit_account" model="ir.ui.view">
|
|
||||||
<field name="model">account.analytic.line</field>
|
|
||||||
<field name="inherit_id" ref="account.view_account_analytic_line_tree_inherit_account"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="general_account_id" position="attributes">
|
|
||||||
<attribute name="optional">show</attribute>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
|
|
||||||
</odoo>
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
<!--
|
||||||
Copyright 2018-2024 Akretion (http://www.akretion.com/)
|
Copyright 2018-2020 Akretion (http://www.akretion.com/)
|
||||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
-->
|
-->
|
||||||
@@ -8,31 +8,56 @@
|
|||||||
<odoo>
|
<odoo>
|
||||||
|
|
||||||
|
|
||||||
<record id="account_invoice_report_view_tree" model="ir.ui.view">
|
<record id="account_invoice_report_tree" model="ir.ui.view">
|
||||||
<field name="name">usability.account.invoice.report.tree</field>
|
<field name="name">usability.account.invoice.report.tree</field>
|
||||||
<field name="model">account.invoice.report</field>
|
<field name="model">account.invoice.report</field>
|
||||||
<field name="inherit_id" ref="account.account_invoice_report_view_tree"/>
|
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<field name="partner_id" position="after">
|
<tree string="Invoices Analysis">
|
||||||
<field name="commercial_partner_id" optional="hide"/>
|
<field name="move_id"/>
|
||||||
|
<field name="journal_id" optional="hide"/>
|
||||||
|
<field name="company_id" optional="hide" groups="base.group_multi_company"/>
|
||||||
|
<field name="invoice_date"/>
|
||||||
|
<field name="invoice_date_due"/>
|
||||||
|
<field name="move_type"/>
|
||||||
|
<field name="commercial_partner_id"/>
|
||||||
|
<field name="partner_id" optional="hide"/>
|
||||||
<field name="country_id" optional="hide"/>
|
<field name="country_id" optional="hide"/>
|
||||||
<field name="industry_id" optional="hide"/>
|
<field name="industry_id" optional="hide"/>
|
||||||
|
<field name="invoice_user_id"/>
|
||||||
<field name="fiscal_position_id" optional="hide"/>
|
<field name="fiscal_position_id" optional="hide"/>
|
||||||
</field>
|
<field name="product_id"/>
|
||||||
<field name="quantity" position="after">
|
<field name="product_categ_id" optional="hide"/>
|
||||||
<field name="product_uom_id" groups="uom.group_uom" optional="hide"/>
|
<field name="account_id" optional="hide"/>
|
||||||
</field>
|
<field name="analytic_account_id" optional="hide" groups="analytic.group_analytic_accounting"/>
|
||||||
|
<field name="quantity" sum="1"/>
|
||||||
|
<field name="product_uom_id" groups="uom.group_uom"/>
|
||||||
|
<field name="price_subtotal" sum="1"/>
|
||||||
|
<field name="state"/>
|
||||||
|
<field name="payment_state" optional="hide"/>
|
||||||
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="view_account_invoice_report_search" model="ir.ui.view">
|
<record id="account.action_account_invoice_report_all_supp" model="ir.actions.act_window">
|
||||||
|
<field name="context">{'search_default_current': 1, 'search_default_supplier': 1, 'group_by': ['invoice_date']}</field> <!-- Remove group_by_no_leaf, which breaks tree view -->
|
||||||
|
<field name="view_mode">pivot,graph</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="account.action_account_invoice_report_all" model="ir.actions.act_window">
|
||||||
|
<field name="context">{'search_default_current': 1, 'search_default_customer': 1, 'group_by': ['invoice_date']}</field> <!-- Remove group_by_no_leaf, which breaks tree view -->
|
||||||
|
<field name="view_mode">pivot,graph</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="view_account_invoice_report_pivot" model="ir.ui.view">
|
||||||
|
<field name="name">usability.account.invoice.report</field>
|
||||||
<field name="model">account.invoice.report</field>
|
<field name="model">account.invoice.report</field>
|
||||||
<field name="inherit_id" ref="account.view_account_invoice_report_search"/>
|
<field name="inherit_id" ref="account.view_account_invoice_report_pivot"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<filter name="category_product" position="after">
|
<pivot position="attributes">
|
||||||
<filter string="Product" name="product_groupby" context="{'group_by': 'product_id', 'residual_invisible':True}"/>
|
<attribute name="disable_linking"></attribute>
|
||||||
</filter>
|
</pivot>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@@ -43,16 +43,6 @@
|
|||||||
<xpath expr="//field[@name='invoice_line_ids']/tree/field[@name='product_id']" position="after">
|
<xpath expr="//field[@name='invoice_line_ids']/tree/field[@name='product_id']" position="after">
|
||||||
<field name="product_barcode" optional="hide"/>
|
<field name="product_barcode" optional="hide"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<field name="invoice_source_email" position="after">
|
|
||||||
<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>
|
|
||||||
<xpath expr="//button[@name='open_duplicated_ref_bill_view']/.." position="attributes">
|
<xpath expr="//button[@name='open_duplicated_ref_bill_view']/.." position="attributes">
|
||||||
<!-- show duplicate warning not only in draft state, but also in posted state -->
|
<!-- show duplicate warning not only in draft state, but also in posted state -->
|
||||||
<attribute name="attrs">{'invisible': ['|', ('state', '=', 'cancel'), ('duplicated_ref_ids', '=', [])]}</attribute>
|
<attribute name="attrs">{'invisible': ['|', ('state', '=', 'cancel'), ('duplicated_ref_ids', '=', [])]}</attribute>
|
||||||
@@ -87,8 +77,6 @@
|
|||||||
<filter name="sent" string="Sent" domain="[('is_move_sent', '=', True), ('move_type', 'in', ('out_invoice', 'out_refund'))]"/>
|
<filter name="sent" string="Sent" domain="[('is_move_sent', '=', True), ('move_type', 'in', ('out_invoice', 'out_refund'))]"/>
|
||||||
<separator/>
|
<separator/>
|
||||||
<filter name="no_attachment" string="Missing Attachment" domain="[('has_attachment', '=', False)]"/>
|
<filter name="no_attachment" string="Missing Attachment" domain="[('has_attachment', '=', False)]"/>
|
||||||
<separator/>
|
|
||||||
<filter name="dispute" string="Dispute" domain="[('blocked', '=', True)]"/>
|
|
||||||
</filter>
|
</filter>
|
||||||
<filter name="salesperson" position="before">
|
<filter name="salesperson" position="before">
|
||||||
<filter name="commercial_partner_groupby" string="Commercial Partner" context="{'group_by': 'commercial_partner_id'}"/>
|
<filter name="commercial_partner_groupby" string="Commercial Partner" context="{'group_by': 'commercial_partner_id'}"/>
|
||||||
@@ -99,23 +87,6 @@
|
|||||||
</field>
|
</field>
|
||||||
</record>
|
</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_type', 'not in', ('liability_payable', 'asset_receivable'))]}</attribute>
|
|
||||||
</xpath>
|
|
||||||
<field name="account_id" position="after">
|
|
||||||
<field name="account_type" invisible="1"/>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="view_move_line_tree" model="ir.ui.view">
|
<record id="view_move_line_tree" model="ir.ui.view">
|
||||||
<field name="model">account.move.line</field>
|
<field name="model">account.move.line</field>
|
||||||
<field name="inherit_id" ref="account.view_move_line_tree"/>
|
<field name="inherit_id" ref="account.view_move_line_tree"/>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# Copyright 2020-2023 Akretion France (http://www.akretion.com)
|
# Copyright 2020-2021 Akretion France (http://www.akretion.com)
|
||||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Base Dynamic List',
|
'name': 'Base Dynamic List',
|
||||||
'version': '16.0.1.0.0',
|
'version': '14.0.1.0.0',
|
||||||
'category': 'Tools',
|
'category': 'Tools',
|
||||||
'license': 'AGPL-3',
|
'license': 'AGPL-3',
|
||||||
'summary': 'Dynamic lists',
|
'summary': 'Dynamic lists',
|
||||||
@@ -58,5 +58,5 @@ Limitation: when you want to have different access rights on these lists dependi
|
|||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
'views/dynamic_list.xml',
|
'views/dynamic_list.xml',
|
||||||
],
|
],
|
||||||
'installable': True,
|
'installable': False,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright 2020-2023 Akretion France (http://www.akretion.com)
|
# Copyright 2020-2021 Akretion France (http://www.akretion.com)
|
||||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
@@ -63,15 +63,18 @@ class DynamicListCode(models.Model):
|
|||||||
res.append((rec.id, '[%s] %s' % (rec.code, rec.name)))
|
res.append((rec.id, '[%s] %s' % (rec.code, rec.name)))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def _name_search(self, name='', args=None, operator='ilike', limit=100, name_get_uid=None):
|
@api.model
|
||||||
|
def name_search(
|
||||||
|
self, name='', args=None, operator='ilike', limit=80):
|
||||||
if args is None:
|
if args is None:
|
||||||
args = []
|
args = []
|
||||||
ids = []
|
|
||||||
if name and operator == 'ilike':
|
if name and operator == 'ilike':
|
||||||
ids = list(self._search([('code', '=', name)] + args, limit=limit))
|
recs = self.search(
|
||||||
if ids:
|
[('code', '=', name)] + args, limit=limit)
|
||||||
return ids
|
if recs:
|
||||||
return super()._name_search(name=name, args=args, operator=operator, limit=limit, name_get_uid=name_get_uid)
|
return recs.name_get()
|
||||||
|
return super().name_search(
|
||||||
|
name=name, args=args, operator=operator, limit=limit)
|
||||||
|
|
||||||
|
|
||||||
class DynamicListCodeTranslate(models.Model):
|
class DynamicListCodeTranslate(models.Model):
|
||||||
@@ -98,12 +101,15 @@ class DynamicListCodeTranslate(models.Model):
|
|||||||
res.append((rec.id, '[%s] %s' % (rec.code, rec.name)))
|
res.append((rec.id, '[%s] %s' % (rec.code, rec.name)))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def _name_search(self, name='', args=None, operator='ilike', limit=100, name_get_uid=None):
|
@api.model
|
||||||
|
def name_search(
|
||||||
|
self, name='', args=None, operator='ilike', limit=80):
|
||||||
if args is None:
|
if args is None:
|
||||||
args = []
|
args = []
|
||||||
ids = []
|
|
||||||
if name and operator == 'ilike':
|
if name and operator == 'ilike':
|
||||||
ids = list(self._search([('code', '=', name)] + args, limit=limit))
|
recs = self.search(
|
||||||
if ids:
|
[('code', '=', name)] + args, limit=limit)
|
||||||
return ids
|
if recs:
|
||||||
return super()._name_search(name=name, args=args, operator=operator, limit=limit, name_get_uid=name_get_uid)
|
return recs.name_get()
|
||||||
|
return super().name_search(
|
||||||
|
name=name, args=args, operator=operator, limit=limit)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
<!--
|
||||||
Copyright 2020-2023 Akretion France (http://www.akretion.com/)
|
Copyright 2020-2021 Akretion France (http://www.akretion.com/)
|
||||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
-->
|
-->
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
from . import models
|
from . import partner_phone
|
||||||
from .post_install import migrate_to_partner_phone
|
from .post_install import migrate_to_partner_phone
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Copyright 2014-2023 Abbaye du Barroux (http://www.barroux.org)
|
# Copyright 2014-2020 Abbaye du Barroux (http://www.barroux.org)
|
||||||
# Copyright 2014-2023 Akretion (http://www.akretion.com>)
|
# Copyright 2014-2020 Akretion (http://www.akretion.com>)
|
||||||
# @author: Frère Bernard <informatique@barroux.org>
|
# @author: Frère Bernard <informatique@barroux.org>
|
||||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Base Partner One2many Phone',
|
'name': 'Base Partner One2many Phone',
|
||||||
'version': '16.0.1.0.0',
|
'version': '14.0.1.0.0',
|
||||||
'category': 'Phone',
|
'category': 'Phone',
|
||||||
'license': 'AGPL-3',
|
'license': 'AGPL-3',
|
||||||
'summary': 'One2many link between partners and phone numbers/emails',
|
'summary': 'One2many link between partners and phone numbers/emails',
|
||||||
@@ -19,14 +19,13 @@ With this module, one partner can have several phone numbers and several emails.
|
|||||||
It has been developped by brother Bernard from Barroux Abbey and Alexis de Lattre from Akretion.
|
It has been developped by brother Bernard from Barroux Abbey and Alexis de Lattre from Akretion.
|
||||||
""",
|
""",
|
||||||
'author': 'Akretion',
|
'author': 'Akretion',
|
||||||
'website': 'https://github.com/akretion/odoo-usability',
|
'website': 'https://akretion.com/',
|
||||||
'depends': ['contacts', 'base_usability', 'phone_validation'],
|
'depends': ['contacts', 'base_usability', 'phone_validation'],
|
||||||
'excludes': ['sms'], # because sms introduces big changes in partner form view
|
'excludes': ['sms'], # because sms introduces big changes in partner form view
|
||||||
'data': [
|
'data': [
|
||||||
'views/res_partner_phone.xml',
|
'partner_phone_view.xml',
|
||||||
'views/res_partner.xml',
|
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
],
|
],
|
||||||
'installable': True,
|
'installable': False,
|
||||||
'post_init_hook': 'migrate_to_partner_phone',
|
'post_init_hook': 'migrate_to_partner_phone',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
from . import res_partner_phone
|
|
||||||
from . import res_partner
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
# Copyright 2014-2023 Abbaye du Barroux (http://www.barroux.org)
|
|
||||||
# Copyright 2016-2023 Akretion (http://www.akretion.com>)
|
|
||||||
# @author: Frère Bernard <informatique@barroux.org>
|
|
||||||
# @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, Command
|
|
||||||
|
|
||||||
|
|
||||||
class ResPartner(models.Model):
|
|
||||||
_inherit = 'res.partner'
|
|
||||||
|
|
||||||
# in v10, we are supposed to have in DB E.164 format
|
|
||||||
# with the current implementation, we have:
|
|
||||||
# in res.partner : PhoneNumberFormat.INTERNATIONAL
|
|
||||||
# in res.partner.phone : E.164
|
|
||||||
# It is not good, but it is not a big bug and it's complex to fix
|
|
||||||
# so let's let it like that. In v12, we store in
|
|
||||||
# PhoneNumberFormat.INTERNATIONAL, so this bug is kind of an anticipation
|
|
||||||
# for the future :)
|
|
||||||
|
|
||||||
phone_ids = fields.One2many(
|
|
||||||
'res.partner.phone', 'partner_id', string='Phones/Emails')
|
|
||||||
phone = fields.Char(compute='_compute_partner_phone', store=True)
|
|
||||||
mobile = fields.Char(compute='_compute_partner_phone', store=True)
|
|
||||||
email = fields.Char(compute='_compute_partner_phone', store=True)
|
|
||||||
|
|
||||||
@api.depends('phone_ids.phone', 'phone_ids.type', 'phone_ids.email')
|
|
||||||
def _compute_partner_phone(self):
|
|
||||||
for partner in self:
|
|
||||||
phone = mobile = email = False
|
|
||||||
for pphone in partner.phone_ids:
|
|
||||||
if pphone.type == '1_email_primary' and pphone.email:
|
|
||||||
email = pphone.email
|
|
||||||
elif pphone.phone:
|
|
||||||
if pphone.type == '5_mobile_primary':
|
|
||||||
mobile = pphone.phone
|
|
||||||
elif pphone.type == '3_phone_primary':
|
|
||||||
phone = pphone.phone
|
|
||||||
partner.phone = phone
|
|
||||||
partner.mobile = mobile
|
|
||||||
partner.email = email
|
|
||||||
|
|
||||||
def _update_create_vals(
|
|
||||||
self, vals, type, partner_field, partner_phone_field):
|
|
||||||
if vals.get(partner_field):
|
|
||||||
vals['phone_ids'].append(
|
|
||||||
Command.create({'type': type, partner_phone_field: vals[partner_field]}))
|
|
||||||
if partner_field in vals:
|
|
||||||
vals.pop(partner_field)
|
|
||||||
|
|
||||||
@api.model_create_multi
|
|
||||||
def create(self, vals_list):
|
|
||||||
for vals in vals_list:
|
|
||||||
if 'phone_ids' not in vals:
|
|
||||||
vals['phone_ids'] = []
|
|
||||||
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')
|
|
||||||
return super().create(vals_list)
|
|
||||||
|
|
||||||
def _update_write_vals(
|
|
||||||
self, vals, type, partner_field, partner_phone_field):
|
|
||||||
self.ensure_one()
|
|
||||||
rppo = self.env['res.partner.phone']
|
|
||||||
if partner_field in vals:
|
|
||||||
pphone = rppo.search([
|
|
||||||
('partner_id', '=', self.id),
|
|
||||||
('type', '=', type)], limit=1)
|
|
||||||
if vals[partner_field]:
|
|
||||||
if pphone:
|
|
||||||
vals['phone_ids'].append(Command.update(pphone.id, {
|
|
||||||
partner_phone_field: vals[partner_field]}))
|
|
||||||
else:
|
|
||||||
vals['phone_ids'].append(Command.create({
|
|
||||||
'type': type,
|
|
||||||
partner_phone_field: vals[partner_field],
|
|
||||||
}))
|
|
||||||
else:
|
|
||||||
if pphone:
|
|
||||||
vals['phone_ids'].append(Command.delete(pphone.id))
|
|
||||||
vals.pop(partner_field)
|
|
||||||
|
|
||||||
def write(self, vals):
|
|
||||||
if 'phone_ids' not in vals:
|
|
||||||
for rec in self:
|
|
||||||
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)
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
# Copyright 2014-2023 Abbaye du Barroux (http://www.barroux.org)
|
|
||||||
# Copyright 2016-2023 Akretion (http://www.akretion.com>)
|
|
||||||
# @author: Frère Bernard <informatique@barroux.org>
|
|
||||||
# @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.exceptions import ValidationError
|
|
||||||
from odoo.addons.phone_validation.tools import phone_validation
|
|
||||||
|
|
||||||
EMAIL_TYPES = ('1_email_primary', '2_email_secondary')
|
|
||||||
PHONE_TYPES = ('3_phone_primary', '4_phone_secondary', '5_mobile_primary', '6_mobile_secondary', '7_fax_primary', '8_fax_secondary')
|
|
||||||
|
|
||||||
|
|
||||||
class ResPartnerPhone(models.Model):
|
|
||||||
_name = 'res.partner.phone'
|
|
||||||
_order = 'partner_id, type'
|
|
||||||
_phone_name_sequence = 8
|
|
||||||
_description = 'Multiple emails and phones for partners'
|
|
||||||
|
|
||||||
partner_id = fields.Many2one(
|
|
||||||
'res.partner', string='Related Partner', index=True, ondelete='cascade')
|
|
||||||
type = fields.Selection([
|
|
||||||
('1_email_primary', 'Primary E-mail'),
|
|
||||||
('2_email_secondary', 'Secondary E-mail'),
|
|
||||||
('3_phone_primary', 'Primary Phone'),
|
|
||||||
('4_phone_secondary', 'Secondary Phone'),
|
|
||||||
('5_mobile_primary', 'Primary Mobile'),
|
|
||||||
('6_mobile_secondary', 'Secondary Mobile'),
|
|
||||||
('7_fax_primary', 'Primary Fax'),
|
|
||||||
('8_fax_secondary', 'Secondary Fax'),
|
|
||||||
],
|
|
||||||
string='Type', required=True, index=True)
|
|
||||||
phone = fields.Char(string='Phone')
|
|
||||||
email = fields.Char(string='E-Mail')
|
|
||||||
note = fields.Char('Note')
|
|
||||||
|
|
||||||
@api.onchange('type')
|
|
||||||
def type_change(self):
|
|
||||||
if self.type:
|
|
||||||
if self.type in EMAIL_TYPES:
|
|
||||||
self.phone = False
|
|
||||||
elif self.type in PHONE_TYPES:
|
|
||||||
self.email = False
|
|
||||||
|
|
||||||
@api.onchange('phone', 'partner_id')
|
|
||||||
def _onchange_phone_validation(self):
|
|
||||||
if self.phone:
|
|
||||||
country = self.partner_id.country_id
|
|
||||||
self.phone = phone_validation.phone_format(
|
|
||||||
self.phone,
|
|
||||||
country.code or None,
|
|
||||||
country.phone_code or None,
|
|
||||||
force_format='INTERNATIONAL',
|
|
||||||
raise_exception=False)
|
|
||||||
|
|
||||||
@api.constrains('type', 'phone', 'email')
|
|
||||||
def _check_partner_phone(self):
|
|
||||||
for rec in self:
|
|
||||||
if rec.type in EMAIL_TYPES:
|
|
||||||
if not rec.email:
|
|
||||||
raise ValidationError(_(
|
|
||||||
"E-mail field must have a value when type is Primary E-mail or Secondary E-mail."))
|
|
||||||
if rec.phone:
|
|
||||||
raise ValidationError(_(
|
|
||||||
"Phone field must be empty when type is Primary E-mail or Secondary E-mail."))
|
|
||||||
elif rec.type in PHONE_TYPES:
|
|
||||||
if not rec.phone:
|
|
||||||
raise ValidationError(_(
|
|
||||||
"Phone field must have a value when type is Primary/Secondary Phone, Primary/Secondary Mobile or Primary/Secondary Fax."))
|
|
||||||
if rec.email:
|
|
||||||
raise ValidationError(_(
|
|
||||||
"E-mail field must be empty when type is Primary/Secondary Phone, Primary/Secondary Mobile or Primary/Secondary Fax."))
|
|
||||||
|
|
||||||
def name_get(self):
|
|
||||||
res = []
|
|
||||||
for pphone in self:
|
|
||||||
if pphone.partner_id:
|
|
||||||
if self._context.get('callerid'):
|
|
||||||
name = pphone.partner_id.display_name
|
|
||||||
else:
|
|
||||||
name = u'%s (%s)' % (pphone.phone, pphone.partner_id.name)
|
|
||||||
else:
|
|
||||||
name = pphone.phone
|
|
||||||
res.append((pphone.id, name))
|
|
||||||
return res
|
|
||||||
|
|
||||||
def init(self):
|
|
||||||
self._cr.execute('''
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS single_email_primary
|
|
||||||
ON res_partner_phone (partner_id, type)
|
|
||||||
WHERE (type='1_email_primary')
|
|
||||||
''')
|
|
||||||
self._cr.execute('''
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS single_phone_primary
|
|
||||||
ON res_partner_phone (partner_id, type)
|
|
||||||
WHERE (type='3_phone_primary')
|
|
||||||
''')
|
|
||||||
self._cr.execute('''
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS single_mobile_primary
|
|
||||||
ON res_partner_phone (partner_id, type)
|
|
||||||
WHERE (type='5_mobile_primary')
|
|
||||||
''')
|
|
||||||
self._cr.execute('''
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS single_fax_primary
|
|
||||||
ON res_partner_phone (partner_id, type)
|
|
||||||
WHERE (type='7_fax_primary')
|
|
||||||
''')
|
|
||||||
193
base_partner_one2many_phone/partner_phone.py
Normal file
193
base_partner_one2many_phone/partner_phone.py
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
# Copyright 2014-2020 Abbaye du Barroux (http://www.barroux.org)
|
||||||
|
# Copyright 2016-2020 Akretion (http://www.akretion.com>)
|
||||||
|
# @author: Frère Bernard <informatique@barroux.org>
|
||||||
|
# @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.exceptions import ValidationError
|
||||||
|
|
||||||
|
EMAIL_TYPES = ('1_email_primary', '2_email_secondary')
|
||||||
|
PHONE_TYPES = ('3_phone_primary', '4_phone_secondary', '5_mobile_primary', '6_mobile_secondary', '7_fax_primary', '8_fax_secondary')
|
||||||
|
|
||||||
|
|
||||||
|
class ResPartnerPhone(models.Model):
|
||||||
|
_name = 'res.partner.phone'
|
||||||
|
_order = 'partner_id, type'
|
||||||
|
_phone_name_sequence = 8
|
||||||
|
_inherit = ['phone.validation.mixin']
|
||||||
|
_description = 'Multiple emails and phones for partners'
|
||||||
|
|
||||||
|
partner_id = fields.Many2one(
|
||||||
|
'res.partner', string='Related Partner', index=True, ondelete='cascade')
|
||||||
|
type = fields.Selection([
|
||||||
|
('1_email_primary', 'Primary E-mail'),
|
||||||
|
('2_email_secondary', 'Secondary E-mail'),
|
||||||
|
('3_phone_primary', 'Primary Phone'),
|
||||||
|
('4_phone_secondary', 'Secondary Phone'),
|
||||||
|
('5_mobile_primary', 'Primary Mobile'),
|
||||||
|
('6_mobile_secondary', 'Secondary Mobile'),
|
||||||
|
('7_fax_primary', 'Primary Fax'),
|
||||||
|
('8_fax_secondary', 'Secondary Fax'),
|
||||||
|
],
|
||||||
|
string='Type', required=True, index=True)
|
||||||
|
phone = fields.Char(string='Phone')
|
||||||
|
email = fields.Char(string='E-Mail')
|
||||||
|
note = fields.Char('Note')
|
||||||
|
|
||||||
|
@api.onchange('type')
|
||||||
|
def type_change(self):
|
||||||
|
if self.type:
|
||||||
|
if self.type in EMAIL_TYPES:
|
||||||
|
self.phone = False
|
||||||
|
elif self.type in PHONE_TYPES:
|
||||||
|
self.email = False
|
||||||
|
|
||||||
|
@api.onchange('phone', 'partner_id')
|
||||||
|
def _onchange_phone_validation(self):
|
||||||
|
if self.phone:
|
||||||
|
self.phone = self.phone_format(self.phone, country=self.partner_id.country_id)
|
||||||
|
|
||||||
|
@api.constrains('type', 'phone', 'email')
|
||||||
|
def _check_partner_phone(self):
|
||||||
|
for rec in self:
|
||||||
|
if rec.type in EMAIL_TYPES:
|
||||||
|
if not rec.email:
|
||||||
|
raise ValidationError(_(
|
||||||
|
"E-mail field must have a value when type is Primary E-mail or Secondary E-mail."))
|
||||||
|
if rec.phone:
|
||||||
|
raise ValidationError(_(
|
||||||
|
"Phone field must be empty when type is Primary E-mail or Secondary E-mail."))
|
||||||
|
elif rec.type in PHONE_TYPES:
|
||||||
|
if not rec.phone:
|
||||||
|
raise ValidationError(_(
|
||||||
|
"Phone field must have a value when type is Primary/Secondary Phone, Primary/Secondary Mobile or Primary/Secondary Fax."))
|
||||||
|
if rec.email:
|
||||||
|
raise ValidationError(_(
|
||||||
|
"E-mail field must be empty when type is Primary/Secondary Phone, Primary/Secondary Mobile or Primary/Secondary Fax."))
|
||||||
|
|
||||||
|
def name_get(self):
|
||||||
|
res = []
|
||||||
|
for pphone in self:
|
||||||
|
if pphone.partner_id:
|
||||||
|
if self._context.get('callerid'):
|
||||||
|
name = pphone.partner_id.display_name
|
||||||
|
else:
|
||||||
|
name = u'%s (%s)' % (pphone.phone, pphone.partner_id.name)
|
||||||
|
else:
|
||||||
|
name = pphone.phone
|
||||||
|
res.append((pphone.id, name))
|
||||||
|
return res
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
self._cr.execute('''
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS single_email_primary
|
||||||
|
ON res_partner_phone (partner_id, type)
|
||||||
|
WHERE (type='1_email_primary')
|
||||||
|
''')
|
||||||
|
self._cr.execute('''
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS single_phone_primary
|
||||||
|
ON res_partner_phone (partner_id, type)
|
||||||
|
WHERE (type='3_phone_primary')
|
||||||
|
''')
|
||||||
|
self._cr.execute('''
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS single_mobile_primary
|
||||||
|
ON res_partner_phone (partner_id, type)
|
||||||
|
WHERE (type='5_mobile_primary')
|
||||||
|
''')
|
||||||
|
self._cr.execute('''
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS single_fax_primary
|
||||||
|
ON res_partner_phone (partner_id, type)
|
||||||
|
WHERE (type='7_fax_primary')
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
class ResPartner(models.Model):
|
||||||
|
_inherit = 'res.partner'
|
||||||
|
|
||||||
|
# in v10, we are supposed to have in DB E.164 format
|
||||||
|
# with the current implementation, we have:
|
||||||
|
# in res.partner : PhoneNumberFormat.INTERNATIONAL
|
||||||
|
# in res.partner.phone : E.164
|
||||||
|
# It is not good, but it is not a big bug and it's complex to fix
|
||||||
|
# so let's let it like that. In v12, we store in
|
||||||
|
# PhoneNumberFormat.INTERNATIONAL, so this bug is kind of an anticipation
|
||||||
|
# for the future :)
|
||||||
|
|
||||||
|
phone_ids = fields.One2many(
|
||||||
|
'res.partner.phone', 'partner_id', string='Phones/Emails')
|
||||||
|
phone = fields.Char(
|
||||||
|
compute='_compute_partner_phone',
|
||||||
|
store=True, readonly=True, compute_sudo=True)
|
||||||
|
mobile = fields.Char(
|
||||||
|
compute='_compute_partner_phone',
|
||||||
|
store=True, readonly=True, compute_sudo=True)
|
||||||
|
email = fields.Char(
|
||||||
|
compute='_compute_partner_phone',
|
||||||
|
store=True, readonly=True, compute_sudo=True)
|
||||||
|
|
||||||
|
@api.depends('phone_ids.phone', 'phone_ids.type', 'phone_ids.email')
|
||||||
|
def _compute_partner_phone(self):
|
||||||
|
for partner in self:
|
||||||
|
phone = mobile = email = False
|
||||||
|
for pphone in partner.phone_ids:
|
||||||
|
if pphone.type == '1_email_primary' and pphone.email:
|
||||||
|
email = pphone.email
|
||||||
|
elif pphone.phone:
|
||||||
|
if pphone.type == '5_mobile_primary':
|
||||||
|
mobile = pphone.phone
|
||||||
|
elif pphone.type == '3_phone_primary':
|
||||||
|
phone = pphone.phone
|
||||||
|
partner.phone = phone
|
||||||
|
partner.mobile = mobile
|
||||||
|
partner.email = email
|
||||||
|
|
||||||
|
def _update_create_vals(
|
||||||
|
self, vals, type, partner_field, partner_phone_field):
|
||||||
|
if vals.get(partner_field):
|
||||||
|
vals['phone_ids'].append(
|
||||||
|
(0, 0, {'type': type, partner_phone_field: vals[partner_field]}))
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def create(self, vals):
|
||||||
|
if 'phone_ids' not in vals:
|
||||||
|
vals['phone_ids'] = []
|
||||||
|
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(
|
||||||
|
self, vals, type, partner_field, partner_phone_field):
|
||||||
|
self.ensure_one()
|
||||||
|
rppo = self.env['res.partner.phone']
|
||||||
|
if partner_field in vals:
|
||||||
|
pphone = rppo.search([
|
||||||
|
('partner_id', '=', self.id),
|
||||||
|
('type', '=', type)], limit=1)
|
||||||
|
if vals[partner_field]:
|
||||||
|
if pphone:
|
||||||
|
vals['phone_ids'].append((1, pphone.id, {
|
||||||
|
partner_phone_field: vals[partner_field]}))
|
||||||
|
else:
|
||||||
|
vals['phone_ids'].append((0, 0, {
|
||||||
|
'type': type,
|
||||||
|
partner_phone_field: vals[partner_field],
|
||||||
|
}))
|
||||||
|
else:
|
||||||
|
if pphone:
|
||||||
|
vals['phone_ids'].append((2, pphone.id))
|
||||||
|
|
||||||
|
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)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return super().write(vals)
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
<!--
|
||||||
Copyright 2014-2023 Abbaye du Barroux (http://www.barroux.org)
|
Copyright 2014-2020 Abbaye du Barroux (http://www.barroux.org)
|
||||||
Copyright 2016-2023 Akretion (http://www.akretion.com>)
|
Copyright 2016-2020 Akretion (http://www.akretion.com>)
|
||||||
@author: Frère Bernard <informatique@barroux.org>
|
@author: Frère Bernard <informatique@barroux.org>
|
||||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
@@ -9,6 +9,65 @@
|
|||||||
|
|
||||||
<odoo>
|
<odoo>
|
||||||
|
|
||||||
|
<!-- Partner phones -->
|
||||||
|
<record id="res_partner_phone_tree" model="ir.ui.view">
|
||||||
|
<field name="name">res.partner.phone.tree</field>
|
||||||
|
<field name="model">res.partner.phone</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree editable="bottom">
|
||||||
|
<field name="partner_id" invisible="not context.get('partner_phone_main_view')"/>
|
||||||
|
<field name="type"/>
|
||||||
|
<field name="phone" widget="phone" options="{'enable_sms': false}" attrs="{'required': [('type', 'not in', ('1_email_primary', '2_email_secondary'))], 'readonly': [('type', 'in', ('1_email_primary', '2_email_secondary'))]}"/>
|
||||||
|
<field name="email" widget="email" attrs="{'readonly': [('type', 'not in', ('1_email_primary', '2_email_secondary'))], 'required': [('type', 'in', ('1_email_primary', '2_email_secondary'))]}"/>
|
||||||
|
<field name="note"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="res_partner_phone_form" model="ir.ui.view">
|
||||||
|
<field name="name">res.partner.phone.form</field>
|
||||||
|
<field name="model">res.partner.phone</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form>
|
||||||
|
<group name="main">
|
||||||
|
<field name="partner_id" invisible="not context.get('partner_phone_main_view')"/>
|
||||||
|
<field name="type"/>
|
||||||
|
<field name="phone" widget="phone" options="{'enable_sms': false}" attrs="{'required': [('type', 'not in', ('1_email_primary', '2_email_secondary'))], 'invisible': [('type', 'in', ('1_email_primary', '2_email_secondary'))]}"/>
|
||||||
|
<field name="email" widget="email" attrs="{'invisible': [('type', 'not in', ('1_email_primary', '2_email_secondary'))], 'required': [('type', 'in', ('1_email_primary', '2_email_secondary'))]}"/>
|
||||||
|
<field name="note"/>
|
||||||
|
</group>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="res_partner_phone_search" model="ir.ui.view">
|
||||||
|
<field name="name">res.partner.phone.search</field>
|
||||||
|
<field name="model">res.partner.phone</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<search>
|
||||||
|
<field name="phone" />
|
||||||
|
<field name="email" />
|
||||||
|
<group name="groupby">
|
||||||
|
<filter name="type_groupby" string="Type" context="{'group_by': 'type'}"/>
|
||||||
|
</group>
|
||||||
|
</search>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="res_partner_phone_action" model="ir.actions.act_window">
|
||||||
|
<field name="name">Phones/E-mails</field>
|
||||||
|
<field name="res_model">res.partner.phone</field>
|
||||||
|
<field name="view_mode">tree</field>
|
||||||
|
<field name="context">{'partner_phone_main_view': True}</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<menuitem id="res_partner_phone_menu" action="res_partner_phone_action"
|
||||||
|
parent="contacts.menu_contacts" sequence="10"/>
|
||||||
|
|
||||||
|
<record id="contacts.res_partner_menu_config" model="ir.ui.menu">
|
||||||
|
<field name="sequence">20</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
<!-- PARTNER views -->
|
<!-- PARTNER views -->
|
||||||
<record id="view_partner_form" model="ir.ui.view">
|
<record id="view_partner_form" model="ir.ui.view">
|
||||||
<field name="name">add.phone_ids.on.partner.form</field>
|
<field name="name">add.phone_ids.on.partner.form</field>
|
||||||
@@ -100,7 +159,7 @@
|
|||||||
<field name="inherit_id" ref="base_usability.view_res_partner_filter"/>
|
<field name="inherit_id" ref="base_usability.view_res_partner_filter"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<field name="name" position="attributes">
|
<field name="name" position="attributes">
|
||||||
<attribute name="filter_domain">['|', '|', '|', '|', ('display_name', 'ilike', self), ('ref', '=ilike', self + '%'), ('phone_ids.email', 'ilike', self), ('vat', 'ilike', self), ('company_registry', 'ilike', self)]</attribute>
|
<attribute name="filter_domain">['|', '|', ('display_name', 'ilike', self), ('ref', '=ilike', self + '%'), ('phone_ids.email', 'ilike', self)]</attribute>
|
||||||
</field>
|
</field>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright 2017-2023 Akretion France (http://www.akretion.com/)
|
# Copyright 2017-2020 Akretion France (http://www.akretion.com/)
|
||||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
@@ -36,6 +36,7 @@ def create_partner_email(cr):
|
|||||||
|
|
||||||
def migrate_to_partner_phone(cr, registry):
|
def migrate_to_partner_phone(cr, registry):
|
||||||
logger.info('start data migration for one2many_phone')
|
logger.info('start data migration for one2many_phone')
|
||||||
|
with api.Environment.manage():
|
||||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||||
rppo = env['res.partner.phone']
|
rppo = env['res.partner.phone']
|
||||||
to_create = []
|
to_create = []
|
||||||
@@ -45,3 +46,4 @@ def migrate_to_partner_phone(cr, registry):
|
|||||||
# I need to create all at the end for invalidation purposes
|
# I need to create all at the end for invalidation purposes
|
||||||
rppo.create(to_create)
|
rppo.create(to_create)
|
||||||
logger.info('end data migration for one2many_phone')
|
logger.info('end data migration for one2many_phone')
|
||||||
|
return
|
||||||
|
|||||||
@@ -8,9 +8,8 @@ from odoo.tests.common import TransactionCase
|
|||||||
|
|
||||||
class TestPartnerPhone(TransactionCase):
|
class TestPartnerPhone(TransactionCase):
|
||||||
|
|
||||||
@classmethod
|
def setUp(self):
|
||||||
def setUpClass(cls):
|
super(TestPartnerPhone, self).setUp()
|
||||||
super().setUpClass()
|
|
||||||
|
|
||||||
def _check_result(self, partner, result):
|
def _check_result(self, partner, result):
|
||||||
rppo = self.env['res.partner.phone']
|
rppo = self.env['res.partner.phone']
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright 2014-2020 Abbaye du Barroux (http://www.barroux.org)
|
|
||||||
Copyright 2016-2020 Akretion (http://www.akretion.com>)
|
|
||||||
@author: Frère Bernard <informatique@barroux.org>
|
|
||||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
|
||||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
|
||||||
-->
|
|
||||||
|
|
||||||
<odoo>
|
|
||||||
|
|
||||||
<!-- Partner phones -->
|
|
||||||
<record id="res_partner_phone_tree" model="ir.ui.view">
|
|
||||||
<field name="name">res.partner.phone.tree</field>
|
|
||||||
<field name="model">res.partner.phone</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<tree editable="bottom">
|
|
||||||
<field name="partner_id" invisible="not context.get('partner_phone_main_view')"/>
|
|
||||||
<field name="type"/>
|
|
||||||
<field name="phone" widget="phone" options="{'enable_sms': false}" attrs="{'required': [('type', 'not in', ('1_email_primary', '2_email_secondary'))], 'readonly': [('type', 'in', ('1_email_primary', '2_email_secondary'))]}"/>
|
|
||||||
<field name="email" widget="email" attrs="{'readonly': [('type', 'not in', ('1_email_primary', '2_email_secondary'))], 'required': [('type', 'in', ('1_email_primary', '2_email_secondary'))]}"/>
|
|
||||||
<field name="note"/>
|
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="res_partner_phone_form" model="ir.ui.view">
|
|
||||||
<field name="name">res.partner.phone.form</field>
|
|
||||||
<field name="model">res.partner.phone</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form>
|
|
||||||
<group name="main">
|
|
||||||
<field name="partner_id" invisible="not context.get('partner_phone_main_view')"/>
|
|
||||||
<field name="type"/>
|
|
||||||
<field name="phone" widget="phone" options="{'enable_sms': false}" attrs="{'required': [('type', 'not in', ('1_email_primary', '2_email_secondary'))], 'invisible': [('type', 'in', ('1_email_primary', '2_email_secondary'))]}"/>
|
|
||||||
<field name="email" widget="email" attrs="{'invisible': [('type', 'not in', ('1_email_primary', '2_email_secondary'))], 'required': [('type', 'in', ('1_email_primary', '2_email_secondary'))]}"/>
|
|
||||||
<field name="note"/>
|
|
||||||
</group>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="res_partner_phone_search" model="ir.ui.view">
|
|
||||||
<field name="name">res.partner.phone.search</field>
|
|
||||||
<field name="model">res.partner.phone</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<search>
|
|
||||||
<field name="phone" />
|
|
||||||
<field name="email" />
|
|
||||||
<group name="groupby">
|
|
||||||
<filter name="type_groupby" string="Type" context="{'group_by': 'type'}"/>
|
|
||||||
</group>
|
|
||||||
</search>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="res_partner_phone_action" model="ir.actions.act_window">
|
|
||||||
<field name="name">Phones/E-mails</field>
|
|
||||||
<field name="res_model">res.partner.phone</field>
|
|
||||||
<field name="view_mode">tree</field>
|
|
||||||
<field name="context">{'partner_phone_main_view': True}</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<menuitem id="res_partner_phone_menu" action="res_partner_phone_action"
|
|
||||||
parent="contacts.menu_contacts" sequence="10"/>
|
|
||||||
|
|
||||||
<record id="contacts.res_partner_menu_config" model="ir.ui.menu">
|
|
||||||
<field name="sequence">20</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
</odoo>
|
|
||||||
@@ -4,10 +4,10 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Odoo Server 16.0\n"
|
"Project-Id-Version: Odoo Server 14.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-03-27 10:15+0000\n"
|
"POT-Creation-Date: 2021-07-01 10:02+0000\n"
|
||||||
"PO-Revision-Date: 2024-03-27 10:15+0000\n"
|
"PO-Revision-Date: 2021-07-01 10:02+0000\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
@@ -15,20 +15,6 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: \n"
|
"Content-Transfer-Encoding: \n"
|
||||||
"Plural-Forms: \n"
|
"Plural-Forms: \n"
|
||||||
|
|
||||||
#. module: base_usability
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "%s with a capital of"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#. module: base_usability
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "APE:"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model:ir.model,name:base_usability.model_res_partner_bank
|
#: model:ir.model,name:base_usability.model_res_partner_bank
|
||||||
msgid "Bank Accounts"
|
msgid "Bank Accounts"
|
||||||
@@ -39,23 +25,11 @@ msgstr ""
|
|||||||
msgid "Bank Name"
|
msgid "Bank Name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: base_usability
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "Capital:"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model:ir.model,name:base_usability.model_res_company
|
#: model:ir.model,name:base_usability.model_res_company
|
||||||
msgid "Companies"
|
msgid "Companies"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: base_usability
|
|
||||||
#: model_terms:ir.ui.view,arch_db:base_usability.ir_property_view_search
|
|
||||||
msgid "Company"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model:ir.model,name:base_usability.model_res_partner
|
#: model:ir.model,name:base_usability.model_res_partner
|
||||||
msgid "Contact"
|
msgid "Contact"
|
||||||
@@ -67,7 +41,6 @@ msgid "Currency"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
#: code:addons/base_usability/models/res_partner.py:0
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
#: code:addons/base_usability/models/res_partner.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
@@ -75,42 +48,61 @@ msgid "Customer Number:"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
#: model:ir.model.fields,field_description:base_usability.field_ir_mail_server__display_name
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_ir_model__display_name
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_company__display_name
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner__display_name
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner_bank__display_name
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner_category__display_name
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_users__display_name
|
||||||
|
msgid "Display Name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: base_usability
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
#: code:addons/base_usability/models/res_company.py:0
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
#: code:addons/base_usability/models/res_partner.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "E-mail:"
|
msgid "E-mail:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: base_usability
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "EORI:"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#. module: base_usability
|
|
||||||
#: model_terms:ir.ui.view,arch_db:base_usability.ir_property_view_search
|
|
||||||
msgid "Field"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
|
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
|
||||||
msgid "Group By"
|
msgid "Group By"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: base_usability
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_ir_mail_server__id
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_ir_model__id
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_company__id
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner__id
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner_bank__id
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner_category__id
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_users__id
|
||||||
|
msgid "ID"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model_terms:ir.ui.view,arch_db:base_usability.view_module_filter
|
#: model_terms:ir.ui.view,arch_db:base_usability.view_module_filter
|
||||||
msgid "Installable"
|
msgid "Installable"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: base_usability
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_ir_mail_server____last_update
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_ir_model____last_update
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_company____last_update
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner____last_update
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner_bank____last_update
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner_category____last_update
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_users____last_update
|
||||||
|
msgid "Last Modified on"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model:ir.model,name:base_usability.model_ir_mail_server
|
#: model:ir.model,name:base_usability.model_ir_mail_server
|
||||||
msgid "Mail Server"
|
msgid "Mail Server"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
#: code:addons/base_usability/models/res_partner.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Mobile:"
|
msgid "Mobile:"
|
||||||
@@ -128,7 +120,7 @@ msgstr ""
|
|||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model_terms:ir.ui.view,arch_db:base_usability.view_res_partner_filter
|
#: model_terms:ir.ui.view,arch_db:base_usability.view_res_partner_filter
|
||||||
msgid "Name or Email or VAT or Reference"
|
msgid "Name or Email or Reference"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
@@ -142,6 +134,11 @@ msgstr ""
|
|||||||
msgid "Nobody (used to hide native menus)"
|
msgid "Nobody (used to hide native menus)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: base_usability
|
||||||
|
#: model:ir.model,name:base_usability.model_res_partner_category
|
||||||
|
msgid "Partner Tags"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model:ir.model.fields,field_description:base_usability.field_res_partner__ref
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner__ref
|
||||||
#: model:ir.model.fields,field_description:base_usability.field_res_users__ref
|
#: model:ir.model.fields,field_description:base_usability.field_res_users__ref
|
||||||
@@ -149,21 +146,11 @@ msgid "Reference"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
msgid "Search Countries"
|
||||||
#, python-format
|
|
||||||
msgid "SIREN:"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "SIRET:"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#. module: base_usability
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
#: code:addons/base_usability/models/res_partner.py:0
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
#: code:addons/base_usability/models/res_partner.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
@@ -171,7 +158,11 @@ msgid "Supplier Number:"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner_category__name
|
||||||
|
msgid "Tag Name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: base_usability
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
#: code:addons/base_usability/models/res_company.py:0
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
#: code:addons/base_usability/models/res_partner.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
@@ -180,25 +171,22 @@ msgstr ""
|
|||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model:ir.model,name:base_usability.model_res_users
|
#: model:ir.model,name:base_usability.model_res_users
|
||||||
msgid "User"
|
msgid "Users"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
#: code:addons/base_usability/models/res_partner.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "VAT Number:"
|
msgid "VAT Number:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
#: code:addons/base_usability/models/res_company.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "VAT:"
|
msgid "VAT:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
#: code:addons/base_usability/models/res_company.py:0
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
#: code:addons/base_usability/models/res_partner.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
|
|||||||
@@ -4,31 +4,17 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Odoo Server 16.0\n"
|
"Project-Id-Version: Odoo Server 14.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-03-27 10:15+0000\n"
|
"POT-Creation-Date: 2021-07-01 10:02+0000\n"
|
||||||
"PO-Revision-Date: 2024-03-27 10:15+0000\n"
|
"PO-Revision-Date: 2021-07-01 12:15+0200\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: Alexis de Lattre <alexis@via.ecp.fr>\n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: \n"
|
"Content-Transfer-Encoding: \n"
|
||||||
"Plural-Forms: \n"
|
"Plural-Forms: \n"
|
||||||
|
|
||||||
#. module: base_usability
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "%s with a capital of"
|
|
||||||
msgstr "%s au capital de"
|
|
||||||
|
|
||||||
#. module: base_usability
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "APE:"
|
|
||||||
msgstr "APE :"
|
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model:ir.model,name:base_usability.model_res_partner_bank
|
#: model:ir.model,name:base_usability.model_res_partner_bank
|
||||||
msgid "Bank Accounts"
|
msgid "Bank Accounts"
|
||||||
@@ -39,27 +25,15 @@ msgstr "Comptes bancaires"
|
|||||||
msgid "Bank Name"
|
msgid "Bank Name"
|
||||||
msgstr "Nom de la banque"
|
msgstr "Nom de la banque"
|
||||||
|
|
||||||
#. module: base_usability
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "Capital:"
|
|
||||||
msgstr "Capital :"
|
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model:ir.model,name:base_usability.model_res_company
|
#: model:ir.model,name:base_usability.model_res_company
|
||||||
msgid "Companies"
|
msgid "Companies"
|
||||||
msgstr "Sociétés"
|
msgstr "Sociétés"
|
||||||
|
|
||||||
#. module: base_usability
|
|
||||||
#: model_terms:ir.ui.view,arch_db:base_usability.ir_property_view_search
|
|
||||||
msgid "Company"
|
|
||||||
msgstr "Société"
|
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model:ir.model,name:base_usability.model_res_partner
|
#: model:ir.model,name:base_usability.model_res_partner
|
||||||
msgid "Contact"
|
msgid "Contact"
|
||||||
msgstr ""
|
msgstr "Contact"
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
|
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
|
||||||
@@ -67,50 +41,67 @@ msgid "Currency"
|
|||||||
msgstr "Devise"
|
msgstr "Devise"
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
#: code:addons/base_usability/models/res_partner.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Customer Number:"
|
msgid "Customer Number:"
|
||||||
msgstr "N° client :"
|
msgstr "N° client :"
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
#: model:ir.model.fields,field_description:base_usability.field_ir_mail_server__display_name
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_ir_model__display_name
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_company__display_name
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner__display_name
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner_bank__display_name
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner_category__display_name
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_users__display_name
|
||||||
|
msgid "Display Name"
|
||||||
|
msgstr "Nom affiché"
|
||||||
|
|
||||||
|
#. module: base_usability
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
#: code:addons/base_usability/models/res_company.py:0
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
#: code:addons/base_usability/models/res_partner.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "E-mail:"
|
msgid "E-mail:"
|
||||||
msgstr "E-mail :"
|
msgstr "E-mail :"
|
||||||
|
|
||||||
#. module: base_usability
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "EORI:"
|
|
||||||
msgstr "EORI :"
|
|
||||||
|
|
||||||
#. module: base_usability
|
|
||||||
#: model_terms:ir.ui.view,arch_db:base_usability.ir_property_view_search
|
|
||||||
msgid "Field"
|
|
||||||
msgstr "Champ"
|
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
|
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
|
||||||
msgid "Group By"
|
msgid "Group By"
|
||||||
msgstr "Grouper par"
|
msgstr "Grouper par"
|
||||||
|
|
||||||
|
#. module: base_usability
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_ir_mail_server__id
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_ir_model__id
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_company__id
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner__id
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner_bank__id
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner_category__id
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_users__id
|
||||||
|
msgid "ID"
|
||||||
|
msgstr "ID"
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model_terms:ir.ui.view,arch_db:base_usability.view_module_filter
|
#: model_terms:ir.ui.view,arch_db:base_usability.view_module_filter
|
||||||
msgid "Installable"
|
msgid "Installable"
|
||||||
msgstr ""
|
msgstr "Installable"
|
||||||
|
|
||||||
|
#. module: base_usability
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_ir_mail_server____last_update
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_ir_model____last_update
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_company____last_update
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner____last_update
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner_bank____last_update
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner_category____last_update
|
||||||
|
#: model:ir.model.fields,field_description:base_usability.field_res_users____last_update
|
||||||
|
msgid "Last Modified on"
|
||||||
|
msgstr "Dernière modification le"
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model:ir.model,name:base_usability.model_ir_mail_server
|
#: model:ir.model,name:base_usability.model_ir_mail_server
|
||||||
msgid "Mail Server"
|
msgid "Mail Server"
|
||||||
msgstr "Serveur de messagerie"
|
msgstr "Serveur mail"
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
#: code:addons/base_usability/models/res_partner.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Mobile:"
|
msgid "Mobile:"
|
||||||
@@ -119,7 +110,7 @@ msgstr "Portable :"
|
|||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model:ir.model,name:base_usability.model_ir_model
|
#: model:ir.model,name:base_usability.model_ir_model
|
||||||
msgid "Models"
|
msgid "Models"
|
||||||
msgstr ""
|
msgstr "Modèles"
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
|
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
|
||||||
@@ -128,8 +119,8 @@ msgstr "Nom ou code"
|
|||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model_terms:ir.ui.view,arch_db:base_usability.view_res_partner_filter
|
#: model_terms:ir.ui.view,arch_db:base_usability.view_res_partner_filter
|
||||||
msgid "Name or Email or VAT or Reference"
|
msgid "Name or Email or Reference"
|
||||||
msgstr "Nom ou e-mail ou n°TVA ou référence"
|
msgstr "Nom ou e-mail ou référence"
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model:ir.model.fields,field_description:base_usability.field_res_partner__name_title
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner__name_title
|
||||||
@@ -142,6 +133,11 @@ msgstr "Nom avec titre"
|
|||||||
msgid "Nobody (used to hide native menus)"
|
msgid "Nobody (used to hide native menus)"
|
||||||
msgstr "Personne (utilisé pour cacher des entrées de menu natifs)"
|
msgstr "Personne (utilisé pour cacher des entrées de menu natifs)"
|
||||||
|
|
||||||
|
#. module: base_usability
|
||||||
|
#: model:ir.model,name:base_usability.model_res_partner_category
|
||||||
|
msgid "Partner Tags"
|
||||||
|
msgstr "Étiquettes du partenaire"
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model:ir.model.fields,field_description:base_usability.field_res_partner__ref
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner__ref
|
||||||
#: model:ir.model.fields,field_description:base_usability.field_res_users__ref
|
#: model:ir.model.fields,field_description:base_usability.field_res_users__ref
|
||||||
@@ -149,29 +145,22 @@ msgid "Reference"
|
|||||||
msgstr "Référence"
|
msgstr "Référence"
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
msgid "Search Countries"
|
||||||
#, python-format
|
msgstr ""
|
||||||
msgid "SIREN:"
|
|
||||||
msgstr "SIREN :"
|
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
|
||||||
#, python-format
|
|
||||||
msgid "SIRET:"
|
|
||||||
msgstr "SIRET :"
|
|
||||||
|
|
||||||
#. module: base_usability
|
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
#: code:addons/base_usability/models/res_partner.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Supplier Number:"
|
msgid "Supplier Number:"
|
||||||
msgstr "N° fournisseur :"
|
msgstr "N° fournisseur :"
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
#: model:ir.model.fields,field_description:base_usability.field_res_partner_category__name
|
||||||
|
msgid "Tag Name"
|
||||||
|
msgstr "Nom de l'étiquette"
|
||||||
|
|
||||||
|
#. module: base_usability
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
#: code:addons/base_usability/models/res_company.py:0
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
#: code:addons/base_usability/models/res_partner.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
@@ -180,25 +169,22 @@ msgstr "Tél :"
|
|||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#: model:ir.model,name:base_usability.model_res_users
|
#: model:ir.model,name:base_usability.model_res_users
|
||||||
msgid "User"
|
msgid "Users"
|
||||||
msgstr ""
|
msgstr "Utilisateurs"
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
#: code:addons/base_usability/models/res_partner.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "VAT Number:"
|
msgid "VAT Number:"
|
||||||
msgstr "N° TVA :"
|
msgstr "N° TVA :"
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
#: code:addons/base_usability/models/res_company.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "VAT:"
|
msgid "VAT:"
|
||||||
msgstr "TVA :"
|
msgstr "TVA :"
|
||||||
|
|
||||||
#. module: base_usability
|
#. module: base_usability
|
||||||
#. odoo-python
|
|
||||||
#: code:addons/base_usability/models/res_company.py:0
|
#: code:addons/base_usability/models/res_company.py:0
|
||||||
#: code:addons/base_usability/models/res_partner.py:0
|
#: code:addons/base_usability/models/res_partner.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
|
|||||||
@@ -4,4 +4,3 @@ from . import res_partner_bank
|
|||||||
from . import res_company
|
from . import res_company
|
||||||
from . import ir_mail_server
|
from . import ir_mail_server
|
||||||
from . import ir_model
|
from . import ir_model
|
||||||
from . import ir_model_fields
|
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
# Copyright 2024 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, models
|
|
||||||
|
|
||||||
|
|
||||||
class IrModelFields(models.Model):
|
|
||||||
_inherit = 'ir.model.fields'
|
|
||||||
|
|
||||||
@api.depends('name', 'field_description')
|
|
||||||
def name_get(self):
|
|
||||||
res = []
|
|
||||||
for rec in self:
|
|
||||||
res.append((rec.id, '%s (%s)' % (rec.field_description, rec.name)))
|
|
||||||
return res
|
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
from odoo import api, models, _
|
from odoo import api, models, _
|
||||||
from odoo.tools.misc import format_amount
|
|
||||||
|
|
||||||
|
|
||||||
class ResCompany(models.Model):
|
class ResCompany(models.Model):
|
||||||
@@ -40,77 +39,32 @@ class ResCompany(models.Model):
|
|||||||
'value': self.phone,
|
'value': self.phone,
|
||||||
# http://www.fileformat.info/info/unicode/char/1f4de/index.htm
|
# http://www.fileformat.info/info/unicode/char/1f4de/index.htm
|
||||||
'icon': '\U0001F4DE',
|
'icon': '\U0001F4DE',
|
||||||
'label': _('Tel:'),
|
'label': _('Tel:')},
|
||||||
},
|
|
||||||
'email': {
|
'email': {
|
||||||
'value': self.email,
|
'value': self.email,
|
||||||
# http://www.fileformat.info/info/unicode/char/2709/index.htm
|
# http://www.fileformat.info/info/unicode/char/2709/index.htm
|
||||||
'icon': '\u2709',
|
'icon': '\u2709',
|
||||||
'label': _('E-mail:'),
|
'label': _('E-mail:')},
|
||||||
},
|
|
||||||
'website': {
|
'website': {
|
||||||
'value': self.website,
|
'value': self.website,
|
||||||
'icon': '\U0001f310',
|
'icon': '\U0001f310',
|
||||||
'label': _('Website:'),
|
'label': _('Website:')},
|
||||||
},
|
|
||||||
'vat': {
|
'vat': {
|
||||||
'value': self.vat,
|
'value': self.vat,
|
||||||
'label': _('VAT:'),
|
'label': _('VAT:')},
|
||||||
},
|
|
||||||
'ape': {
|
|
||||||
'value': hasattr(self, 'ape') and self.ape or False,
|
|
||||||
'label': _('APE:'),
|
|
||||||
},
|
|
||||||
'siret': {
|
|
||||||
'value': hasattr(self, 'siret') and self.siret or False,
|
|
||||||
'label': _('SIRET:'),
|
|
||||||
},
|
|
||||||
'siren': {
|
|
||||||
'value': hasattr(self, 'siren') and self.siren or False,
|
|
||||||
'label': _('SIREN:'),
|
|
||||||
},
|
|
||||||
'eori': {
|
|
||||||
'value': self._get_eori(),
|
|
||||||
'label': _('EORI:'),
|
|
||||||
},
|
|
||||||
'capital': {
|
|
||||||
# 'capital_amount' added by base_company_extension
|
|
||||||
'value': hasattr(self, 'capital_amount') and self.capital_amount and format_amount(self.env, self.capital_amount, self.currency_id) or False,
|
|
||||||
'label': _('Capital:'),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
# 'legal_type' added by base_company_extension
|
|
||||||
if hasattr(self, 'legal_type') and self.legal_type:
|
|
||||||
options['capital']['label'] = _('%s with a capital of') % self.legal_type
|
|
||||||
return options
|
return options
|
||||||
|
|
||||||
def _get_eori(self):
|
|
||||||
eori = False
|
|
||||||
if self.partner_id.country_id.code == 'FR' and hasattr(self, 'siret') and self.siret:
|
|
||||||
# Currently migrating from EORI-SIRET to EORI-SIREN :
|
|
||||||
# https://www.pwcavocats.com/fr/ealertes/ealertes-france/2023/avril/reforme-numero-eori-siren-siret.html
|
|
||||||
# But, for the moment, we continue to use EORI-SIRET
|
|
||||||
eori = f'FR{self.siret}'
|
|
||||||
return eori
|
|
||||||
|
|
||||||
def _report_company_legal_name(self):
|
def _report_company_legal_name(self):
|
||||||
'''Method inherited in the module base_company_extension'''
|
'''Method inherited in the module base_company_extension'''
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def _report_header_line_details(self):
|
|
||||||
"""This method is designed to be inherited"""
|
|
||||||
# I decided not to put email in the default header because only a few very small
|
|
||||||
# companies have a generic company email address
|
|
||||||
line_details = [['phone', 'website', 'capital'], ['vat', 'siret', 'eori', 'ape']]
|
|
||||||
return line_details
|
|
||||||
|
|
||||||
# for reports
|
# for reports
|
||||||
def _display_report_header(
|
def _display_report_header(
|
||||||
self, line_details=None, icon=True, line_separator=' - '):
|
self, line_details=[['phone', 'website'], ['vat']],
|
||||||
|
icon=True, line_separator=' - '):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
if line_details is None:
|
|
||||||
line_details = self._report_header_line_details()
|
|
||||||
res = ''
|
res = ''
|
||||||
address = self.partner_id._display_address(without_company=True)
|
address = self.partner_id._display_address(without_company=True)
|
||||||
address = address.replace('\n', ' - ')
|
address = address.replace('\n', ' - ')
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
diff --git a/addons/web/static/src/search/filter_menu/custom_filter_item.js b/addons/web/static/src/search/filter_menu/custom_filter_item.js
|
|
||||||
index f67f5fb40af..22525b7cbfd 100644
|
|
||||||
--- a/addons/web/static/src/search/filter_menu/custom_filter_item.js
|
|
||||||
+++ b/addons/web/static/src/search/filter_menu/custom_filter_item.js
|
|
||||||
@@ -46,6 +46,8 @@ const FIELD_OPERATORS = {
|
|
||||||
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 },
|
|
||||||
@@ -257,6 +259,10 @@ export class CustomFilterItem extends Component {
|
|
||||||
[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]]);
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
diff --git a/addons/web/controllers/export.py b/addons/web/controllers/export.py
|
|
||||||
index 5a1bbcb6b02..04c70131660 100644
|
|
||||||
--- a/addons/web/controllers/export.py
|
|
||||||
+++ b/addons/web/controllers/export.py
|
|
||||||
@@ -308,7 +308,6 @@ class Export(http.Controller):
|
|
||||||
def get_fields(self, model, prefix='', parent_name='',
|
|
||||||
import_compat=True, parent_field_type=None,
|
|
||||||
parent_field=None, exclude=None):
|
|
||||||
-
|
|
||||||
fields = self.fields_get(model)
|
|
||||||
if import_compat:
|
|
||||||
if parent_field_type in ['many2one', 'many2many']:
|
|
||||||
@@ -347,7 +346,7 @@ class Export(http.Controller):
|
|
||||||
# Add name field when expand m2o and m2m fields in import-compatible mode
|
|
||||||
val = prefix
|
|
||||||
name = parent_name + (parent_name and '/' or '') + field['string']
|
|
||||||
- record = {'id': ident, 'string': name,
|
|
||||||
+ record = {'id': ident, 'string': name + f' ({field_name})',
|
|
||||||
'value': val, 'children': False,
|
|
||||||
'field_type': field.get('type'),
|
|
||||||
'required': field.get('required'),
|
|
||||||
@@ -3,20 +3,19 @@
|
|||||||
<odoo>
|
<odoo>
|
||||||
|
|
||||||
<menuitem id="conf_tech" parent="base.menu_administration" name="🧰" groups="base.group_erp_manager" sequence="1">
|
<menuitem id="conf_tech" parent="base.menu_administration" name="🧰" groups="base.group_erp_manager" sequence="1">
|
||||||
<menuitem id="model" name="Models" action="base.action_model_model" sequence="10"/>
|
<menuitem id="model" name="Model" action="base.action_model_model" sequence="10"/>
|
||||||
<menuitem id="fields" name="Fields" action="base.action_model_fields" sequence="10"/>
|
<menuitem id="view" name="View" action="base.action_ui_view" sequence="20" />
|
||||||
<menuitem id="rec_rule" name="📑 Record Rules" action="base.action_rule" sequence="20" />
|
<menuitem id="rec_rule" name="Record Rule" action="base.action_rule" sequence="30" />
|
||||||
<menuitem id="view" name="Views" action="base.action_ui_view" sequence="30" />
|
<menuitem id="menu" name="Menu" action="base.grant_menu_access" sequence="100" />
|
||||||
<menuitem id="menu" name="📃 Menus" action="base.grant_menu_access" sequence="40" />
|
<menuitem id="seq" name="Sequence" action="base.ir_sequence_form" sequence="100" />
|
||||||
<menuitem id="model_data" name="Model Data" action="base.action_model_data" sequence="50" />
|
<menuitem id="model_data" name="Model Data" action="base.action_model_data" sequence="100" />
|
||||||
<menuitem id="cron" name="📅 Crons" action="base.ir_cron_act" sequence="70" />
|
<menuitem id="param" name="Param" action="base.ir_config_list_action" sequence="100" />
|
||||||
<menuitem id="window" name="Act Windows" action="base.ir_action_window" sequence="80" />
|
<menuitem id="cron" name="Cron" action="base.ir_cron_act" sequence="100" />
|
||||||
<menuitem id="server" name="⚙ Act Server" action="base.action_server_action" sequence="90" />
|
<menuitem id="window" name="Act Window" action="base.ir_action_window" sequence="100" />
|
||||||
<menuitem id="report" name="📄 Reports" action="base.ir_action_report" sequence="100" />
|
<menuitem id="server" name="Act Server" action="base.action_server_action" sequence="100" />
|
||||||
<menuitem id="param" name="Params" action="base.ir_config_list_action" sequence="110" />
|
<menuitem id="report" name="Report" action="base.ir_action_report" sequence="100" />
|
||||||
<menuitem id="seq" name="🔢 Sequences" action="base.ir_sequence_form" sequence="115" />
|
<menuitem id="mail_tmpl" name="Mail Tmpl" action="mail.action_email_template_tree_all" sequence="100" />
|
||||||
<menuitem id="property" name="Properties" action="base.ir_property_form" sequence="120" />
|
<menuitem id="property" name="Property" action="base.ir_property_form" sequence="100" />
|
||||||
<menuitem id="mail_tmpl" name="📧 Mail Tmpl" action="mail.action_email_template_tree_all" sequence="140" />
|
|
||||||
</menuitem>
|
</menuitem>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# Copyright 2019-2023 Akretion France (http://www.akretion.com)
|
# Copyright 2019-2021 Akretion France (http://www.akretion.com)
|
||||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Link Tracker Usability',
|
'name': 'Link Tracker Usability',
|
||||||
'version': '16.0.1.0.0',
|
'version': '14.0.1.0.0',
|
||||||
'category': 'Marketing',
|
'category': 'Marketing',
|
||||||
'license': 'AGPL-3',
|
'license': 'AGPL-3',
|
||||||
'summary': 'Improve usability for link tracker',
|
'summary': 'Improve usability for link tracker',
|
||||||
@@ -18,10 +18,10 @@ This module has been written by Alexis de Lattre from Akretion
|
|||||||
<alexis.delattre@akretion.com>.
|
<alexis.delattre@akretion.com>.
|
||||||
""",
|
""",
|
||||||
'author': 'Akretion',
|
'author': 'Akretion',
|
||||||
'website': 'https://github.com/akretion/odoo-usability',
|
'website': 'http://www.akretion.com',
|
||||||
'depends': ['link_tracker'],
|
'depends': ['link_tracker'],
|
||||||
'data': [
|
'data': [
|
||||||
'views/link_tracker_click.xml',
|
'views/link_tracker_click.xml',
|
||||||
],
|
],
|
||||||
'installable': True,
|
'installable': False,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
<!--
|
||||||
Copyright 2019-2023 Akretion France (http://www.akretion.com/)
|
Copyright 2019-2021 Akretion France (http://www.akretion.com/)
|
||||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
-->
|
-->
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
# 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': '16.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,
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<?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>
|
|
||||||
@@ -3,26 +3,12 @@
|
|||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
|
||||||
from odoo import fields, models, Command
|
from odoo import api, models
|
||||||
|
|
||||||
|
|
||||||
class MrpProduction(models.Model):
|
class MrpProduction(models.Model):
|
||||||
_inherit = 'mrp.production'
|
_inherit = 'mrp.production'
|
||||||
|
|
||||||
location_dest_id = fields.Many2one(tracking=True)
|
|
||||||
|
|
||||||
# Target: allow to modify location_dest_id until the button 'Mark as done' is pushed
|
|
||||||
# I didn't find a better implementation... feel free to improve if you find one
|
|
||||||
def _compute_move_finished_ids(self):
|
|
||||||
for prod in self:
|
|
||||||
if prod.state not in ('draft', 'done') and prod.location_dest_id:
|
|
||||||
vals = {'location_dest_id': prod.location_dest_id.id}
|
|
||||||
prod.move_finished_ids = [
|
|
||||||
Command.update(m.id, vals) for m in prod.move_finished_ids
|
|
||||||
if m.state != 'done'
|
|
||||||
]
|
|
||||||
super()._compute_move_finished_ids()
|
|
||||||
|
|
||||||
# Method used by the report, inherited in this module
|
# Method used by the report, inherited in this module
|
||||||
# @api.model
|
# @api.model
|
||||||
# def get_stock_move_sold_out_report(self, move):
|
# def get_stock_move_sold_out_report(self, move):
|
||||||
|
|||||||
@@ -13,17 +13,11 @@
|
|||||||
<field name="model">mrp.production</field>
|
<field name="model">mrp.production</field>
|
||||||
<field name="inherit_id" ref="mrp.mrp_production_form_view"/>
|
<field name="inherit_id" ref="mrp.mrp_production_form_view"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<field name="user_id" position="before">
|
<!--
|
||||||
<!-- I can't use position="move" because it would match another field in an embedded tree view -->
|
<label for="product_qty" position="before">
|
||||||
<field name="location_src_id" groups="stock.group_stock_multi_locations" options="{'no_create': True}" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
<field name="location_src_id" groups="stock.group_stock_multi_locations" options="{'no_create': True}" attrs="{'readonly': [('state', '!=', 'draft')]}" position="move"/>
|
||||||
<field name="location_dest_id" groups="stock.group_stock_multi_locations" options="{'no_create': True}" attrs="{'readonly': [('state', 'in', ('done', 'cancel'))]}"/>
|
<field name="location_dest_id" groups="stock.group_stock_multi_locations" options="{'no_create': True}" attrs="{'readonly': [('state', '!=', 'draft')]}" position="move"/>
|
||||||
</field>
|
</label> -->
|
||||||
<!-- It is important to remove the original field location_dest_id
|
|
||||||
and not just set it as invisible because it cancels the changes -->
|
|
||||||
<xpath expr="//page[@name='miscellaneous']/group/group/field[@name='location_dest_id']" position="replace"/>
|
|
||||||
<xpath expr="//page[@name='miscellaneous']/group/group/field[@name='location_src_id']" position="attributes">
|
|
||||||
<attribute name="invisible">1</attribute>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//page[@name='miscellaneous']/group/group/field[@name='date_deadline']" position="after">
|
<xpath expr="//page[@name='miscellaneous']/group/group/field[@name='date_deadline']" position="after">
|
||||||
<field name="date_start"/>
|
<field name="date_start"/>
|
||||||
<field name="date_finished"/>
|
<field name="date_finished"/>
|
||||||
|
|||||||
@@ -31,8 +31,6 @@ Akretion:
|
|||||||
"views/report_pos_order.xml",
|
"views/report_pos_order.xml",
|
||||||
"views/pos_category.xml",
|
"views/pos_category.xml",
|
||||||
"views/pos_session.xml",
|
"views/pos_session.xml",
|
||||||
"views/pos_payment_method.xml",
|
|
||||||
"views/pos_order.xml",
|
|
||||||
"views/product.xml",
|
"views/product.xml",
|
||||||
],
|
],
|
||||||
"installable": True,
|
"installable": True,
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
from . import product
|
from . import product
|
||||||
from . import pos_category
|
from . import pos_category
|
||||||
from . import pos_payment_method
|
from . import pos_payment_method
|
||||||
from . import pos_order
|
|
||||||
from . import pos_session
|
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
# Copyright 2024 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
|
|
||||||
|
|
||||||
|
|
||||||
class PosOrder(models.Model):
|
|
||||||
_inherit = 'pos.order'
|
|
||||||
|
|
||||||
# field displayed in pos.order list view
|
|
||||||
payments_char = fields.Char(
|
|
||||||
string="Payment Methods", compute="_compute_payments_char", store=True)
|
|
||||||
|
|
||||||
@api.depends('payment_ids')
|
|
||||||
def _compute_payments_char(self):
|
|
||||||
for order in self:
|
|
||||||
payments = set()
|
|
||||||
for pay in order.payment_ids:
|
|
||||||
if pay.payment_method_id.name:
|
|
||||||
# unfortunately, 'name' of pos.payment.method is translate=True
|
|
||||||
payments.add(pay.payment_method_id.name)
|
|
||||||
order.payments_char = ', '.join(payments)
|
|
||||||
@@ -8,9 +8,7 @@ from odoo import fields, models
|
|||||||
class PosPaymentMethod(models.Model):
|
class PosPaymentMethod(models.Model):
|
||||||
_inherit = 'pos.payment.method'
|
_inherit = 'pos.payment.method'
|
||||||
_check_company_auto = True
|
_check_company_auto = True
|
||||||
_order = 'sequence, id'
|
|
||||||
|
|
||||||
outstanding_account_id = fields.Many2one(check_company=True)
|
outstanding_account_id = fields.Many2one(check_company=True)
|
||||||
receivable_account_id = fields.Many2one(check_company=True)
|
receivable_account_id = fields.Many2one(check_company=True)
|
||||||
journal_id = fields.Many2one(check_company=True)
|
journal_id = fields.Many2one(check_company=True)
|
||||||
sequence = fields.Integer(default=10)
|
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
# 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 models
|
|
||||||
|
|
||||||
|
|
||||||
class PosSession(models.Model):
|
|
||||||
_inherit = 'pos.session'
|
|
||||||
|
|
||||||
def _loader_params_pos_payment_method(self):
|
|
||||||
res = super()._loader_params_pos_payment_method()
|
|
||||||
res['search_params']['order'] = "sequence, id"
|
|
||||||
return res
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
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 e8ddb4d173c..684be2484a2 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
|
|
||||||
@@ -190,7 +190,9 @@ odoo.define('point_of_sale.PaymentScreen', function (require) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async _finalizeValidation() {
|
|
||||||
- if ((this.currentOrder.is_paid_with_cash() || this.currentOrder.get_change()) && this.env.pos.config.iface_cashdrawer && this.env.proxy && this.env.proxy.printer) {
|
|
||||||
+ //if ((this.currentOrder.is_paid_with_cash() || this.currentOrder.get_change()) && this.env.pos.config.iface_cashdrawer && this.env.proxy && this.env.proxy.printer) {
|
|
||||||
+ // Always open cashbox (by default, Odoo only opens cashbox for cash payments)
|
|
||||||
+ if (this.env.pos.config.iface_cashdrawer && this.env.proxy && this.env.proxy.printer) {
|
|
||||||
this.env.proxy.printer.open_cashbox();
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
<?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>
|
|
||||||
|
|
||||||
|
|
||||||
<record id="view_pos_order_tree" model="ir.ui.view">
|
|
||||||
<field name="model">pos.order</field>
|
|
||||||
<field name="inherit_id" ref="point_of_sale.view_pos_order_tree"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="amount_total" position="after">
|
|
||||||
<field name="payments_char" optional="show"/>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
</odoo>
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
<?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>
|
|
||||||
|
|
||||||
<record id="pos_payment_method_view_form" model="ir.ui.view">
|
|
||||||
<field name="model">pos.payment.method</field>
|
|
||||||
<field name="inherit_id" ref="point_of_sale.pos_payment_method_view_form"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="company_id" position="after">
|
|
||||||
<!-- company_id without groups="base.group_multi_company" is missing -->
|
|
||||||
<field name="company_id" invisible="1"/>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
|
|
||||||
</odoo>
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
# Copyright 2014-2023 Akretion (http://www.akretion.com/)
|
# Copyright 2014-2020 Akretion (http://www.akretion.com/)
|
||||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Product Manager Group',
|
'name': 'Product Manager Group',
|
||||||
'version': '16.0.1.0.0',
|
'version': '14.0.1.0.0',
|
||||||
'category': 'Hidden',
|
'category': 'Hidden',
|
||||||
'license': 'AGPL-3',
|
'license': 'AGPL-3',
|
||||||
'summary': 'Add a group Product Manager',
|
'summary': 'Add a group Product Manager',
|
||||||
@@ -23,5 +23,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
|
|||||||
'security/product_security.xml',
|
'security/product_security.xml',
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
],
|
],
|
||||||
'installable': True,
|
'installable': False,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# Copyright 2014-2023 Akretion (http://www.akretion.com)
|
# Copyright 2014-2020 Akretion (http://www.akretion.com)
|
||||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Product Manager Group Stock',
|
'name': 'Product Manager Group Stock',
|
||||||
'version': '16.0.1.0.0',
|
'version': '14.0.1.0.0',
|
||||||
'category': 'Hidden',
|
'category': 'Hidden',
|
||||||
'license': 'AGPL-3',
|
'license': 'AGPL-3',
|
||||||
'summary': 'Extend the group Product Manager to Stock',
|
'summary': 'Extend the group Product Manager to Stock',
|
||||||
@@ -22,6 +22,6 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
|
|||||||
'data': [
|
'data': [
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
],
|
],
|
||||||
'installable': True,
|
'installable': False,
|
||||||
'auto_install': True,
|
'auto_install': True,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,14 +39,13 @@ This module has been written by Alexis de Lattre from Akretion
|
|||||||
'depends': [
|
'depends': [
|
||||||
'point_of_sale',
|
'point_of_sale',
|
||||||
'barcodes',
|
'barcodes',
|
||||||
|
'base_report_to_printer',
|
||||||
],
|
],
|
||||||
'external_dependencies': {'python': ['python-barcode>=0.14.0']},
|
'external_dependencies': {'python': ['python-barcode>=0.14.0']},
|
||||||
'data': [
|
'data': [
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
'wizard/product_print_zpl_barcode_view.xml',
|
'wizard/product_print_zpl_barcode_view.xml',
|
||||||
'wizard/res_config_settings_view.xml',
|
|
||||||
'views/product.xml',
|
'views/product.xml',
|
||||||
'views/stock_picking.xml',
|
|
||||||
'data/barcode_sequence.xml',
|
'data/barcode_sequence.xml',
|
||||||
],
|
],
|
||||||
'installable': True,
|
'installable': True,
|
||||||
|
|||||||
@@ -1,412 +0,0 @@
|
|||||||
# 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"
|
|
||||||
@@ -1,392 +0,0 @@
|
|||||||
# 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,2 +1 @@
|
|||||||
from . import product
|
from . import product
|
||||||
from . import stock_picking
|
|
||||||
|
|||||||
@@ -29,6 +29,22 @@ class ProductTemplate(models.Model):
|
|||||||
% (self.display_name, self.product_variant_count))
|
% (self.display_name, self.product_variant_count))
|
||||||
return self.product_variant_ids[0].generate_barcode_from_product_product()
|
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):
|
class ProductProduct(models.Model):
|
||||||
_inherit = 'product.product'
|
_inherit = 'product.product'
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
# 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,3 +1,2 @@
|
|||||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
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.group_user,1,1,1,1
|
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.group_user,1,1,1,1
|
|
||||||
|
|||||||
|
@@ -27,17 +27,7 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<button name="action_open_label_layout" position="after">
|
<button name="action_open_label_layout" position="after">
|
||||||
<button name="generate_barcode_from_product_template" type="object" string="Generate Barcode" attrs="{'invisible': ['|', ('product_variant_count', '>', 1), ('barcode', '!=', False)]}"/>
|
<button name="generate_barcode_from_product_template" type="object" string="Generate Barcode" 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" 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>
|
|
||||||
</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">
|
|
||||||
<button name="action_open_label_layout" position="after">
|
|
||||||
<button name="%(product_print_zpl_barcode.product_print_zpl_barcode_action)d" type="action" string="Print Barcodes"/>
|
|
||||||
</button>
|
</button>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -49,19 +39,10 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<button name="action_open_label_layout" position="after">
|
<button name="action_open_label_layout" position="after">
|
||||||
<button name="generate_barcode_from_product_product" type="object" string="Generate Barcode" attrs="{'invisible': [('barcode', '!=', False)]}"/>
|
<button name="generate_barcode_from_product_product" type="object" string="Generate Barcode" attrs="{'invisible': [('barcode', '!=', False)]}"/>
|
||||||
<button name="%(product_print_zpl_barcode.product_print_zpl_barcode_action)d" type="action" string="Print Barcode" attrs="{'invisible': [('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': [('barcode', '=', False)]}"/>
|
||||||
</button>
|
</button>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</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">
|
|
||||||
<button name="action_open_label_layout" position="after">
|
|
||||||
<button name="%(product_print_zpl_barcode.product_print_zpl_barcode_action)d" type="action" string="Print Barcodes"/>
|
|
||||||
</button>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
<?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,2 +1 @@
|
|||||||
from . import product_print_zpl_barcode
|
from . import product_print_zpl_barcode
|
||||||
from . import res_config_settings
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright 2016-2023 Akretion France (http://www.akretion.com/)
|
# Copyright 2016-2020 Akretion France (http://www.akretion.com/)
|
||||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
@@ -8,23 +8,24 @@ from odoo.tools import float_compare, float_is_zero
|
|||||||
from stdnum.ean import is_valid, calc_check_digit
|
from stdnum.ean import is_valid, calc_check_digit
|
||||||
import base64
|
import base64
|
||||||
import re
|
import re
|
||||||
import socket
|
|
||||||
import ipaddress
|
|
||||||
|
|
||||||
import logging
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
TIMEOUT = 5
|
|
||||||
PRINTER_PORT = 9100
|
|
||||||
|
|
||||||
|
|
||||||
class ProductPrintZplBarcode(models.TransientModel):
|
class ProductPrintZplBarcode(models.TransientModel):
|
||||||
_name = 'product.print.zpl.barcode'
|
_name = 'product.print.zpl.barcode'
|
||||||
_description = 'Generate and print product barcodes in ZPL'
|
_description = 'Generate and print product barcodes in ZPL'
|
||||||
_check_company_auto = True
|
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def default_get(self, fields_list):
|
def default_get(self, fields_list):
|
||||||
res = super().default_get(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')
|
nomenclature = self.env.ref('barcodes.default_barcode_nomenclature')
|
||||||
company = self.env.company
|
company = self.env.company
|
||||||
posconfig = self.env['pos.config'].sudo().search(
|
posconfig = self.env['pos.config'].sudo().search(
|
||||||
@@ -38,219 +39,82 @@ class ProductPrintZplBarcode(models.TransientModel):
|
|||||||
], limit=1)
|
], limit=1)
|
||||||
if not pricelist:
|
if not pricelist:
|
||||||
raise UserError(_(
|
raise UserError(_(
|
||||||
"There are no pricelist in company '%s'.") % company.name)
|
"There are no pricelist in company %s ?") % company.name)
|
||||||
|
|
||||||
printer_ip = self.env['ir.config_parameter'].sudo().get_param(
|
printer = self.env['printing.printer'].get_default()
|
||||||
'product_print_zpl_barcode.printer_ip')
|
|
||||||
|
|
||||||
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({
|
res.update({
|
||||||
'company_id': company.id,
|
|
||||||
'nomenclature_id': nomenclature.id,
|
'nomenclature_id': nomenclature.id,
|
||||||
'pricelist_id': pricelist.id,
|
'pricelist_id': pricelist.id,
|
||||||
'zpl_printer_ip': printer_ip,
|
'currency_id': pricelist.currency_id.id,
|
||||||
'line_ids': line_ids,
|
'barcode': product.barcode,
|
||||||
|
'product_name': product.name,
|
||||||
|
'product_id': product_id,
|
||||||
|
'zpl_printer_id': printer and printer.id or False,
|
||||||
})
|
})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@api.model
|
product_id = fields.Many2one(
|
||||||
def _update_line_ids(self, line_ids, product, copies=1):
|
'product.product', string='Product', required=True, readonly=True)
|
||||||
if product.barcode:
|
uom_id = fields.Many2one(related='product_id.uom_id')
|
||||||
line_ids.append((0, 0, {
|
# 1 line = un peu moins de 30
|
||||||
'barcode': product.barcode,
|
product_name = fields.Char('Product Label', required=True, size=56)
|
||||||
'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(
|
nomenclature_id = fields.Many2one(
|
||||||
'barcode.nomenclature', 'Barcode Nomenclature', required=True,
|
'barcode.nomenclature', 'Barcode Nomenclature', required=True)
|
||||||
states={'step2': [('readonly', True)]})
|
rule_id = fields.Many2one(
|
||||||
# label_size: remove readonly=True when we will support more labels
|
'barcode.rule', string='Barcode Rule', readonly=True,
|
||||||
|
compute='_compute_rule_id')
|
||||||
|
barcode_type = fields.Selection(related='rule_id.type', string="Barcode Type")
|
||||||
label_size = fields.Selection([
|
label_size = fields.Selection([
|
||||||
('38x25', '38x25 mm'),
|
('38x25', '38x25 mm'),
|
||||||
], required=True, default='38x25', readonly=True)
|
], required=True, default='38x25')
|
||||||
pricelist_id = fields.Many2one(
|
pricelist_id = fields.Many2one(
|
||||||
'product.pricelist', string='Pricelist', required=True,
|
'product.pricelist', string='Pricelist', required=True)
|
||||||
states={'step2': [('readonly', True)]}, check_company=True,
|
currency_id = fields.Many2one(related='pricelist_id.currency_id')
|
||||||
domain="['|', ('company_id', '=', False), ('company_id', '=', company_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')
|
||||||
state = fields.Selection([
|
state = fields.Selection([
|
||||||
('step1', 'Step1'),
|
('step1', 'Step1'),
|
||||||
('step2', 'Step2'),
|
('step2', 'Step2'),
|
||||||
], default='step1', readonly=True)
|
], default='step1', readonly=True)
|
||||||
zpl_file = fields.Binary(string='ZPL File', readonly=True)
|
zpl_file = fields.Binary(string='ZPL File', readonly=True)
|
||||||
zpl_filename = fields.Char('ZPL Filename')
|
zpl_filename = fields.Char('ZPL Filename')
|
||||||
zpl_printer_ip = fields.Char(string='ZPL Printer IP Address')
|
|
||||||
line_ids = fields.One2many(
|
|
||||||
'product.print.zpl.barcode.line', 'parent_id',
|
|
||||||
string='Lines', states={'step2': [('readonly', True)]})
|
|
||||||
|
|
||||||
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_ip:
|
|
||||||
raise UserError(_(
|
|
||||||
"You must configure the IP address of the ZPL Printer."))
|
|
||||||
try:
|
|
||||||
ip = ipaddress.ip_address(self.zpl_printer_ip)
|
|
||||||
except Exception as e:
|
|
||||||
raise UserError(str(e))
|
|
||||||
version = ip.version
|
|
||||||
# TODO works with DNS ?
|
|
||||||
if version == 6: # IPv6
|
|
||||||
socket_inet = socket.AF_INET6
|
|
||||||
else: # IPv4
|
|
||||||
socket_inet = socket.AF_INET
|
|
||||||
with socket.socket(socket_inet, socket.SOCK_STREAM) as s:
|
|
||||||
s.settimeout(TIMEOUT)
|
|
||||||
try:
|
|
||||||
s.connect((str(ip), PRINTER_PORT))
|
|
||||||
except Exception as e:
|
|
||||||
raise UserError(_(
|
|
||||||
"Cannot connect to ZPL printer on %(ip)s. Error: %(error)s",
|
|
||||||
ip=ip, error=e))
|
|
||||||
zpl_file_bytes = base64.decodebytes(self.zpl_file)
|
|
||||||
s.send(zpl_file_bytes)
|
|
||||||
s.close()
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
barcode = fields.Char(readonly=True)
|
||||||
copies = fields.Integer(string='# Labels', default=1, required=True)
|
copies = fields.Integer(
|
||||||
|
string='Number of Labels', default=1, required=True)
|
||||||
|
zpl_printer_id = fields.Many2one(
|
||||||
|
'printing.printer', string='ZPL Printer')
|
||||||
|
|
||||||
@api.depends('parent_id.pricelist_id', 'quantity', 'product_id')
|
@api.depends('pricelist_id', 'quantity', 'product_id')
|
||||||
def _compute_price(self):
|
def _compute_price(self):
|
||||||
# for regular barcodes
|
# for regular barcodes
|
||||||
for line in self:
|
for wiz in self:
|
||||||
pricelist = line.parent_id.pricelist_id
|
if wiz.pricelist_id and wiz.product_id:
|
||||||
price_uom = price = 0.0
|
price_uom = wiz.pricelist_id._get_product_price(
|
||||||
if pricelist and line.product_id:
|
wiz.product_id, 1, False)
|
||||||
price_uom = pricelist._get_product_price(line.product_id, 1, False)
|
wiz.price_uom = price_uom
|
||||||
price = price_uom * line.quantity
|
wiz.price = price_uom * wiz.quantity
|
||||||
line.price_uom = price_uom
|
|
||||||
line.price = price
|
|
||||||
|
|
||||||
@api.depends('parent_id.nomenclature_id')
|
@api.depends('nomenclature_id')
|
||||||
def _compute_rule_id(self):
|
def _compute_rule_id(self):
|
||||||
for line in self:
|
for wiz in self:
|
||||||
nomenclature = line.parent_id.nomenclature_id
|
|
||||||
match_rule = False
|
match_rule = False
|
||||||
if nomenclature and line.barcode:
|
if wiz.nomenclature_id and wiz.barcode:
|
||||||
for rule in nomenclature.rule_ids:
|
for rule in wiz.nomenclature_id.rule_ids:
|
||||||
match = nomenclature.match_pattern(
|
match = wiz.nomenclature_id.match_pattern(
|
||||||
line.barcode, rule.pattern)
|
wiz.barcode, rule.pattern)
|
||||||
if match.get('match'):
|
if match.get('match'):
|
||||||
match_rule = rule.id
|
match_rule = rule.id
|
||||||
break
|
break
|
||||||
line.rule_id = match_rule
|
wiz.rule_id = match_rule
|
||||||
|
|
||||||
def _prepare_price_weight_barcode_type(self):
|
def _prepare_price_weight_barcode_type(self):
|
||||||
dpo = self.env['decimal.precision']
|
dpo = self.env['decimal.precision']
|
||||||
|
bno = self.env['barcode.nomenclature']
|
||||||
prec = dpo.precision_get('Stock Weight')
|
prec = dpo.precision_get('Stock Weight')
|
||||||
value = self.quantity
|
value = self.quantity
|
||||||
pbarcode = self.barcode
|
pbarcode = self.barcode
|
||||||
@@ -275,7 +139,7 @@ class ProductPrintZplBarcodeLine(models.TransientModel):
|
|||||||
barcode = pbarcode[0:len(prefix)]
|
barcode = pbarcode[0:len(prefix)]
|
||||||
# print("barcode=", barcode)
|
# print("barcode=", barcode)
|
||||||
# print("pattern=", pattern)
|
# print("pattern=", pattern)
|
||||||
m = re.search(r'\{N+D+\}', pattern)
|
m = re.search('\{N+D+\}', pattern)
|
||||||
# print("m=", m)
|
# print("m=", m)
|
||||||
assert m
|
assert m
|
||||||
pattern_val = m.group(0)
|
pattern_val = m.group(0)
|
||||||
@@ -308,7 +172,7 @@ class ProductPrintZplBarcodeLine(models.TransientModel):
|
|||||||
assert len(barcode) == 13
|
assert len(barcode) == 13
|
||||||
assert is_valid(barcode)
|
assert is_valid(barcode)
|
||||||
# print("barcode FINAL=", barcode)
|
# print("barcode FINAL=", barcode)
|
||||||
zpl_str = self._price_weight_barcode_type_zpl() % {
|
zpl_unicode = self._price_weight_barcode_type_zpl() % {
|
||||||
'product_name': self.product_name,
|
'product_name': self.product_name,
|
||||||
'ean_zpl_command': len(self.barcode) == 8 and 'B8' or 'BE',
|
'ean_zpl_command': len(self.barcode) == 8 and 'B8' or 'BE',
|
||||||
'ean_no_checksum': barcode[:-1],
|
'ean_no_checksum': barcode[:-1],
|
||||||
@@ -319,7 +183,12 @@ class ProductPrintZplBarcodeLine(models.TransientModel):
|
|||||||
'quantity': value,
|
'quantity': value,
|
||||||
'uom_name': self.uom_id.name,
|
'uom_name': self.uom_id.name,
|
||||||
}
|
}
|
||||||
return (barcode, zpl_str)
|
zpl_bytes = zpl_unicode.encode('utf-8')
|
||||||
|
vals = {
|
||||||
|
'zpl_file': base64.encodebytes(zpl_bytes),
|
||||||
|
'barcode': barcode,
|
||||||
|
}
|
||||||
|
return vals
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _price_weight_barcode_type_zpl(self):
|
def _price_weight_barcode_type_zpl(self):
|
||||||
@@ -360,7 +229,7 @@ class ProductPrintZplBarcodeLine(models.TransientModel):
|
|||||||
return label
|
return label
|
||||||
|
|
||||||
def _prepare_product_barcode_type(self):
|
def _prepare_product_barcode_type(self):
|
||||||
zpl_str = self._product_barcode_type_zpl() % {
|
zpl_unicode = self._product_barcode_type_zpl() % {
|
||||||
'product_name': self.product_name,
|
'product_name': self.product_name,
|
||||||
'ean_zpl_command': len(self.barcode) == 8 and 'B8' or 'BE',
|
'ean_zpl_command': len(self.barcode) == 8 and 'B8' or 'BE',
|
||||||
'ean_no_checksum': self.barcode[:-1],
|
'ean_no_checksum': self.barcode[:-1],
|
||||||
@@ -368,4 +237,60 @@ class ProductPrintZplBarcodeLine(models.TransientModel):
|
|||||||
'currency_symbol': self.currency_id.symbol, # symbol is a required field
|
'currency_symbol': self.currency_id.symbol, # symbol is a required field
|
||||||
'copies': self.copies,
|
'copies': self.copies,
|
||||||
}
|
}
|
||||||
return (self.barcode, zpl_str)
|
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
|
||||||
|
|||||||
@@ -11,41 +11,38 @@
|
|||||||
<field name="name">product_print_zpl_barcode.form</field>
|
<field name="name">product_print_zpl_barcode.form</field>
|
||||||
<field name="model">product.print.zpl.barcode</field>
|
<field name="model">product.print.zpl.barcode</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form>
|
<form string="Generate and Print Product Barcode">
|
||||||
<group name="step1">
|
<group name="step1" string="Configuration">
|
||||||
<field name="state" invisible="1"/>
|
<field name="state" invisible="1"/>
|
||||||
<field name="company_id" groups="base.group_multi_company"/>
|
<field name="currency_id" invisible="1"/>
|
||||||
<field name="company_id" invisible="1"/>
|
<field name="product_id"/>
|
||||||
|
<field name="product_name" attrs="{'readonly': [('state', '=', 'step2')]}"/>
|
||||||
<field name="pricelist_id" attrs="{'readonly': [('state', '=', 'step2')]}"/>
|
<field name="pricelist_id" attrs="{'readonly': [('state', '=', 'step2')]}"/>
|
||||||
|
<field name="price_uom"/>
|
||||||
<field name="label_size" attrs="{'readonly': [('state', '=', 'step2')]}"/>
|
<field name="label_size" attrs="{'readonly': [('state', '=', 'step2')]}"/>
|
||||||
<field name="nomenclature_id" 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>
|
||||||
<group name="step2" states="step2">
|
<group string="Enter Quantity" attrs="{'invisible': [('barcode_type', '=', 'product')]}">
|
||||||
|
<label for="quantity"/>
|
||||||
|
<div name="qty_uom" class="o_row">
|
||||||
|
<field name="quantity" attrs="{'readonly': [('state', '=', 'step2')]}" class="oe_inline"/>
|
||||||
|
<field name="uom_id" class="oe_inline" style="margin-left: 5px"/> </div>
|
||||||
|
</group>
|
||||||
|
<group name="step2" states="step2" string="Label">
|
||||||
|
<field name="price" attrs="{'invisible': [('barcode_type', 'not in', ('price', 'weight'))]}"/>
|
||||||
<field name="zpl_file" filename="zpl_filename" />
|
<field name="zpl_file" filename="zpl_filename" />
|
||||||
<field name="zpl_filename" invisible="1"/>
|
<field name="zpl_filename" invisible="1"/>
|
||||||
<field name="zpl_printer_ip" attrs="{'required': [('state', '=', 'step2')]}"/>
|
<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>
|
</group>
|
||||||
<footer>
|
<footer>
|
||||||
<button name="generate" type="object" string="Generate Labels" class="btn-primary" states="step1"/>
|
<button name="generate" type="object" string="Generate Label" class="btn-primary" states="step1"/>
|
||||||
<button special="cancel" string="Cancel" class="btn-default" 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" 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"/>
|
<button special="cancel" string="Close" class="btn-default" states="step2"/>
|
||||||
</footer>
|
</footer>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
# Copyright 2023 Akretion France (http://www.akretion.com/)
|
|
||||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
|
||||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
|
||||||
|
|
||||||
from odoo import api, fields, models
|
|
||||||
from odoo.exceptions import ValidationError
|
|
||||||
import ipaddress
|
|
||||||
|
|
||||||
|
|
||||||
class ResConfigSettings(models.TransientModel):
|
|
||||||
_inherit = "res.config.settings"
|
|
||||||
|
|
||||||
zpl_printer_ip = fields.Char(
|
|
||||||
config_parameter="product_print_zpl_barcode.printer_ip",
|
|
||||||
string="ZPL Printer IP Address")
|
|
||||||
|
|
||||||
@api.constrains('zpl_printer_ip')
|
|
||||||
def _check_zpl_printer_ip(self):
|
|
||||||
for wiz in self:
|
|
||||||
if wiz.zpl_printer_ip:
|
|
||||||
try:
|
|
||||||
ipaddress.ip_address(wiz.zpl_printer_ip)
|
|
||||||
except Exception as e:
|
|
||||||
raise ValidationError(str(e))
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright 2024 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="res_config_settings_view_form" model="ir.ui.view">
|
|
||||||
<field name="model">res.config.settings</field>
|
|
||||||
<field name="inherit_id" ref="base_setup.res_config_settings_view_form" />
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<xpath expr="//div[@id='companies']" position='after'>
|
|
||||||
<h2>Barcode printing</h2>
|
|
||||||
<div class="row mt16 o_settings_container" name="zpl_printer">
|
|
||||||
<div class="col-xs-12 col-md-6 o_setting_box">
|
|
||||||
<div class="o_setting_right_pane" id="zpl_printer_ip">
|
|
||||||
<div class="row">
|
|
||||||
<label for="zpl_printer_ip" class="col-md-5" />
|
|
||||||
<field name="zpl_printer_ip" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</xpath>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
</odoo>
|
|
||||||
@@ -16,16 +16,6 @@ class ProductProduct(models.Model):
|
|||||||
active = fields.Boolean(tracking=40)
|
active = fields.Boolean(tracking=40)
|
||||||
barcode_type = fields.Char(compute='_compute_barcode_type')
|
barcode_type = fields.Char(compute='_compute_barcode_type')
|
||||||
|
|
||||||
_sql_constraints = [(
|
|
||||||
# Maybe it could be better to have a constrain per company
|
|
||||||
# but the company_id field is on product.template,
|
|
||||||
# not on product.product
|
|
||||||
# If it's a problem, we'll create a company_id field on
|
|
||||||
# product.product
|
|
||||||
'default_code_uniq',
|
|
||||||
'unique(default_code)',
|
|
||||||
'This internal reference already exists!')]
|
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _get_barcode_type(self, barcode):
|
def _get_barcode_type(self, barcode):
|
||||||
barcode_type = False
|
barcode_type = False
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ This module has been written by Alexis de Lattre from Akretion France.
|
|||||||
],
|
],
|
||||||
'data': [
|
'data': [
|
||||||
'views/stock_picking.xml',
|
'views/stock_picking.xml',
|
||||||
'views/purchase_order.xml',
|
|
||||||
'views/stock_move.xml',
|
|
||||||
'views/stock_move_line.xml',
|
|
||||||
],
|
],
|
||||||
'installable': True,
|
'installable': True,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1 @@
|
|||||||
from . import purchase
|
from . import purchase
|
||||||
from . import stock_move
|
|
||||||
from . import stock_move_line
|
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
# 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 StockMove(models.Model):
|
|
||||||
_inherit = 'stock.move'
|
|
||||||
|
|
||||||
# for optional display in tree view
|
|
||||||
product_supplier_code = fields.Char(
|
|
||||||
compute='_compute_product_supplier_code', string="Vendor Product Code")
|
|
||||||
|
|
||||||
def _compute_product_supplier_code(self):
|
|
||||||
pso = self.env['product.supplierinfo']
|
|
||||||
for move in self:
|
|
||||||
code = False
|
|
||||||
if move.purchase_line_id and move.purchase_line_id.order_id:
|
|
||||||
po = move.purchase_line_id.order_id
|
|
||||||
partner_id = po.partner_id.commercial_partner_id.id
|
|
||||||
if partner_id:
|
|
||||||
sinfo = pso.search_read([
|
|
||||||
('product_tmpl_id', '=', move.product_id.product_tmpl_id.id),
|
|
||||||
('product_id', 'in', (False, move.product_id.id)),
|
|
||||||
('partner_id', '=', partner_id),
|
|
||||||
('product_code', '!=', False),
|
|
||||||
('company_id', 'in', (False, move.company_id.id)),
|
|
||||||
], ['product_code'], limit=1, order='product_id')
|
|
||||||
# if I order by product_id, I get the null values at the end
|
|
||||||
if sinfo:
|
|
||||||
code = sinfo[0]['product_code']
|
|
||||||
move.product_supplier_code = code
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
# 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 StockMoveLine(models.Model):
|
|
||||||
_inherit = 'stock.move.line'
|
|
||||||
|
|
||||||
# for optional display in tree view
|
|
||||||
product_supplier_code = fields.Char(
|
|
||||||
compute='_compute_product_supplier_code', string="Vendor Product Code")
|
|
||||||
|
|
||||||
def _compute_product_supplier_code(self):
|
|
||||||
pso = self.env['product.supplierinfo']
|
|
||||||
for mline in self:
|
|
||||||
code = False
|
|
||||||
move = mline.move_id
|
|
||||||
if move and move.purchase_line_id and move.purchase_line_id.order_id:
|
|
||||||
po = move.purchase_line_id.order_id
|
|
||||||
partner_id = po.partner_id.commercial_partner_id.id
|
|
||||||
if partner_id:
|
|
||||||
sinfo = pso.search_read([
|
|
||||||
('product_tmpl_id', '=', mline.product_id.product_tmpl_id.id),
|
|
||||||
('product_id', 'in', (False, mline.product_id.id)),
|
|
||||||
('partner_id', '=', partner_id),
|
|
||||||
('product_code', '!=', False),
|
|
||||||
('company_id', 'in', (False, mline.company_id.id)),
|
|
||||||
], ['product_code'], limit=1, order='product_id')
|
|
||||||
# if I order by product_id, I get the null values at the end
|
|
||||||
if sinfo:
|
|
||||||
code = sinfo[0]['product_code']
|
|
||||||
mline.product_supplier_code = code
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
<?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="partner_id" 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_stock.purchase_order_view_tree_inherit"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="partner_id" 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="partner_id" position="after">
|
|
||||||
<field name="picking_type_id" optional="hide"/>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</odoo>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<?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_move_tree" model="ir.ui.view">
|
|
||||||
<field name="model">stock.move</field>
|
|
||||||
<field name="inherit_id" ref="stock.view_move_tree" />
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<!-- picking.purchase_id is a native field ; it is added to the picking form view in this module -->
|
|
||||||
<field name="product_id" position="after">
|
|
||||||
<field name="product_supplier_code" optional="hide" attrs="{'column_invisible': [('parent.purchase_id', '=', False)]}"/>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
</odoo>
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
<?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_move_line_tree" model="ir.ui.view">
|
|
||||||
<field name="model">stock.move.line</field>
|
|
||||||
<field name="inherit_id" ref="stock.view_move_line_tree" />
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="product_id" position="after">
|
|
||||||
<field name="product_supplier_code" optional="hide"/>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- View embedded in picking -->
|
|
||||||
<record id="view_stock_move_line_detailed_operation_tree" model="ir.ui.view">
|
|
||||||
<field name="model">stock.move.line</field>
|
|
||||||
<field name="inherit_id" ref="stock.view_stock_move_line_detailed_operation_tree" />
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="product_id" position="after">
|
|
||||||
<field name="product_supplier_code" optional="hide" attrs="{'column_invisible': [('parent.purchase_id', '=', False)]}"/>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
</odoo>
|
|
||||||
@@ -16,9 +16,6 @@
|
|||||||
<field name="origin" position="after">
|
<field name="origin" position="after">
|
||||||
<field name="purchase_id" attrs="{'invisible': [('purchase_id', '=', False)]}"/>
|
<field name="purchase_id" attrs="{'invisible': [('purchase_id', '=', False)]}"/>
|
||||||
</field>
|
</field>
|
||||||
<xpath expr="//field[@name='move_ids_without_package']/tree/field[@name='product_id']" position="after">
|
|
||||||
<field name="product_supplier_code" optional="hide" attrs="{'column_invisible': [('parent.purchase_id', '=', False)]}"/>
|
|
||||||
</xpath>
|
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|||||||
@@ -79,22 +79,15 @@ class PurchaseOrderLine(models.Model):
|
|||||||
compute='_compute_product_supplier_code', string='Vendor Product Code')
|
compute='_compute_product_supplier_code', string='Vendor Product Code')
|
||||||
|
|
||||||
def _compute_product_supplier_code(self):
|
def _compute_product_supplier_code(self):
|
||||||
pso = self.env['product.supplierinfo']
|
|
||||||
for line in self:
|
for line in self:
|
||||||
code = False
|
code = False
|
||||||
if not line.display_type and line.product_id and line.order_id:
|
if not line.display_type and line.product_id and line.order_id:
|
||||||
partner_id = line.order_id.partner_id.commercial_partner_id.id
|
partner_id = line.order_id.partner_id.commercial_partner_id.id
|
||||||
if partner_id:
|
if partner_id:
|
||||||
sinfo = pso.search_read([
|
for supplier_info in line.product_id.seller_ids:
|
||||||
('product_tmpl_id', '=', line.product_id.product_tmpl_id.id),
|
if supplier_info.partner_id.id == partner_id:
|
||||||
('product_id', 'in', (False, line.product_id.id)),
|
code = supplier_info.product_code
|
||||||
('partner_id', '=', partner_id),
|
break
|
||||||
('product_code', '!=', False),
|
|
||||||
('company_id', 'in', (False, line.order_id.company_id.id)),
|
|
||||||
], ['product_code'], limit=1, order='product_id')
|
|
||||||
# if I order by product_id, I get the null values at the end
|
|
||||||
if sinfo:
|
|
||||||
code = sinfo[0]['product_code']
|
|
||||||
line.product_supplier_code = code
|
line.product_supplier_code = code
|
||||||
|
|
||||||
def _get_product_purchase_description(self, product_lang):
|
def _get_product_purchase_description(self, product_lang):
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Sale Order Route',
|
'name': 'Sale Order Route',
|
||||||
'version': '16.0.1.0.0',
|
'version': '14.0.1.0.0',
|
||||||
'category': 'Sales',
|
'category': 'Sales',
|
||||||
'license': 'AGPL-3',
|
'license': 'AGPL-3',
|
||||||
'summary': 'Set route on sale order',
|
'summary': 'Set route on sale order',
|
||||||
@@ -17,6 +17,6 @@ This module has been written by Alexis de Lattre from Akretion
|
|||||||
'author': 'Akretion',
|
'author': 'Akretion',
|
||||||
'website': 'http://www.akretion.com',
|
'website': 'http://www.akretion.com',
|
||||||
'depends': ['sale_stock'],
|
'depends': ['sale_stock'],
|
||||||
'data': ['views/sale_order.xml', 'views/sale_report.xml'],
|
'data': ['views/sale_order.xml'],
|
||||||
'installable': True,
|
'installable': False,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
from . import sale_order
|
from . import sale_order
|
||||||
from . import sale_report
|
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
from odoo import api, fields, models
|
from odoo import fields, models
|
||||||
|
|
||||||
|
|
||||||
class SaleOrder(models.Model):
|
class SaleOrder(models.Model):
|
||||||
_inherit = 'sale.order'
|
_inherit = 'sale.order'
|
||||||
|
|
||||||
route_id = fields.Many2one(
|
route_id = fields.Many2one(
|
||||||
'stock.route', string='Route',
|
'stock.location.route', string='Route',
|
||||||
ondelete='restrict', readonly=True, tracking=True,
|
ondelete='restrict', readonly=True, tracking=True,
|
||||||
states={'draft': [('readonly', False)], 'sent': [('readonly', False)]},
|
states={'draft': [('readonly', False)], 'sent': [('readonly', False)]},
|
||||||
check_company=True,
|
check_company=True,
|
||||||
@@ -24,18 +24,3 @@ class SaleOrder(models.Model):
|
|||||||
lambda l:
|
lambda l:
|
||||||
l.product_id and l.product_id.type in ('product', 'consu')).write(vals)
|
l.product_id and l.product_id.type in ('product', 'consu')).write(vals)
|
||||||
return super()._action_confirm()
|
return super()._action_confirm()
|
||||||
|
|
||||||
|
|
||||||
class SaleOrderLine(models.Model):
|
|
||||||
_inherit = 'sale.order.line'
|
|
||||||
|
|
||||||
# It's important when you add a line AFTER order confirmation
|
|
||||||
route_id = fields.Many2one(compute='_compute_route_id', readonly=False, store=True, precompute=True)
|
|
||||||
|
|
||||||
@api.depends('display_type', 'product_id')
|
|
||||||
def _compute_route_id(self):
|
|
||||||
for line in self:
|
|
||||||
if not line.display_type and line.product_id and line.product_id.type in ('product', 'consu'):
|
|
||||||
line.route_id = line.order_id.route_id or False
|
|
||||||
else:
|
|
||||||
line.route_id = False
|
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
# Copyright 2024 Akretion France (http://www.akretion.com/)
|
|
||||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
|
||||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
|
||||||
|
|
||||||
from odoo import fields, models
|
|
||||||
|
|
||||||
|
|
||||||
class SaleReport(models.Model):
|
|
||||||
_inherit = "sale.report"
|
|
||||||
|
|
||||||
route_id = fields.Many2one('stock.route', string='Route', readonly=True)
|
|
||||||
|
|
||||||
def _select_additional_fields(self):
|
|
||||||
res = super()._select_additional_fields()
|
|
||||||
res['route_id'] = "s.route_id"
|
|
||||||
return res
|
|
||||||
|
|
||||||
def _group_by_sale(self):
|
|
||||||
res = super()._group_by_sale()
|
|
||||||
res += ', s.route_id'
|
|
||||||
return res
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright 2024 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_order_product_search" model="ir.ui.view">
|
|
||||||
<field name="model">sale.report</field>
|
|
||||||
<field name="inherit_id" ref="sale.view_order_product_search"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<filter name="status" position="after">
|
|
||||||
<filter string="Route" name="route_id_groupby" context="{'group_by':'route_id'}"/>
|
|
||||||
</filter>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
</odoo>
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
===============================
|
|
||||||
Sale Remove My Quotation Filter
|
|
||||||
===============================
|
|
||||||
|
|
||||||
This module removes the default filter **My Quotations** in the menu entry *Sales > Orders > Quotations*.
|
|
||||||
|
|
||||||
Credits
|
|
||||||
=======
|
|
||||||
|
|
||||||
Authors
|
|
||||||
~~~~~~~
|
|
||||||
|
|
||||||
* Akretion
|
|
||||||
|
|
||||||
Contributors
|
|
||||||
~~~~~~~~~~~~
|
|
||||||
|
|
||||||
* Alexis de Lattre <alexis.delattre@akretion.com>
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# Copyright 2023 Akretion France (https://www.akretion.com)
|
|
||||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
|
||||||
|
|
||||||
{
|
|
||||||
'name': 'Sale remove My Quotations filter',
|
|
||||||
'version': '16.0.1.0.0',
|
|
||||||
'category': 'Sales',
|
|
||||||
'license': 'AGPL-3',
|
|
||||||
'summary': 'Remove default filter My Quotations',
|
|
||||||
'author': 'Akretion',
|
|
||||||
'website': 'https://github.com/akretion/odoo-usability',
|
|
||||||
'depends': ['sale'],
|
|
||||||
'data': ['views/sale_order.xml'],
|
|
||||||
'installable': True,
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<?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="sale.action_quotations_with_onboarding" model="ir.actions.act_window">
|
|
||||||
<field name="context"></field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="sale.action_quotations" model="ir.actions.act_window">
|
|
||||||
<field name="context"></field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
</odoo>
|
|
||||||
@@ -24,7 +24,6 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
|
|||||||
'depends': ['sale_stock'],
|
'depends': ['sale_stock'],
|
||||||
'data': [
|
'data': [
|
||||||
'views/sale_order.xml',
|
'views/sale_order.xml',
|
||||||
'views/sale_report.xml',
|
|
||||||
'views/procurement_group.xml',
|
'views/procurement_group.xml',
|
||||||
'views/stock_move.xml',
|
'views/stock_move.xml',
|
||||||
'views/stock_picking.xml',
|
'views/stock_picking.xml',
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright 2024 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_order_product_search" model="ir.ui.view">
|
|
||||||
<field name="model">sale.report</field>
|
|
||||||
<field name="inherit_id" ref="sale.view_order_product_search"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<filter name="status" position="after">
|
|
||||||
<filter string="Warehouse" name="warehouse_id_groupby" context="{'group_by':'warehouse_id'}"/>
|
|
||||||
</filter>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
</odoo>
|
|
||||||
@@ -73,9 +73,6 @@
|
|||||||
<field name="state" position="attributes">
|
<field name="state" position="attributes">
|
||||||
<attribute name="invisible">0</attribute>
|
<attribute name="invisible">0</attribute>
|
||||||
<attribute name="optional">hide</attribute>
|
<attribute name="optional">hide</attribute>
|
||||||
<attribute name="widget">badge</attribute>
|
|
||||||
<attribute name="decoration-success">state == 'done'</attribute>
|
|
||||||
<attribute name="decoration-info">state == 'sale'</attribute>
|
|
||||||
</field>
|
</field>
|
||||||
<field name="partner_id" position="after">
|
<field name="partner_id" position="after">
|
||||||
<field name="client_order_ref" optional="show"/>
|
<field name="client_order_ref" optional="show"/>
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ class StockQuant(models.Model):
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
{
|
{
|
||||||
"picking_id": picking_id,
|
|
||||||
"product_id": product_id,
|
"product_id": product_id,
|
||||||
"product_uom_id": uom_id,
|
"product_uom_id": uom_id,
|
||||||
"qty_done": qty,
|
"qty_done": qty,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
from . import stock_move
|
from . import stock_move
|
||||||
from . import stock_move_line
|
from . import stock_move_line
|
||||||
from . import stock_picking
|
from . import stock_picking
|
||||||
from . import stock_picking_type
|
|
||||||
from . import stock_warehouse_orderpoint
|
from . import stock_warehouse_orderpoint
|
||||||
from . import stock_quant
|
from . import stock_quant
|
||||||
from . import procurement_group
|
from . import procurement_group
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
# 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).
|
|
||||||
|
|
||||||
from odoo import api, fields, models
|
|
||||||
|
|
||||||
|
|
||||||
class StockPickingType(models.Model):
|
|
||||||
_inherit = 'stock.picking.type'
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -38,14 +38,3 @@ class StockQuant(models.Model):
|
|||||||
len(self._context['search_location']) == 1):
|
len(self._context['search_location']) == 1):
|
||||||
res['location_id'] = self._context['search_location'][0]
|
res['location_id'] = self._context['search_location'][0]
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@api.model
|
|
||||||
def action_view_inventory(self):
|
|
||||||
action = super().action_view_inventory()
|
|
||||||
# Remove filter 'My Counts' set by default for Stock Users
|
|
||||||
if (
|
|
||||||
action.get('context') and
|
|
||||||
isinstance(action['context'], dict) and
|
|
||||||
action['context'].get('search_default_my_count')):
|
|
||||||
action['context'].pop('search_default_my_count')
|
|
||||||
return action
|
|
||||||
|
|||||||
@@ -16,18 +16,6 @@
|
|||||||
<field name="responsible_id" position="attributes">
|
<field name="responsible_id" position="attributes">
|
||||||
<attribute name="optional">hide</attribute>
|
<attribute name="optional">hide</attribute>
|
||||||
</field>
|
</field>
|
||||||
<field name="virtual_available" position="before">
|
|
||||||
<field name="incoming_qty" optional="hide" sum="1"/>
|
|
||||||
<field name="outgoing_qty" optional="hide" sum="1"/>
|
|
||||||
<!-- we would like to also have free_qty, as on product.product, but this field doesn't exist on product.template -->
|
|
||||||
</field>
|
|
||||||
<!-- we have sum=1 on product.product qty fields, but not on product.template...so I add it on product.template -->
|
|
||||||
<field name="virtual_available" position="attributes">
|
|
||||||
<attribute name="sum">1</attribute>
|
|
||||||
</field>
|
|
||||||
<field name="qty_available" position="attributes">
|
|
||||||
<attribute name="sum">1</attribute>
|
|
||||||
</field>
|
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|||||||
@@ -56,10 +56,6 @@
|
|||||||
<field name="product_id" position="after">
|
<field name="product_id" position="after">
|
||||||
<field name="product_barcode" optional="hide"/>
|
<field name="product_barcode" optional="hide"/>
|
||||||
</field>
|
</field>
|
||||||
<field name="reference" position="after">
|
|
||||||
<field name="origin" optional="hide"/>
|
|
||||||
<field name="partner_id" optional="hide"/>
|
|
||||||
</field>
|
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
<!--
|
||||||
Copyright 2014-2023 Akretion (http://www.akretion.com/)
|
Copyright 2014-2022 Akretion (http://www.akretion.com/)
|
||||||
@author Alexis de Lattre <alexis.delattre@akretion.com>
|
@author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<odoo>
|
<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="return_picking_type_id" position="before">
|
|
||||||
<field name="is_dropship"/>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
|
|
||||||
<record id="view_picking_type_tree" model="ir.ui.view">
|
<record id="view_picking_type_tree" model="ir.ui.view">
|
||||||
<field name="name">usability.stock.picking.type.tree</field>
|
<field name="name">usability.stock.picking.type.tree</field>
|
||||||
<field name="model">stock.picking.type</field>
|
<field name="model">stock.picking.type</field>
|
||||||
|
|||||||
Reference in New Issue
Block a user