Compare commits

...

81 Commits

Author SHA1 Message Date
clementmbr
1467e7e8da purchase_stock_usability: picking_status french translation 2021-12-06 12:38:34 +01:00
clementmbr
35ff2835b8 purchase_stock_usability: Add picking_status for PO ...like in sale_stock_usability : https://github.com/akretion/odoo-usability/blob/14.0/sale_stock_usability/models/sale_order.py#L14 2021-12-06 12:38:34 +01:00
Alexis de Lattre
0be112dc84 Improve pos_usability
Fix FR translation of base_partner_one2many_phone to avoid a crash when loading the FR translation
2021-10-30 00:40:33 +02:00
Kevin.roche
2854d4fdda [IMP] sale_usability: access to sale orders from invoice view 2021-10-21 22:51:08 +02:00
Alexis de Lattre
6c51a92acc account_usability: delete invoice PDF attachment when putting a customer invoice/refund back to draft
This feature was native up to v12, but was forgotten in the invoice/move merge of v13
2021-10-21 22:48:51 +02:00
Alexis de Lattre
f3910ab528 account_usability: remove field default_move_line_name which we don't use any more 2021-10-20 23:29:04 +02:00
clementmbr
05374c4b4a [FIX] mrp_usability: button action for BoMs needs _for_xml_id()
Avoiding blocking access for users without Admin rigts
2021-10-11 22:16:59 +02:00
Alexis de Lattre
f6ddbb48ac [MIG] stock_picking_type_default_partner from v10 to v14 2021-10-01 21:21:31 +02:00
Alexis de Lattre
d3bddf5fda Port stock_picking_type_default_partner to v10 2021-10-01 21:13:11 +02:00
Alexis de Lattre
6f3a468a7c Mass rename from __openerp__.py to __manifest__.py 2021-10-01 21:13:11 +02:00
Alexis de Lattre
0bfa960153 Set all modules as uninstallable 2021-10-01 21:13:11 +02:00
Alexis de Lattre
a520ccff51 Add module stock_picking_type_default_partner 2021-10-01 21:13:11 +02:00
Alexis de Lattre
fa7611eb08 Push missing file 2021-10-01 21:11:30 +02:00
Alexis de Lattre
b2eda2a23b [MIG] sale_confirm_wizard from v10 to v14 2021-10-01 21:10:54 +02:00
Alexis de Lattre
74ff1b5cb5 sale_confirm_wizard: add ability to skip wizard via inherit in some scenarios 2021-10-01 20:52:44 +02:00
Alexis de Lattre
a7b4ed65eb sale_confirm_wizard: don't show main block when sale_warn = block 2021-10-01 20:52:44 +02:00
Alexis de Lattre
7dfb32c2d6 sale_confirm_warning: add sale_warn 2021-10-01 20:52:44 +02:00
Alexis de Lattre
d081bb0fd2 Add module sale_force_invoice_status 2021-10-01 20:52:44 +02:00
Alexis de Lattre
f3fdbec140 Add module sale_confirm_wizard 2021-10-01 20:52:44 +02:00
Alexis de Lattre
ac54c5cc75 Register payment on account.move form view is not highlighted any more 2021-09-30 20:37:00 +02:00
Alexis de Lattre
78c11411c3 Add filter on inventory lines
Always show field prefill_counted_quantity on inventory form
2021-09-26 22:49:24 +02:00
Alexis de Lattre
28ce11b216 stock.inventory improvement 2021-09-26 20:10:58 +02:00
Alexis de Lattre
00e034dacf Show invoice_origin on move form 2021-09-22 14:56:40 +02:00
Alexis de Lattre
8510b9518a Add module hr_contract_usability 2021-09-14 23:45:05 +02:00
Alexis de Lattre
15ef5df155 account_usability: add account_type in res.partner.bank tree view embedded in partner form view 2021-09-09 18:06:56 +00:00
Alexis de Lattre
a28a853f45 base_usabilty: translate=False on print_report_name 2021-08-28 00:00:07 +02:00
Alexis de Lattre
82b9a1e502 Move tracking=True for res.partner fields to mail_usability 2021-08-27 12:10:34 +02:00
Alexis de Lattre
b05abba064 [MIG] sale_order_route to v14 2021-08-26 23:18:37 +02:00
Alexis de Lattre
75e3463a76 Add name_search in base_partner_ref 2021-08-26 23:06:38 +02:00
Alexis de Lattre
3066c0545d Add print buttons in direct access on sale.order and account.invoice 2021-08-26 12:44:50 +02:00
Alexis de Lattre
62a84469c8 [FIX] account_usability: line order in py3o report 2021-08-26 10:45:59 +02:00
Alexis de Lattre
00339e44b6 MIG delivery_usability to v14 2021-08-25 21:57:43 +02:00
Alexis de Lattre
d1ae620079 Add product_barcode with optional=hide in tree view of inventory lines and quants 2021-08-25 20:29:46 +02:00
Alexis de Lattre
3db9f0f096 MIG eradicate_quick_create to v14 2021-08-25 18:25:17 +02:00
Alexis de Lattre
732ee2c55b base_dynamic_list: update module desc 2021-08-24 22:59:25 +02:00
Alexis de Lattre
e08d658b25 [MIG] base_dynamic_list from v10 to v14 2021-08-24 21:54:06 +02:00
Alexis de Lattre
2a7ec92a37 Add archive filter 2021-08-24 21:43:14 +02:00
Alexis de Lattre
dc30ce4e69 Add index=True on domain 2021-08-24 21:43:14 +02:00
Alexis de Lattre
32d45d228b Add new module base_dynamic_list 2021-08-24 21:43:14 +02:00
Alexis de Lattre
939de0c9bd base_partner_one2many_phone: improve country handling in phone reformat 2021-08-23 18:50:43 +02:00
Alexis de Lattre
48a19b8f97 stock_usability: remove unnecessary inherit (native colors ok) 2021-07-20 13:09:11 +02:00
Alexis de Lattre
8a2e662d43 base_usability: update FR translation 2021-07-01 19:20:59 +02:00
Alexis de Lattre
de2e5f2121 stock_account_usability: show to_refund on stock.move form 2021-05-21 11:29:18 +02:00
Alexis de Lattre
42e014bcb1 sale_usability: add no-attachment filter on sale.order
account_usability: small code improvement on has_attachment
2021-05-20 19:29:31 +02:00
Alexis de Lattre
e70e3b23cf Improve picking view 2021-04-28 11:51:30 +02:00
Alexis de Lattre
50b4944c8b Always show location_id on stock inventory line 2021-04-28 11:34:28 +02:00
Alexis de Lattre
96bfda6e1b Add product_barcode in SO lines, PO lines, stock move lines and invoice lines with optional="hide"
Show warning about double VAT partner even when not in editable mode
2021-04-28 11:27:04 +02:00
Alexis de Lattre
cfb58ed80f Add inherit of account.move.line filter view 2021-04-27 16:25:50 +02:00
Alexis de Lattre
91e9c1fe33 account_usability: allow to manually create a journal item in cash and check journals 2021-04-22 23:58:03 +02:00
Alexis de Lattre
dff4e47cf5 Add sudo() to access ir.actions.act_windows... stupid v14! 2021-04-14 08:13:53 +02:00
Alexis de Lattre
452cc399c5 stock_usability: add button to access stock moves before button to access product moves, because stock moves are more important than product moves 2021-04-12 21:29:23 +02:00
Clément Mombereau
f4c22501a7 Merge pull request #144 from akretion/14.0-fix-message-post-picking
[FIX] picking.message_post() needs explicit 'body' argument
2021-04-07 00:53:22 +02:00
clementmbr
9e8874eb4b [FIX] picking.message_post() needs explicit 'body' argument 2021-04-07 00:04:02 +02:00
Alexis de Lattre
fc6c0384ed stock_usability: create ir.config_parameter stock.no_default_immediate_tranfer=True upon install 2021-04-01 11:47:12 +02:00
Alexis de Lattre
96bd915c4f Add reconcile field in account.account form view 2021-03-04 11:30:32 +01:00
beau sebastien
f61296cafc Merge pull request #140 from akretion/14.0-mig-product_no_translation
[14.0][MIG] product_no_translation: Migrate to 14.0
2021-02-18 18:47:25 +01:00
Sébastien BEAU
b585d06489 [FIX] fix duplicated label 2021-02-18 18:43:02 +01:00
Alexis de Lattre
cef81ad749 Add Tax include / tax exclude next the prices on product form view 2021-02-18 09:48:17 +01:00
Alexis de Lattre
7c1a2fabd3 base_usability: add supplier_ref in display_full_address, to have the proper label for POs 2021-02-17 18:07:43 +01:00
Alexis de Lattre
c3f72a9b68 base_usability: Add vat, ref and commercial_ref in _display_full_address()
Add fr translation
2021-02-17 17:49:00 +01:00
Alexis de Lattre
a0d73834ad sale_usability: code cleanup 2021-02-17 15:37:52 +01:00
Alexis de Lattre
66ebc5c6ad account_usability: Fix py3o method 2021-02-17 15:14:54 +01:00
Alexis de Lattre
5c06d79b69 base_partner_one2many_phone: email field on res.partner is now really invisible in form view (it was replaced by the mail module) 2021-02-04 12:34:01 +01:00
Alexis de Lattre
034c89b399 Forgot a file in my previous commit ! 2021-02-03 18:54:31 +01:00
Alexis de Lattre
6356171619 Merge branch '14.0' of github.com:akretion/odoo-usability into 14.0 2021-02-03 18:48:10 +01:00
Alexis de Lattre
771001ca2e [MIG] purchase_stock_usability to v14 2021-02-03 18:47:44 +01:00
Alexis de Lattre
45d734badf Fix access rights in product_print_zpl_barcode
In odoo v14, read of ir.actions.act_windows is restricted to base.group_system
2021-02-03 18:05:03 +01:00
Alexis de Lattre
0d4ff37786 pos_usability: add missing check_company=True on pos.payment.method, field cash_journal_id 2021-02-03 11:53:22 +01:00
Alexis de Lattre
9c30d4ef53 stock_usability: responsible_id is now hidden by default in tree view 2021-02-02 18:40:27 +01:00
Alexis de Lattre
b2ce8f0aca MIG *_product_tree_default to v14
Add module pos_product_tree_default
Improve orderpoint views
2021-02-02 18:33:03 +01:00
Alexis de Lattre
183bba3752 product_usability: make seller_id a stored field, for those who want to display in tree view
Add tracking on some fields
2021-02-02 09:59:26 +01:00
Alexis de Lattre
92742dfc9d product_usability: Improve tree view of supplierinfo 2021-02-01 19:55:43 +01:00
Alexis de Lattre
f30bf4791a purchase_usability: add py3o_lines_layout() 2021-02-01 17:54:26 +01:00
Alexis de Lattre
ca6de3adf6 [MIG] pos_usability to v14 2021-02-01 13:41:38 +01:00
Kevin Khao
5e2d25f7c4 [14.0][MIG] product_no_translation: Migrate to 14.0 2021-01-26 11:45:42 +01:00
Alexis de Lattre
d64262099b Update readme 2021-01-22 17:12:02 +01:00
Alexis de Lattre
6ad589d4bd Merge branch '14.0' of github.com:akretion/odoo-usability into 14.0 2021-01-22 15:01:14 +01:00
Alexis de Lattre
5496aa38f8 product_print_zpl_barcode: Add support for barcode generation
Add support for EAN-8 (in additional to EAN-13)
2021-01-22 15:00:14 +01:00
Sébastien BEAU
b7c0b4720c [FIX] remove dependency on sale_product_configurator 2021-01-22 07:36:22 +01:00
Sébastien BEAU
bd25fe4866 [FIX] fix inherit 2021-01-21 22:44:18 +01:00
beau sebastien
c3da933e62 Merge pull request #135 from akretion/14.0-mig-sale_no_optional_product-sale_no_preview_button
[14.0][MIG] sale_no_optional_product, sale_no_preview_button: migration to 14.0
2021-01-21 16:18:45 +01:00
128 changed files with 2916 additions and 407 deletions

View File

@@ -25,6 +25,7 @@
'views/account_move.xml',
'views/account_menu.xml',
'views/account_tax.xml',
'views/product.xml',
'views/res_config_settings.xml',
'views/res_partner.xml',
'views/account_report.xml',

View File

@@ -6,3 +6,4 @@ from . import account_journal
from . import account_move
from . import account_partial_reconcile
from . import res_partner
from . import product

View File

