[MERGE] base: make ir.property private
Only system users can access ir.property records. This PR is part of the long-term task id 8203 that plans to remove all access to ir.* models "Official" methods to interact with `ir.property`: - `_set_default(name, model, value, company=False)` - `_set_multi(name, model, values, default_value=None)` - `_get(name, model, res_id=False)` - `_get_multi(name, model, ids)` Done in this PR: - remove ACL on ir.property (only system users can access directly) - make all getter/setters private with sudo - use these methods everywhere instead of CRUD calls - add sudo where needed closes odoo/odoo#51658 Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
This commit is contained in:
@@ -432,9 +432,12 @@ class AccountAccount(models.Model):
|
||||
raise UserError(_('You cannot perform this action on an account that contains journal items.'))
|
||||
#Checking whether the account is set as a property to any Partner or not
|
||||
values = ['account.account,%s' % (account_id,) for account_id in self.ids]
|
||||
partner_prop_acc = self.env['ir.property'].search([('value_reference', 'in', values)], limit=1)
|
||||
partner_prop_acc = self.env['ir.property'].sudo().search([('value_reference', 'in', values)], limit=1)
|
||||
if partner_prop_acc:
|
||||
raise UserError(_('You cannot remove/deactivate an account which is set on a customer or vendor.'))
|
||||
account_name = partner_prop_acc.get_by_record().display_name
|
||||
raise UserError(
|
||||
_('You cannot remove/deactivate the account %s which is set on a customer or vendor.') % account_name
|
||||
)
|
||||
return super(AccountAccount, self).unlink()
|
||||
|
||||
def action_read_account(self):
|
||||
|
||||
@@ -71,8 +71,9 @@ class AccountPaymentTerm(models.Model):
|
||||
for terms in self:
|
||||
if self.env['account.move'].search([('invoice_payment_term_id', 'in', terms.ids)]):
|
||||
raise UserError(_('You can not delete payment terms as other records still reference it. However, you can archive it.'))
|
||||
property_recs = self.env['ir.property'].search([('value_reference', 'in', ['account.payment.term,%s'%payment_term.id for payment_term in terms])])
|
||||
property_recs.unlink()
|
||||
self.env['ir.property'].sudo().search(
|
||||
[('value_reference', 'in', ['account.payment.term,%s'%payment_term.id for payment_term in terms])]
|
||||
).unlink()
|
||||
return super(AccountPaymentTerm, self).unlink()
|
||||
|
||||
|
||||
|
||||
@@ -207,9 +207,9 @@ class AccountChartTemplate(models.Model):
|
||||
existing_journals = self.env['account.journal'].search([('company_id', '=', company.id)])
|
||||
if existing_journals:
|
||||
prop_values.extend(['account.journal,%s' % (journal_id,) for journal_id in existing_journals.ids])
|
||||
accounting_props = self.env['ir.property'].search([('value_reference', 'in', prop_values)])
|
||||
if accounting_props:
|
||||
accounting_props.sudo().unlink()
|
||||
self.env['ir.property'].sudo().search(
|
||||
[('value_reference', 'in', prop_values)]
|
||||
).unlink()
|
||||
|
||||
# delete account, journal, tax, fiscal position and reconciliation model
|
||||
models_to_delete = ['account.reconcile.model', 'account.fiscal.position', 'account.tax', 'account.move', 'account.journal', 'account.group']
|
||||
@@ -463,34 +463,22 @@ class AccountChartTemplate(models.Model):
|
||||
self.ensure_one()
|
||||
PropertyObj = self.env['ir.property']
|
||||
todo_list = [
|
||||
('property_account_receivable_id', 'res.partner', 'account.account'),
|
||||
('property_account_payable_id', 'res.partner', 'account.account'),
|
||||
('property_account_expense_categ_id', 'product.category', 'account.account'),
|
||||
('property_account_income_categ_id', 'product.category', 'account.account'),
|
||||
('property_account_expense_id', 'product.template', 'account.account'),
|
||||
('property_account_income_id', 'product.template', 'account.account'),
|
||||
('property_tax_payable_account_id', 'account.tax.group', 'account.account'),
|
||||
('property_tax_receivable_account_id', 'account.tax.group', 'account.account'),
|
||||
('property_advance_tax_payment_account_id', 'account.tax.group', 'account.account'),
|
||||
('property_account_receivable_id', 'res.partner'),
|
||||
('property_account_payable_id', 'res.partner'),
|
||||
('property_account_expense_categ_id', 'product.category'),
|
||||
('property_account_income_categ_id', 'product.category'),
|
||||
('property_account_expense_id', 'product.template'),
|
||||
('property_account_income_id', 'product.template'),
|
||||
('property_tax_payable_account_id', 'account.tax.group'),
|
||||
('property_tax_receivable_account_id', 'account.tax.group'),
|
||||
('property_advance_tax_payment_account_id', 'account.tax.group'),
|
||||
]
|
||||
for record in todo_list:
|
||||
account = getattr(self, record[0])
|
||||
value = account and 'account.account,' + str(acc_template_ref[account.id]) or False
|
||||
for field, model in todo_list:
|
||||
account = self[field]
|
||||
value = acc_template_ref[account.id] if account else False
|
||||
if value:
|
||||
field = self.env['ir.model.fields'].search([('name', '=', record[0]), ('model', '=', record[1]), ('relation', '=', record[2])], limit=1)
|
||||
vals = {
|
||||
'name': record[0],
|
||||
'company_id': company.id,
|
||||
'fields_id': field.id,
|
||||
'value': value,
|
||||
}
|
||||
properties = PropertyObj.search([('name', '=', record[0]), ('company_id', '=', company.id)])
|
||||
if properties:
|
||||
#the property exist: modify it
|
||||
properties.write(vals)
|
||||
else:
|
||||
#create the property
|
||||
PropertyObj.create(vals)
|
||||
PropertyObj._set_default(field, model, value, company=company)
|
||||
|
||||
stock_properties = [
|
||||
'property_stock_account_input_categ_id',
|
||||
'property_stock_account_output_categ_id',
|
||||
|
||||
@@ -213,11 +213,11 @@ class AccountTestCommon(SavepointCase):
|
||||
|
||||
# Properties: Product income and expense accounts, default parameters
|
||||
Property = cls.env['ir.property']
|
||||
Property.set_default('property_account_receivable_id', 'res.partner', cls.a_recv, cls.company)
|
||||
Property.set_default('property_account_payable_id', 'res.partner', cls.a_pay, cls.company)
|
||||
Property.set_default('property_account_position_id', 'res.partner', False, cls.company)
|
||||
Property.set_default('property_account_expense_categ_id', 'product.category', cls.a_expense, cls.company)
|
||||
Property.set_default('property_account_income_categ_id', 'product.category', cls.a_sale, cls.company)
|
||||
Property._set_default('property_account_receivable_id', 'res.partner', cls.a_recv, cls.company)
|
||||
Property._set_default('property_account_payable_id', 'res.partner', cls.a_pay, cls.company)
|
||||
Property._set_default('property_account_position_id', 'res.partner', False, cls.company)
|
||||
Property._set_default('property_account_expense_categ_id', 'product.category', cls.a_expense, cls.company)
|
||||
Property._set_default('property_account_income_categ_id', 'product.category', cls.a_sale, cls.company)
|
||||
|
||||
# Bank Accounts
|
||||
cls.bank_account = cls.env['res.partner.bank'].create({
|
||||
|
||||
@@ -8,7 +8,6 @@ access_hr_employee_resource_user,resource.resource.user,resource.model_resource_
|
||||
access_hr_department_user,hr.department.user,model_hr_department,group_hr_user,1,1,1,1
|
||||
access_hr_department_employee,hr.department.employee,model_hr_department,base.group_user,1,0,0,0
|
||||
access_hr_job_user,hr.job user,model_hr_job,group_hr_user,1,1,1,1
|
||||
access_ir_property_hr_user,ir_property hr_user,base.model_ir_property,group_hr_user,1,1,1,0
|
||||
access_hr_plan_activity_type_employee,access_hr_plan_activity_type,model_hr_plan_activity_type,base.group_user,1,0,0,0
|
||||
access_hr_plan_employee,access_hr_plan_employee,model_hr_plan,base.group_user,1,0,0,0
|
||||
access_hr_plan_activity_type_hr_user,access_hr_plan_activity_type,model_hr_plan_activity_type,group_hr_user,1,1,1,1
|
||||
|
||||
|
@@ -26,7 +26,7 @@ class HrExpense(models.Model):
|
||||
|
||||
@api.model
|
||||
def _default_account_id(self):
|
||||
return self.env['ir.property'].get('property_account_expense_categ_id', 'product.category')
|
||||
return self.env['ir.property']._get('property_account_expense_categ_id', 'product.category')
|
||||
|
||||
@api.model
|
||||
def _get_employee_id_domain(self):
|
||||
@@ -365,7 +365,7 @@ class HrExpense(models.Model):
|
||||
raise UserError(
|
||||
_("No Expense account found for the product %s (or for its category), please configure one.") % (self.product_id.name))
|
||||
else:
|
||||
account = self.env['ir.property'].with_company(self.company_id).get('property_account_expense_categ_id', 'product.category')
|
||||
account = self.env['ir.property'].with_company(self.company_id)._get('property_account_expense_categ_id', 'product.category')
|
||||
if not account:
|
||||
raise UserError(_('Please configure Default Expense account for Product expense: `property_account_expense_categ_id`.'))
|
||||
return account
|
||||
|
||||
@@ -21,10 +21,6 @@ class ResCompany(models.Model):
|
||||
|
||||
def _create_subcontracting_location(self):
|
||||
parent_location = self.env.ref('stock.stock_location_locations', raise_if_not_found=False)
|
||||
property_stock_subcontractor_res_partner_field = self.env['ir.model.fields'].search([
|
||||
('model', '=', 'res.partner'),
|
||||
('name', '=', 'property_stock_subcontractor')
|
||||
])
|
||||
for company in self:
|
||||
subcontracting_location = self.env['stock.location'].create({
|
||||
'name': _('Subcontracting Location'),
|
||||
@@ -32,10 +28,10 @@ class ResCompany(models.Model):
|
||||
'location_id': parent_location.id,
|
||||
'company_id': company.id,
|
||||
})
|
||||
self.env['ir.property'].create({
|
||||
'name': 'property_stock_subcontractor_%s' % company.name,
|
||||
'fields_id': property_stock_subcontractor_res_partner_field.id,
|
||||
'company_id': company.id,
|
||||
'value': 'stock.location,%d' % subcontracting_location.id,
|
||||
})
|
||||
self.env['ir.property']._set_default(
|
||||
"property_stock_subcontractor",
|
||||
"res.partner",
|
||||
subcontracting_location,
|
||||
company,
|
||||
)
|
||||
company.subcontracting_location_id = subcontracting_location
|
||||
|
||||
@@ -30,12 +30,7 @@ class TestPointOfSaleHttpCommon(odoo.tests.HttpCase):
|
||||
'reconcile': True})
|
||||
self.env.company.account_default_pos_receivable_account_id = account_receivable
|
||||
|
||||
self.env['ir.property'].set_default(
|
||||
'property_account_receivable_id',
|
||||
'res.partner',
|
||||
account_receivable,
|
||||
main_company,
|
||||
)
|
||||
self.env['ir.property']._set_default('property_account_receivable_id', 'res.partner', account_receivable, main_company)
|
||||
|
||||
cash_journal = journal_obj.create({
|
||||
'name': 'Cash Test',
|
||||
@@ -400,12 +395,11 @@ class TestPointOfSaleHttpCommon(odoo.tests.HttpCase):
|
||||
|
||||
# Change the default sale pricelist of customers,
|
||||
# so the js tests can expect deterministically this pricelist when selecting a customer.
|
||||
field = env['ir.model.fields']._get('res.partner', 'property_product_pricelist')
|
||||
env['ir.property'].search([
|
||||
('name', '=', 'property_product_pricelist'),
|
||||
('fields_id', '=', field.id),
|
||||
('res_id', '=', False)
|
||||
]).write({'value_reference': 'product.pricelist,%s' % public_pricelist.id})
|
||||
env['ir.property']._set_default(
|
||||
"property_product_pricelist",
|
||||
"res.partner",
|
||||
public_pricelist,
|
||||
)
|
||||
|
||||
|
||||
@odoo.tests.tagged('post_install', '-at_install')
|
||||
|
||||
@@ -86,7 +86,7 @@ class TestFrontend(odoo.tests.HttpCase):
|
||||
'user_type_id': self.env.ref('account.data_account_type_receivable').id,
|
||||
'reconcile': True})
|
||||
|
||||
self.env['ir.property'].set_default(
|
||||
self.env['ir.property']._set_default(
|
||||
'property_account_receivable_id',
|
||||
'res.partner',
|
||||
account_receivable,
|
||||
|
||||
@@ -340,7 +340,7 @@ class Pricelist(models.Model):
|
||||
pl_domain = self._get_partner_pricelist_multi_search_domain_hook(company_id)
|
||||
|
||||
# if no specific property, try to find a fitting pricelist
|
||||
result = Property.get_multi('property_product_pricelist', Partner._name, partner_ids)
|
||||
result = Property._get_multi('property_product_pricelist', Partner._name, partner_ids)
|
||||
|
||||
remaining_partner_ids = [pid for pid, val in result.items() if not val or
|
||||
not val._get_partner_pricelist_multi_filter_hook()]
|
||||
@@ -348,7 +348,7 @@ class Pricelist(models.Model):
|
||||
# get fallback pricelist when no pricelist for a given country
|
||||
pl_fallback = (
|
||||
Pricelist.search(pl_domain + [('country_group_ids', '=', False)], limit=1) or
|
||||
Property.get('property_product_pricelist', 'res.partner') or
|
||||
Property._get('property_product_pricelist', 'res.partner') or
|
||||
Pricelist.search(pl_domain, limit=1)
|
||||
)
|
||||
# group partners by country, and find a pricelist for each country
|
||||
|
||||
@@ -18,7 +18,7 @@ class ResCompany(models.Model):
|
||||
'name': _("Default %(currency)s pricelist") % params,
|
||||
'currency_id': new_company.currency_id.id,
|
||||
})
|
||||
self.env['ir.property'].sudo().set_default(
|
||||
self.env['ir.property']._set_default(
|
||||
'property_product_pricelist',
|
||||
'res.partner',
|
||||
pricelist,
|
||||
@@ -54,7 +54,7 @@ class ResCompany(models.Model):
|
||||
'name': _("Default %(currency)s pricelist") % params,
|
||||
'currency_id': currency_id,
|
||||
})
|
||||
self.env['ir.property'].sudo().set_default(
|
||||
self.env['ir.property']._set_default(
|
||||
'property_product_pricelist',
|
||||
'res.partner',
|
||||
pricelist,
|
||||
|
||||
@@ -29,11 +29,11 @@ class Partner(models.Model):
|
||||
limit=1
|
||||
)
|
||||
default_for_country = pls and pls[0]
|
||||
actual = self.env['ir.property'].get('property_product_pricelist', 'res.partner', 'res.partner,%s' % partner.id)
|
||||
actual = self.env['ir.property']._get('property_product_pricelist', 'res.partner', 'res.partner,%s' % partner.id)
|
||||
# update at each change country, and so erase old pricelist
|
||||
if partner.property_product_pricelist or (actual and default_for_country and default_for_country.id != actual.id):
|
||||
# keep the company of the current user before sudo
|
||||
self.env['ir.property'].sudo().set_multi(
|
||||
self.env['ir.property']._set_multi(
|
||||
'property_product_pricelist',
|
||||
partner._name,
|
||||
{partner.id: partner.property_product_pricelist or default_for_country.id},
|
||||
|
||||
@@ -19,7 +19,6 @@ access_sale_order_readonly,sale.order.accountant,model_sale_order,account.group_
|
||||
access_sale_order_accountant,sale.order.accountant,model_sale_order,account.group_account_user,1,1,0,0
|
||||
access_sale_report_salesman,sale.report,model_sale_report,sales_team.group_sale_salesman,1,1,1,0
|
||||
access_sale_report_manager,sale.report,model_sale_report,sales_team.group_sale_manager,1,1,1,1
|
||||
access_ir_property_sales,ir.property.sales,base.model_ir_property,sales_team.group_sale_salesman,1,1,1,1
|
||||
access_sale_account_journal,account.journal sale order.user,account.model_account_journal,sales_team.group_sale_salesman,1,0,0,0
|
||||
access_res_partner_sale_user,res.partner.sale.user,base.model_res_partner,sales_team.group_sale_salesman,1,0,0,0
|
||||
access_res_partner_sale_manager,res.partner.sale.manager,base.model_res_partner,sales_team.group_sale_manager,1,1,1,0
|
||||
|
||||
|
@@ -47,7 +47,6 @@ class Company(models.Model):
|
||||
|
||||
def _create_inventory_loss_location(self):
|
||||
parent_location = self.env.ref('stock.stock_location_locations_virtual', raise_if_not_found=False)
|
||||
inventory_loss_product_template_field = self.env['ir.model.fields'].search([('model','=','product.template'),('name','=','property_stock_inventory')])
|
||||
for company in self:
|
||||
inventory_loss_location = self.env['stock.location'].create({
|
||||
'name': 'Inventory adjustment',
|
||||
@@ -55,16 +54,15 @@ class Company(models.Model):
|
||||
'location_id': parent_location.id,
|
||||
'company_id': company.id,
|
||||
})
|
||||
self.env['ir.property'].create({
|
||||
'name': 'property_stock_inventory_%s' % company.name,
|
||||
'fields_id': inventory_loss_product_template_field.id,
|
||||
'company_id': company.id,
|
||||
'value': 'stock.location,%d' % inventory_loss_location.id,
|
||||
})
|
||||
self.env['ir.property']._set_default(
|
||||
"property_stock_inventory",
|
||||
"product.template",
|
||||
inventory_loss_location,
|
||||
company.id,
|
||||
)
|
||||
|
||||
def _create_production_location(self):
|
||||
parent_location = self.env.ref('stock.stock_location_locations_virtual', raise_if_not_found=False)
|
||||
production_product_template_field = self.env['ir.model.fields'].search([('model','=','product.template'),('name','=','property_stock_production')])
|
||||
for company in self:
|
||||
production_location = self.env['stock.location'].create({
|
||||
'name': 'Production',
|
||||
@@ -72,12 +70,13 @@ class Company(models.Model):
|
||||
'location_id': parent_location.id,
|
||||
'company_id': company.id,
|
||||
})
|
||||
self.env['ir.property'].create({
|
||||
'name': 'property_stock_inventory_%s' % company.name,
|
||||
'fields_id': production_product_template_field.id,
|
||||
'company_id': company.id,
|
||||
'value': 'stock.location,%d' % production_location.id,
|
||||
})
|
||||
self.env['ir.property']._set_default(
|
||||
"property_stock_production",
|
||||
"product.template",
|
||||
production_location,
|
||||
company.id,
|
||||
)
|
||||
|
||||
|
||||
def _create_scrap_location(self):
|
||||
parent_location = self.env.ref('stock.stock_location_locations_virtual', raise_if_not_found=False)
|
||||
@@ -129,16 +128,16 @@ class Company(models.Model):
|
||||
@api.model
|
||||
def create_missing_inventory_loss_location(self):
|
||||
company_ids = self.env['res.company'].search([])
|
||||
inventory_loss_product_template_field = self.env['ir.model.fields'].search([('model','=','product.template'),('name','=','property_stock_inventory')])
|
||||
companies_having_property = self.env['ir.property'].search([('fields_id', '=', inventory_loss_product_template_field.id)]).mapped('company_id')
|
||||
inventory_loss_product_template_field = self.env['ir.model.fields']._get('product.template', 'property_stock_inventory')
|
||||
companies_having_property = self.env['ir.property'].sudo().search([('fields_id', '=', inventory_loss_product_template_field.id)]).mapped('company_id')
|
||||
company_without_property = company_ids - companies_having_property
|
||||
company_without_property._create_inventory_loss_location()
|
||||
|
||||
@api.model
|
||||
def create_missing_production_location(self):
|
||||
company_ids = self.env['res.company'].search([])
|
||||
production_product_template_field = self.env['ir.model.fields'].search([('model','=','product.template'),('name','=','property_stock_production')])
|
||||
companies_having_property = self.env['ir.property'].search([('fields_id', '=', production_product_template_field.id)]).mapped('company_id')
|
||||
production_product_template_field = self.env['ir.model.fields']._get('product.template', 'property_stock_production')
|
||||
companies_having_property = self.env['ir.property'].sudo().search([('fields_id', '=', production_product_template_field.id)]).mapped('company_id')
|
||||
company_without_property = company_ids - companies_having_property
|
||||
company_without_property._create_production_location()
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ access_product_product_stock_manager,product.product stock_manager,product.model
|
||||
access_product_packaging_stock_manager,product.packaging stock_manager,product.model_product_packaging,stock.group_stock_manager,1,1,1,1
|
||||
access_product_supplierinfo_stock_manager,product.supplierinfo stock_manager,product.model_product_supplierinfo,stock.group_stock_manager,1,1,1,1
|
||||
access_product_pricelist_stock_manager,product.pricelist stock_manager,product.model_product_pricelist,stock.group_stock_manager,1,1,1,1
|
||||
access_ir_property_group_stock_manager,ir_property group_stock_manager,base.model_ir_property,stock.group_stock_manager,1,1,1,1
|
||||
access_product_group_res_partner_stock_manager,res_partner group_stock_manager,base.model_res_partner,stock.group_stock_manager,1,1,1,0
|
||||
access_product_pricelist_item_stock_manager,product.pricelist.item stock_manager,product.model_product_pricelist_item,stock.group_stock_manager,1,1,1,1
|
||||
access_stock_warehouse_orderpoint,stock.warehouse.orderpoint,model_stock_warehouse_orderpoint,stock.group_stock_user,1,0,0,0
|
||||
|
||||
|
@@ -16,8 +16,9 @@ def _configure_journals(cr, registry):
|
||||
|
||||
for company_id in company_ids:
|
||||
# Check if property exists for stock account journal exists
|
||||
properties = env['ir.property'].search([
|
||||
('name', '=', 'property_stock_journal'),
|
||||
field = env['ir.model.fields']._get("product.category", "property_stock_journal")
|
||||
properties = env['ir.property'].sudo().search([
|
||||
('fields_id', '=', field.id),
|
||||
('company_id', '=', company_id.id)])
|
||||
|
||||
# If not, check if you can find a journal that is already there with the same name, otherwise create one
|
||||
@@ -34,7 +35,7 @@ def _configure_journals(cr, registry):
|
||||
'company_id': company_id.id,
|
||||
'show_on_dashboard': False
|
||||
}).id
|
||||
env['ir.property'].set_default(
|
||||
env['ir.property']._set_default(
|
||||
'property_stock_journal',
|
||||
'product.category',
|
||||
journal_id,
|
||||
@@ -51,7 +52,7 @@ def _configure_journals(cr, registry):
|
||||
for name in todo_list:
|
||||
account = getattr(company_id, name)
|
||||
if account:
|
||||
env['ir.property'].set_default(
|
||||
env['ir.property']._set_default(
|
||||
name,
|
||||
'product.category',
|
||||
account,
|
||||
|
||||
@@ -20,43 +20,16 @@ class AccountChartTemplate(models.Model):
|
||||
PropertyObj = self.env['ir.property'] # Property Stock Journal
|
||||
value = self.env['account.journal'].search([('company_id', '=', company.id), ('code', '=', 'STJ'), ('type', '=', 'general')], limit=1)
|
||||
if value:
|
||||
field = self.env['ir.model.fields'].search([('name', '=', 'property_stock_journal'), ('model', '=', 'product.category'), ('relation', '=', 'account.journal')], limit=1)
|
||||
vals = {
|
||||
'name': 'property_stock_journal',
|
||||
'company_id': company.id,
|
||||
'fields_id': field.id,
|
||||
'value': 'account.journal,%s' % value.id,
|
||||
}
|
||||
properties = PropertyObj.search([('name', '=', 'property_stock_journal'), ('company_id', '=', company.id)])
|
||||
if properties:
|
||||
# the property exist: modify it
|
||||
properties.write(vals)
|
||||
else:
|
||||
# create the property
|
||||
PropertyObj.create(vals)
|
||||
PropertyObj._set_default("property_stock_journal", "product.category", value, company)
|
||||
|
||||
todo_list = [ # Property Stock Accounts
|
||||
'property_stock_account_input_categ_id',
|
||||
'property_stock_account_output_categ_id',
|
||||
'property_stock_valuation_account_id',
|
||||
]
|
||||
for record in todo_list:
|
||||
account = getattr(self, record)
|
||||
value = account and 'account.account,' + str(acc_template_ref[account.id]) or False
|
||||
if value:
|
||||
field = self.env['ir.model.fields'].search([('name', '=', record), ('model', '=', 'product.category'), ('relation', '=', 'account.account')], limit=1)
|
||||
vals = {
|
||||
'name': record,
|
||||
'company_id': company.id,
|
||||
'fields_id': field.id,
|
||||
'value': value,
|
||||
}
|
||||
properties = PropertyObj.search([('name', '=', record), ('company_id', '=', company.id)], limit=1)
|
||||
if not properties:
|
||||
# create the property
|
||||
PropertyObj.create(vals)
|
||||
elif not properties.value_reference:
|
||||
# update the property if False
|
||||
properties.write(vals)
|
||||
for field in todo_list:
|
||||
account = self[field]
|
||||
value = acc_template_ref[account.id] if account else False
|
||||
PropertyObj._set_default(field, "product.category", value, company)
|
||||
|
||||
return res
|
||||
|
||||
@@ -11,13 +11,13 @@ class StockAccountTestCommon(AccountTestCommon):
|
||||
super(StockAccountTestCommon, cls).setUpClass()
|
||||
|
||||
# Properties: Stock valuation account and journal
|
||||
cls.env['ir.property'].set_default(
|
||||
cls.env['ir.property']._set_default(
|
||||
'property_stock_valuation_account_id',
|
||||
'product.category',
|
||||
cls.stk,
|
||||
cls.env.company,
|
||||
)
|
||||
cls.env['ir.property'].set_default(
|
||||
cls.env['ir.property']._set_default(
|
||||
'property_stock_journal',
|
||||
'product.category',
|
||||
cls.miscellaneous_journal,
|
||||
|
||||
@@ -28,12 +28,7 @@ class StockLandedCost(models.Model):
|
||||
if self.env.company.lc_journal_id:
|
||||
lc_journal = self.env.company.lc_journal_id
|
||||
else:
|
||||
ir_property = self.env['ir.property'].search([
|
||||
('name', '=', 'property_stock_journal'),
|
||||
('company_id', '=', self.env.company.id)
|
||||
], limit=1)
|
||||
if ir_property:
|
||||
lc_journal = ir_property.get_by_record()
|
||||
lc_journal = self.env['ir.property']._get("property_stock_journal", "product.category")
|
||||
return lc_journal
|
||||
|
||||
name = fields.Char(
|
||||
|
||||
@@ -41,8 +41,8 @@ class TestUi(TestUICommon):
|
||||
})
|
||||
|
||||
Property = self.env['ir.property']
|
||||
Property.set_default('property_account_receivable_id', 'res.partner', a_recv, self.env.company)
|
||||
Property.set_default('property_account_payable_id', 'res.partner', a_pay, self.env.company)
|
||||
Property._set_default('property_account_receivable_id', 'res.partner', a_recv, self.env.company)
|
||||
Property._set_default('property_account_payable_id', 'res.partner', a_pay, self.env.company)
|
||||
|
||||
product_course_channel_6 = self.env['product.product'].create({
|
||||
'name': 'DIY Furniture Course',
|
||||
|
||||
@@ -432,19 +432,9 @@ class TestWebsitePriceListMultiCompany(TransactionCaseWithUserDemo):
|
||||
# Ensure everything was done correctly
|
||||
self.assertEqual(self.demo_user.partner_id.with_company(self.company1.id).property_product_pricelist, self.c1_pl)
|
||||
self.assertEqual(self.demo_user.partner_id.with_company(self.company2.id).property_product_pricelist, self.c2_pl)
|
||||
irp1 = self.env['ir.property'].search([
|
||||
('name', '=', 'property_product_pricelist'),
|
||||
('company_id', '=', self.company1.id),
|
||||
('res_id', '=', 'res.partner,%s' % self.demo_user.partner_id.id),
|
||||
('value_reference', '=', 'product.pricelist,%s' % self.c1_pl.id),
|
||||
])
|
||||
irp2 = self.env['ir.property'].search([
|
||||
('name', '=', 'property_product_pricelist'),
|
||||
('company_id', '=', self.company2.id),
|
||||
('res_id', '=', 'res.partner,%s' % self.demo_user.partner_id.id),
|
||||
('value_reference', '=', 'product.pricelist,%s' % self.c2_pl.id),
|
||||
])
|
||||
self.assertEqual(len(irp1 + irp2), 2, "Ensure there is an `ir.property` for demo partner for every company, and that the pricelist is the company specific one.")
|
||||
irp1 = self.env['ir.property'].with_company(self.company1)._get("property_product_pricelist", "res.partner", self.demo_user.partner_id.id)
|
||||
irp2 = self.env['ir.property'].with_company(self.company2)._get("property_product_pricelist", "res.partner", self.demo_user.partner_id.id)
|
||||
self.assertEqual((irp1, irp2), (self.c1_pl, self.c2_pl), "Ensure there is an `ir.property` for demo partner for every company, and that the pricelist is the company specific one.")
|
||||
simulate_frontend_context(self)
|
||||
# ---------------------------------- IR.PROPERTY -------------------------------------
|
||||
# id | name | res_id | company_id | value_reference
|
||||
|
||||
@@ -176,7 +176,7 @@ class Property(models.Model):
|
||||
return False
|
||||
|
||||
@api.model
|
||||
def set_default(self, name, model, value, company=False):
|
||||
def _set_default(self, name, model, value, company=False):
|
||||
""" Set the given field's generic value for the given company.
|
||||
|
||||
:param name: the field's name
|
||||
@@ -186,7 +186,7 @@ class Property(models.Model):
|
||||
"""
|
||||
field_id = self.env['ir.model.fields']._get(model, name).id
|
||||
company_id = int(company) if company else False
|
||||
prop = self.search([
|
||||
prop = self.sudo().search([
|
||||
('fields_id', '=', field_id),
|
||||
('company_id', '=', company_id),
|
||||
('res_id', '=', False),
|
||||
@@ -194,7 +194,7 @@ class Property(models.Model):
|
||||
if prop:
|
||||
prop.write({'value': value})
|
||||
else:
|
||||
self.create({
|
||||
prop.create({
|
||||
'fields_id': field_id,
|
||||
'company_id': company_id,
|
||||
'res_id': False,
|
||||
@@ -204,7 +204,14 @@ class Property(models.Model):
|
||||
})
|
||||
|
||||
@api.model
|
||||
def get(self, name, model, res_id=False):
|
||||
def _get(self, name, model, res_id=False):
|
||||
""" Get the given field's generic value for the record.
|
||||
|
||||
:param name: the field's name
|
||||
:param model: the field's model name
|
||||
:param res_id: optional resource, format: "<id>" (int) or
|
||||
"<model>,<id>" (str)
|
||||
"""
|
||||
if not res_id:
|
||||
t, v = self._get_default_property(name, model)
|
||||
if not v or t != 'many2one':
|
||||
@@ -216,7 +223,7 @@ class Property(models.Model):
|
||||
return p.get_by_record()
|
||||
return False
|
||||
|
||||
# only cache Property.get(res_id=False) as that's
|
||||
# only cache Property._get(res_id=False) as that's
|
||||
# sub-optimally.
|
||||
COMPANY_KEY = "self.env.company.id"
|
||||
@ormcache(COMPANY_KEY, 'name', 'model')
|
||||
@@ -232,10 +239,12 @@ class Property(models.Model):
|
||||
def _get_property(self, name, model, res_id):
|
||||
domain = self._get_domain(name, model)
|
||||
if domain is not None:
|
||||
if res_id and isinstance(res_id, int):
|
||||
res_id = "%s,%s" % (model, res_id)
|
||||
domain = [('res_id', '=', res_id)] + domain
|
||||
#make the search with company_id asc to make sure that properties specific to a company are given first
|
||||
return self.search(domain, limit=1, order='company_id')
|
||||
return self.browse(())
|
||||
return self.sudo().search(domain, limit=1, order='company_id')
|
||||
return self.sudo().browse(())
|
||||
|
||||
def _get_domain(self, prop_name, model):
|
||||
self._cr.execute("SELECT id FROM ir_model_fields WHERE name=%s AND model=%s", (prop_name, model))
|
||||
@@ -246,7 +255,7 @@ class Property(models.Model):
|
||||
return [('fields_id', '=', res[0]), ('company_id', 'in', [company_id, False])]
|
||||
|
||||
@api.model
|
||||
def get_multi(self, name, model, ids):
|
||||
def _get_multi(self, name, model, ids):
|
||||
""" Read the property field `name` for the records of model `model` with
|
||||
the given `ids`, and return a dictionary mapping `ids` to their
|
||||
corresponding value.
|
||||
@@ -310,7 +319,7 @@ class Property(models.Model):
|
||||
}
|
||||
|
||||
@api.model
|
||||
def set_multi(self, name, model, values, default_value=None):
|
||||
def _set_multi(self, name, model, values, default_value=None):
|
||||
""" Assign the property field `name` for the records of model `model`
|
||||
with `values` (dictionary mapping record ids to their value).
|
||||
If the value for a given record is the same as the default
|
||||
@@ -331,14 +340,14 @@ class Property(models.Model):
|
||||
if domain is None:
|
||||
raise Exception()
|
||||
# retrieve the default value for the field
|
||||
default_value = clean(self.get(name, model))
|
||||
default_value = clean(self._get(name, model))
|
||||
|
||||
# retrieve the properties corresponding to the given record ids
|
||||
self._cr.execute("SELECT id FROM ir_model_fields WHERE name=%s AND model=%s", (name, model))
|
||||
field_id = self._cr.fetchone()[0]
|
||||
company_id = self.env.company.id
|
||||
refs = {('%s,%s' % (model, id)): id for id in values}
|
||||
props = self.search([
|
||||
props = self.sudo().search([
|
||||
('fields_id', '=', field_id),
|
||||
('company_id', '=', company_id),
|
||||
('res_id', 'in', list(refs)),
|
||||
@@ -351,8 +360,6 @@ class Property(models.Model):
|
||||
if value == default_value:
|
||||
# avoid prop.unlink(), as it clears the record cache that can
|
||||
# contain the value of other properties to set on record!
|
||||
prop.check_access_rights('unlink')
|
||||
prop.check_access_rule('unlink')
|
||||
self._cr.execute("DELETE FROM ir_property WHERE id=%s", [prop.id])
|
||||
elif value != clean(prop.get_by_record()):
|
||||
prop.write({'value': value})
|
||||
@@ -370,7 +377,7 @@ class Property(models.Model):
|
||||
'value': value,
|
||||
'type': self.env[model]._fields[name].type,
|
||||
})
|
||||
self.create(vals_list)
|
||||
self.sudo().create(vals_list)
|
||||
|
||||
@api.model
|
||||
def search_multi(self, name, model, operator, value):
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
"access_ir_module_module_group_user","ir_module_module group_user","model_ir_module_module","group_system",1,1,1,1
|
||||
"access_ir_module_module_dependency_group_system","ir_module_module_dependency group_system","model_ir_module_module_dependency","group_system",1,1,1,1
|
||||
"access_ir_module_module_exclusion_group_system","ir_module_module_exclusion group_system","model_ir_module_module_exclusion","group_system",1,1,1,1
|
||||
"access_ir_property_group_user","ir_property group_user","model_ir_property",,1,0,0,0
|
||||
"access_ir_property_group_user_manager","ir_property group_manager","model_ir_property","base.group_partner_manager",1,1,1,0
|
||||
"access_ir_property_group_user","ir_property group_user","model_ir_property",,0,0,0,0
|
||||
"access_ir_property_group_system","ir_property group_system","model_ir_property","base.group_system",1,1,1,0
|
||||
"access_ir_rule_group_erp_manager","ir_rule group_erp_manager","model_ir_rule","group_erp_manager",1,1,1,1
|
||||
"access_ir_sequence_group_user","ir_sequence group_user","model_ir_sequence","group_user",1,0,0,0
|
||||
"access_ir_sequence_group_system","ir_sequence group_system","model_ir_sequence","group_system",1,1,1,1
|
||||
|
||||
|
@@ -235,21 +235,18 @@ class TestORM(TransactionCase):
|
||||
'groups_id': [(6, 0, [self.ref('base.group_partner_manager')])],
|
||||
})
|
||||
p1 = self.env['res.partner'].with_user(user).create({'name': 'Zorro'})
|
||||
p1_prop = self.env['ir.property'].with_user(user).create({
|
||||
'name': 'Slip en laine',
|
||||
'res_id': 'res.partner,{}'.format(p1.id),
|
||||
'fields_id': self.env['ir.model.fields'].search([
|
||||
('model', '=', 'res.partner'), ('name', '=', 'ref')], limit=1).id,
|
||||
'value_text': 'Nain poilu',
|
||||
'type': 'char',
|
||||
})
|
||||
self.env['ir.property'].with_user(user)._set_multi("ref", "res.partner", {p1.id: "Nain poilu"})
|
||||
p1_prop = self.env['ir.property'].with_user(user)._get("ref", "res.partner", res_id=p1.id)
|
||||
self.assertEqual(
|
||||
p1_prop, "Nain poilu", 'p1_prop should have been created')
|
||||
|
||||
# Unlink with unprivileged user
|
||||
p1.unlink()
|
||||
|
||||
# ir.property is deleted
|
||||
p1_prop = self.env['ir.property'].with_user(user)._get("ref", "res.partner", res_id=p1.id)
|
||||
self.assertEqual(
|
||||
p1_prop.exists(), self.env['ir.property'], 'p1_prop should have been deleted')
|
||||
p1_prop, False, 'p1_prop should have been deleted')
|
||||
|
||||
def test_create_multi(self):
|
||||
""" create for multiple records """
|
||||
|
||||
@@ -37,11 +37,11 @@ class BaseTestUi(odoo.tests.HttpCase):
|
||||
})
|
||||
|
||||
Property = self.env['ir.property']
|
||||
Property.set_default('property_account_receivable_id', 'res.partner', a_recv, self.env.company)
|
||||
Property.set_default('property_account_payable_id', 'res.partner', a_pay, self.env.company)
|
||||
Property.set_default('property_account_position_id', 'res.partner', False, self.env.company)
|
||||
Property.set_default('property_account_expense_categ_id', 'product.category', a_expense, self.env.company)
|
||||
Property.set_default('property_account_income_categ_id', 'product.category', a_sale, self.env.company)
|
||||
Property._set_default('property_account_receivable_id', 'res.partner', a_recv, self.env.company)
|
||||
Property._set_default('property_account_payable_id', 'res.partner', a_pay, self.env.company)
|
||||
Property._set_default('property_account_position_id', 'res.partner', False, self.env.company)
|
||||
Property._set_default('property_account_expense_categ_id', 'product.category', a_expense, self.env.company)
|
||||
Property._set_default('property_account_income_categ_id', 'product.category', a_sale, self.env.company)
|
||||
|
||||
self.expenses_journal = self.env['account.journal'].create({
|
||||
'name': 'Vendor Bills - Test',
|
||||
|
||||
@@ -1071,9 +1071,9 @@ class TestFields(TransactionCaseWithUserDemo):
|
||||
tag2 = self.env['test_new_api.multi.tag'].create({'name': 'Quuz'})
|
||||
|
||||
# create default values for the company-dependent fields
|
||||
self.env['ir.property'].set_default('foo', 'test_new_api.company', 'default')
|
||||
self.env['ir.property'].set_default('foo', 'test_new_api.company', 'default1', company1)
|
||||
self.env['ir.property'].set_default('tag_id', 'test_new_api.company', tag0)
|
||||
self.env['ir.property']._set_default('foo', 'test_new_api.company', 'default')
|
||||
self.env['ir.property']._set_default('foo', 'test_new_api.company', 'default1', company1)
|
||||
self.env['ir.property']._set_default('tag_id', 'test_new_api.company', tag0)
|
||||
|
||||
# assumption: users don't have access to 'ir.property'
|
||||
accesses = self.env['ir.model.access'].search([('model_id.model', '=', 'ir.property')])
|
||||
|
||||
@@ -459,7 +459,7 @@ class TestIrPropertyOptimizations(TransactionCase):
|
||||
self.Eggs = self.env['test_performance.eggs']
|
||||
|
||||
def test_with_falsy_default(self):
|
||||
self.assertFalse(self.env['ir.property'].get('property_eggs', 'test_performance.bacon'))
|
||||
self.assertFalse(self.env['ir.property']._get('property_eggs', 'test_performance.bacon'))
|
||||
|
||||
# warmup
|
||||
eggs = self.Eggs.create({})
|
||||
@@ -485,14 +485,9 @@ class TestIrPropertyOptimizations(TransactionCase):
|
||||
|
||||
def test_with_truthy_default(self):
|
||||
eggs = self.Eggs.create({})
|
||||
field = self.env['ir.model.fields']._get('test_performance.bacon', 'property_eggs')
|
||||
self.env['ir.property'].create({
|
||||
'name': 'property_eggs_with_bacon',
|
||||
'fields_id': field.id,
|
||||
'value': eggs,
|
||||
})
|
||||
self.env['ir.property']._set_default("property_eggs", "test_performance.bacon", eggs)
|
||||
|
||||
self.assertEqual(eggs, self.env['ir.property'].get('property_eggs', 'test_performance.bacon'))
|
||||
self.assertEqual(eggs, self.env['ir.property']._get('property_eggs', 'test_performance.bacon'))
|
||||
|
||||
# warmup
|
||||
self.Bacon.create({})
|
||||
|
||||
+3
-3
@@ -571,12 +571,12 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
#
|
||||
|
||||
def _default_company_dependent(self, model):
|
||||
return model.env['ir.property'].get(self.name, self.model_name)
|
||||
return model.env['ir.property']._get(self.name, self.model_name)
|
||||
|
||||
def _compute_company_dependent(self, records):
|
||||
# read property as superuser, as the current user may not have access
|
||||
Property = records.env['ir.property'].sudo()
|
||||
values = Property.get_multi(self.name, self.model_name, records.ids)
|
||||
values = Property._get_multi(self.name, self.model_name, records.ids)
|
||||
for record in records:
|
||||
record[self.name] = values.get(record.id)
|
||||
|
||||
@@ -587,7 +587,7 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
record.id: self.convert_to_write(record[self.name], record)
|
||||
for record in records
|
||||
}
|
||||
Property.set_multi(self.name, self.model_name, values)
|
||||
Property._set_multi(self.name, self.model_name, values)
|
||||
|
||||
def _search_company_dependent(self, records, operator, value):
|
||||
Property = records.env['ir.property']
|
||||
|
||||
+1
-1
@@ -3705,7 +3705,7 @@ Record ids: %(records)s
|
||||
if not field:
|
||||
raise ValueError("Invalid field %r on model %r" % (key, self._name))
|
||||
if field.company_dependent:
|
||||
irprop_def = self.env['ir.property'].get(key, self._name)
|
||||
irprop_def = self.env['ir.property']._get(key, self._name)
|
||||
cached_def = field.convert_to_cache(irprop_def, self)
|
||||
cached_val = field.convert_to_cache(val, self)
|
||||
if cached_val == cached_def:
|
||||
|
||||
Reference in New Issue
Block a user