[ADD] base: model ir.default to store user-defined defaults
This commit is contained in:
@@ -684,15 +684,13 @@ class AccountTax(models.Model):
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
company_id = self.env.user.company_id.id
|
||||
ir_values = self.env['ir.values']
|
||||
supplier_taxes_id = set(ir_values.get_default('product.template', 'supplier_taxes_id', company_id=company_id) or [])
|
||||
deleted_sup_tax = self.filtered(lambda tax: tax.id in supplier_taxes_id)
|
||||
if deleted_sup_tax:
|
||||
ir_values.sudo().set_default('product.template', "supplier_taxes_id", list(supplier_taxes_id - set(deleted_sup_tax.ids)), for_all_users=True, company_id=company_id)
|
||||
taxes_id = set(self.env['ir.values'].get_default('product.template', 'taxes_id', company_id=company_id) or [])
|
||||
deleted_tax = self.filtered(lambda tax: tax.id in taxes_id)
|
||||
if deleted_tax:
|
||||
ir_values.sudo().set_default('product.template', "taxes_id", list(taxes_id - set(deleted_tax.ids)), for_all_users=True, company_id=company_id)
|
||||
IrDefault = self.env['ir.default']
|
||||
taxes = self.browse(IrDefault.get('product.template', 'taxes_id', company_id=company_id) or [])
|
||||
if self & taxes:
|
||||
IrDefault.sudo().set('product.template', 'taxes_id', (taxes - self).ids, company_id=company_id)
|
||||
taxes = self.browse(IrDefault.get('product.template', 'supplier_taxes_id', company_id=company_id) or [])
|
||||
if self & taxes:
|
||||
IrDefault.sudo().set('product.template', 'supplier_taxes_id', (taxes - self).ids, company_id=company_id)
|
||||
return super(AccountTax, self).unlink()
|
||||
|
||||
@api.one
|
||||
|
||||
@@ -82,9 +82,9 @@ class AccountConfigSettings(models.TransientModel):
|
||||
if self.group_multi_currency:
|
||||
self.env.ref('base.group_user').write({'implied_ids': [(4, self.env.ref('product.group_sale_pricelist').id)]})
|
||||
""" Set the product taxes if they have changed """
|
||||
ir_values_obj = self.env['ir.values']
|
||||
ir_values_obj.sudo().set_default('product.template', "taxes_id", [self.default_sale_tax_id.id] if self.default_sale_tax_id else False, for_all_users=True, company_id=self.company_id.id)
|
||||
ir_values_obj.sudo().set_default('product.template', "supplier_taxes_id", [self.default_purchase_tax_id.id] if self.default_purchase_tax_id else False, for_all_users=True, company_id=self.company_id.id)
|
||||
IrDefault = self.env['ir.default'].sudo()
|
||||
IrDefault.set('product.template', "taxes_id", self.default_sale_tax_id.ids, company_id=self.company_id.id)
|
||||
IrDefault.set('product.template', "supplier_taxes_id", self.default_purchase_tax_id.ids, company_id=self.company_id.id)
|
||||
""" install a chart of accounts for the given company (if required) """
|
||||
if self.chart_template_id and self.chart_template_id != self.company_id.chart_template_id:
|
||||
wizard = self.env['wizard.multi.charts.accounts'].create({
|
||||
|
||||
@@ -876,7 +876,6 @@ class WizardMultiChartsAccounts(models.TransientModel):
|
||||
res.unlink()
|
||||
existing_accounts.unlink()
|
||||
|
||||
ir_values_obj = self.env['ir.values']
|
||||
company = self.company_id
|
||||
self.company_id.write({'currency_id': self.currency_id.id,
|
||||
'accounts_code_digits': self.code_digits,
|
||||
@@ -903,10 +902,11 @@ class WizardMultiChartsAccounts(models.TransientModel):
|
||||
acc_template_ref, taxes_ref = self.chart_template_id._install_template(company, code_digits=self.code_digits, transfer_account_id=self.transfer_account_id)
|
||||
|
||||
# write values of default taxes for product as super user
|
||||
IrDefault = self.env['ir.default']
|
||||
if self.sale_tax_id and taxes_ref:
|
||||
ir_values_obj.sudo().set_default('product.template', "taxes_id", [taxes_ref[self.sale_tax_id.id]], for_all_users=True, company_id=company.id)
|
||||
IrDefault.sudo().set('product.template', "taxes_id", [taxes_ref[self.sale_tax_id.id]], company_id=company.id)
|
||||
if self.purchase_tax_id and taxes_ref:
|
||||
ir_values_obj.sudo().set_default('product.template', "supplier_taxes_id", [taxes_ref[self.purchase_tax_id.id]], for_all_users=True, company_id=company.id)
|
||||
IrDefault.sudo().set('product.template', "supplier_taxes_id", [taxes_ref[self.purchase_tax_id.id]], company_id=company.id)
|
||||
|
||||
# Create Bank journals
|
||||
self._create_bank_journals_from_o2m(company, acc_template_ref)
|
||||
|
||||
@@ -199,7 +199,7 @@ class IrHttp(models.AbstractModel):
|
||||
|
||||
@classmethod
|
||||
def _get_default_lang(cls):
|
||||
lang_code = request.env['ir.values'].sudo().get_default('res.partner', 'lang')
|
||||
lang_code = request.env['ir.default'].sudo().get('res.partner', 'lang')
|
||||
if lang_code:
|
||||
return request.env['res.lang'].search([('code', '=', lang_code)], limit=1)
|
||||
return request.env['res.lang'].search([], limit=1)
|
||||
|
||||
@@ -540,14 +540,6 @@ http://kjs.mof.gov.cn/zhengwuxinxi/zhengcefabu/201111/t20111107_605525.html
|
||||
<field name="expense_currency_exchange_account_id" ref="small_business_chart5712"/>
|
||||
</record>
|
||||
|
||||
<record id="l10n_chart_china_small_business_value" model="ir.values">
|
||||
<field name="name">小企业会计科目表(财会[2011]17号《小企业会计准则》)</field>
|
||||
<field name="model">account.chart.template</field>
|
||||
<field name="key">default</field>
|
||||
<field name="res_id" ref="l10n_chart_china_small_business"/>
|
||||
<field name="value" ref="base.CNY"/>
|
||||
</record>
|
||||
|
||||
<!-- Account Tax Tags-->
|
||||
<record id="tax_tag1" model="account.account.tag">
|
||||
<field name="name">增值税17%销项税</field>
|
||||
|
||||
@@ -10,12 +10,5 @@
|
||||
<field name="income_currency_exchange_account_id" ref="account_6061" />
|
||||
<field name="expense_currency_exchange_account_id" ref="account_6061" />
|
||||
</record>
|
||||
<record id="l10n_chart_china_standard_business_value" model="ir.values">
|
||||
<field name="name">中国会计科目表 (财会[2006]3号《企业会计准则》)</field>
|
||||
<field name="model">account.chart.template</field>
|
||||
<field name="key">default</field>
|
||||
<field name="res_id" ref="l10n_chart_china_standard_business" />
|
||||
<field name="value" ref="base.CNY" />
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -31,7 +31,7 @@ class WebsitePayment(http.Controller):
|
||||
|
||||
# Try default one then fallback on first
|
||||
acquirer_id = acquirer_id and int(acquirer_id) or \
|
||||
env['ir.values'].get_default('payment.transaction', 'acquirer_id', company_id=user.company_id.id) or \
|
||||
env['ir.default'].get('payment.transaction', 'acquirer_id', company_id=user.company_id.id) or \
|
||||
env['payment.acquirer'].search([('website_published', '=', True), ('company_id', '=', user.company_id.id)])[0].id
|
||||
|
||||
acquirer = env['payment.acquirer'].with_context(submit_class='btn btn-primary pull-right',
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<data noupdate="1">
|
||||
|
||||
<function id="purchase_default_set"
|
||||
model="ir.values" name="set_default"
|
||||
model="ir.default" name="set"
|
||||
eval="('purchase.requisition', 'warehouse_id', ref('stock.warehouse0'))"/>
|
||||
|
||||
<record id="type_single" model="purchase.requisition.type">
|
||||
|
||||
@@ -38,7 +38,7 @@ class Website(models.Model):
|
||||
return self.env['res.lang'].search([]).ids
|
||||
|
||||
def _default_language(self):
|
||||
lang_code = self.env['ir.values'].get_default('res.partner', 'lang')
|
||||
lang_code = self.env['ir.default'].get('res.partner', 'lang')
|
||||
def_lang = self.env['res.lang'].search([('code', '=', lang_code)], limit=1)
|
||||
return def_lang.id if def_lang else self._active_languages()[0]
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ class Website(models.Model):
|
||||
values = super(Website, self)._prepare_sale_order_values(partner, pricelist)
|
||||
if values['company_id']:
|
||||
warehouse_id = (
|
||||
self.env['ir.values'].get_default('sale.order', 'warehouse_id', company_id=values.get('company_id')) or
|
||||
self.env['ir.values'].get_default('sale.order', 'warehouse_id') or
|
||||
self.env['ir.default'].get('sale.order', 'warehouse_id', company_id=values.get('company_id')) or
|
||||
self.env['ir.default'].get('sale.order', 'warehouse_id') or
|
||||
self.env['stock.warehouse'].sudo().search([('company_id', '=', values['company_id'])], limit=1).id
|
||||
)
|
||||
if warehouse_id:
|
||||
|
||||
@@ -18,14 +18,14 @@ class WebsiteConfigSettings(models.TransientModel):
|
||||
@api.multi
|
||||
def set_values(self):
|
||||
super(WebsiteConfigSettings, self).set_values()
|
||||
self.env['ir.values'].sudo().set_default('product.template', 'inventory_availability', self.inventory_availability)
|
||||
self.env['ir.values'].sudo().set_default('product.template', 'available_threshold', self.available_threshold if self.inventory_availability == 'threshold' else None)
|
||||
IrDefault = self.env['ir.default'].sudo()
|
||||
IrDefault.set('product.template', 'inventory_availability', self.inventory_availability)
|
||||
IrDefault.set('product.template', 'available_threshold', self.available_threshold if self.inventory_availability == 'threshold' else None)
|
||||
|
||||
@api.model
|
||||
def get_values(self):
|
||||
res = super(WebsiteConfigSettings, self).get_values()
|
||||
param = self.env['ir.values'].sudo()
|
||||
res.update(inventory_availability=param.get_default('product.template', 'inventory_availability') or 'never',
|
||||
available_threshold=param.get_default('product.template', 'available_threshold') or 5.0
|
||||
)
|
||||
IrDefault = self.env['ir.default'].sudo()
|
||||
res.update(inventory_availability=IrDefault.get('product.template', 'inventory_availability') or 'never',
|
||||
available_threshold=IrDefault.get('product.template', 'available_threshold') or 5.0)
|
||||
return res
|
||||
|
||||
@@ -33,6 +33,7 @@ The kernel of Odoo, needed for all installation.
|
||||
'ir/ir_ui_menu_view.xml',
|
||||
'ir/ir_ui_view_view.xml',
|
||||
'ir/ir_values_view.xml',
|
||||
'ir/ir_default_view.xml',
|
||||
'ir/ir_autovacuum.xml',
|
||||
'ir/ir_model_report.xml',
|
||||
'ir/report_ir_model.xml',
|
||||
|
||||
@@ -11,6 +11,7 @@ from . import ir_attachment
|
||||
from . import ir_cron
|
||||
from . import ir_filters
|
||||
from . import ir_values
|
||||
from . import ir_default
|
||||
from . import ir_translation
|
||||
from . import ir_exports
|
||||
from . import ir_rule
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import json
|
||||
|
||||
from odoo import api, fields, models, tools, _
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class IrDefault(models.Model):
|
||||
""" User-defined default values for fields. """
|
||||
_name = 'ir.default'
|
||||
_rec_name = 'field_id'
|
||||
|
||||
field_id = fields.Many2one('ir.model.fields', string="Field", required=True,
|
||||
ondelete='cascade', index=True)
|
||||
user_id = fields.Many2one('res.users', string='User', ondelete='cascade', index=True,
|
||||
help="If set, action binding only applies for this user.")
|
||||
company_id = fields.Many2one('res.company', string='Company', ondelete='cascade', index=True,
|
||||
help="If set, action binding only applies for this company")
|
||||
condition = fields.Char('Condition', help="If set, applies the default upon condition.")
|
||||
json_value = fields.Char('Default Value (JSON format)', required=True)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
self.clear_caches()
|
||||
return super(IrDefault, self).create(vals)
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
if self:
|
||||
self.clear_caches()
|
||||
return super(IrDefault, self).write(vals)
|
||||
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
if self:
|
||||
self.clear_caches()
|
||||
return super(IrDefault, self).unlink()
|
||||
|
||||
@api.model
|
||||
def set(self, model_name, field_name, value, user_id=False, company_id=False, condition=False):
|
||||
""" Defines a default value for the given field. Any entry for the same
|
||||
scope (field, user, company) will be replaced. The value is encoded
|
||||
in JSON to be stored to the database.
|
||||
|
||||
:param user_id: may be ``False`` for all users, ``True`` for the
|
||||
current user, or any user id
|
||||
:param company_id: may be ``False`` for all companies, ``True`` for
|
||||
the current user's company, or any company id
|
||||
:param condition: optional condition that restricts the
|
||||
applicability of the default value; this is an
|
||||
opaque string, but the client typically uses
|
||||
single-field conditions in the form ``'key=val'``.
|
||||
"""
|
||||
if user_id is True:
|
||||
user_id = self.env.uid
|
||||
if company_id is True:
|
||||
company_id = self.env.user.company_id.id
|
||||
|
||||
# check consistency of model_name, field_name, and value
|
||||
try:
|
||||
model = self.env[model_name]
|
||||
field = model._fields[field_name]
|
||||
field.convert_to_cache(value, model)
|
||||
json_value = json.dumps(value, ensure_ascii=False)
|
||||
except KeyError:
|
||||
raise ValidationError(_("Invalid field %s.%s") % (model_name, field_name))
|
||||
except Exception:
|
||||
raise ValidationError(_("Invalid value for %s.%s: %s") % (model_name, field_name, value))
|
||||
|
||||
# update existing default for the same scope, or create one
|
||||
field = self.env['ir.model.fields']._get(model_name, field_name)
|
||||
default = self.search([
|
||||
('field_id', '=', field.id),
|
||||
('user_id', '=', user_id),
|
||||
('company_id', '=', company_id),
|
||||
('condition', '=', condition),
|
||||
])
|
||||
if default:
|
||||
default.write({'json_value': json_value})
|
||||
else:
|
||||
self.create({
|
||||
'field_id': field.id,
|
||||
'user_id': user_id,
|
||||
'company_id': company_id,
|
||||
'condition': condition,
|
||||
'json_value': json_value,
|
||||
})
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def get(self, model_name, field_name, user_id=False, company_id=False, condition=False):
|
||||
""" Return the default value for the given field, user and company, or
|
||||
``None`` if no default is available.
|
||||
|
||||
:param user_id: may be ``False`` for all users, ``True`` for the
|
||||
current user, or any user id
|
||||
:param company_id: may be ``False`` for all companies, ``True`` for
|
||||
the current user's company, or any company id
|
||||
:param condition: optional condition that restricts the
|
||||
applicability of the default value; this is an
|
||||
opaque string, but the client typically uses
|
||||
single-field conditions in the form ``'key=val'``.
|
||||
"""
|
||||
if user_id is True:
|
||||
user_id = self.env.uid
|
||||
if company_id is True:
|
||||
company_id = self.env.user.company_id.id
|
||||
|
||||
field = self.env['ir.model.fields']._get(model_name, field_name)
|
||||
default = self.search([
|
||||
('field_id', '=', field.id),
|
||||
('user_id', '=', user_id),
|
||||
('company_id', '=', company_id),
|
||||
('condition', '=', condition),
|
||||
], limit=1)
|
||||
return json.loads(default.json_value) if default else None
|
||||
|
||||
@api.model
|
||||
@tools.ormcache('self.env.uid', 'model_name', 'condition')
|
||||
# Note about ormcache invalidation: it is not needed when deleting a field,
|
||||
# a user, or a company, as the corresponding defaults will no longer be
|
||||
# requested. It must only be done when a user's company is modified.
|
||||
def get_model_defaults(self, model_name, condition=False):
|
||||
""" Return the available default values for the given model (for the
|
||||
current user), as a dict mapping field names to values.
|
||||
"""
|
||||
cr = self.env.cr
|
||||
query = """ SELECT f.name, d.json_value FROM ir_default d
|
||||
JOIN ir_model_fields f ON d.field_id=f.id
|
||||
JOIN res_users u ON u.id=%s
|
||||
WHERE f.model=%s
|
||||
AND (d.user_id IS NULL OR d.user_id=u.id)
|
||||
AND (d.company_id IS NULL OR d.company_id=u.company_id)
|
||||
AND {}
|
||||
ORDER BY d.user_id, d.company_id, d.id
|
||||
"""
|
||||
params = [self.env.uid, model_name]
|
||||
if condition:
|
||||
query = query.format("d.condition=%s")
|
||||
params.append(condition)
|
||||
else:
|
||||
query = query.format("d.condition IS NULL")
|
||||
cr.execute(query, params)
|
||||
result = {}
|
||||
for row in cr.fetchall():
|
||||
# keep the highest priority default for each field
|
||||
if row[0] not in result:
|
||||
result[row[0]] = json.loads(row[1])
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def discard_records(self, records):
|
||||
""" Discard all the defaults of many2one fields using any of the given
|
||||
records.
|
||||
"""
|
||||
json_vals = [json.dumps(id) for id in records.ids]
|
||||
domain = [('field_id.ttype', '=', 'many2one'),
|
||||
('field_id.relation', '=', records._name),
|
||||
('json_value', 'in', json_vals)]
|
||||
return self.search(domain).unlink()
|
||||
|
||||
@api.model
|
||||
def discard_values(self, model_name, field_name, values):
|
||||
""" Discard all the defaults for any of the given values. """
|
||||
field = self.env['ir.model.fields']._get(model_name, field_name)
|
||||
json_vals = [json.dumps(value, ensure_ascii=False) for value in values]
|
||||
domain = [('field_id', '=', field.id), ('json_value', 'in', json_vals)]
|
||||
return self.search(domain).unlink()
|
||||
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="ir_default_form_view" model="ir.ui.view">
|
||||
<field name="name">ir.default form view</field>
|
||||
<field name="model">ir.default</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="User-defined Defaults">
|
||||
<group>
|
||||
<group>
|
||||
<field name="field_id"/>
|
||||
<field name="json_value"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="user_id"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="ir_default_tree_view" model="ir.ui.view">
|
||||
<field name="name">ir.default tree view</field>
|
||||
<field name="model">ir.default</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="User-defined Defaults">
|
||||
<field name="field_id"/>
|
||||
<field name="json_value"/>
|
||||
<field name="user_id"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="ir_default_search_view" model="ir.ui.view">
|
||||
<field name="name">ir.default search view</field>
|
||||
<field name="model">ir.default</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="User-defined Defaults">
|
||||
<field name="field_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="User" domain="[]" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Company" domain="[]" context="{'group_by':'company_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="ir_default_menu_action" model="ir.actions.act_window">
|
||||
<field name="name">User-defined Defaults</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">ir.default</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="ir_default_search_view"/>
|
||||
</record>
|
||||
<menuitem action="ir_default_menu_action" id="ir_default_menu" parent="next_id_6"/>
|
||||
|
||||
</odoo>
|
||||
@@ -469,14 +469,14 @@ class ResConfigSettings(models.TransientModel, ResConfigModuleInstallationMixin)
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields):
|
||||
IrValues = self.env['ir.values']
|
||||
IrDefault = self.env['ir.default']
|
||||
classified = self._get_classified_fields()
|
||||
|
||||
res = super(ResConfigSettings, self).default_get(fields)
|
||||
|
||||
# defaults: take the corresponding default value they set
|
||||
for name, model, field in classified['default']:
|
||||
value = IrValues.get_default(model, field)
|
||||
value = IrDefault.get(model, field)
|
||||
if value is not None:
|
||||
res[name] = value
|
||||
|
||||
@@ -517,7 +517,7 @@ class ResConfigSettings(models.TransientModel, ResConfigModuleInstallationMixin)
|
||||
classified = self._get_classified_fields()
|
||||
|
||||
# default values fields
|
||||
IrValues = self.env['ir.values'].sudo()
|
||||
IrDefault = self.env['ir.default'].sudo()
|
||||
for name, model, field in classified['default']:
|
||||
if isinstance(self[name], models.BaseModel):
|
||||
if self._fields[name].type == 'many2one':
|
||||
@@ -526,7 +526,7 @@ class ResConfigSettings(models.TransientModel, ResConfigModuleInstallationMixin)
|
||||
value = self[name].ids
|
||||
else:
|
||||
value = self[name]
|
||||
IrValues.set_default(model, field, value)
|
||||
IrDefault.set(model, field, value)
|
||||
|
||||
# group fields: modify group / implied groups
|
||||
for name, groups, implied_group in classified['group']:
|
||||
|
||||
@@ -163,10 +163,10 @@ class Lang(models.Model):
|
||||
lang = self.search([('code', '=', lang_code)])
|
||||
if not lang:
|
||||
self.load_lang(lang_code)
|
||||
IrValues = self.env['ir.values']
|
||||
default_value = IrValues.get_defaults('res.partner', condition=False)
|
||||
if not default_value:
|
||||
IrValues.set_default('res.partner', 'lang', lang_code, condition=False)
|
||||
IrDefault = self.env['ir.default']
|
||||
default_value = IrDefault.get('res.partner', 'lang')
|
||||
if default_value is None:
|
||||
IrDefault.set('res.partner', 'lang', lang_code)
|
||||
# set language of main company, created directly by db bootstrap SQL
|
||||
partner = self.env.user.company_id.partner_id
|
||||
if not partner.lang:
|
||||
@@ -219,13 +219,8 @@ class Lang(models.Model):
|
||||
if vals.get('active') == False:
|
||||
if self.env['res.users'].search([('lang', 'in', lang_codes)]):
|
||||
raise UserError(_("Cannot unactivate a language that is currently used by users."))
|
||||
# delete linked ir.value specifying default partner's language
|
||||
default_lang = self.env['ir.values'].search([
|
||||
('key', '=', 'default'),
|
||||
('name', '=', 'lang'),
|
||||
('model', '=', 'res.partner')])
|
||||
if default_lang and default_lang.value_unpickle in lang_codes:
|
||||
default_lang.unlink()
|
||||
# delete linked ir.default specifying default partner's language
|
||||
self.env['ir.default'].discard_values('res.partner', 'lang', lang_codes)
|
||||
|
||||
res = super(Lang, self).write(vals)
|
||||
self.clear_caches()
|
||||
|
||||
@@ -355,7 +355,7 @@ class Users(models.Model):
|
||||
if user.partner_id.company_id and user.partner_id.company_id.id != values['company_id']:
|
||||
user.partner_id.write({'company_id': user.company_id.id})
|
||||
# clear default ir values when company changes
|
||||
self.env['ir.values'].get_defaults_dict.clear_cache(self.env['ir.values'])
|
||||
self.env['ir.default'].clear_caches()
|
||||
|
||||
# clear caches linked to the users
|
||||
if 'groups_id' in values:
|
||||
|
||||
@@ -111,6 +111,22 @@
|
||||
<field name="perm_read" eval="False"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="ir_default_user_rule">
|
||||
<field name="name">Defaults: alter personal defaults</field>
|
||||
<field name="model_id" ref="model_ir_default"/>
|
||||
<field name="domain_force">[('user_id','=',user.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
|
||||
<field name="perm_read" eval="False"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="ir_default_system_rule">
|
||||
<field name="name">Defaults: alter all defaults</field>
|
||||
<field name="model_id" ref="model_ir_default"/>
|
||||
<field name="domain_force">[(1,'=',1)]</field>
|
||||
<field name="groups" eval="[(4, ref('base.group_system'))]"/>
|
||||
<field name="perm_read" eval="False"/>
|
||||
</record>
|
||||
|
||||
<!-- Used for dashboard customizations, users should only be able to edit their own dashboards -->
|
||||
<record model="ir.rule" id="ir_ui_view_custom_personal">
|
||||
<field name="name">ir.ui.view_custom rule</field>
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
"access_ir_ui_view_group_system","ir_ui_view group_system","model_ir_ui_view","group_system",1,1,1,1
|
||||
"access_ir_ui_view_custom_group_user","ir_ui_view_custom_group_user","model_ir_ui_view_custom",,1,1,1,1
|
||||
"access_ir_values_group_all","ir_values group_all","model_ir_values",,1,1,1,1
|
||||
"access_ir_default_all","ir_default all","model_ir_default",,1,0,0,0
|
||||
"access_ir_default_group_user","ir_default group_user","model_ir_default","group_user",1,1,1,1
|
||||
"access_ir_default_group_system","ir_default group_system","model_ir_default","group_system",1,1,1,1
|
||||
"access_res_company_group_erp_manager","res_company group_erp_manager","model_res_company","group_erp_manager",1,1,1,1
|
||||
"access_res_company_group_user","res_company group_user","model_res_company",,1,0,0,0
|
||||
"access_res_country_group_all","res_country group_user_all","model_res_country",,1,0,0,0
|
||||
|
||||
|
@@ -13,6 +13,7 @@ from . import test_ir_filters
|
||||
from . import test_ir_sequence
|
||||
from . import test_ir_sequence_date_range
|
||||
from . import test_ir_values
|
||||
from . import test_ir_default
|
||||
from . import test_mail
|
||||
from . import test_menu
|
||||
from . import test_mimetypes
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestIrDefault(TransactionCase):
|
||||
|
||||
def test_defaults(self):
|
||||
""" check the mechanism of user-defined defaults """
|
||||
companyA = self.env.user.company_id
|
||||
companyB = companyA.create({'name': 'CompanyB'})
|
||||
user1 = self.env.user
|
||||
user2 = user1.create({'name': 'u2', 'login': 'u2'})
|
||||
user3 = user1.create({'name': 'u3', 'login': 'u3',
|
||||
'company_id': companyB.id,
|
||||
'company_ids': companyB.ids})
|
||||
|
||||
# create some default value for some model
|
||||
IrDefault1 = self.env['ir.default']
|
||||
IrDefault2 = IrDefault1.sudo(user2)
|
||||
IrDefault3 = IrDefault1.sudo(user3)
|
||||
|
||||
# set a default value for all users
|
||||
IrDefault1.search([('field_id.model', '=', 'res.partner')]).unlink()
|
||||
IrDefault1.set('res.partner', 'ref', 'GLOBAL', user_id=False, company_id=False)
|
||||
self.assertEqual(IrDefault1.get_model_defaults('res.partner'), {'ref': 'GLOBAL'},
|
||||
"Can't retrieve the created default value for all users.")
|
||||
self.assertEqual(IrDefault2.get_model_defaults('res.partner'), {'ref': 'GLOBAL'},
|
||||
"Can't retrieve the created default value for all users.")
|
||||
self.assertEqual(IrDefault3.get_model_defaults('res.partner'), {'ref': 'GLOBAL'},
|
||||
"Can't retrieve the created default value for all users.")
|
||||
|
||||
# set a default value for current company (behavior of 'set default' from debug mode)
|
||||
IrDefault1.set('res.partner', 'ref', 'COMPANY', user_id=False, company_id=True)
|
||||
self.assertEqual(IrDefault1.get_model_defaults('res.partner'), {'ref': 'COMPANY'},
|
||||
"Can't retrieve the created default value for company.")
|
||||
self.assertEqual(IrDefault2.get_model_defaults('res.partner'), {'ref': 'COMPANY'},
|
||||
"Can't retrieve the created default value for company.")
|
||||
self.assertEqual(IrDefault3.get_model_defaults('res.partner'), {'ref': 'GLOBAL'},
|
||||
"Unexpected default value for company.")
|
||||
|
||||
# set a default value for current user (behavior of 'set default' from debug mode)
|
||||
IrDefault2.set('res.partner', 'ref', 'USER', user_id=True, company_id=True)
|
||||
self.assertEqual(IrDefault1.get_model_defaults('res.partner'), {'ref': 'COMPANY'},
|
||||
"Can't retrieve the created default value for user.")
|
||||
self.assertEqual(IrDefault2.get_model_defaults('res.partner'), {'ref': 'USER'},
|
||||
"Unexpected default value for user.")
|
||||
self.assertEqual(IrDefault3.get_model_defaults('res.partner'), {'ref': 'GLOBAL'},
|
||||
"Unexpected default value for company.")
|
||||
|
||||
# check default values on partners
|
||||
default1 = IrDefault1.env['res.partner'].default_get(['ref']).get('ref')
|
||||
self.assertEqual(default1, 'COMPANY', "Wrong default value.")
|
||||
default2 = IrDefault2.env['res.partner'].default_get(['ref']).get('ref')
|
||||
self.assertEqual(default2, 'USER', "Wrong default value.")
|
||||
default3 = IrDefault3.env['res.partner'].default_get(['ref']).get('ref')
|
||||
self.assertEqual(default3, 'GLOBAL', "Wrong default value.")
|
||||
|
||||
def test_conditions(self):
|
||||
""" check user-defined defaults with condition """
|
||||
IrDefault = self.env['ir.default']
|
||||
|
||||
# default without condition
|
||||
IrDefault.search([('field_id.model', '=', 'res.partner')]).unlink()
|
||||
IrDefault.set('res.partner', 'ref', 'X')
|
||||
self.assertEqual(IrDefault.get_model_defaults('res.partner'),
|
||||
{'ref': 'X'})
|
||||
self.assertEqual(IrDefault.get_model_defaults('res.partner', condition='name=Agrolait'),
|
||||
{})
|
||||
|
||||
# default with a condition
|
||||
IrDefault.search([('field_id.model', '=', 'res.partner.title')]).unlink()
|
||||
IrDefault.set('res.partner.title', 'shortcut', 'X')
|
||||
IrDefault.set('res.partner.title', 'shortcut', 'Mr', condition='name=Mister')
|
||||
self.assertEqual(IrDefault.get_model_defaults('res.partner.title'),
|
||||
{'shortcut': 'X'})
|
||||
self.assertEqual(IrDefault.get_model_defaults('res.partner.title', condition='name=Miss'),
|
||||
{})
|
||||
self.assertEqual(IrDefault.get_model_defaults('res.partner.title', condition='name=Mister'),
|
||||
{'shortcut': 'Mr'})
|
||||
|
||||
def test_invalid(self):
|
||||
""" check error cases with 'ir.default' """
|
||||
IrDefault = self.env['ir.default']
|
||||
with self.assertRaises(ValidationError):
|
||||
IrDefault.set('unknown_model', 'unknown_field', 42)
|
||||
with self.assertRaises(ValidationError):
|
||||
IrDefault.set('res.partner', 'unknown_field', 42)
|
||||
with self.assertRaises(ValidationError):
|
||||
IrDefault.set('res.partner', 'lang', 'some_LANG')
|
||||
with self.assertRaises(ValidationError):
|
||||
IrDefault.set('res.partner', 'credit_limit', 'foo')
|
||||
|
||||
def test_removal(self):
|
||||
""" check defaults for many2one with their value being removed """
|
||||
IrDefault = self.env['ir.default']
|
||||
IrDefault.search([('field_id.model', '=', 'res.partner')]).unlink()
|
||||
|
||||
# set a record as a default value
|
||||
title = self.env['res.partner.title'].create({'name': 'President'})
|
||||
IrDefault.set('res.partner', 'title', title.id)
|
||||
self.assertEqual(IrDefault.get_model_defaults('res.partner'), {'title': title.id})
|
||||
|
||||
# delete the record, and check the presence of the default value
|
||||
title.unlink()
|
||||
self.assertEqual(IrDefault.get_model_defaults('res.partner'), {})
|
||||
+10
-6
@@ -975,6 +975,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
|
||||
defaults = {}
|
||||
parent_fields = defaultdict(list)
|
||||
ir_defaults = self.env['ir.default'].get_model_defaults(self._name)
|
||||
|
||||
for name in fields_list:
|
||||
# 1. look up context
|
||||
@@ -983,11 +984,9 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
defaults[name] = self._context[key]
|
||||
continue
|
||||
|
||||
# 2. look up ir_values
|
||||
# Note: performance is good, because get_defaults_dict is cached!
|
||||
ir_values_dict = self.env['ir.values'].get_defaults_dict(self._name)
|
||||
if name in ir_values_dict:
|
||||
defaults[name] = ir_values_dict[name]
|
||||
# 2. look up ir.default
|
||||
if name in ir_defaults:
|
||||
defaults[name] = ir_defaults[name]
|
||||
continue
|
||||
|
||||
field = self._fields.get(name)
|
||||
@@ -2045,7 +2044,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
def _init_column(self, column_name):
|
||||
""" Initialize the value of the given column for existing rows. """
|
||||
# get the default value; ideally, we should use default_get(), but it
|
||||
# fails due to ir.values not being ready
|
||||
# fails due to ir.default not being ready
|
||||
field = self._fields[column_name]
|
||||
if field.default:
|
||||
value = field.default(self)
|
||||
@@ -2842,6 +2841,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
cr = self._cr
|
||||
Data = self.env['ir.model.data'].sudo().with_context({})
|
||||
Values = self.env['ir.values']
|
||||
Defaults = self.env['ir.default'].sudo()
|
||||
Attachment = self.env['ir.attachment']
|
||||
|
||||
for sub_ids in cr.split_for_in_conditions(self.ids):
|
||||
@@ -2867,6 +2867,10 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
if values:
|
||||
values.unlink()
|
||||
|
||||
# For the same reason, remove the defaults having some of the
|
||||
# records as value
|
||||
Defaults.discard_records(self.browse(sub_ids))
|
||||
|
||||
# For the same reason, remove the relevant records in ir_attachment
|
||||
# (the search is performed with sql as the search method of
|
||||
# ir_attachment is overridden to hide attachments of deleted
|
||||
|
||||
Reference in New Issue
Block a user