@@ -5,13 +5,12 @@
from odoo import api, fields, models
from odoo.tools import float_is_zero
from odoo.tools.misc import format_date
from odoo.osv import expression
class AccountMove(models.Model):
_inherit = 'account.move'
default_move_line_name = fields.Char(
string='Default Label', states={'posted': [('readonly', True)]})
# By default, we can still modify "ref" when account move is posted
# which seems a bit lazy for me...
ref = fields.Char(states={'posted': [('readonly', True)]})
@@ -49,11 +48,11 @@ class AccountMove(models.Model):
def _compute_has_attachment(self):
iao = self.env['ir.attachment']
for move in self:
if iao.search([
if iao.search_count([
('res_model', '=', 'account.move'),
('res_id', '=', move.id),
('type', '=', 'binary'),
('company_id', '=', move.company_id.id)], limit=1):
('company_id', '=', move.company_id.id)]):
move.has_attachment = True
else:
move.has_attachment = False
@@ -121,8 +120,12 @@ class AccountMove(models.Model):
res = []
has_sections = False
subtotal = 0.0
sign = self.type == 'out_refund' and -1 or 1
for line in self.invoice_line_ids:
sign = self.move_type == 'out_refund' and -1 or 1
# Warning: the order of invoice line is forced in the view
# <tree editable="bottom" default_order="sequence, date desc, move_name desc, id"
# it's not the same as the _order in the class AccountMoveLine
lines = self.env['account.move.line'].search([('exclude_from_invoice_tab', '=', False), ('move_id', '=', self.id)], order="sequence, date desc, move_name desc, id")
for line in lines:
if line.display_type == 'line_section':
# insert line
if has_sections:
@@ -157,6 +160,53 @@ class AccountMove(models.Model):
for x in sales]
inv.sale_dates = ", ".join(dates)
# allow to manually create moves not only in general journals,
# but also in cash journal and check journals (= bank journals not linked to a bank account)
@api.depends('company_id', 'invoice_filter_type_domain')
def _compute_suitable_journal_ids(self):
for move in self:
if move.invoice_filter_type_domain:
super(AccountMove, move)._compute_suitable_journal_ids()
else:
company_id = move.company_id.id or self.env.company.id
domain = expression.AND([
[('company_id', '=', company_id)],
expression.OR([
[('type', 'in', ('general', 'cash'))],
[('type', '=', 'bank'), ('bank_account_id', '=', False)]
])
])
move.suitable_journal_ids = self.env['account.journal'].search(domain)
def button_draft(self):
super().button_draft()
# Delete attached pdf invoice
try:
report_invoice = self.env['ir.actions.report']._get_report_from_name('account.report_invoice')
except IndexError:
report_invoice = False
if report_invoice and report_invoice.attachment:
for move in self.filtered(lambda x: x.move_type in ('out_invoice', 'out_refund')):
# The pb is that the filename is dynamic and related to move.state
# in v12, the feature was native and they used that kind of code:
# with invoice.env.do_in_draft():
# invoice.number, invoice.state = invoice.move_name, 'open'
# attachment = self.env.ref('account.account_invoices').retrieve_attachment(invoice)
# But do_in_draft() doesn't exists in v14
# If you know how we could do that, please update the code below
attachment = self.env['ir.attachment'].search([
('name', '=', self._get_invoice_attachment_name()),
('res_id', '=', move.id),
('res_model', '=', self._name),
('type', '=', 'binary'),
], limit=1)
if attachment:
attachment.unlink()
def _get_invoice_attachment_name(self):
self.ensure_one()
return '%s.pdf' % (self.name and self.name.replace('/', '_') or 'INV')
class AccountMoveLine(models.Model):
_inherit = 'account.move.line'
@@ -176,6 +226,8 @@ class AccountMoveLine(models.Model):
matched_credit_ids = fields.One2many(string='Partial Reconcile Credit')
reconcile_string = fields.Char(
compute='_compute_reconcile_string', string='Reconcile', store=True)
# for optional display in tree view
product_barcode = fields.Char(related='product_id.barcode', string="Product Barcode")
def show_account_move_form(self):
self.ensure_one()

View File

@@ -0,0 +1,45 @@
# Copyright 2015-2021 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 ProductTemplate(models.Model):
_inherit = 'product.template'
# DON'T put store=True on those fields, because they are company dependent
sale_price_type = fields.Selection(
'_sale_purchase_price_type_sel', compute='_compute_sale_price_type',
string='Sale Price Type', compute_sudo=False, readonly=True)
purchase_price_type = fields.Selection(
'_sale_purchase_price_type_sel', compute='_compute_purchase_price_type',
string='Purchase Price Type', compute_sudo=False, readonly=True)
@api.model
def _sale_purchase_price_type_sel(self):
return [('incl', _('Tax incl.')), ('excl', _('Tax excl.'))]
@api.depends('taxes_id')
def _compute_sale_price_type(self):
for pt in self:
sale_price_type = 'incl'
if pt.taxes_id and all([not t.price_include for t in pt.taxes_id if t.amount_type == 'percent']):
sale_price_type = 'excl'
pt.sale_price_type = sale_price_type
@api.depends('supplier_taxes_id')
def _compute_purchase_price_type(self):
for pt in self:
purchase_price_type = 'incl'
if pt.supplier_taxes_id and all([not t.price_include for t in pt.supplier_taxes_id if t.amount_type == 'percent']):
purchase_price_type = 'excl'
pt.purchase_price_type = purchase_price_type
class ProductSupplierinfo(models.Model):
_inherit = 'product.supplierinfo'
# DON'T put store=True on those fields, because they are company dependent
purchase_price_type = fields.Selection(
related='product_tmpl_id.purchase_price_type', related_sudo=False)

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2020 Akretion France (http://www.akretion.com/)
Copyright 2015-2021 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).
-->
@@ -8,6 +8,18 @@
<odoo>
<record id="view_account_form" model="ir.ui.view">
<field name="name">account.account.form</field>
<field name="model">account.account</field>
<field name="inherit_id" ref="account.view_account_form"/>
<field name="arch" type="xml">
<field name="deprecated" position="before">
<field name="reconcile" attrs="{'invisible': ['|', ('internal_type','=','liquidity'), ('internal_group', '=', 'off_balance')]}"/>
</field>
</field>
</record>
<record id="view_account_search" model="ir.ui.view">
<field name="name">account.account.search</field>
<field name="model">account.account</field>

View File

@@ -18,8 +18,20 @@
<field name="invoice_incoterm_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<button name="action_register_payment" position="attributes">
<attribute name="class">btn-default</attribute>
</button>
<button name="action_register_payment" position="before">
<button name="%(account.account_invoices)d" type="action" string="Print" attrs="{'invisible': [('move_type', 'not in', ('out_invoice', 'out_refund'))]}"/>
</button>
<button name="preview_invoice" position="attributes">
<attribute name="attrs">{'invisible': 1}</attribute>
</button>
<!-- move sent field and make it visible -->
<field name="is_move_sent" position="replace"/>
<field name="invoice_origin" position="attributes">
<attribute name="invisible">0</attribute>
</field>
<field name="invoice_origin" position="after">
<field name="is_move_sent" attrs="{'invisible': [('move_type', 'not in', ('out_invoice', 'out_refund'))]}"/>
</field>
@@ -30,6 +42,9 @@
<field name="matching_number" optional="hide"/>
<field name="reconcile_string" optional="show"/>
</xpath>
<xpath expr="//field[@name='invoice_line_ids']/tree/field[@name='product_id']" position="after">
<field name="product_barcode" optional="hide"/>
</xpath>
</field>
</record>
@@ -58,6 +73,36 @@
</field>
</record>
<record id="view_account_move_line_filter" model="ir.ui.view">
<field name="name">account_usability.account_move_line_search</field>
<field name="model">account.move.line</field>
<field name="inherit_id" ref="account.view_account_move_line_filter"/>
<field name="arch" type="xml">
<filter name="unposted" position="before">
<filter name="current_year" string="Current Year" domain="[('date', '&gt;=', (context_today().strftime('%Y-01-01'))), ('date', '&lt;=', (context_today().strftime('%Y-12-31')))]"/>
<filter name="previous_year" string="Previous Year" domain="[('date', '&gt;=', (context_today() + relativedelta(day=1, month=1, years=-1)).strftime('%Y-%m-%d')), ('date', '&lt;=', (context_today() + relativedelta(day=31, month=12, years=-1)).strftime('%Y-%m-%d'))]"/>
<separator/>
</filter>
<field name="partner_id" position="after">
<field name="reconcile_string" />
<field name="debit" filter_domain="['|', ('debit', '=', self), ('credit', '=', self)]" string="Debit or Credit"/>
</field>
<filter name="unreconciled" position="before">
<filter name="reconciled" string="Fully Reconciled" domain="[('full_reconcile_id', '!=', False)]"/>
</filter>
<filter name="unreconciled" position="attributes">
<attribute name="string">Unreconciled or Partially Reconciled</attribute>
</filter>
<!--
<field name="name" position="attributes">
<attribute name="string">Name or Reference</attribute>
</field> -->
<field name="partner_id" position="attributes">
<attribute name="domain">['|', ('parent_id', '=', False), ('is_company', '=', True)]</attribute>
</field>
</field>
</record>
<record id="account.action_move_journal_line" model="ir.actions.act_window">
<field name="context">{'default_move_type': 'entry', 'view_no_maturity': True}</field>
<!-- Remove 'search_default_misc_filter': 1 -->

View File

