diff --git a/addons/account/models/account_account.py b/addons/account/models/account_account.py index c9d2de963bd..d4def8834aa 100644 --- a/addons/account/models/account_account.py +++ b/addons/account/models/account_account.py @@ -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): diff --git a/addons/account/models/account_payment_term.py b/addons/account/models/account_payment_term.py index bb918807168..c7d8dd8d734 100644 --- a/addons/account/models/account_payment_term.py +++ b/addons/account/models/account_payment_term.py @@ -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() diff --git a/addons/account/models/chart_template.py b/addons/account/models/chart_template.py index 202aa38b291..6f12b955724 100644 --- a/addons/account/models/chart_template.py +++ b/addons/account/models/chart_template.py @@ -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', diff --git a/addons/account/tests/common.py b/addons/account/tests/common.py index b46ca6f93c4..5c665ef1092 100644 --- a/addons/account/tests/common.py +++ b/addons/account/tests/common.py @@ -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({ diff --git a/addons/hr/security/ir.model.access.csv b/addons/hr/security/ir.model.access.csv index 906cef3ee87..5f5fbd458c9 100644 --- a/addons/hr/security/ir.model.access.csv +++ b/addons/hr/security/ir.model.access.csv @@ -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 diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py index fe9e0bddc60..7c1c6734234 100644 --- a/addons/hr_expense/models/hr_expense.py +++ b/addons/hr_expense/models/hr_expense.py @@ -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 diff --git a/addons/mrp_subcontracting/models/res_company.py b/addons/mrp_subcontracting/models/res_company.py index 14a7955e98f..583d2413916 100644 --- a/addons/mrp_subcontracting/models/res_company.py +++ b/addons/mrp_subcontracting/models/res_company.py @@ -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 diff --git a/addons/point_of_sale/tests/test_frontend.py b/addons/point_of_sale/tests/test_frontend.py index 63807196588..9fe59733ba1 100644 --- a/addons/point_of_sale/tests/test_frontend.py +++ b/addons/point_of_sale/tests/test_frontend.py @@ -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') diff --git a/addons/pos_restaurant/tests/test_frontend.py b/addons/pos_restaurant/tests/test_frontend.py index 44ae56444c2..28d023f294e 100644 --- a/addons/pos_restaurant/tests/test_frontend.py +++ b/addons/pos_restaurant/tests/test_frontend.py @@ -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, diff --git a/addons/product/models/product_pricelist.py b/addons/product/models/product_pricelist.py index 4938c9c313b..680ed729cf9 100644 --- a/addons/product/models/product_pricelist.py +++ b/addons/product/models/product_pricelist.py @@ -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 diff --git a/addons/product/models/res_company.py b/addons/product/models/res_company.py index 94e053eda23..5a44de1afc1 100644 --- a/addons/product/models/res_company.py +++ b/addons/product/models/res_company.py @@ -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, diff --git a/addons/product/models/res_partner.py b/addons/product/models/res_partner.py index 786923ef5a4..5b641d5f811 100644 --- a/addons/product/models/res_partner.py +++ b/addons/product/models/res_partner.py @@ -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}, diff --git a/addons/sale/security/ir.model.access.csv b/addons/sale/security/ir.model.access.csv index c09cd3a62ff..e380e0d77a1 100644 --- a/addons/sale/security/ir.model.access.csv +++ b/addons/sale/security/ir.model.access.csv @@ -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 diff --git a/addons/stock/models/res_company.py b/addons/stock/models/res_company.py index 2e7c5bd474c..4ae579ebaeb 100644 --- a/addons/stock/models/res_company.py +++ b/addons/stock/models/res_company.py @@ -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() diff --git a/addons/stock/security/ir.model.access.csv b/addons/stock/security/ir.model.access.csv index ea20a1f51c5..3ad0386e7d6 100644 --- a/addons/stock/security/ir.model.access.csv +++ b/addons/stock/security/ir.model.access.csv @@ -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 diff --git a/addons/stock_account/__init__.py b/addons/stock_account/__init__.py index e0fb76fd2d7..d4786823b49 100644 --- a/addons/stock_account/__init__.py +++ b/addons/stock_account/__init__.py @@ -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, diff --git a/addons/stock_account/models/account_chart_template.py b/addons/stock_account/models/account_chart_template.py index 16796b947c5..8f6105d09bb 100644 --- a/addons/stock_account/models/account_chart_template.py +++ b/addons/stock_account/models/account_chart_template.py @@ -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 diff --git a/addons/stock_account/tests/common.py b/addons/stock_account/tests/common.py index 68d79a1b8d9..6eec8bce93c 100644 --- a/addons/stock_account/tests/common.py +++ b/addons/stock_account/tests/common.py @@ -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, diff --git a/addons/stock_landed_costs/models/stock_landed_cost.py b/addons/stock_landed_costs/models/stock_landed_cost.py index 66f5a6e9a45..63222bc1385 100644 --- a/addons/stock_landed_costs/models/stock_landed_cost.py +++ b/addons/stock_landed_costs/models/stock_landed_cost.py @@ -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( diff --git a/addons/test_website_slides_full/tests/test_ui_wslides.py b/addons/test_website_slides_full/tests/test_ui_wslides.py index e8b45d55d7e..c3e999db7a8 100644 --- a/addons/test_website_slides_full/tests/test_ui_wslides.py +++ b/addons/test_website_slides_full/tests/test_ui_wslides.py @@ -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', diff --git a/addons/website_sale/tests/test_website_sale_pricelist.py b/addons/website_sale/tests/test_website_sale_pricelist.py index 04306b9b263..01d5e58049d 100644 --- a/addons/website_sale/tests/test_website_sale_pricelist.py +++ b/addons/website_sale/tests/test_website_sale_pricelist.py @@ -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 diff --git a/odoo/addons/base/models/ir_property.py b/odoo/addons/base/models/ir_property.py index f554f013ac5..aa9a6c04535 100644 --- a/odoo/addons/base/models/ir_property.py +++ b/odoo/addons/base/models/ir_property.py @@ -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: "" (int) or + "," (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): diff --git a/odoo/addons/base/security/ir.model.access.csv b/odoo/addons/base/security/ir.model.access.csv index 328d36cc421..0a0abc9d090 100644 --- a/odoo/addons/base/security/ir.model.access.csv +++ b/odoo/addons/base/security/ir.model.access.csv @@ -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 diff --git a/odoo/addons/base/tests/test_orm.py b/odoo/addons/base/tests/test_orm.py index 2e0406e6b5b..285e4b67290 100644 --- a/odoo/addons/base/tests/test_orm.py +++ b/odoo/addons/base/tests/test_orm.py @@ -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 """ diff --git a/odoo/addons/test_main_flows/tests/test_flow.py b/odoo/addons/test_main_flows/tests/test_flow.py index 4aaca90ed4d..6d2cfab311b 100644 --- a/odoo/addons/test_main_flows/tests/test_flow.py +++ b/odoo/addons/test_main_flows/tests/test_flow.py @@ -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', diff --git a/odoo/addons/test_new_api/tests/test_new_fields.py b/odoo/addons/test_new_api/tests/test_new_fields.py index 6df342aaf94..44a1fe695bf 100644 --- a/odoo/addons/test_new_api/tests/test_new_fields.py +++ b/odoo/addons/test_new_api/tests/test_new_fields.py @@ -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')]) diff --git a/odoo/addons/test_performance/tests/test_performance.py b/odoo/addons/test_performance/tests/test_performance.py index d77ef7c1a21..01bab7187e2 100644 --- a/odoo/addons/test_performance/tests/test_performance.py +++ b/odoo/addons/test_performance/tests/test_performance.py @@ -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({}) diff --git a/odoo/fields.py b/odoo/fields.py index d64555e0025..56f58364809 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -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'] diff --git a/odoo/models.py b/odoo/models.py index 8af30b89bb5..f88bcce1dca 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -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: