Compare commits

..

18 Commits

Author SHA1 Message Date
clementmbr
45500f5bd8 product_usability: Improve filter domain on supplier product names 2021-09-03 15:25:55 +02: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
43 changed files with 611 additions and 112 deletions

View File

@@ -123,7 +123,11 @@ class AccountMove(models.Model):
has_sections = False
subtotal = 0.0
sign = self.move_type == 'out_refund' and -1 or 1
for line in self.invoice_line_ids:
# 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:

View File

@@ -18,6 +18,12 @@
<field name="invoice_incoterm_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<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="after">

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

@@ -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

@@ -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

@@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-02-17 16:55+0000\n"
"PO-Revision-Date: 2021-02-17 16:55+0000\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"

View File

@@ -6,9 +6,9 @@ msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-02-17 16:55+0000\n"
"PO-Revision-Date: 2021-02-17 16:55+0000\n"
"Last-Translator: \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"
@@ -33,16 +33,15 @@ msgstr "Sociétés"
#. module: base_usability
#: model:ir.model,name:base_usability.model_res_partner
msgid "Contact"
msgstr ""
msgstr "Contact"
#. module: base_usability
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
msgid "Currency"
msgstr "Monnaie"
msgstr "Devise"
#. 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 "N° client :"
@@ -68,7 +67,7 @@ msgstr "E-mail :"
#. module: base_usability
#: model_terms:ir.ui.view,arch_db:base_usability.res_country_search
msgid "Group By"
msgstr ""
msgstr "Grouper par"
#. module: base_usability
#: model:ir.model.fields,field_description:base_usability.field_ir_mail_server__id
@@ -79,12 +78,12 @@ msgstr ""
#: 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 ""
msgstr "ID"
#. module: base_usability
#: model_terms:ir.ui.view,arch_db:base_usability.view_module_filter
msgid "Installable"
msgstr ""
msgstr "Installable"
#. module: base_usability
#: model:ir.model.fields,field_description:base_usability.field_ir_mail_server____last_update
@@ -100,7 +99,7 @@ msgstr "Dernière modification le"
#. module: base_usability
#: model:ir.model,name:base_usability.model_ir_mail_server
msgid "Mail Server"
msgstr "Serveur d'email"
msgstr "Serveur mail"
#. module: base_usability
#: code:addons/base_usability/models/res_partner.py:0
@@ -132,7 +131,7 @@ msgstr "Nom avec titre"
#. module: base_usability
#: model:res.groups,name:base_usability.group_nobody
msgid "Nobody (used to hide native menus)"
msgstr ""
msgstr "Personne (utilisé pour cacher des entrées de menu natifs)"
#. module: base_usability
#: model:ir.model,name:base_usability.model_res_partner_category
@@ -152,7 +151,6 @@ 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 "N° fournisseur :"

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

@@ -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(

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

@@ -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

@@ -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,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,7 +12,7 @@
<field name="inherit_id" ref="product.product_supplierinfo_search_view"/>
<field name="arch" type="xml">
<field name="product_tmpl_id" position="after">
<field name="product_code"/>
<field name="product_name" filter_domain="['|', ('product_code', 'ilike', self), ('product_name', 'ilike', self)]" />
</field>
</field>
</record>

View File

@@ -10,3 +10,17 @@ class PurchaseOrder(models.Model):
picking_type_id = fields.Many2one(tracking=True)
incoterm_id = fields.Many2one(tracking=True)
# 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

@@ -14,11 +14,15 @@ class PurchaseOrder(models.Model):
payment_term_id = fields.Many2one(tracking=True)
fiscal_position_id = fields.Many2one(tracking=True)
partner_ref = fields.Char(tracking=True)
# the field 'delivery_partner_id' is used in report
# the compute method of that field is inherited in purchase_stock_usability
delivery_partner_id = fields.Many2one(
'res.partner', compute='_compute_delivery_partner_id')
def print_order(self):
report = self.env.ref('purchase.action_report_purchase_order')
action = report.report_action(self)
return action
@api.depends('dest_address_id')
def _compute_delivery_partner_id(self):
for order in self:
order.delivery_partner_id = order.dest_address_id
# Re-write native name_get() to use amount_untaxed instead of amount_total
@api.depends('name', 'partner_ref')

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>

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

@@ -26,6 +26,9 @@
<field name="date_order" position="after">
<field name="client_order_ref"/>
</field>
<button name="action_quotation_send" states="sent,sale" position="after">
<button name="%(sale.action_report_saleorder)d" type="action" string="Print" states="draft,sent,sale,done"/>
</button>
<xpath expr="//field[@name='order_line']/tree/field[@name='product_template_id']" position="after">
<field name="product_barcode" optional="hide"/>
</xpath>

View File

@@ -3,6 +3,7 @@ from . import stock_picking
from . import stock_location_route
from . import stock_warehouse_orderpoint
from . import stock_quant
from . import stock_inventory
from . import procurement_group
from . import procurement_scheduler_log
from . import product

View File

@@ -0,0 +1,11 @@
# Copyright 2021 Akretion France (http://www.akretion.com/)
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
class StockInventoryLine(models.Model):
_inherit = 'stock.inventory.line'
product_barcode = fields.Char(related='product_id.barcode', string="Product Barcode")

View File

@@ -2,12 +2,14 @@
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models
from odoo import fields, models
class StockQuant(models.Model):
_inherit = 'stock.quant'
product_barcode = fields.Char(related='product_id.barcode', string="Product Barcode")
def action_stock_move_lines_reserved(self):
self.ensure_one()
action = self.action_view_stock_moves()

View File

@@ -12,6 +12,9 @@
<field name="model">stock.inventory.line</field>
<field name="inherit_id" ref="stock.stock_inventory_line_tree"/>
<field name="arch" type="xml">
<field name="product_id" position="after">
<field name="product_barcode" optional="hide"/>
</field>
<tree position="attributes">
<!-- native :
decoration-danger="product_qty != theoretical_qty"
@@ -27,16 +30,4 @@
</field>
</record>
<record id="view_inventory_tree" model="ir.ui.view">
<field name="name">usability.stock.inventory.tree</field>
<field name="model">stock.inventory</field>
<field name="inherit_id" ref="stock.view_inventory_tree"/>
<field name="arch" type="xml">
<tree position="attributes">
<attribute name="decoration-info">state == 'draft'</attribute>
<attribute name="decoration-warning">state == 'confirm'</attribute>
</tree>
</field>
</record>
</odoo>

View File

@@ -13,6 +13,9 @@
<field name="model">stock.quant</field>
<field name="inherit_id" ref="stock.view_stock_quant_tree"/>
<field name="arch" type="xml">
<field name="product_id" position="after">
<field name="product_barcode" optional="hide"/>
</field>
<field name="quantity" position="attributes">
<attribute name="sum">1</attribute>
</field>