@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017-2020 Akretion (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<!-- In the official account module, on product category and product template,
some fields/groups are on account.group_account_invoice, some on
account.group_account_user and some on account.group_account_manager
Here, we set all those fields on account.group_account_invoice
-->
<record id="product_template_form_view" model="ir.ui.view">
<field name="name">account_usability.product.template.form</field>
<field name="model">product.template</field>
<field name="priority">100</field> <!-- when you replace a field, it's always better to inherit at the end -->
<field name="inherit_id" ref="account.product_template_form_view"/>
<field name="arch" type="xml">
<field name="property_account_income_id" position="attributes">
<attribute name="groups">account.group_account_invoice</attribute>
</field>
<field name="property_account_expense_id" position="attributes">
<attribute name="groups">account.group_account_invoice</attribute>
</field>
<field name="list_price" position="replace">
<div name="list_price">
<field name="list_price" widget='monetary' options="{'currency_field': 'currency_id'}" class="oe_inline"/>
<label for="sale_price_type" string=" "/>
<field name="sale_price_type"/>
</div>
</field>
</field>
</record>
<record id="view_category_property_form" model="ir.ui.view">
<field name="name">account_usability.product.category.form</field>
<field name="model">product.category</field>
<field name="inherit_id" ref="account.view_category_property_form"/>
<field name="arch" type="xml">
<group name="account_property" position="attributes">
<attribute name="groups">account.group_account_invoice</attribute>
</group>
</field>
</record>
<record id="product_supplierinfo_form_view" model="ir.ui.view">
<field name="name">account_usability.product.supplierinfo.form</field>
<field name="model">product.supplierinfo</field>
<field name="inherit_id" ref="product.product_supplierinfo_form_view"/>
<field name="arch" type="xml">
<field name="currency_id" position="after">
<field name="purchase_price_type"/>
</field>
</field>
</record>
<record id="product_supplierinfo_tree_view" model="ir.ui.view">
<field name="name">account_usability.product.supplierinfo.tree</field>
<field name="model">product.supplierinfo</field>
<field name="inherit_id" ref="product.product_supplierinfo_tree_view"/>
<field name="arch" type="xml">
<field name="price" position="after">
<field name="purchase_price_type" string="Tax"/>
</field>
</field>
</record>
</odoo>

View File

@@ -16,6 +16,9 @@
<field name="property_account_position_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<xpath expr="//field[@name='bank_ids']/tree/field[@name='acc_number']" position="after">
<field name="acc_type"/>
</xpath>
</field>
</record>

View File

@@ -0,0 +1 @@
from . import models

View File

@@ -0,0 +1,62 @@
# Copyright 2020-2021 Akretion France (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Base Dynamic List',
'version': '14.0.1.0.0',
'category': 'Tools',
'license': 'AGPL-3',
'summary': 'Dynamic lists',
'description': """
Base Dynamic List
=================
Very often during an Odoo implementation, we need to add selection fields on a native objet, and we don't want to have a hard-coded selection list (fields.Selection), but a selection list that can be changed by users (Many2one field). For that, the developper needs to add a new object (with just a 'name' and 'sequence' field) with a form/tree view. The goal of this module is to speed-up this process by defining a dynamic list object that already has all the required views.
This module provides several ready-to-go objects:
* simple list : fields *name*, *sequence* and *active*
* translatable list : fields *name* with translate=True, *sequence* and *active*
* code list : fields *code* (unique), *name*, *sequence* and *active*
* translatable code list : fields *code* (unique), *name* with translate=True, *sequence* and *active*
These objects are readable by the employee group. The system group has full rights on it.
To use it, you need to do 2 or 3 things :
1) Add an entry in the domain field and the object you selected:
domain = fields.Selection(selection_add=[('risk.type', "Risk Type")], ondelete={"risk.type": "cascade"})
2) Add the many2one field on your object:
risk_type_id = fields.Many2one(
'dynamic.list', string="Risk Type",
ondelete='restrict', domain=[('domain', '=', 'risk.type')])
3) Optionally, you can add a dedicated action and a menu entry (otherwize, you can use the generic menu entry under *Settings > Technical > Dynamic Lists*:
<record id="dynamic_list_risk_type_action" model="ir.actions.act_window">
<field name="name">Risk Type</field>
<field name="res_model">dynamic.list</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('domain', '=', 'risk.type')]</field>
<field name="context">{'default_domain': 'risk.type'}</field>
</record>
<menuitem id="dynamic_list_risk_type_menu" action="dynamic_list_risk_type_action"
parent="parent_menu_xmlid"/>
Limitation: when you want to have different access rights on these lists depending on the source object, you should prefer to use dedicated objects.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['base'],
'data': [
'security/ir.model.access.csv',
'views/dynamic_list.xml',
],
'installable': True,
}

View File

@@ -0,0 +1 @@
from . import dynamic_list

View File

@@ -0,0 +1,115 @@
# Copyright 2020-2021 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 DynamicList(models.Model):
_name = 'dynamic.list'
_description = 'Dynamic List (non translatable)'
_order = 'sequence, id'
name = fields.Char(required=True)
sequence = fields.Integer(default=10)
active = fields.Boolean(default=True)
domain = fields.Selection([], string='Domain', required=True, index=True)
_sql_constraint = [(
'domain_name_uniq',
'unique(domain, name)',
'This entry already exists!'
)]
class DynamicListTranslate(models.Model):
_name = 'dynamic.list.translate'
_description = 'Translatable Dynamic List'
_order = 'sequence, id'
name = fields.Char(translate=True, required=True)
sequence = fields.Integer(default=10)
active = fields.Boolean(default=True)
domain = fields.Selection([], string='Domain', required=True, index=True)
_sql_constraint = [(
'domain_name_uniq',
'unique(domain, name)',
'This entry already exists!'
)]
class DynamicListCode(models.Model):
_name = 'dynamic.list.code'
_description = 'Dynamic list with code'
_order = 'sequence, id'
code = fields.Char(required=True)
name = fields.Char(translate=True, required=True)
sequence = fields.Integer(default=10)
active = fields.Boolean(default=True)
domain = fields.Selection([], string='Domain', required=True, index=True)
_sql_constraint = [(
'domain_code_uniq',
'unique(domain, code)',
'This code already exists!'
)]
@api.depends('code', 'name')
def name_get(self):
res = []
for rec in self:
res.append((rec.id, '[%s] %s' % (rec.code, rec.name)))
return res
@api.model
def name_search(
self, name='', args=None, operator='ilike', limit=80):
if args is None:
args = []
if name and operator == 'ilike':
recs = self.search(
[('code', '=', name)] + args, limit=limit)
if recs:
return recs.name_get()
return super().name_search(
name=name, args=args, operator=operator, limit=limit)
class DynamicListCodeTranslate(models.Model):
_name = 'dynamic.list.code.translate'
_description = 'Translatable dynamic list with code'
_order = 'sequence, id'
code = fields.Char(required=True)
name = fields.Char(translate=True, required=True)
sequence = fields.Integer(default=10)
active = fields.Boolean(default=True)
domain = fields.Selection([], string='Domain', required=True, index=True)
_sql_constraint = [(
'domain_code_uniq',
'unique(domain, code)',
'This code already exists!'
)]
@api.depends('code', 'name')
def name_get(self):
res = []
for rec in self:
res.append((rec.id, '[%s] %s' % (rec.code, rec.name)))
return res
@api.model
def name_search(
self, name='', args=None, operator='ilike', limit=80):
if args is None:
args = []
if name and operator == 'ilike':
recs = self.search(
[('code', '=', name)] + args, limit=limit)
if recs:
return recs.name_get()
return super().name_search(
name=name, args=args, operator=operator, limit=limit)

View File

@@ -0,0 +1,9 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_dynamic_list_read,Read access on dynamic.list to employees,model_dynamic_list,base.group_user,1,0,0,0
access_dynamic_list_full,Full access to dynamic.list to System group,model_dynamic_list,base.group_system,1,1,1,1
access_dynamic_list_translate_read,Read access on dynamic.list.translate to employees,model_dynamic_list_translate,base.group_user,1,0,0,0
access_dynamic_list_translate_full,Full access to dynamic.list.translate to System group,model_dynamic_list_translate,base.group_system,1,1,1,1
access_dynamic_list_code_read,Read access on dynamic.list.code to employees,model_dynamic_list_code,base.group_user,1,0,0,0
access_dynamic_list_code_full,Full access to dynamic.list.code to System group,model_dynamic_list_code,base.group_system,1,1,1,1
access_dynamic_list_code_translate_read,Read access on dynamic.list.code.translate to employees,model_dynamic_list_code_translate,base.group_user,1,0,0,0
access_dynamic_list_code_translate_full,Full access to dynamic.list.code.translate to System group,model_dynamic_list_code_translate,base.group_system,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_dynamic_list_read Read access on dynamic.list to employees model_dynamic_list base.group_user 1 0 0 0
3 access_dynamic_list_full Full access to dynamic.list to System group model_dynamic_list base.group_system 1 1 1 1
4 access_dynamic_list_translate_read Read access on dynamic.list.translate to employees model_dynamic_list_translate base.group_user 1 0 0 0
5 access_dynamic_list_translate_full Full access to dynamic.list.translate to System group model_dynamic_list_translate base.group_system 1 1 1 1
6 access_dynamic_list_code_read Read access on dynamic.list.code to employees model_dynamic_list_code base.group_user 1 0 0 0
7 access_dynamic_list_code_full Full access to dynamic.list.code to System group model_dynamic_list_code base.group_system 1 1 1 1
8 access_dynamic_list_code_translate_read Read access on dynamic.list.code.translate to employees model_dynamic_list_code_translate base.group_user 1 0 0 0
9 access_dynamic_list_code_translate_full Full access to dynamic.list.code.translate to System group model_dynamic_list_code_translate base.group_system 1 1 1 1

View File

@@ -0,0 +1,220 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2020-2021 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>
<menuitem id="dynamic_list_root_menu" name="Dynamic Lists" parent="base.menu_custom" sequence="100"/>
<record id="dynamic_list_form" model="ir.ui.view">
<field name="model">dynamic.list</field>
<field name="arch" type="xml">
<form>
<sheet>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<group name="main">
<field name="name"/>
<field name="domain" invisible="not context.get('dynamic_list_main_view')"/>
<field name="active" invisible="1"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="dynamic_list_tree" model="ir.ui.view">
<field name="model">dynamic.list</field>
<field name="arch" type="xml">
<tree>
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="domain" invisible="not context.get('dynamic_list_main_view')"/>
</tree>
</field>
</record>
<record id="dynamic_list_search" model="ir.ui.view">
<field name="model">dynamic.list</field>
<field name="arch" type="xml">
<search>
<field name="name"/>
<separator/>
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
<group string="Group By" name="groupby">
<filter name="domain_groupby" string="Domain" context="{'group_by': 'domain'}"/>
</group>
</search>
</field>
</record>
<record id="dynamic_list_action" model="ir.actions.act_window">
<field name="name">Simple List</field>
<field name="res_model">dynamic.list</field>
<field name="view_mode">tree,form</field>
<field name="context">{'dynamic_list_main_view': True, 'search_default_domain_groupby': True}</field>
</record>
<menuitem id="dynamic_list_menu" action="dynamic_list_action" parent="dynamic_list_root_menu" sequence="10"/>
<record id="dynamic_list_translate_form" model="ir.ui.view">
<field name="model">dynamic.list.translate</field>
<field name="arch" type="xml">
<form>
<sheet>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<group name="main">
<field name="name"/>
<field name="domain" invisible="not context.get('dynamic_list_translate_main_view')"/>
<field name="active" invisible="1"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="dynamic_list_translate_tree" model="ir.ui.view">
<field name="model">dynamic.list.translate</field>
<field name="arch" type="xml">
<tree>
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="domain" invisible="not context.get('dynamic_list_translate_main_view')"/>
</tree>
</field>
</record>
<record id="dynamic_list_translate_search" model="ir.ui.view">
<field name="model">dynamic.list.translate</field>
<field name="arch" type="xml">
<search>
<field name="name"/>
<separator/>
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
<group string="Group By" name="groupby">
<filter name="domain_groupby" string="Domain" context="{'group_by': 'domain'}"/>
</group>
</search>
</field>
</record>
<record id="dynamic_list_translate_action" model="ir.actions.act_window">
<field name="name">Translatable Simple List</field>
<field name="res_model">dynamic.list.translate</field>
<field name="view_mode">tree,form</field>
<field name="context">{'dynamic_list_translate_main_view': True, 'search_default_domain_groupby': True}</field>
</record>
<menuitem id="dynamic_list_translate_menu" action="dynamic_list_translate_action" parent="dynamic_list_root_menu" sequence="20"/>
<record id="dynamic_list_code_form" model="ir.ui.view">
<field name="model">dynamic.list.code</field>
<field name="arch" type="xml">
<form>
<sheet>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<group name="main">
<field name="code"/>
<field name="name"/>
<field name="domain" invisible="not context.get('dynamic_list_code_main_view')"/>
<field name="active" invisible="1"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="dynamic_list_code_tree" model="ir.ui.view">
<field name="model">dynamic.list.code</field>
<field name="arch" type="xml">
<tree>
<field name="sequence" widget="handle"/>
<field name="code"/>
<field name="name"/>
<field name="domain" invisible="not context.get('dynamic_list_code_main_view')"/>
</tree>
</field>
</record>
<record id="dynamic_list_code_search" model="ir.ui.view">
<field name="model">dynamic.list.code</field>
<field name="arch" type="xml">
<search>
<field name="name" string="Name or Code" filter_domain="['|', ('name', 'ilike', self), ('code', 'ilike', self)]"/>
<separator/>
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
<field name="code"/>
<group string="Group By" name="groupby">
<filter name="domain_groupby" string="Domain" context="{'group_by': 'domain'}"/>
</group>
</search>
</field>
</record>
<record id="dynamic_list_code_action" model="ir.actions.act_window">
<field name="name">Code List</field>
<field name="res_model">dynamic.list.code</field>
<field name="view_mode">tree,form</field>
<field name="context">{'dynamic_list_code_main_view': True, 'search_default_domain_groupby': True}</field>
</record>
<menuitem id="dynamic_list_code_menu" action="dynamic_list_code_action" parent="dynamic_list_root_menu" sequence="30"/>
<record id="dynamic_list_code_translate_form" model="ir.ui.view">
<field name="model">dynamic.list.code.translate</field>
<field name="arch" type="xml">
<form>
<sheet>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<group name="main">
<field name="code"/>
<field name="name"/>
<field name="domain" invisible="not context.get('dynamic_list_code_translate_main_view')"/>
<field name="active" invisible="1"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="dynamic_list_code_translate_tree" model="ir.ui.view">
<field name="model">dynamic.list.code.translate</field>
<field name="arch" type="xml">
<tree>
<field name="sequence" widget="handle"/>
<field name="code"/>
<field name="name"/>
<field name="domain" invisible="not context.get('dynamic_list_code_translate_main_view')"/>
</tree>
</field>
</record>
<record id="dynamic_list_code_translate_search" model="ir.ui.view">
<field name="model">dynamic.list.code.translate</field>
<field name="arch" type="xml">
<search>
<field name="name" string="Name or Code" filter_domain="['|', ('name', 'ilike', self), ('code', 'ilike', self)]"/>
<field name="code"/>
<separator/>
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
<group string="Group By" name="groupby">
<filter name="domain_groupby" string="Domain" context="{'group_by': 'domain'}"/>
</group>
</search>
</field>
</record>
<record id="dynamic_list_code_translate_action" model="ir.actions.act_window">
<field name="name">Translatable Code List</field>
<field name="res_model">dynamic.list.code.translate</field>
<field name="view_mode">tree,form</field>
<field name="context">{'dynamic_list_code_translate_main_view': True, 'search_default_domain_groupby': True}</field>
</record>
<menuitem id="dynamic_list_code_translate_menu" action="dynamic_list_code_translate_action" parent="dynamic_list_root_menu" sequence="40"/>
</odoo>

View File

@@ -1,14 +1,14 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_partner_one2many_phone
# * base_partner_one2many_phone
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 10.0\n"
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-27 18:03+0000\n"
"PO-Revision-Date: 2020-01-27 18:03+0000\n"
"Last-Translator: <>\n"
"POT-Creation-Date: 2021-10-29 21:12+0000\n"
"PO-Revision-Date: 2021-10-29 21:12+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -16,92 +16,120 @@ msgstr ""
"Plural-Forms: \n"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_create_uid
#: model:ir.model,name:base_partner_one2many_phone.model_res_partner
msgid "Contact"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__create_uid
msgid "Created by"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_create_date
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__create_date
msgid "Created on"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_display_name
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__display_name
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__display_name
msgid "Display Name"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_email
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__email
msgid "E-Mail"
msgstr ""
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:61
#: code:addons/base_partner_one2many_phone/partner_phone.py:0
#, python-format
msgid "E-mail field must be empty when type is Primary/Secondary Phone, Primary/Secondary Mobile or Primary/Secondary Fax."
msgid ""
"E-mail field must be empty when type is Primary/Secondary Phone, "
"Primary/Secondary Mobile or Primary/Secondary Fax."
msgstr ""
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:51
#: code:addons/base_partner_one2many_phone/partner_phone.py:0
#, python-format
msgid "E-mail field must have a value when type is Primary E-mail or Secondary E-mail."
msgid ""
"E-mail field must have a value when type is Primary E-mail or Secondary "
"E-mail."
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_id
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__email
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users__email
msgid "Email"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__id
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__id
msgid "ID"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone___last_update
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner____last_update
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone____last_update
msgid "Last Modified on"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_write_uid
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__write_uid
msgid "Last Updated by"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_write_date
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__write_date
msgid "Last Updated on"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_note
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__mobile
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users__mobile
msgid "Mobile"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model,name:base_partner_one2many_phone.model_res_partner_phone
msgid "Multiple emails and phones for partners"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__note
msgid "Note"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model,name:base_partner_one2many_phone.model_res_partner
msgid "Partner"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users__phone
msgid "Phone"
msgstr ""
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:54
#: model_terms:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_form
msgid "Phone and E-mail"
msgstr ""
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:0
#, python-format
msgid "Phone field must be empty when type is Primary E-mail or Secondary E-mail."
msgid ""
"Phone field must be empty when type is Primary E-mail or Secondary E-mail."
msgstr ""
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:58
#: code:addons/base_partner_one2many_phone/partner_phone.py:0
#, python-format
msgid "Phone field must have a value when type is Primary/Secondary Phone, Primary/Secondary Mobile or Primary/Secondary Fax."
msgid ""
"Phone field must have a value when type is Primary/Secondary Phone, "
"Primary/Secondary Mobile or Primary/Secondary Fax."
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_ids
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users_phone_ids
msgid "Phones"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_tree
#: model_terms:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_tree
msgid "Phones and E-mail"
msgstr ""
@@ -112,63 +140,63 @@ msgid "Phones/E-mails"
msgstr ""
#. module: base_partner_one2many_phone
#: selection:res.partner.phone,type:0
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__phone_ids
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users__phone_ids
msgid "Phones/Emails"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__1_email_primary
msgid "Primary E-mail"
msgstr ""
#. module: base_partner_one2many_phone
#: selection:res.partner.phone,type:0
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__7_fax_primary
msgid "Primary Fax"
msgstr ""
#. module: base_partner_one2many_phone
#: selection:res.partner.phone,type:0
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__5_mobile_primary
msgid "Primary Mobile"
msgstr ""
#. module: base_partner_one2many_phone
#: selection:res.partner.phone,type:0
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__3_phone_primary
msgid "Primary Phone"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_partner_id
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__partner_id
msgid "Related Partner"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_search
#: model_terms:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_search
msgid "Search Phones/E-mail"
msgstr ""
#. module: base_partner_one2many_phone
#: selection:res.partner.phone,type:0
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__2_email_secondary
msgid "Secondary E-mail"
msgstr ""
#. module: base_partner_one2many_phone
#: selection:res.partner.phone,type:0
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__8_fax_secondary
msgid "Secondary Fax"
msgstr ""
#. module: base_partner_one2many_phone
#: selection:res.partner.phone,type:0
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__6_mobile_secondary
msgid "Secondary Mobile"
msgstr ""
#. module: base_partner_one2many_phone
#: selection:res.partner.phone,type:0
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__4_phone_secondary
msgid "Secondary Phone"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_type
#: model:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_search
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__type
#: model_terms:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_search
msgid "Type"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model,name:base_partner_one2many_phone.model_res_partner_phone
msgid "res.partner.phone"
msgstr ""

View File

@@ -1,14 +1,14 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_partner_one2many_phone
# * base_partner_one2many_phone
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 10.0\n"
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-27 17:56+0000\n"
"PO-Revision-Date: 2020-01-27 17:56+0000\n"
"Last-Translator: <>\n"
"POT-Creation-Date: 2021-10-29 21:12+0000\n"
"PO-Revision-Date: 2021-10-29 21:12+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -16,159 +16,187 @@ msgstr ""
"Plural-Forms: \n"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_create_uid
#: model:ir.model,name:base_partner_one2many_phone.model_res_partner
msgid "Contact"
msgstr "Contact"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__create_uid
msgid "Created by"
msgstr "Créé par"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_create_date
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__create_date
msgid "Created on"
msgstr "Créé le"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_display_name
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__display_name
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__display_name
msgid "Display Name"
msgstr "Nom à afficher"
msgstr "Nom affiché"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_email
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__email
msgid "E-Mail"
msgstr "Courriel"
msgstr "E-Mail"
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:61
#: code:addons/base_partner_one2many_phone/partner_phone.py:0
#, python-format
msgid "E-mail field must be empty when type is Primary/Secondary Phone, Primary/Secondary Mobile or Primary/Secondary Fax."
msgstr "Le champ courriel doit être vide quand le type est tél. primaire/secondaire, portable primaire/secondaire ou fax primaire/secondaire."
msgid ""
"E-mail field must be empty when type is Primary/Secondary Phone, "
"Primary/Secondary Mobile or Primary/Secondary Fax."
msgstr "Le champ E-mail doit être vide quand le type est Tél. principal/secondaire, Portable principal/secondaire ou Fax principal/secondaire."
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:51
#: code:addons/base_partner_one2many_phone/partner_phone.py:0
#, python-format
msgid "E-mail field must have a value when type is Primary E-mail or Secondary E-mail."
msgstr "Le champ courriel doit être renseigné quand le type est courriel primaire ou courriel secondaire."
msgid ""
"E-mail field must have a value when type is Primary E-mail or Secondary "
"E-mail."
msgstr "Le champ E-mail doit avoir une valeur quand le type est E-mail principal ou secondaire."
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_id
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__email
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users__email
msgid "Email"
msgstr "E-mail"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__id
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__id
msgid "ID"
msgstr "ID"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone___last_update
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner____last_update
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone____last_update
msgid "Last Modified on"
msgstr "Dernière modification le"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_write_uid
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__write_uid
msgid "Last Updated by"
msgstr "Dernière mise à jour par"
msgstr "Dernière modification par"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_write_date
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__write_date
msgid "Last Updated on"
msgstr "Dernière mise à jour le"
msgstr "Dernière modification le"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_note
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__mobile
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users__mobile
msgid "Mobile"
msgstr "Portable"
#. module: base_partner_one2many_phone
#: model:ir.model,name:base_partner_one2many_phone.model_res_partner_phone
msgid "Multiple emails and phones for partners"
msgstr "Multiples e-mails et téléphones pour les partenaires"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__note
msgid "Note"
msgstr "Note"
#. module: base_partner_one2many_phone
#: model:ir.model,name:base_partner_one2many_phone.model_res_partner
msgid "Partner"
msgstr "Partenaire"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users__phone
msgid "Phone"
msgstr "Téléphone"
msgstr "Tél."
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:54
#: model_terms:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_form
msgid "Phone and E-mail"
msgstr "Tél. et E-mail"
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:0
#, python-format
msgid "Phone field must be empty when type is Primary E-mail or Secondary E-mail."
msgstr "Le champ téléphone doit être vide quand le type est courriel primaire ou courriel secondaire."
msgid ""
"Phone field must be empty when type is Primary E-mail or Secondary E-mail."
msgstr "Le champ Tél. doit être vide quand le type est E-mail principal ou E-mail secondaire."
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:58
#: code:addons/base_partner_one2many_phone/partner_phone.py:0
#, python-format
msgid "Phone field must have a value when type is Primary/Secondary Phone, Primary/Secondary Mobile or Primary/Secondary Fax."
msgstr "Le champ téléphone doit être renseigné quand le type est tél. primaire/secondaire, portable primaire/secondaire ou fax primaire/secondaire.."
msgid ""
"Phone field must have a value when type is Primary/Secondary Phone, "
"Primary/Secondary Mobile or Primary/Secondary Fax."
msgstr "Le champ Tél. doit avoir une valeur quand le type est Tél. principal/secondaire, Portable principal/secondaire ou Fax principal/secondaire."
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_ids
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users_phone_ids
msgid "Phones"
msgstr "Téléphones"
#. module: base_partner_one2many_phone
#: model:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_tree
#: model_terms:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_tree
msgid "Phones and E-mail"
msgstr "Téls et courriels"
msgstr "Téls et E-mail"
#. module: base_partner_one2many_phone
#: model:ir.actions.act_window,name:base_partner_one2many_phone.res_partner_phone_action
#: model:ir.ui.menu,name:base_partner_one2many_phone.res_partner_phone_menu
msgid "Phones/E-mails"
msgstr "Téls/Courriels"
msgstr "Téls/E-mails"
#. module: base_partner_one2many_phone
#: selection:res.partner.phone,type:0
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__phone_ids
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users__phone_ids
msgid "Phones/Emails"
msgstr "Téls/E-mails"
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__1_email_primary
msgid "Primary E-mail"
msgstr "Courriel principal"
msgstr "E-mail principal"
#. module: base_partner_one2many_phone
#: selection:res.partner.phone,type:0
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__7_fax_primary
msgid "Primary Fax"
msgstr "Fax principal"
#. module: base_partner_one2many_phone
#: selection:res.partner.phone,type:0
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__5_mobile_primary
msgid "Primary Mobile"
msgstr "Portable principal"
#. module: base_partner_one2many_phone
#: selection:res.partner.phone,type:0
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__3_phone_primary
msgid "Primary Phone"
msgstr "Tél principal"
msgstr "Tél. principal"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_partner_id
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__partner_id
msgid "Related Partner"
msgstr "Partenaire associé"
#. module: base_partner_one2many_phone
#: model:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_search
#: model_terms:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_search
msgid "Search Phones/E-mail"
msgstr "Search Phones/E-mail"
msgstr ""
#. module: base_partner_one2many_phone
#: selection:res.partner.phone,type:0
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__2_email_secondary
msgid "Secondary E-mail"
msgstr "Courriel secondaire"
msgstr "E-mail secondaire"
#. module: base_partner_one2many_phone
#: selection:res.partner.phone,type:0
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__8_fax_secondary
msgid "Secondary Fax"
msgstr "Fax secondaire"
#. module: base_partner_one2many_phone
#: selection:res.partner.phone,type:0
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__6_mobile_secondary
msgid "Secondary Mobile"
msgstr "Portable secondaire"
#. module: base_partner_one2many_phone
#: selection:res.partner.phone,type:0
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__4_phone_secondary
msgid "Secondary Phone"
msgstr "Tél. secondaire"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone_type
#: model:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_search
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__type
#: model_terms:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_search
msgid "Type"
msgstr "Type"
#. module: base_partner_one2many_phone
#: model:ir.model,name:base_partner_one2many_phone.model_res_partner_phone
msgid "res.partner.phone"
msgstr "res.partner.phone"

View File

@@ -46,7 +46,7 @@ class ResPartnerPhone(models.Model):
@api.onchange('phone', 'partner_id')
def _onchange_phone_validation(self):
if self.phone:
self.phone = self.phone_format(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):

View File

@@ -14,7 +14,7 @@
<field name="name">res.partner.phone.tree</field>
<field name="model">res.partner.phone</field>
<field name="arch" type="xml">
<tree string="Phones and E-mail" editable="bottom">
<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'))]}"/>
@@ -28,7 +28,7 @@
<field name="name">res.partner.phone.form</field>
<field name="model">res.partner.phone</field>
<field name="arch" type="xml">
<form string="Phone and E-mail">
<form>
<group name="main">
<field name="partner_id" invisible="not context.get('partner_phone_main_view')"/>
<field name="type"/>
@@ -44,7 +44,7 @@
<field name="name">res.partner.phone.search</field>
<field name="model">res.partner.phone</field>
<field name="arch" type="xml">
<search string="Search Phones/E-mail">
<search>
<field name="phone" />
<field name="email" />
<group name="groupby">
@@ -72,7 +72,9 @@
<record id="view_partner_form" model="ir.ui.view">
<field name="name">add.phone_ids.on.partner.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="inherit_id" ref="mail.res_partner_view_form_inherit_mail"/>
<!-- This module depends on contacts which depends on mail
and the mail module replaces the email field -->
<field name="arch" type="xml">
<field name="phone" position="after">
<field name="phone_ids" nolabel="1" colspan="2"/>
@@ -83,9 +85,12 @@
<field name="mobile" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="email" position="attributes">
<label for="email" position="attributes">
<attribute name="invisible">1</attribute>
</field>
</label>
<xpath expr="//field[@name='email']/.." position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<!-- I can't display phone_ids in the Contacts
because there is a very strange thing in the web client: if
you have a res.partner.phone on one of the fields,

View File

@@ -28,7 +28,7 @@ class ResPartner(models.Model):
# START modif of native method
if partner.ref:
name = u"[%s] %s" % (partner.ref, name)
name = "[%s] %s" % (partner.ref, name)
# END modif of native method
if partner.company_name or partner.parent_id:
if not name and partner.type in ['invoice', 'delivery', 'other']:
@@ -55,3 +55,13 @@ class ResPartner(models.Model):
if self._context.get('show_vat') and partner.vat:
name = "%s %s" % (name, partner.vat)
return name
@api.model
def name_search(self, name='', args=None, operator='ilike', limit=100):
if args is None:
args = []
if name and operator == 'ilike':
recs = self.search([('ref', '=', name)] + args, limit=limit)
if recs:
return recs.name_get()
return super().name_search(name=name, args=args, operator=operator, limit=limit)

View File

@@ -0,0 +1,194 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_usability
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-07-01 10:02+0000\n"
"PO-Revision-Date: 2021-07-01 10:02+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: base_usability
#: model:ir.model,name:base_usability.model_res_partner_bank
msgid "Bank Accounts"
msgstr ""
#. module: base_usability
#: model:ir.model.fields,field_description:base_usability.field_res_partner_bank__bank_name
msgid "Bank Name"
msgstr ""
#. module: base_usability
#: model:ir.model,name:base_usability.model_res_company
msgid "Companies"
msgstr ""
#. module: base_usability
#: model:ir.model,name:base_usability.model_res_partner
msgid "Contact"
msgstr ""
#. module: base_usability
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
msgid "Currency"
msgstr ""
#. module: base_usability
#: code:addons/base_usability/models/res_partner.py:0
#: code:addons/base_usability/models/res_partner.py:0
#, python-format
msgid "Customer Number:"
msgstr ""
#. module: base_usability
#: 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_partner.py:0
#, python-format
msgid "E-mail:"
msgstr ""
#. module: base_usability
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
msgid "Group By"
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
#: model_terms:ir.ui.view,arch_db:base_usability.view_module_filter
msgid "Installable"
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
#: model:ir.model,name:base_usability.model_ir_mail_server
msgid "Mail Server"
msgstr ""
#. module: base_usability
#: code:addons/base_usability/models/res_partner.py:0
#, python-format
msgid "Mobile:"
msgstr ""
#. module: base_usability
#: model:ir.model,name:base_usability.model_ir_model
msgid "Models"
msgstr ""
#. module: base_usability
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
msgid "Name or Code"
msgstr ""
#. module: base_usability
#: model_terms:ir.ui.view,arch_db:base_usability.view_res_partner_filter
msgid "Name or Email or Reference"
msgstr ""
#. 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_users__name_title
msgid "Name with Title"
msgstr ""
#. module: base_usability
#: model:res.groups,name:base_usability.group_nobody
msgid "Nobody (used to hide native menus)"
msgstr ""
#. module: base_usability
#: model:ir.model,name:base_usability.model_res_partner_category
msgid "Partner Tags"
msgstr ""
#. 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_users__ref
msgid "Reference"
msgstr ""
#. module: base_usability
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
msgid "Search Countries"
msgstr ""
#. module: base_usability
#: code:addons/base_usability/models/res_partner.py:0
#: code:addons/base_usability/models/res_partner.py:0
#, python-format
msgid "Supplier Number:"
msgstr ""
#. module: base_usability
#: 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_partner.py:0
#, python-format
msgid "Tel:"
msgstr ""
#. module: base_usability
#: model:ir.model,name:base_usability.model_res_users
msgid "Users"
msgstr ""
#. module: base_usability
#: code:addons/base_usability/models/res_partner.py:0
#, python-format
msgid "VAT Number:"
msgstr ""
#. module: base_usability
#: code:addons/base_usability/models/res_company.py:0
#, python-format
msgid "VAT:"
msgstr ""
#. module: base_usability
#: code:addons/base_usability/models/res_company.py:0
#: code:addons/base_usability/models/res_partner.py:0
#, python-format
msgid "Website:"
msgstr ""

192
base_usability/i18n/fr.po Normal file
View File

@@ -0,0 +1,192 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_usability
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-07-01 10:02+0000\n"
"PO-Revision-Date: 2021-07-01 12:15+0200\n"
"Last-Translator: Alexis de Lattre <alexis@via.ecp.fr>\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: base_usability
#: model:ir.model,name:base_usability.model_res_partner_bank
msgid "Bank Accounts"
msgstr "Comptes bancaires"
#. module: base_usability
#: model:ir.model.fields,field_description:base_usability.field_res_partner_bank__bank_name
msgid "Bank Name"
msgstr "Nom de la banque"
#. module: base_usability
#: model:ir.model,name:base_usability.model_res_company
msgid "Companies"
msgstr "Sociétés"
#. module: base_usability
#: model:ir.model,name:base_usability.model_res_partner
msgid "Contact"
msgstr "Contact"
#. module: base_usability
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
msgid "Currency"
msgstr "Devise"
#. module: base_usability
#: code:addons/base_usability/models/res_partner.py:0
#, python-format
msgid "Customer Number:"
msgstr "N° client :"
#. module: base_usability
#: 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_partner.py:0
#, python-format
msgid "E-mail:"
msgstr "E-mail :"
#. module: base_usability
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
msgid "Group By"
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
#: model_terms:ir.ui.view,arch_db:base_usability.view_module_filter
msgid "Installable"
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
#: model:ir.model,name:base_usability.model_ir_mail_server
msgid "Mail Server"
msgstr "Serveur mail"
#. module: base_usability
#: code:addons/base_usability/models/res_partner.py:0
#, python-format
msgid "Mobile:"
msgstr "Portable :"
#. module: base_usability
#: model:ir.model,name:base_usability.model_ir_model
msgid "Models"
msgstr "Modèles"
#. module: base_usability
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
msgid "Name or Code"
msgstr "Nom ou code"
#. module: base_usability
#: model_terms:ir.ui.view,arch_db:base_usability.view_res_partner_filter
msgid "Name or Email or Reference"
msgstr "Nom ou e-mail ou référence"
#. 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_users__name_title
msgid "Name with Title"
msgstr "Nom avec titre"
#. module: base_usability
#: model:res.groups,name:base_usability.group_nobody
msgid "Nobody (used to hide native menus)"
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
#: model:ir.model.fields,field_description:base_usability.field_res_partner__ref
#: model:ir.model.fields,field_description:base_usability.field_res_users__ref
msgid "Reference"
msgstr "Référence"
#. module: base_usability
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
msgid "Search Countries"
msgstr ""
#. module: base_usability
#: code:addons/base_usability/models/res_partner.py:0
#, python-format
msgid "Supplier Number:"
msgstr "N° fournisseur :"
#. module: base_usability
#: 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_partner.py:0
#, python-format
msgid "Tel:"
msgstr "Tél :"
#. module: base_usability
#: model:ir.model,name:base_usability.model_res_users
msgid "Users"
msgstr "Utilisateurs"
#. module: base_usability
#: code:addons/base_usability/models/res_partner.py:0
#, python-format
msgid "VAT Number:"
msgstr "N° TVA :"
#. module: base_usability
#: code:addons/base_usability/models/res_company.py:0
#, python-format
msgid "VAT:"
msgstr "TVA :"
#. module: base_usability
#: code:addons/base_usability/models/res_company.py:0
#: code:addons/base_usability/models/res_partner.py:0
#, python-format
msgid "Website:"
msgstr "Site web :"

View File

@@ -4,4 +4,5 @@ from . import res_partner_bank
from . import res_partner_category
from . import res_company
from . import ir_mail_server
from . import ir_actions_report
from . import ir_model

View File

@@ -0,0 +1,15 @@
# Copyright 2021 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 IrActionsReport(models.Model):
_inherit = "ir.actions.report"
# since v13, print_report_name is a translatable field
# It means that you can't set the value via an inherit of
# ir.actions.report as XML
# I think it was easier when this field was not translatable
print_report_name = fields.Char(translate=False)

View File

@@ -51,7 +51,7 @@ class ResCompany(models.Model):
'label': _('Website:')},
'vat': {
'value': self.vat,
'label': _('TVA :')}, # TODO translate
'label': _('VAT:')},
}
return options

View File

@@ -8,25 +8,9 @@ from odoo import models, fields, api, _
class ResPartner(models.Model):
_inherit = 'res.partner'
# track_visibility is handled in the 'mail' module, and base_usability
# doesn't depend on 'mail', but that doesn't hurt, it will just be
# ignored if mail is not installed
# TODO move to mail module
# name = fields.Char(tracking=True)
# parent_id = fields.Many2one(tracking=True)
# ref = fields.Char(tracking=True)
# lang = fields.Selection(tracking=True)
# user_id = fields.Many2one(tracking=True)
# vat = fields.Char(tracking=True)
# street = fields.Char(tracking=True)
# street2 = fields.Char(tracking=True)
# zip = fields.Char(tracking=True)
# city = fields.Char(tracking=True)
# state_id = fields.Many2one(tracking=True)
# country_id = fields.Many2one(tracking=True)
# is_company = fields.Boolean(tracking=True)
# active = fields.Boolean(tracking=True)
# company_id = fields.Many2one(tracking=True)
# tracking=True is handled in the 'mail' module, and base_usability
# doesn't depend on 'mail', so adding tracking on res.partner fields
# has been moved to mail_usability
ref = fields.Char(copy=False)
# For reports
name_title = fields.Char(
@@ -56,9 +40,8 @@ class ResPartner(models.Model):
# for reports
def _display_full_address(
self, details=[
'company', 'name', 'address', 'phone',
'mobile', 'email'],
self,
details=['company', 'name', 'address', 'phone', 'mobile', 'email'],
icon=True):
self.ensure_one()
# To make the icons work with py3o with PDF export, on the py3o server:
@@ -119,7 +102,28 @@ class ResPartner(models.Model):
},
'address': {
'value': self._display_address(without_company=True),
}
},
'vat': {
'value': self.commercial_partner_id.vat,
'label': _('VAT Number:'),
},
'commercial_ref': {
'value': self.commercial_partner_id.ref,
'label': _('Customer Number:'),
},
'ref': {
'value': self.ref,
'label': _('Customer Number:'),
},
# Same with 'supplier_' prefix, to change the label
'supplier_commercial_ref': {
'value': self.commercial_partner_id.ref,
'label': _('Supplier Number:'),
},
'supplier_ref': {
'value': self.ref,
'label': _('Supplier Number:'),
},
}
res = []
for detail in details:

View File

@@ -25,7 +25,7 @@
<field name="name">base_usability.res.country.search</field>
<field name="model">res.country</field>
<field name="arch" type="xml">
<search string="Search Countries">
<search>
<field name="name" filter_domain="['|', ('name', 'ilike', self), ('code', '=', self)]" string="Name or Code"/>
<field name="code"/>
<field name="currency_id"/>

View File

@@ -16,6 +16,10 @@
<xpath expr="//field[@name='child_ids']/form//field[@name='title']" position="attributes">
<attribute name="attrs"></attribute>
</xpath>
<!-- Show double VAT partner even when not in editable mode -->
<div attrs="{'invisible': [('same_vat_partner_id', '=', False)]}" position="attributes">
<attribute name="class">alert alert-warning</attribute>
</div>
</field>
</record>

View File

@@ -1 +1 @@
from . import stock
from . import models

View File

@@ -1,10 +1,10 @@
# Copyright 2018-2019 Akretion (http://www.akretion.com)
# Copyright 2018-2021 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': 'Delivery Usability',
'version': '12.0.1.0.0',
'version': '14.0.1.0.0',
'category': 'Stock',
'license': 'AGPL-3',
'summary': 'Several usability enhancements in Delivery',
@@ -14,7 +14,6 @@ Delivery Usability
The usability enhancements include:
* allow modification of carrier and it's tracking ref. on a done picking
* display field 'invoice_shipping_on_delivery' on sale.order form view
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
""",
@@ -22,8 +21,7 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com',
'depends': ['delivery'],
'data': [
'sale_view.xml',
'stock_view.xml',
'views/stock_picking.xml',
],
'installable': False,
'installable': True,
}

View File

@@ -0,0 +1 @@
from . import stock_picking

View File

@@ -1,4 +1,4 @@
# Copyright 2018-2019 Akretion (http://www.akretion.com)
# Copyright 2018-2021 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).
@@ -8,5 +8,5 @@ from odoo import fields, models
class StockPicking(models.Model):
_inherit = 'stock.picking'
carrier_id = fields.Many2one(track_visibility='onchange')
carrier_tracking_ref = fields.Char(track_visibility='onchange')
carrier_id = fields.Many2one(tracking=True)
carrier_tracking_ref = fields.Char(tracking=True)

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018-2019 Akretion
@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_form_with_carrier" model="ir.ui.view">
<field name="name">delivery_usability.sale.order.form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="delivery.view_order_form_with_carrier"/>
<field name="arch" type="xml">
<group name="sale_pay" position="inside">
<field name="invoice_shipping_on_delivery"/>
</group>
</field>
</record>
</odoo>

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
Copyright 2018-2021 Akretion France
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->

View File

@@ -1,9 +1,9 @@
# Copyright 2014-2019 Akretion France (http://www.akretion.com)
# Copyright 2014-2021 Akretion France (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
{
'name': 'Eradicate Quick Create',
'version': '12.0.2.0.0',
'version': '14.0.1.0.0',
'category': 'Tools',
'license': 'AGPL-3',
'summary': 'Disable quick create on all objects',
@@ -13,7 +13,7 @@ Eradicate Quick Create
Disable quick create on all objects of Odoo.
This new version of the module uses the module *web_m2x_options* from the OCA *web* project instead of the module *base_optional_quick_create* from the OCA project *server-ux*.
This module uses the module *web_m2x_options* from the OCA *web* project (in v10 and lower, it was using the module *base_optional_quick_create* from the OCA project *server-ux*).
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
""",
@@ -21,5 +21,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com',
'depends': ['web_m2x_options'],
'post_init_hook': 'web_m2x_options_create',
'installable': False,
'installable': True,
}

View File

@@ -1,4 +1,4 @@
# Copyright 2019 Akretion France
# Copyright 2019-2021 Akretion France
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
@@ -11,7 +11,7 @@ def web_m2x_options_create(cr, registry):
config_parameter = env['ir.config_parameter'].search(
[('key', '=', 'web_m2x_options.create')])
if config_parameter and config_parameter.value != 'False':
config_parameter.value = 'False'
config_parameter.write({'value': 'False'})
else:
env['ir.config_parameter'].create({
'key': 'web_m2x_options.create',

View File

@@ -0,0 +1 @@
from . import models

View File

@@ -0,0 +1,20 @@
# Copyright 2021 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': 'HR Contract Usability',
'version': '14.0.1.0.0',
'category': 'Human Resources/Contracts',
'license': 'AGPL-3',
'summary': 'Usability improvements on HR Contract module',
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': [
'hr_contract',
],
'data': [
'views/hr_payroll_structure_type.xml',
],
'installable': True,
}

View File

@@ -0,0 +1 @@
from . import hr_payroll_structure_type

View File

@@ -0,0 +1,10 @@
# Copyright 2021 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class HrPayrollStructureType(models.Model):
_inherit = 'hr.payroll.structure.type'
active = fields.Boolean(default=True)

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2021 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="hr_payroll_structure_type_form" model="ir.ui.view">
<field name="model">hr.payroll.structure.type</field>
<field name="arch" type="xml">
<form>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<group name="main">
<field name="name"/>
<field name="default_resource_calendar_id"/>
<field name="active" invisible="1"/>
<field name="country_id"/>
</group>
</form>
</field>
</record>
<record id="hr_payroll_structure_type_tree" model="ir.ui.view">
<field name="model">hr.payroll.structure.type</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="default_resource_calendar_id" optional="show"/>
<field name="country_id"/>
</tree>
</field>
</record>
<record id="hr_payroll_structure_type_search" model="ir.ui.view">
<field name="model">hr.payroll.structure.type</field>
<field name="arch" type="xml">
<search>
<field name="name"/>
<separator/>
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
<group name="groupby">
<filter name="country_groupby" string="Country" context="{'group_by': 'country_id'}"/>
</group>
</search>
</field>
</record>
<record id="hr_payroll_structure_type_action" model="ir.actions.act_window">
<field name="name">Salary Structure Types</field>
<field name="res_model">hr.payroll.structure.type</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem
id="hr_payroll_structure_type_menu"
action="hr_payroll_structure_type_action"
parent="hr_contract.menu_human_resources_configuration_contract"
sequence="10"/>
</odoo>

View File

@@ -0,0 +1 @@
from . import models

View File

@@ -0,0 +1,32 @@
# Copyright 2016-2021 Akretion France (http://www.akretion.com)
# @author Benoît Guillot <benoit.guillot@akretion.com>
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Mail Usability',
'version': '14.0.1.0.0',
'category': 'Productivity/Discuss',
'license': 'AGPL-3',
'summary': 'Usability improvements on mails',
'description': """
Mail Usability
==============
Small usability improvements on mails:
* remove link in mail footer (TODO mig v14)
* remove 'sent by' in notification footer (TODO mig v14)
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['mail'],
'data': [
#'views/mail_view.xml',
#'data/mail_data.xml',
#'wizard/email_template_preview_view.xml',
#'wizard/mail_compose_message_view.xml',
],
'installable': True,
}

View File

@@ -0,0 +1,2 @@
from . import res_partner
from . import mail_template

View File

@@ -0,0 +1,11 @@
# Copyright 2018-2021 Akretion France (http://www.akretion.com).
# @author Sébastien BEAU <sebastien.beau@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class MailTemplate(models.Model):
_inherit = 'mail.template'
auto_delete = fields.Boolean(default=False)

View File

@@ -0,0 +1,26 @@
# Copyright 2015-2021 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, fields
class ResPartner(models.Model):
_inherit = 'res.partner'
# tracking=True is handled in the 'mail' module, so it's better
# to have this in mail_usability than in base_usability
name = fields.Char(tracking=True)
parent_id = fields.Many2one(tracking=True)
ref = fields.Char(tracking=True)
lang = fields.Selection(tracking=True)
vat = fields.Char(tracking=True)
street = fields.Char(tracking=True)
street2 = fields.Char(tracking=True)
zip = fields.Char(tracking=True)
city = fields.Char(tracking=True)
state_id = fields.Many2one(tracking=True)
country_id = fields.Many2one(tracking=True)
is_company = fields.Boolean(tracking=True)
active = fields.Boolean(tracking=True)
company_id = fields.Many2one(tracking=True)

View File

@@ -12,16 +12,20 @@ class ProductTemplate(models.Model):
only one BoM form or a list of BoMs."""
self.ensure_one()
if self.bom_count == 1:
action = self.env.ref("mrp.mrp_bom_form_action").read()[0]
action_xml_id = "mrp.mrp_bom_form_action"
action = self.env["ir.actions.actions"]._for_xml_id(action_xml_id)
bom = self.env["mrp.bom"].search([("product_tmpl_id", "=", self.id)])
action.update({
"context": {"default_product_tmpl_id": self.id},
"views": False,
"view_mode": "form,tree",
"res_id": bom.id,
})
action.update(
{
"context": {"default_product_tmpl_id": self.id},
"views": False,
"view_mode": "form,tree",
"res_id": bom.id,
}
)
else:
action = self.env.ref("mrp.template_open_bom").read()[0]
action_xml_id = "mrp.template_open_bom"
action = self.env["ir.actions.actions"]._for_xml_id(action_xml_id)
return action
@@ -32,9 +36,11 @@ class ProductProduct(models.Model):
action = super().action_view_bom()
bom_target_ids = self.env["mrp.bom"].search(action["domain"])
if len(bom_target_ids) == 1:
action.update({
"views": False,
"view_mode": "form,tree",
"res_id": bom_target_ids[0].id,
})
action.update(
{
"views": False,
"view_mode": "form,tree",
"res_id": bom_target_ids[0].id,
}
)
return action

View File

View File

@@ -0,0 +1,22 @@
# Copyright 2021 Akretion (http://www.akretion.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'POS Product Tree Default',
'version': '14.0.1.0.0',
'category': 'Product',
'license': 'AGPL-3',
'summary': 'Tree view by default instead of kanban for Products',
'description': """
Replace default kanban view by tree view for product menu in Point of Sale
main menu
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['point_of_sale'],
'data': [
'views/product_template.xml'
],
'installable': True,
}

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="point_of_sale.product_template_action_pos_product" model="ir.actions.act_window">
<field name="view_mode">tree,form,kanban,activity</field>
</record>
</odoo>

View File

@@ -0,0 +1 @@
from . import models

View File

@@ -1,8 +1,10 @@
# Copyright 2014-2021 Akretion France (http://www.akretion.com/)
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "POS Usability",
"version": "12.0.1.0.0",
"version": "14.0.1.0.0",
"category": "Point of sale",
"license": "AGPL-3",
"summary": "Misc usability improvement for point of sale",
@@ -24,6 +26,12 @@ Akretion:
"author": "Akretion",
"website": "http://www.akretion.com",
"depends": ["point_of_sale"],
"data": ["report/pos.xml"],
"installable": False,
"data": [
"report/pos.xml",
"views/report_pos_order.xml",
"views/pos_category.xml",
"views/pos_session.xml",
"views/product.xml",
],
"installable": True,
}

View File

@@ -0,0 +1,3 @@
from . import product
from . import pos_category
from . import pos_payment_method

View File

@@ -0,0 +1,25 @@
# Copyright 2017-2021 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 PosCategory(models.Model):
_inherit = 'pos.category'
product_count = fields.Integer(
'# Products', compute='_compute_product_count',
help="The number of products under this point of sale category "
"(does not consider the children categories)")
# inspired by the code of odoo/addons/product/models/product.py
def _compute_product_count(self):
read_group_res = self.env['product.template'].read_group(
[('pos_categ_id', 'in', self.ids)],
['pos_categ_id'], ['pos_categ_id'])
group_data = dict(
(data['pos_categ_id'][0], data['pos_categ_id_count']) for data
in read_group_res)
for pos_categ in self:
pos_categ.product_count = group_data.get(pos_categ.id, 0)

View File

@@ -0,0 +1,12 @@
# Copyright 2021 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 PosPaymentMethod(models.Model):
_inherit = 'pos.payment.method'
_check_company_auto = True
cash_journal_id = fields.Many2one(check_company=True)

View File

@@ -0,0 +1,12 @@
# Copyright 2017-2021 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 ProductTemplate(models.Model):
_inherit = 'product.template'
available_in_pos = fields.Boolean(tracking=True)
pos_categ_id = fields.Many2one(tracking=True)

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2021 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="product_pos_category_form_view" model="ir.ui.view">
<field name="name">pos_usability.pos.category.form</field>
<field name="model">pos.category</field>
<field name="inherit_id" ref="point_of_sale.product_pos_category_form_view"/>
<field name="arch" type="xml">
<div class="oe_title" position="before">
<div class="oe_button_box" name="button_box">
<button class="oe_stat_button"
name="%(product.product_template_action_all)d"
icon="fa-th-list"
type="action"
context="{'search_default_pos_categ_id': active_id}">
<div class="o_form_field o_stat_info">
<span class="o_stat_value"><field name="product_count"/></span>
<span class="o_stat_text"> Products</span>
</div>
</button>
</div>
</div>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2021 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_session_form" model="ir.ui.view">
<field name="model">pos.session</field>
<field name="inherit_id" ref="point_of_sale.view_pos_session_form"/>
<field name="arch" type="xml">
<button name="show_journal_items" position="after">
<button name="%(point_of_sale.action_report_pos_order_all)d" type="action" class="oe_stat_button" icon="fa-table" string="Stats" context="{'search_default_session_id': active_id}"/>
</button>
</field>
</record>
<record id="view_pos_session_tree" model="ir.ui.view">
<field name="model">pos.session</field>
<field name="inherit_id" ref="point_of_sale.view_pos_session_tree"/>
<field name="arch" type="xml">
<field name="state" position="attributes">
<attribute name="decoration-success">state == 'opened'</attribute>
</field>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2021 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>
<!-- put option "available in POS" at the top of product form view -->
<record id="product_template_form_view" model="ir.ui.view">
<field name="name">usability.pos.product.template</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="point_of_sale.product_template_form_view"/>
<field name="arch" type="xml">
<xpath expr="//group[@name='pos']//field[@name='available_in_pos']" position="replace"/>
<xpath expr="//div[@name='options']//field[@name='sale_ok']/.." position="after">
<div name="available_in_pos">
<field name="available_in_pos"/>
<label for="available_in_pos"/>
</div>
</xpath>
</field>
</record>
<record id="product_template_search_view" model="ir.ui.view">
<field name="name">pos_usability.product.template.search</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_search_view"/>
<field name="arch" type="xml">
<field name="categ_id" position="after">
<field name="pos_categ_id" filter_domain="[('pos_categ_id', 'child_of', raw_value)]"/>
</field>
<filter name="categ_id" position="after">
<filter name="pos_categ_groupby" string="Point of Sale Category" context="{'group_by': 'pos_categ_id'}"/>
</filter>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2021 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_report_pos_order_search" model="ir.ui.view">
<field name="model">report.pos.order</field>
<field name="inherit_id" ref="point_of_sale.view_report_pos_order_search"/>
<field name="arch" type="xml">
<field name="product_categ_id" position="after">
<field name="session_id"/>
</field>
</field>
</record>
<record id="point_of_sale.action_report_pos_order_all" model="ir.actions.act_window">
<field name="view_mode">pivot,graph</field> <!-- invert native order -->
</record>
</odoo>

View File

@@ -23,7 +23,7 @@
{
'name': 'Product no Translation',
'version': '12.0.0.0.1',
'version': '14.0.1.0.0',
'category': 'Sales Management',
'license': 'AGPL-3',
'summary': 'For companies that work with only one language',
@@ -37,5 +37,5 @@ And it reduces the start time of the Point of Sale !
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['product'],
'installable': False,
'installable': True,
}

View File

@@ -31,13 +31,6 @@ class ProductTemplate(models.Model):
description = fields.Text(translate=False)
name = fields.Char(translate=False)
class ProductCategory(models.Model):
_inherit = "product.category"
name = fields.Char(translate=False)
class ProductAttribute(models.Model):
_inherit = "product.attribute"

View File

@@ -1,3 +1,2 @@
# -*- coding: utf-8 -*-
from . import models
from . import wizard

View File

@@ -17,7 +17,7 @@ This module adds a wizard on product.product form view which allows to generate
* regular product barcode stickers. These stickers will show:
* product name
* product price
* EAN13 barcode
* EAN13 or EAN8 barcode
* price/weight barcode stickers. These stickers will show:
* product name
@@ -26,6 +26,8 @@ This module adds a wizard on product.product form view which allows to generate
* price per kg
* EAN13 barcode
It also allows to generate a private barcode for products without barcode. For that, you must configure the sequence "private.product.barcode". This sequence must be configured to produce 12 digits (for EAN13) or 7 digits (for EAN8) ; the checksum will be added automatically.
This module has been written by Alexis de Lattre from Akretion
<alexis.delattre@akretion.com>.
""",
@@ -43,6 +45,7 @@ This module has been written by Alexis de Lattre from Akretion
'security/ir.model.access.csv',
'wizard/product_print_zpl_barcode_view.xml',
'views/product.xml',
'data/barcode_sequence.xml',
],
'installable': True,
}

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!--
GS1 prefixes : https://www.gs1.org/standards/id-keys/company-prefix
200 - 299 : Used to issue GS1 Restricted Circulation Numbers
within a geographic region (MO defined)
21, 22 and 23 are already used by Odoo for Weight, Price & Discount barcodes
So I use 298 by default
Another option would to be use a small country at the other side of the world,
for example 623 : Brunei
-->
<record id="private_product_barcode_seq" model="ir.sequence">
<field name="name">Private Product Barcode</field>
<field name="code">private.product.barcode</field>
<field name="prefix">298</field>
<field name="padding">9</field>
<field name="number_next">1</field>
<field name="company_id" eval="False"/>
</record>
</data>
</odoo>

View File

@@ -0,0 +1 @@
from . import product

View File

@@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
# Copyright 2020 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.exceptions import UserError
from stdnum.ean import calc_check_digit
class ProductTemplate(models.Model):
_inherit = "product.template"
must_print_barcode = fields.Boolean(
string="Must Print Barcode",
help="Enable that option for products for which you must "
"print a barcode upon reception in stock.")
def generate_barcode_from_product_template(self):
self.ensure_one()
if self.product_variant_count != 1:
raise UserError(_(
"You cannot call the method "
"generate_barcode_from_product_template on product '%s' "
"because it has %d variants and not just one.")
% (self.display_name, self.product_variant_count))
return self.product_variant_ids[0].generate_barcode_from_product_product()
def print_zpl_barcode_from_product_template(self):
self.ensure_one()
if self.product_variant_count != 1:
raise UserError(_(
"You cannot call the method "
"print_zpl_barcode_from_product_template on product '%s' "
"because it has %d variants and not just one.")
% (self.display_name, self.product_variant_count))
action = self.env.ref(
'product_print_zpl_barcode.product_print_zpl_barcode_action').sudo().read()[0]
action['context'] = {
'active_id': self.product_variant_ids[0].id,
'active_model': 'product.product',
}
return action
class ProductProduct(models.Model):
_inherit = 'product.product'
def generate_barcode_from_product_product(self):
self.ensure_one()
if self.barcode:
raise UserError(_(
"The product '%s' already has a barcode.") % self.display_name)
barcode_without_checksum = self.env['ir.sequence'].next_by_code(
'private.product.barcode')
if len(barcode_without_checksum) not in (7, 12):
raise UserError(_(
"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." % len(barcode_without_checksum)))
checksum = calc_check_digit(barcode_without_checksum)
barcode = barcode_without_checksum + str(checksum)
self.write({
'barcode': barcode,
'must_print_barcode': True,
})

View File

@@ -1,20 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2016 Akretion (http://www.akretion.com/)
Copyright 2020-2021 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="product_template_form_view" model="ir.ui.view">
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_form_view"/>
<field name="arch" type="xml">
<div name="options" position="inside">
<div id="must_print_barcode">
<field name="must_print_barcode"/>
<label for="must_print_barcode"/>
</div>
</div>
</field>
</record>
<record id="product_template_only_form_view" model="ir.ui.view">
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_only_form_view"/>
<field name="arch" type="xml">
<header position="inside">
<button name="generate_barcode_from_product_template" type="object" string="Generate Barcode" attrs="{'invisible': ['|', ('product_variant_count', '>', 1), ('barcode', '!=', False)]}"/>
<button name="print_zpl_barcode_from_product_template" type="object" string="Print Barcode" groups="base_report_to_printer.printing_group_user" attrs="{'invisible': ['|', ('product_variant_count', '>', 1), ('barcode', '=', False)]}"/>
</header>
</field>
</record>
<record id="product_normal_form_view" model="ir.ui.view">
<field name="name">generate.weight.price.barcode.product.product.form</field>
<field name="model">product.product</field>
<field name="inherit_id" ref="product.product_normal_form_view" />
<field name="arch" type="xml">
<header position="inside">
<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"/>
<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" groups="base_report_to_printer.printing_group_user" attrs="{'invisible': [('barcode', '=', False)]}"/>
</header>
</field>
</record>

View File

@@ -5,6 +5,7 @@
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.tools import float_compare, float_is_zero
from stdnum.ean import is_valid
import base64
import re
@@ -172,7 +173,8 @@ class ProductPrintZplBarcode(models.TransientModel):
# print "barcode FINAL=", barcode
zpl_unicode = self._price_weight_barcode_type_zpl() % {
'product_name': self.product_name,
'ean13_no_checksum': barcode[:12],
'ean_zpl_command': len(self.barcode) == 8 and 'B8' or 'BE',
'ean_no_checksum': barcode[:-1],
'price_uom': self.price_uom,
'price': self.price,
'currency_symbol': self.currency_id.symbol,
@@ -189,7 +191,7 @@ class ProductPrintZplBarcode(models.TransientModel):
@api.model
def _price_weight_barcode_type_zpl(self):
label = u"""
label = """
^XA
^CI28
^PW304
@@ -201,7 +203,7 @@ class ProductPrintZplBarcode(models.TransientModel):
^FO15,30^FB270,3,0,C^FD%(product_name)s^FS
^CF0,25
^FO15,75^FB270,1,0,C^FD%(quantity).3f %(uom_name)s %(price_uom).2f %(currency_symbol)s/%(uom_name)s^FS
^FO60,110^BEN,50^FD%(ean13_no_checksum)s^FS
^FO60,110^%(ean_zpl_command)sN,50^FD%(ean_no_checksum)s^FS
^PQ%(copies)s
^XZ
"""
@@ -209,7 +211,7 @@ class ProductPrintZplBarcode(models.TransientModel):
@api.model
def _product_barcode_type_zpl(self):
label = u"""
label = """
^XA
^CI28
^PW304
@@ -219,7 +221,7 @@ class ProductPrintZplBarcode(models.TransientModel):
^FO15,0^FB270,1,0,C^FD%(price_uom).2f %(currency_symbol)s^FS
^CF0,20
^FO15,30^FB270,3,0,C^FD%(product_name)s^FS
^FO60,100^BEN,60^FD%(ean13_no_checksum)s^FS
^FO60,100^%(ean_zpl_command)sN,60^FD%(ean_no_checksum)s^FS
^PQ%(copies)s
^XZ
"""
@@ -228,7 +230,8 @@ class ProductPrintZplBarcode(models.TransientModel):
def _prepare_product_barcode_type(self):
zpl_unicode = self._product_barcode_type_zpl() % {
'product_name': self.product_name,
'ean13_no_checksum': self.barcode[:12],
'ean_zpl_command': len(self.barcode) == 8 and 'B8' or 'BE',
'ean_no_checksum': self.barcode[:-1],
'price_uom': self.price_uom,
'currency_symbol': self.currency_id.symbol, # symbol is a required field
'copies': self.copies,
@@ -242,12 +245,16 @@ class ProductPrintZplBarcode(models.TransientModel):
def generate(self):
assert self.barcode
if len(self.barcode) != 13:
if len(self.barcode) not in (8, 13):
raise UserError(_(
"This wizard only supports EAN13 for the moment. Barcode '%s' "
"has %d digits instead of 13") % (
"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'):
@@ -263,7 +270,7 @@ class ProductPrintZplBarcode(models.TransientModel):
'zpl_filename': 'barcode_%s.zpl' % vals['barcode'],
})
self.write(vals)
action = self.env.ref('product_print_zpl_barcode.product_print_zpl_barcode_action').read()[0]
action = self.env.ref('product_print_zpl_barcode.product_print_zpl_barcode_action').sudo().read()[0]
action.update({
'res_id': self.id,
'context': self._context,
@@ -278,7 +285,7 @@ class ProductPrintZplBarcode(models.TransientModel):
self.zpl_filename, base64.decodebytes(self.zpl_file), format='raw')
action = True
if self._context.get('print_and_new'):
action = self.env.ref('product_print_zpl_barcode.product_print_zpl_barcode_action').read()[0]
action = self.env.ref('product_print_zpl_barcode.product_print_zpl_barcode_action').sudo().read()[0]
action.update({
'views': False,
'context': self._context,

View File

@@ -14,25 +14,16 @@ class ProductTemplate(models.Model):
# in v10, that field was defined in procurement_suggest, but we will
# probably not port procurement_suggest because it is native in v14
seller_id = fields.Many2one(
'res.partner', related='seller_ids.name', string='Main Supplier')
'res.partner', related='seller_ids.name', store=True,
string='Main Supplier')
# name = fields.Char(
# track_visibility='onchange')
# type = fields.Selection(
# track_visibility='onchange')
# categ_id = fields.Many2one(
# track_visibility='onchange')
# list_price = fields.Float(
# track_visibility='onchange')
# sale_ok = fields.Boolean(
# track_visibility='onchange')
# purchase_ok = fields.Boolean(
# track_visibility='onchange')
# active = fields.Boolean(
# track_visibility='onchange')
# in v14, I noticed that the tracking of the fields of product.template
# are only shown in the form view of product.template, not in the form
# view of product.product
name = fields.Char(tracking=10)
categ_id = fields.Many2one(tracking=20)
type = fields.Selection(tracking=30)
list_price = fields.Float(tracking=40)
sale_ok = fields.Boolean(tracking=50)
purchase_ok = fields.Boolean(tracking=60)
active = fields.Boolean(tracking=70)

View File

@@ -17,4 +17,15 @@
</field>
</record>
<record id="product_supplierinfo_tree_view" model="ir.ui.view">
<field name="model">product.supplierinfo</field>
<field name="inherit_id" ref="product.product_supplierinfo_tree_view"/>
<field name="arch" type="xml">
<field name="product_code" position="attributes">
<attribute name="optional">show</attribute>
</field>
</field>
</record>
</odoo>

View File

@@ -4,7 +4,7 @@
{
'name': 'Purchase Product Tree Default',
'version': '12.0.1.0.0',
'version': '14.0.1.0.0',
'category': 'Product',
'license': 'AGPL-3',
'summary': 'Tree view by default instead of kanban for Products',
@@ -18,5 +18,5 @@
'data': [
'views/product_template.xml'
],
'installable': False,
'installable': True,
}

View File

@@ -1 +1 @@
from . import purchase
from . import models

View File

@@ -1,10 +1,10 @@
# Copyright (C) 2014-2019 Akretion (http://www.akretion.com)
# Copyright (C) 2014-2021 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': 'Purchase Stock Usability',
'version': '12.0.1.0.0',
'version': '14.0.1.0.0',
'category': 'Purchases',
'license': 'AGPL-3',
'summary': 'Usability improvements on purchase_stock module',
@@ -23,7 +23,8 @@ Please contact Alexis de Lattre from Akretion <alexis.delattre@akretion.com> for
'purchase_usability',
],
'data': [
'stock_view.xml',
'views/purchase_order_views.xml',
'views/stock_picking.xml',
],
'installable': False,
'installable': True,
}

View File

@@ -0,0 +1,105 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * purchase_stock_usability
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-10 09:06+0000\n"
"PO-Revision-Date: 2021-09-10 09:06+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: purchase_stock_usability
#: model:ir.model.fields,field_description:purchase_stock_usability.field_purchase_order__picking_type_id
msgid "Deliver To"
msgstr "Livrer à"
#. module: purchase_stock_usability
#: model:ir.model.fields,field_description:purchase_stock_usability.field_purchase_order__display_name
msgid "Display Name"
msgstr "Nom affiché"
#. module: purchase_stock_usability
#: model:ir.model.fields.selection,name:purchase_stock_usability.selection__purchase_order__picking_status__received
msgid "Fully Received"
msgstr "Entièrement reçue"
#. module: purchase_stock_usability
#: model:ir.model.fields,field_description:purchase_stock_usability.field_purchase_order__id
msgid "ID"
msgstr ""
#. module: purchase_stock_usability
#: model:ir.model.fields,field_description:purchase_stock_usability.field_purchase_order__incoterm_id
msgid "Incoterm"
msgstr ""
#. module: purchase_stock_usability
#: model:ir.model.fields,help:purchase_stock_usability.field_purchase_order__incoterm_id
msgid ""
"International Commercial Terms are a series of predefined commercial terms "
"used in international transactions."
msgstr ""
"Les Incoterms sont une série prédéfinie de termes commerciaux utilisés dans "
"les transactions internationales."
#. module: purchase_stock_usability
#: model:ir.model.fields,field_description:purchase_stock_usability.field_purchase_order____last_update
msgid "Last Modified on"
msgstr "Dernière modification le"
#. module: purchase_stock_usability
#: model:ir.model.fields.selection,name:purchase_stock_usability.selection__purchase_order__picking_status__no
msgid "Nothing to Receive"
msgstr "Rien à recevoir"
#. module: purchase_stock_usability
#: model:ir.model.fields.selection,name:purchase_stock_usability.selection__purchase_order__picking_status__partially_received
msgid "Partially Received"
msgstr "Partiellement reçue"
#. module: purchase_stock_usability
#: model:ir.model.fields,field_description:purchase_stock_usability.field_purchase_order__picking_status
msgid "Picking Status"
msgstr "Statut de la réception"
#. module: purchase_stock_usability
#: model_terms:ir.ui.view,arch_db:purchase_stock_usability.purchase_order_view_search
msgid "Pickings fully received"
msgstr "Entièrement reçues"
#. module: purchase_stock_usability
#: model_terms:ir.ui.view,arch_db:purchase_stock_usability.purchase_order_view_search
msgid "Pickings partially received"
msgstr "Partiellement reçues"
#. module: purchase_stock_usability
#: model_terms:ir.ui.view,arch_db:purchase_stock_usability.purchase_order_view_search
msgid "Pickings to receive"
msgstr "À recevoir"
#. module: purchase_stock_usability
#: model:ir.model,name:purchase_stock_usability.model_purchase_order
msgid "Purchase Order"
msgstr "Commande fournisseur"
#. module: purchase_stock_usability
#: model:ir.model.fields.selection,name:purchase_stock_usability.selection__purchase_order__picking_status__cancel
msgid "Receipt Cancelled"
msgstr "Réception annulée"
#. module: purchase_stock_usability
#: model:ir.model.fields,help:purchase_stock_usability.field_purchase_order__picking_type_id
msgid "This will determine operation type of incoming shipment"
msgstr "Cela déterminera le type d'opération des réceptions"
#. module: purchase_stock_usability
#: model:ir.model.fields.selection,name:purchase_stock_usability.selection__purchase_order__picking_status__to_receive
msgid "To Receive"
msgstr "À recevoir"

View File

@@ -0,0 +1,103 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * purchase_stock_usability
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-10 09:06+0000\n"
"PO-Revision-Date: 2021-09-10 09:06+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: purchase_stock_usability
#: model:ir.model.fields,field_description:purchase_stock_usability.field_purchase_order__picking_type_id
msgid "Deliver To"
msgstr ""
#. module: purchase_stock_usability
#: model:ir.model.fields,field_description:purchase_stock_usability.field_purchase_order__display_name
msgid "Display Name"
msgstr ""
#. module: purchase_stock_usability
#: model:ir.model.fields.selection,name:purchase_stock_usability.selection__purchase_order__picking_status__received
msgid "Fully Received"
msgstr ""
#. module: purchase_stock_usability
#: model:ir.model.fields,field_description:purchase_stock_usability.field_purchase_order__id
msgid "ID"
msgstr ""
#. module: purchase_stock_usability
#: model:ir.model.fields,field_description:purchase_stock_usability.field_purchase_order__incoterm_id
msgid "Incoterm"
msgstr ""
#. module: purchase_stock_usability
#: model:ir.model.fields,help:purchase_stock_usability.field_purchase_order__incoterm_id
msgid ""
"International Commercial Terms are a series of predefined commercial terms "
"used in international transactions."
msgstr ""
#. module: purchase_stock_usability
#: model:ir.model.fields,field_description:purchase_stock_usability.field_purchase_order____last_update
msgid "Last Modified on"
msgstr ""
#. module: purchase_stock_usability
#: model:ir.model.fields.selection,name:purchase_stock_usability.selection__purchase_order__picking_status__no
msgid "Nothing to Receive"
msgstr ""
#. module: purchase_stock_usability
#: model:ir.model.fields.selection,name:purchase_stock_usability.selection__purchase_order__picking_status__partially_received
msgid "Partially Received"
msgstr ""
#. module: purchase_stock_usability
#: model:ir.model.fields,field_description:purchase_stock_usability.field_purchase_order__picking_status
msgid "Picking Status"
msgstr ""
#. module: purchase_stock_usability
#: model_terms:ir.ui.view,arch_db:purchase_stock_usability.purchase_order_view_search
msgid "Pickings fully received"
msgstr ""
#. module: purchase_stock_usability
#: model_terms:ir.ui.view,arch_db:purchase_stock_usability.purchase_order_view_search
msgid "Pickings partially received"
msgstr ""
#. module: purchase_stock_usability
#: model_terms:ir.ui.view,arch_db:purchase_stock_usability.purchase_order_view_search
msgid "Pickings to receive"
msgstr ""
#. module: purchase_stock_usability
#: model:ir.model,name:purchase_stock_usability.model_purchase_order
msgid "Purchase Order"
msgstr ""
#. module: purchase_stock_usability
#: model:ir.model.fields.selection,name:purchase_stock_usability.selection__purchase_order__picking_status__cancel
msgid "Receipt Cancelled"
msgstr ""
#. module: purchase_stock_usability
#: model:ir.model.fields,help:purchase_stock_usability.field_purchase_order__picking_type_id
msgid "This will determine operation type of incoming shipment"
msgstr ""
#. module: purchase_stock_usability
#: model:ir.model.fields.selection,name:purchase_stock_usability.selection__purchase_order__picking_status__to_receive
msgid "To Receive"
msgstr ""

View File

@@ -0,0 +1 @@
from . import purchase

View File

@@ -0,0 +1,64 @@
# Copyright 2015-2021 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 PurchaseOrder(models.Model):
_inherit = 'purchase.order'
picking_type_id = fields.Many2one(tracking=True)
incoterm_id = fields.Many2one(tracking=True)
picking_status = fields.Selection([
('received', 'Fully Received'),
('partially_received', 'Partially Received'),
('to_receive', 'To Receive'),
('cancel', 'Receipt Cancelled'),
('no', 'Nothing to Receive')
], string='Picking Status', compute='_compute_picking_status',
store=True)
@api.depends('state', 'picking_ids.state')
def _compute_picking_status(self):
"""
Compute the picking status for the PO. Possible statuses:
- no: if the PO is not in status 'purchase' nor 'done', we consider that
there is nothing to receive. This is also the default value if the
conditions of no other status is met.
- cancel: all pickings are cancelled
- received: if all pickings are done or cancel.
- partially_received: If at least one picking is done.
- to_receive: if all pickings are in confirmed, assigned, waiting or
cancel state.
"""
for order in self:
picking_status = 'no'
if order.state in ('purchase', 'done') and order.picking_ids:
pstates = [
picking.state for picking in order.picking_ids]
if all([state == 'cancel' for state in pstates]):
picking_status = 'cancel'
elif all([state in ('done', 'cancel') for state in pstates]):
picking_status = 'received'
elif any([state == 'done' for state in pstates]):
picking_status = 'partially_received'
elif all([
state in ('confirmed', 'assigned', 'waiting', 'cancel')
for state in pstates]):
picking_status = 'to_receive'
order.picking_status = picking_status
# inherit compute method of the field delivery_partner_id
# defined in purchase_usability
@api.depends('dest_address_id', 'picking_type_id')
def _compute_delivery_partner_id(self):
for o in self:
delivery_partner_id = False
if o.dest_address_id:
delivery_partner_id = o.dest_address_id
elif (
o.picking_type_id.warehouse_id and
o.picking_type_id.warehouse_id.partner_id):
delivery_partner_id = o.picking_type_id.warehouse_id.partner_id
o.delivery_partner_id = delivery_partner_id

View File

@@ -1,27 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2015-2019 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, fields, api
class PurchaseOrder(models.Model):
_inherit = 'purchase.order'
picking_type_id = fields.Many2one(track_visibility='onchange')
incoterm_id = fields.Many2one(track_visibility='onchange')
# inherit compute method of the field delivery_partner_id
# defined in purchase_usability
@api.depends('dest_address_id', 'picking_type_id')
def _compute_delivery_partner_id(self):
for o in self:
delivery_partner_id = False
if o.dest_address_id:
delivery_partner_id = o.dest_address_id
elif (
o.picking_type_id.warehouse_id and
o.picking_type_id.warehouse_id.partner_id):
delivery_partner_id = o.picking_type_id.warehouse_id.partner_id
o.delivery_partner_id = delivery_partner_id

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="purchase_order_view_tree" model="ir.ui.view">
<field name="name">purchase.order.view.tree (in purchase_stock_usability)</field>
<field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_view_tree"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='invoice_status']" position="before">
<field name="picking_status" decoration-success="picking_status == 'received'" decoration-info="picking_status == 'to_receive'" decoration-warning="picking_status == 'partially_received'" decoration-danger="picking_status == 'cancel'" widget="badge" optional="show"/>
</xpath>
</field>
</record>
<record id="purchase_order_view_search" model="ir.ui.view">
<field name="name">purchase.order.select (in purchase_stock_usability)</field>
<field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_view_search"/>
<field name="arch" type="xml">
<xpath expr="//filter[@name='order_date']" position="before">
<filter name="received" string="Pickings fully received" domain="[('picking_status', '=', 'received')]"/>
<filter name="partially_received" string="Pickings partially received" domain="[('picking_status', '=', 'partially_received')]"/>
<filter name="to_receive" string="Pickings to receive" domain="[('picking_status', '=', 'to_receive')]"/>
<separator/>
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,14 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2017-2019 Akretion (http://www.akretion.com/)
Copyright 2017-2021 Akretion (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_picking_form" model="ir.ui.view">
<field name="name">purchase_usability.stock.picking.form</field>
<field name="name">purchase_stock_usability.stock.picking.form</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_form"/>
<field name="arch" type="xml">

View File

@@ -24,11 +24,6 @@ class PurchaseOrder(models.Model):
for order in self:
order.delivery_partner_id = order.dest_address_id
def print_order(self):
report = self.env.ref('purchase.action_report_purchase_order')
action = report.report_action(self)
return action
# Re-write native name_get() to use amount_untaxed instead of amount_total
@api.depends('name', 'partner_ref')
def name_get(self):
@@ -42,3 +37,39 @@ class PurchaseOrder(models.Model):
self.env, po.amount_untaxed, currency_obj=po.currency_id)
result.append((po.id, name))
return result
# for report
def py3o_lines_layout(self):
self.ensure_one()
res = []
has_sections = False
subtotal = 0.0
for line in self.order_line:
if line.display_type == 'line_section':
# insert line
if has_sections:
res.append({'subtotal': subtotal})
subtotal = 0.0 # reset counter
has_sections = True
else:
if not line.display_type:
subtotal += line.price_subtotal
res.append({'line': line})
if has_sections: # insert last subtotal line
res.append({'subtotal': subtotal})
# res:
# [
# {'line': sale_order_line(1) with display_type=='line_section'},
# {'line': sale_order_line(2) without display_type},
# {'line': sale_order_line(3) without display_type},
# {'line': sale_order_line(4) with display_type=='line_note'},
# {'subtotal': 8932.23},
# ]
return res
class PurchaseOrderLine(models.Model):
_inherit = 'purchase.order.line'
# for optional display in tree view
product_barcode = fields.Char(related='product_id.barcode', string="Product Barcode")

View File

@@ -14,7 +14,7 @@
<field name="inherit_id" ref="purchase.purchase_order_form"/>
<field name="arch" type="xml">
<button name="action_rfq_send" states="purchase" position="after">
<button name="print_order" states="purchase" string="Print Order" type="object"/>
<button name="%(purchase.action_report_purchase_order)d" states="purchase,done" string="Print" type="action"/>
</button>
<field name="fiscal_position_id" position="attributes">
<attribute name="widget">selection</attribute>
@@ -34,6 +34,9 @@
<xpath expr="//field[@name='order_line']/form//field[@name='analytic_tag_ids']" position="attributes">
<attribute name="groups">analytic.group_analytic_tags</attribute>
</xpath>
<xpath expr="//field[@name='order_line']/tree//field[@name='product_id']" position="after">
<field name="product_barcode" optional="hide"/>
</xpath>
</field>
</record>

View File

@@ -0,0 +1,2 @@
from . import models
from . import wizard

View File

@@ -0,0 +1,38 @@
# Copyright 2017-2021 Akretion France (http://www.akretion.com/)
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Sale Confirm Wizard',
'version': '14.0.1.0.0',
'category': 'Sales',
'license': 'AGPL-3',
'summary': 'Open a wizard when you confirm a sale order to update important info',
'description': """
Sale Confirm Wizard
===================
When you confirm a quotation, Odoo will open a small wizard where you will be able to check and update important information:
* customer PO number,
* delivery address,
* invoicing address,
* payment terms.
It will also display the sale warning if the customer's company has one. And it is a blocker warning, the user won't be able to confirm the quotation.
This module has been developped because the experience has shown, when a sales assistant confirms a quotation in Odoo, it overlooks the important information written in the customer PO that may be different from the information of the quotation in Odoo, which causes many errors in delivery and invoicing.
This module has been written by Alexis de Lattre from Akretion
<alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['sale'],
'data': [
'wizard/sale_confirm_view.xml',
'views/sale_order.xml',
'security/ir.model.access.csv',
],
'installable': True,
}

View File

@@ -0,0 +1 @@
from . import sale_order

View File

@@ -0,0 +1,17 @@
# Copyright 2020-2021 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 SaleOrder(models.Model):
_inherit = 'sale.order'
def sale_confirm_wizard_button(self):
"""This method is designed to be inherited.
For example, inherit it if you don't want to start the wizard in
some scenarios"""
action = self.sudo().env.ref(
'sale_confirm_wizard.sale_confirm_action').read()[0]
return action

View File

@@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sale_confirm_wizard,Full access on sale.confirm wizard,model_sale_confirm,sales_team.group_sale_salesman,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_sale_confirm_wizard Full access on sale.confirm wizard model_sale_confirm sales_team.group_sale_salesman 1 1 1 1

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017-2021 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_form" model="ir.ui.view">
<field name="name">sale.confirm.wizard.sale_order_form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<button id="action_confirm" position="attributes">
<attribute name="name">sale_confirm_wizard_button</attribute>
</button>
<button name="action_confirm" attrs="{'invisible': [('state', 'not in', ['draft'])]}" position="attributes">
<attribute name="name">sale_confirm_wizard_button</attribute>
</button>
</field>
</record>
</odoo>

View File

@@ -0,0 +1 @@
from . import sale_confirm

View File

@@ -0,0 +1,78 @@
# Copyright 2017-2021 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, fields, api, _
from odoo.exceptions import UserError
from odoo.addons.base.models.res_partner import WARNING_MESSAGE
class SaleConfirm(models.TransientModel):
_name = 'sale.confirm'
_description = 'Wizard to confirm a sale order'
sale_id = fields.Many2one(
'sale.order', string='Sale Order', readonly=True)
client_order_ref = fields.Char(string='Customer PO Number')
payment_term_id = fields.Many2one(
'account.payment.term', string='Payment Terms')
partner_invoice_id = fields.Many2one(
'res.partner', 'Invoice Address', required=True)
show_partner_invoice_id = fields.Many2one(
related='partner_invoice_id',
string='Detailed Invoice Address')
partner_shipping_id = fields.Many2one(
'res.partner', 'Delivery Address', required=True)
show_partner_shipping_id = fields.Many2one(
related='partner_shipping_id',
string='Detailed Delivery Address')
sale_warn = fields.Selection(
WARNING_MESSAGE, 'Sale Warning Type', readonly=True)
sale_warn_msg = fields.Text(string='Sale Warning Message', readonly=True)
@api.model
def _prepare_default_get(self, order):
partner = order.partner_id.commercial_partner_id
default = {
'sale_id': order.id,
'client_order_ref': order.client_order_ref,
'payment_term_id': order.payment_term_id.id or False,
'partner_invoice_id': order.partner_invoice_id.id,
'partner_shipping_id': order.partner_shipping_id.id,
'sale_warn_msg': partner.sale_warn_msg,
'sale_warn': partner.sale_warn,
}
return default
@api.model
def default_get(self, fields):
res = super().default_get(fields)
assert self._context.get('active_model') == 'sale.order',\
'active_model should be sale.order'
order = self.env['sale.order'].browse(self._context.get('active_id'))
default = self._prepare_default_get(order)
res.update(default)
return res
def _prepare_update_so(self):
self.ensure_one()
return {
'client_order_ref': self.client_order_ref,
'payment_term_id': self.payment_term_id.id or False,
'partner_invoice_id': self.partner_invoice_id.id,
'partner_shipping_id': self.partner_shipping_id.id,
}
def confirm(self):
self.ensure_one()
partner = self.sale_id.partner_id.commercial_partner_id
if partner.sale_warn == 'block':
raise UserError(_(
"You cannot confirm this quotation because "
"customer '%s' has a blocker sale warning:\n\n%s")
% (partner.display_name, partner.sale_warn_msg))
vals = self._prepare_update_so()
self.sale_id.write(vals)
# confirm sale order
self.sale_id.action_confirm()
return True

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017-2021 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_confirm_form" model="ir.ui.view">
<field name="name">sale.confirm.form</field>
<field name="model">sale.confirm</field>
<field name="arch" type="xml">
<form string="Confirm Order">
<div><p>At this stage, you have received the Purchase Order from the customer and you are about to convert the related quotation to an order.</p></div>
<group name="warn" groups="sale.group_warning_sale" attrs="{'invisible': ['|', ('sale_warn', '=', False), ('sale_warn', '=', 'no-message')]}" string="Warning" col="4">
<field name="sale_warn" nolabel="1"/>
<field name="sale_warn_msg" nolabel="1" colspan="3"/>
</group>
<group name="main" attrs="{'invisible': [('sale_warn', '=', 'block')]}">
<field name="sale_id" invisible="1"/>
<field name="client_order_ref"/>
<field name="partner_invoice_id" context="{'default_type': 'invoice'}"
groups="sale.group_delivery_invoice_address"/>
<!-- partner_invoice_id can't show the full address because
we are in edit mode -->
<field name="show_partner_invoice_id" options="{'always_reload': True}"
context="{'show_address': 1}"
groups="sale.group_delivery_invoice_address"/>
<field name="partner_shipping_id"
context="{'default_type': 'delivery'}"
groups="sale.group_delivery_invoice_address"/>
<field name="show_partner_shipping_id" options="{'always_reload': True}"
context="{'show_address': 1}"
groups="sale.group_delivery_invoice_address"/>
<field name="payment_term_id"/>
</group>
<footer>
<button type="object" name="confirm"
string="Confirm Sale" class="btn-primary" attrs="{'invisible': [('sale_warn', '=', 'block')]}"/>
<button special="cancel" string="Annuler" class="btn-default"/>
</footer>
</form>
</field>
</record>
<record id="sale_confirm_action" model="ir.actions.act_window">
<field name="name">Confirm Order</field>
<field name="res_model">sale.confirm</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</odoo>

View File

@@ -18,10 +18,8 @@
},
"depends": [
"sale_management",
"sale_product_configurator"
],
"data": [
"views/product_template_view.xml",
"views/sale_order_view.xml",
],
"demo": [

View File

@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="product_template_view_form" model="ir.ui.view">
<field name="model">product.template</field>
<field name="inherit_id" ref="sale.product_template_form_view"/>
<field name="arch" type="xml">
<group name="options" position="attributes">
<attribute name="invisible"/>
</group>
</field>
</record>
</odoo>

View File

@@ -1,3 +1 @@
# -*- coding: utf-8 -*-
from . import models

View File

@@ -1,10 +1,10 @@
# Copyright 2019 Akretion France (http://www.akretion.com/)
# Copyright 2019-2021 Akretion France (http://www.akretion.com/)
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Sale Order Route',
'version': '12.0.1.0.0',
'version': '14.0.1.0.0',
'category': 'Sales',
'license': 'AGPL-3',
'summary': 'Set route on sale order',
@@ -18,5 +18,5 @@ This module has been written by Alexis de Lattre from Akretion
'website': 'http://www.akretion.com',
'depends': ['sale_stock'],
'data': ['views/sale_order.xml'],
'installable': False,
'installable': True,
}

View File

@@ -1,3 +1 @@
# -*- coding: utf-8 -*-
from . import sale_order

View File

@@ -1,4 +1,4 @@
# Copyright 2019 Akretion France (http://www.akretion.com/)
# Copyright 2019-2021 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).
@@ -10,17 +10,17 @@ class SaleOrder(models.Model):
route_id = fields.Many2one(
'stock.location.route', string='Route',
ondelete='restrict', readonly=True, track_visibility='onchange',
ondelete='restrict', readonly=True, tracking=True,
states={'draft': [('readonly', False)], 'sent': [('readonly', False)]},
domain=[('sale_selectable', '=', True)])
check_company=True,
domain="['|', ('company_id', '=', company_id), ('company_id', '=', False), ('sale_selectable', '=', True)]")
def _action_confirm(self):
# Caution: take into account the scenario where
# route_id has a value, then SO is cancelled+back to draft,
# then route_id = False and SO is confirmed again
# Takes into account the scenario where route_id has a value, then SO is
# cancelled+back to draft, then route_id = False and SO is confirmed again
for order in self:
vals = {'route_id': order.route_id.id or False}
order.order_line.filtered(
lambda l:
l.product_id.type in ('product', 'consu')).write(vals)
super(SaleOrder, self)._action_confirm()
l.product_id and l.product_id.type in ('product', 'consu')).write(vals)
return super()._action_confirm()

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2019 Akretion France (http://www.akretion.com/)
Copyright 2019-2021 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).
-->

View File

@@ -4,7 +4,7 @@
{
'name': 'Sale Product Tree Default',
'version': '12.0.1.0.0',
'version': '14.0.1.0.0',
'category': 'Product',
'license': 'AGPL-3',
'summary': 'Tree view by default instead of kanban for Products',
@@ -18,5 +18,5 @@
'data': [
'views/product_template.xml'
],
'installable': False,
'installable': True,
}

View File

@@ -4,7 +4,7 @@
<record id="sale.product_template_action" model="ir.actions.act_window">
<field name="view_mode">tree,form,kanban,activity</field>
<field name="view_id" ref="product.product_template_tree_view"/>
<field name="view_id" eval="False"/>
</record>
</odoo>

Some files were not shown because too many files have changed in this diff Show More