[IMP] *: Convert single create method into multi

Taskid: 2703085
Part-of: odoo/odoo#80824
Co-authored-by: Victor Feyens <vfe@odoo.com>
This commit is contained in:
Yannick Tivisse
2021-12-14 19:13:18 +00:00
co-authored by Victor Feyens
parent b403c7e068
commit 18952cdc76
81 changed files with 1027 additions and 1033 deletions
+12 -11
View File
@@ -639,21 +639,22 @@ class AccountJournal(models.Model):
if 'refund_sequence' not in vals:
vals['refund_sequence'] = vals['type'] in ('sale', 'purchase')
@api.model
def create(self, vals):
# OVERRIDE
self._fill_missing_values(vals)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
self._fill_missing_values(vals)
journal = super(AccountJournal, self.with_context(mail_create_nolog=True)).create(vals)
journals = super(AccountJournal, self.with_context(mail_create_nolog=True)).create(vals_list)
if 'alias_name' in vals:
journal._update_mail_alias(vals)
for journal, vals in zip(journals, vals_list):
if 'alias_name' in vals:
journal._update_mail_alias(vals)
# Create the bank_account_id if necessary
if journal.type == 'bank' and not journal.bank_account_id and vals.get('bank_acc_number'):
journal.set_bank_account(vals.get('bank_acc_number'), vals.get('bank_id'))
# Create the bank_account_id if necessary
if journal.type == 'bank' and not journal.bank_account_id and vals.get('bank_acc_number'):
journal.set_bank_account(vals.get('bank_acc_number'), vals.get('bank_id'))
return journal
return journals
def set_bank_account(self, acc_number, bank_id=None):
""" Create a res.partner.bank (if not exists) and set it as value of the field bank_account_id """
@@ -156,10 +156,11 @@ class AccountPaymentMethodLine(models.Model):
account.reconcile = True
return super().write(vals)
@api.model
@api.model_create_multi
def create(self, vals_list):
if 'payment_account_id' in vals_list:
account = self.env['account.account'].browse(vals_list['payment_account_id'])
if not account.reconcile:
account.reconcile = True
for vals in vals_list:
if 'payment_account_id' in vals:
account = self.env['account.account'].browse(vals['payment_account_id'])
if not account.reconcile:
account.reconcile = True
return super().create(vals_list)
+16 -15
View File
@@ -1187,25 +1187,26 @@ class AccountTaxRepartitionLineTemplate(models.Model):
plus_report_line_ids = fields.Many2many(string="Plus Tax Report Lines", relation='account_tax_repartition_plus_report_line', comodel_name='account.tax.report.line', copy=True, help="Tax report lines whose '+' tag will be assigned to move lines by this repartition line")
minus_report_line_ids = fields.Many2many(string="Minus Report Lines", relation='account_tax_repartition_minus_report_line', comodel_name='account.tax.report.line', copy=True, help="Tax report lines whose '-' tag will be assigned to move lines by this repartition line")
@api.model
def create(self, vals):
if vals.get('plus_report_line_ids'):
vals['plus_report_line_ids'] = self._convert_tag_syntax_to_orm(vals['plus_report_line_ids'])
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get('plus_report_line_ids'):
vals['plus_report_line_ids'] = self._convert_tag_syntax_to_orm(vals['plus_report_line_ids'])
if vals.get('minus_report_line_ids'):
vals['minus_report_line_ids'] = self._convert_tag_syntax_to_orm(vals['minus_report_line_ids'])
if vals.get('minus_report_line_ids'):
vals['minus_report_line_ids'] = self._convert_tag_syntax_to_orm(vals['minus_report_line_ids'])
if vals.get('tag_ids'):
vals['tag_ids'] = self._convert_tag_syntax_to_orm(vals['tag_ids'])
if vals.get('tag_ids'):
vals['tag_ids'] = self._convert_tag_syntax_to_orm(vals['tag_ids'])
if vals.get('use_in_tax_closing') is None:
if not vals.get('account_id'):
vals['use_in_tax_closing'] = False
else:
internal_group = self.env['account.account.template'].browse(vals.get('account_id')).user_type_id.internal_group
vals['use_in_tax_closing'] = not (internal_group == 'income' or internal_group == 'expense')
if vals.get('use_in_tax_closing') is None:
if not vals.get('account_id'):
vals['use_in_tax_closing'] = False
else:
internal_group = self.env['account.account.template'].browse(vals.get('account_id')).user_type_id.internal_group
vals['use_in_tax_closing'] = not (internal_group == 'income' or internal_group == 'expense')
return super(AccountTaxRepartitionLineTemplate, self).create(vals)
return super().create(vals_list)
@api.model
def _convert_tag_syntax_to_orm(self, tags_list):
+8 -7
View File
@@ -148,13 +148,14 @@ class AccountFiscalPosition(models.Model):
zip_to = zip_to.rjust(max_length, '0')
return zip_from, zip_to
@api.model
def create(self, vals):
zip_from = vals.get('zip_from')
zip_to = vals.get('zip_to')
if zip_from and zip_to:
vals['zip_from'], vals['zip_to'] = self._convert_zip_values(zip_from, zip_to)
return super(AccountFiscalPosition, self).create(vals)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
zip_from = vals.get('zip_from')
zip_to = vals.get('zip_to')
if zip_from and zip_to:
vals['zip_from'], vals['zip_to'] = self._convert_zip_values(zip_from, zip_to)
return super().create(vals_list)
def write(self, vals):
zip_from = vals.get('zip_from')
+10 -9
View File
@@ -87,21 +87,22 @@ class SetupBarBankConfigWizard(models.TransientModel):
for record in self:
record.new_journal_name = record.acc_number
@api.model
def create(self, vals):
@api.model_create_multi
def create(self, vals_list):
""" This wizard is only used to setup an account for the current active
company, so we always inject the corresponding partner when creating
the model.
"""
vals['partner_id'] = self.env.company.partner_id.id
vals['new_journal_name'] = vals['acc_number']
for vals in vals_list:
vals['partner_id'] = self.env.company.partner_id.id
vals['new_journal_name'] = vals['acc_number']
# If no bank has been selected, but we have a bic, we are using it to find or create the bank
if not vals['bank_id'] and vals['bank_bic']:
vals['bank_id'] = self.env['res.bank'].search([('bic', '=', vals['bank_bic'])], limit=1).id \
or self.env['res.bank'].create({'name': vals['bank_bic'], 'bic': vals['bank_bic']}).id
# If no bank has been selected, but we have a bic, we are using it to find or create the bank
if not vals['bank_id'] and vals['bank_bic']:
vals['bank_id'] = self.env['res.bank'].search([('bic', '=', vals['bank_bic'])], limit=1).id \
or self.env['res.bank'].create({'name': vals['bank_bic'], 'bic': vals['bank_bic']}).id
return super(SetupBarBankConfigWizard, self).create(vals)
return super().create(vals_list)
@api.onchange('linked_journal_id')
def _onchange_new_journal_related_data(self):
@@ -57,12 +57,11 @@ class AccountJournal(models.Model):
journal.check_sequence_id.sudo().number_next_actual = int(journal.check_next_number)
journal.check_sequence_id.sudo().padding = len(journal.check_next_number)
@api.model
def create(self, vals):
rec = super(AccountJournal, self).create(vals)
if not rec.check_sequence_id:
rec._create_check_sequence()
return rec
@api.model_create_multi
def create(self, vals_list):
journals = super().create(vals_list)
journals.filtered(lambda j: not j.check_sequence_id)._create_check_sequence()
return journals
@api.returns('self', lambda value: value.id)
def copy(self, default=None):
@@ -53,21 +53,22 @@ class TestStreetFields(TransactionCase):
# test street -> street values (compute)
for idx, (company_values, expected_vals) in enumerate(zip(input_values, expected)):
company_values['name'] = 'Test-%2d' % idx
company = self.env['res.company'].create(company_values)
values = dict(company_values, name='Test-%2d' % idx)
company = self.env['res.company'].create(values)
self.assertStreetVals(company, expected_vals)
self.assertStreetVals(company.partner_id, expected_vals)
# test street_values -> street (inverse)
for idx, (company_values, expected_vals) in enumerate(zip(input_values, expected)):
company_values['name'] = 'TestNew-%2d' % idx
expected_street = company_values.pop('street')
company_values.update(expected_vals)
company = self.env['res.company'].create(company_values)
values = dict(company_values)
values['name'] = 'TestNew-%2d' % idx
expected_street = values.pop('street')
values.update(expected_vals)
company = self.env['res.company'].create(values)
self.assertEqual(company.street, expected_street)
self.assertStreetVals(company, company_values)
self.assertStreetVals(company, values)
self.assertEqual(company.partner_id.street, expected_street)
self.assertStreetVals(company.partner_id, company_values)
self.assertStreetVals(company.partner_id, values)
def test_company_write(self):
""" Will test the compute and inverse methods of street fields when updating partner records. """
+7 -5
View File
@@ -83,14 +83,16 @@ class CouponProgram(models.Model):
if self.discount_type == 'fixed_amount':
self.discount_apply_on = 'on_order'
@api.model
def create(self, vals):
program = super(CouponProgram, self).create(vals)
if not vals.get('discount_line_product_id', False):
@api.model_create_multi
def create(self, vals_list):
programs = super().create(vals_list)
for program in programs:
if program.discount_line_product_id:
continue
values = program._get_discount_product_values()
discount_line_product_id = self.env['product.product'].create(values)
program.write({'discount_line_product_id': discount_line_product_id.id})
return program
return programs
def write(self, vals):
res = super(CouponProgram, self).write(vals)
+23 -19
View File
@@ -237,26 +237,30 @@ class FleetVehicle(models.Model):
res.append(('id', search_operator, res_ids))
return res
@api.model
def create(self, vals):
# Fleet administrator may not have rights to create the plan_to_change_car value when the driver_id is a res.user
@api.model_create_multi
def create(self, vals_list):
# Fleet administrator may not have rights to create the plan_to_change_car
# value when the driver_id is a res.user.
# This trick is used to prevent access right error.
ptc_value = 'plan_to_change_car' in vals.keys() and {'plan_to_change_car': vals.pop('plan_to_change_car')}
res = super(FleetVehicle, self).create(vals)
if ptc_value:
res.sudo().write(ptc_value)
if 'driver_id' in vals and vals['driver_id']:
res.create_driver_history(vals)
if 'future_driver_id' in vals and vals['future_driver_id']:
state_waiting_list = self.env.ref('fleet.fleet_vehicle_state_waiting_list', raise_if_not_found=False)
states = res.mapped('state_id').ids
if not state_waiting_list or state_waiting_list.id not in states:
future_driver = self.env['res.partner'].browse(vals['future_driver_id'])
if self.vehicle_type == 'bike':
future_driver.sudo().write({'plan_to_change_bike': True})
if self.vehicle_type == 'car':
future_driver.sudo().write({'plan_to_change_car': True})
return res
ptc_values = [
'plan_to_change_car' in vals.keys() and {'plan_to_change_car': vals.pop('plan_to_change_car')} for vals in vals_list
]
vehicles = super().create(vals_list)
for vehicle, vals, ptc_value in zip(vehicles, vals_list, ptc_values):
if ptc_value:
vehicle.sudo().write(ptc_value)
if 'driver_id' in vals and vals['driver_id']:
vehicle.create_driver_history(vals)
if 'future_driver_id' in vals and vals['future_driver_id']:
state_waiting_list = self.env.ref('fleet.fleet_vehicle_state_waiting_list', raise_if_not_found=False)
states = vehicle.mapped('state_id').ids
if not state_waiting_list or state_waiting_list.id not in states:
future_driver = self.env['res.partner'].browse(vals['future_driver_id'])
if self.vehicle_type == 'bike':
future_driver.sudo().write({'plan_to_change_bike': True})
if self.vehicle_type == 'car':
future_driver.sudo().write({'plan_to_change_car': True})
return vehicles
def write(self, vals):
if 'driver_id' in vals and vals['driver_id']:
+8 -7
View File
@@ -53,16 +53,17 @@ class Department(models.Model):
if not self._check_recursion():
raise ValidationError(_('You cannot create recursive departments.'))
@api.model
def create(self, vals):
@api.model_create_multi
def create(self, vals_list):
# TDE note: auto-subscription of manager done by hand, because currently
# the tracking allows to track+subscribe fields linked to a res.user record
# An update of the limited behavior should come, but not currently done.
department = super(Department, self.with_context(mail_create_nosubscribe=True)).create(vals)
manager = self.env['hr.employee'].browse(vals.get("manager_id"))
if manager.user_id:
department.message_subscribe(partner_ids=manager.user_id.partner_id.ids)
return department
departments = super(Department, self.with_context(mail_create_nosubscribe=True)).create(vals_list)
for department, vals in zip(departments, vals_list):
manager = self.env['hr.employee'].browse(vals.get("manager_id"))
if manager.user_id:
department.message_subscribe(partner_ids=manager.user_id.partner_id.ids)
return departments
def write(self, vals):
""" If updating manager of a department, we need to update all the employees
+22 -20
View File
@@ -277,26 +277,28 @@ class HrEmployeePrivate(models.Model):
vals['tz'] = user.tz
return vals
@api.model
def create(self, vals):
if vals.get('user_id'):
user = self.env['res.users'].browse(vals['user_id'])
vals.update(self._sync_user(user, bool(vals.get('image_1920'))))
vals['name'] = vals.get('name', user.name)
employee = super(HrEmployeePrivate, self).create(vals)
if employee.department_id:
self.env['mail.channel'].sudo().search([
('subscription_department_ids', 'in', employee.department_id.id)
])._subscribe_users_automatically()
# Launch onboarding plans
url = '/web#%s' % url_encode({
'action': 'hr.plan_wizard_action',
'active_id': employee.id,
'active_model': 'hr.employee',
'menu_id': self.env.ref('hr.menu_hr_root').id,
})
employee._message_log(body=_('<b>Congratulations!</b> May I recommend you to setup an <a href="%s">onboarding plan?</a>') % (url))
return employee
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get('user_id'):
user = self.env['res.users'].browse(vals['user_id'])
vals.update(self._sync_user(user, bool(vals.get('image_1920'))))
vals['name'] = vals.get('name', user.name)
employees = super().create(vals_list)
for employee in employees:
if employee.department_id:
self.env['mail.channel'].sudo().search([
('subscription_department_ids', 'in', employee.department_id.id)
])._subscribe_users_automatically()
# Launch onboarding plans
url = '/web#%s' % url_encode({
'action': 'hr.plan_wizard_action',
'active_id': employee.id,
'active_model': 'hr.employee',
'menu_id': self.env.ref('hr.menu_hr_root').id,
})
employee._message_log(body=_('<b>Congratulations!</b> May I recommend you to setup an <a href="%s">onboarding plan?</a>') % (url))
return employees
def write(self, vals):
if 'address_home_id' in vals:
+3 -3
View File
@@ -44,10 +44,10 @@ class Job(models.Model):
job.no_of_employee = result.get(job.id, 0)
job.expected_employees = result.get(job.id, 0) + job.no_of_recruitment
@api.model
def create(self, values):
@api.model_create_multi
def create(self, vals_list):
""" We don't want the current user to be follower of all created job """
return super(Job, self.with_context(mail_create_nosubscribe=True)).create(values)
return super(Job, self.with_context(mail_create_nosubscribe=True)).create(vals_list)
@api.returns('self', lambda value: value.id)
def copy(self, default=None):
+4 -5
View File
@@ -229,11 +229,10 @@ class Contract(models.Model):
return res
@api.model
def create(self, vals):
contracts = super(Contract, self).create(vals)
if vals.get('state') == 'open':
contracts._assign_open_contract()
@api.model_create_multi
def create(self, vals_list):
contracts = super().create(vals_list)
contracts.filtered(lambda c: c.state == 'open')._assign_open_contract()
open_contracts = contracts.filtered(lambda c: c.state == 'open' or c.state == 'draft' and c.kanban_state == 'done')
# sync contract calendar -> calendar employee
for contract in open_contracts.filtered(lambda c: c.employee_id and c.resource_calendar_id):
+20 -11
View File
@@ -946,16 +946,16 @@ class HrExpenseSheet(models.Model):
if any(expense.company_id != sheet.company_id for expense in sheet.expense_line_ids):
raise ValidationError(_('An expense report must contain only lines from the same company.'))
@api.model
def create(self, vals):
@api.model_create_multi
def create(self, vals_list):
context = clean_context(self.env.context)
context.update({
'mail_create_nosubscribe': True,
'mail_auto_subscribe_no_notify': True
})
sheet = super(HrExpenseSheet, self.with_context(context)).create(vals)
sheet.activity_update()
return sheet
sheets = super(HrExpenseSheet, self.with_context(context)).create(vals_list)
sheets.activity_update()
return sheets
@api.ondelete(at_uninstall=False)
def _unlink_except_posted_or_paid(self):
@@ -1134,12 +1134,21 @@ class HrExpenseSheet(models.Model):
return self.env['res.users']
def activity_update(self):
for expense_report in self.filtered(lambda hol: hol.state == 'submit'):
self.activity_schedule(
'hr_expense.mail_act_expense_approval',
user_id=expense_report.sudo()._get_responsible_for_approval().id or self.env.user.id)
self.filtered(lambda hol: hol.state == 'approve').activity_feedback(['hr_expense.mail_act_expense_approval'])
self.filtered(lambda hol: hol.state in ('draft', 'cancel')).activity_unlink(['hr_expense.mail_act_expense_approval'])
reports_requiring_feedback = self.env['hr.expense.sheet']
reports_activity_unlink = self.env['hr.expense.sheet']
for expense_report in self:
if expense_report.state == 'submit':
expense_report.activity_schedule(
'hr_expense.mail_act_expense_approval',
user_id=expense_report.sudo()._get_responsible_for_approval().id or self.env.user.id)
elif expense_report.state == 'approve':
reports_requiring_feedback |= expense_report
elif expense_report.state in ('draft', 'cancel'):
reports_activity_unlink |= expense_report
if reports_requiring_feedback:
reports_requiring_feedback.activity_feedback(['hr_expense.mail_act_expense_approval'])
if reports_activity_unlink:
reports_activity_unlink.activity_unlink(['hr_expense.mail_act_expense_approval'])
def action_register_payment(self):
''' Open the account.payment.register wizard to pay the selected journal entries.
+5 -4
View File
@@ -90,10 +90,11 @@ class FleetVehicle(models.Model):
employee = employee_ids[0].id
vals['future_driver_employee_id'] = employee
@api.model
def create(self, vals):
self._update_create_write_vals(vals)
return super().create(vals)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
self._update_create_write_vals(vals)
return super().create(vals_list)
def write(self, vals):
self._update_create_write_vals(vals)
+13 -10
View File
@@ -182,16 +182,19 @@ class HrEmployeeBase(models.AbstractModel):
])
return [('id', 'in', holidays.mapped('employee_id').ids)]
@api.model
def create(self, values):
if 'parent_id' in values:
manager = self.env['hr.employee'].browse(values['parent_id']).user_id
values['leave_manager_id'] = values.get('leave_manager_id', manager.id)
if values.get('leave_manager_id', False):
approver_group = self.env.ref('hr_holidays.group_hr_holidays_responsible', raise_if_not_found=False)
if approver_group:
approver_group.sudo().write({'users': [(4, values['leave_manager_id'])]})
return super(HrEmployeeBase, self).create(values)
@api.model_create_multi
def create(self, vals_list):
approver_group = self.env.ref('hr_holidays.group_hr_holidays_responsible', raise_if_not_found=False)
group_updates = []
for vals in vals_list:
if 'parent_id' in vals:
manager = self.env['hr.employee'].browse(vals['parent_id']).user_id
vals['leave_manager_id'] = vals.get('leave_manager_id', manager.id)
if approver_group and vals.get('leave_manager_id'):
group_updates.append((4, vals['leave_manager_id']))
if group_updates:
approver_group.sudo().write({'users': group_updates})
return super().create(vals_list)
def write(self, values):
if 'parent_id' in values:
+20 -18
View File
@@ -41,18 +41,19 @@ class MaintenanceEquipment(models.Model):
equipment.employee_id = equipment.employee_id
equipment.assign_date = fields.Date.context_today(self)
@api.model
def create(self, vals):
equipment = super(MaintenanceEquipment, self).create(vals)
# subscribe employee or department manager when equipment assign to him.
partner_ids = []
if equipment.employee_id and equipment.employee_id.user_id:
partner_ids.append(equipment.employee_id.user_id.partner_id.id)
if equipment.department_id and equipment.department_id.manager_id and equipment.department_id.manager_id.user_id:
partner_ids.append(equipment.department_id.manager_id.user_id.partner_id.id)
if partner_ids:
equipment.message_subscribe(partner_ids=partner_ids)
return equipment
@api.model_create_multi
def create(self, vals_list):
equipments = super().create(vals_list)
for equipment in equipments:
# subscribe employee or department manager when equipment assign to him.
partner_ids = []
if equipment.employee_id and equipment.employee_id.user_id:
partner_ids.append(equipment.employee_id.user_id.partner_id.id)
if equipment.department_id and equipment.department_id.manager_id and equipment.department_id.manager_id.user_id:
partner_ids.append(equipment.department_id.manager_id.user_id.partner_id.id)
if partner_ids:
equipment.message_subscribe(partner_ids=partner_ids)
return equipments
def write(self, vals):
partner_ids = []
@@ -95,12 +96,13 @@ class MaintenanceRequest(models.Model):
else:
r.owner_user_id = False
@api.model
def create(self, vals):
result = super(MaintenanceRequest, self).create(vals)
if result.employee_id.user_id:
result.message_subscribe(partner_ids=[result.employee_id.user_id.partner_id.id])
return result
@api.model_create_multi
def create(self, vals_list):
requests = super().create(vals_list)
for request in requests:
if request.employee_id.user_id:
request.message_subscribe(partner_ids=[request.employee_id.user_id.partner_id.id])
return requests
def write(self, vals):
if vals.get('employee_id'):
+10 -9
View File
@@ -23,12 +23,13 @@ class HrEmployee(models.Model):
])
return [('id', 'in', employees.ids)]
@api.model
def create(self, vals):
new_employee = super(HrEmployee, self).create(vals)
if new_employee.applicant_id:
new_employee.applicant_id.message_post_with_view(
'hr_recruitment.applicant_hired_template',
values={'applicant': new_employee.applicant_id},
subtype_id=self.env.ref("hr_recruitment.mt_applicant_hired").id)
return new_employee
@api.model_create_multi
def create(self, vals_list):
employees = super().create(vals_list)
for employee in employees:
if employee.applicant_id:
employee.applicant_id.message_post_with_view(
'hr_recruitment.applicant_hired_template',
values={'applicant': employee.applicant_id},
subtype_id=self.env.ref("hr_recruitment.mt_applicant_hired").id)
return employees
+9 -8
View File
@@ -120,18 +120,19 @@ class Job(models.Model):
})
return values
@api.model
def create(self, vals):
vals['favorite_user_ids'] = vals.get('favorite_user_ids', []) + [(4, self.env.uid)]
new_job = super(Job, self).create(vals)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
vals['favorite_user_ids'] = vals.get('favorite_user_ids', []) + [(4, self.env.uid)]
jobs = super().create(vals_list)
utm_linkedin = self.env.ref("utm.utm_source_linkedin", raise_if_not_found=False)
if utm_linkedin:
source_vals = {
source_vals = [{
'source_id': utm_linkedin.id,
'job_id': new_job.id,
}
'job_id': job.id,
} for job in jobs]
self.env['hr.recruitment.source'].create(source_vals)
return new_job
return jobs
def write(self, vals):
res = super().write(vals)
+20 -21
View File
@@ -340,31 +340,30 @@ class Applicant(models.Model):
if not applicant.stage_id.hired_stage:
applicant.date_closed = False
@api.model
def create(self, vals):
if vals.get('department_id') and not self._context.get('default_department_id'):
self = self.with_context(default_department_id=vals.get('department_id'))
if vals.get('user_id'):
vals['date_open'] = fields.Datetime.now()
if vals.get('email_from'):
vals['email_from'] = vals['email_from'].strip()
res = super().create(vals)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get('user_id'):
vals['date_open'] = fields.Datetime.now()
if vals.get('email_from'):
vals['email_from'] = vals['email_from'].strip()
applicants = super().create(vals_list)
# Record creation through calendar, creates the calendar event directly, it will also create the activity.
if 'default_activity_date_deadline' in self.env.context:
deadline = fields.Datetime.to_datetime(self.env.context.get('default_activity_date_deadline'))
partners = res.partner_id | res.user_id.partner_id | res.department_id.manager_id.user_id.partner_id
category = self.env.ref('hr_recruitment.categ_meet_interview')
self.env['calendar.event'].sudo().with_context(default_applicant_id=res.id).create({
'applicant_id': res.id,
'partner_ids': [(6, 0, partners.ids)],
'user_id': self.env.uid,
'name': res.name,
'categ_ids': [category.id],
'start': deadline,
'stop': deadline + relativedelta(minutes=30),
})
return res
for applicant in applicants:
partners = applicant.partner_id | applicant.user_id.partner_id | applicant.department_id.manager_id.user_id.partner_id
self.env['calendar.event'].sudo().with_context(default_applicant_id=applicant.id).create({
'applicant_id': applicant.id,
'partner_ids': [(6, 0, partners.ids)],
'user_id': self.env.uid,
'name': applicant.name,
'categ_ids': [category.id],
'start': deadline,
'stop': deadline + relativedelta(minutes=30),
})
return applicants
def write(self, vals):
# user_id change: update date_open
+6 -6
View File
@@ -167,13 +167,13 @@ class Project(models.Model):
Note: create it before calling super() to avoid raising the ValidationError from _check_allow_timesheet
"""
defaults = self.default_get(['allow_timesheets', 'analytic_account_id'])
for values in vals_list:
allow_timesheets = values.get('allow_timesheets', defaults.get('allow_timesheets'))
analytic_account_id = values.get('analytic_account_id', defaults.get('analytic_account_id'))
for vals in vals_list:
allow_timesheets = vals.get('allow_timesheets', defaults.get('allow_timesheets'))
analytic_account_id = vals.get('analytic_account_id', defaults.get('analytic_account_id'))
if allow_timesheets and not analytic_account_id:
analytic_account = self._create_analytic_account_from_values(values)
values['analytic_account_id'] = analytic_account.id
return super(Project, self).create(vals_list)
analytic_account = self._create_analytic_account_from_values(vals)
vals['analytic_account_id'] = analytic_account.id
return super().create(vals_list)
def write(self, values):
# create the AA for project still allowing timesheet
+7 -6
View File
@@ -150,12 +150,13 @@ class ResPartnerBank(models.Model):
else:
record.l10n_ch_qr_iban = None
@api.model
def create(self, vals):
if vals.get('l10n_ch_qr_iban'):
validate_qr_iban(vals['l10n_ch_qr_iban'])
vals['l10n_ch_qr_iban'] = pretty_iban(normalize_iban(vals['l10n_ch_qr_iban']))
return super().create(vals)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get('l10n_ch_qr_iban'):
validate_qr_iban(vals['l10n_ch_qr_iban'])
vals['l10n_ch_qr_iban'] = pretty_iban(normalize_iban(vals['l10n_ch_qr_iban']))
return super().create(vals_list)
def write(self, vals):
if vals.get('l10n_ch_qr_iban'):
+6 -5
View File
@@ -47,11 +47,12 @@ class ResPartner(models.Model):
n_vat, n_dv = vat_l[0], vat_l[1]
return '%s-%s' % (format(int(n_vat), ',d').replace(',', '.'), n_dv)
@api.model
def create(self, values):
if values.get('vat'):
values['vat'] = self._format_vat_cl(values)
return super().create(values)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get('vat'):
vals['vat'] = self._format_vat_cl(vals)
return super().create(vals_list)
def write(self, values):
if any(field in values for field in ['vat', 'l10n_latam_identification_type_id', 'country_id']):
@@ -61,27 +61,28 @@ class Certificate(models.Model):
# LOW-LEVEL METHODS
# -------------------------------------------------------------------------
@api.model
def create(self, vals):
record = super().create(vals)
@api.model_create_multi
def create(self, vals_list):
certificates = super().create(vals_list)
spain_tz = timezone('Europe/Madrid')
spain_dt = self._get_es_current_datetime()
try:
_pem_certificate, _pem_private_key, certificate = record._decode_certificate()
cert_date_start = spain_tz.localize(certificate.not_valid_before)
cert_date_end = spain_tz.localize(certificate.not_valid_after)
except Exception:
raise ValidationError(_(
"There has been a problem with the certificate, some usual problems can be:\n"
"- The password given or the certificate are not valid.\n"
"- The certificate content is invalid."
))
# Assign extracted values from the certificate
record.write({
'date_start': fields.Datetime.to_string(cert_date_start),
'date_end': fields.Datetime.to_string(cert_date_end),
})
if spain_dt > cert_date_end:
raise ValidationError(_("The certificate is expired since %s", record.date_end))
return record
for certificate in certificates:
try:
_pem_certificate, _pem_private_key, certif = certificate._decode_certificate()
cert_date_start = spain_tz.localize(certif.not_valid_before)
cert_date_end = spain_tz.localize(certif.not_valid_after)
except Exception:
raise ValidationError(_(
"There has been a problem with the certificate, some usual problems can be:\n"
"- The password given or the certificate are not valid.\n"
"- The certificate content is invalid."
))
# Assign extracted values from the certificate
certificate.write({
'date_start': fields.Datetime.to_string(cert_date_start),
'date_end': fields.Datetime.to_string(cert_date_end),
})
if spain_dt > cert_date_end:
raise ValidationError(_("The certificate is expired since %s", certificate.date_end))
return certificates
@@ -43,20 +43,21 @@ class StockPickingType(models.Model):
ir_seq_prefix = sequence_code + '/DDT'
return ir_seq_name, ir_seq_prefix
@api.model
def create(self, vals):
company = self.env['res.company'].browse(vals['company_id'])
if 'l10n_it_ddt_sequence_id' not in vals or not vals['l10n_it_ddt_sequence_id'] and vals['code'] == 'outgoing' \
and company.country_id.code == 'IT':
ir_seq_name, ir_seq_prefix = self._get_dtt_ir_seq_vals(vals.get('warehouse_id'), vals['sequence_code'])
vals['l10n_it_ddt_sequence_id'] = self.env['ir.sequence'].create({
'name': ir_seq_name,
'prefix': ir_seq_prefix,
'padding': 5,
'company_id': vals['company_id'],
'implementation': 'no_gap',
}).id
return super(StockPickingType, self).create(vals)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
company = self.env['res.company'].browse(vals['company_id'])
if 'l10n_it_ddt_sequence_id' not in vals or not vals['l10n_it_ddt_sequence_id'] and vals['code'] == 'outgoing' \
and company.country_id.code == 'IT':
ir_seq_name, ir_seq_prefix = self._get_dtt_ir_seq_vals(vals.get('warehouse_id'), vals['sequence_code'])
vals['l10n_it_ddt_sequence_id'] = self.env['ir.sequence'].create({
'name': ir_seq_name,
'prefix': ir_seq_prefix,
'padding': 5,
'company_id': vals['company_id'],
'implementation': 'no_gap',
}).id
return super().create(vals_list)
def write(self, vals):
if 'sequence_code' in vals:
+9 -7
View File
@@ -6,13 +6,15 @@ from odoo import models, fields, api
class ResCompany(models.Model):
_inherit = 'res.company'
@api.model
def create(self, vals):
@api.model_create_multi
def create(self, vals_list):
""" If exists, use specific vat identification.type for the country of the company """
country_id = vals.get('country_id')
if country_id:
companies = super().create(vals_list)
for company in companies:
if not company.country_id:
continue
country_vat_type = self.env['l10n_latam.identification.type'].search(
[('is_vat', '=', True), ('country_id', '=', country_id)], limit=1)
[('is_vat', '=', True), ('country_id', '=', company.country_id.id)], limit=1)
if country_vat_type:
self = self.with_context(default_l10n_latam_identification_type_id=country_vat_type.id)
return super().create(vals)
company.partner_id.l10n_latam_identification_type_id = country_vat_type
return companies
+16 -12
View File
@@ -116,18 +116,22 @@ class LunchOrder(models.Model):
if not check:
raise ValidationError(errors[quantity] % label)
@api.model
def create(self, values):
lines = self._find_matching_lines({
**values,
'toppings': self._extract_toppings(values),
})
if lines:
# YTI FIXME This will update multiple lines in the case there are multiple
# matching lines which should not happen through the interface
lines.update_quantity(1)
return lines[:1]
return super().create(values)
@api.model_create_multi
def create(self, vals_list):
orders = self.env['lunch.order']
for vals in vals_list:
lines = self._find_matching_lines({
**vals,
'toppings': self._extract_toppings(vals),
})
if lines:
# YTI FIXME This will update multiple lines in the case there are multiple
# matching lines which should not happen through the interface
lines.update_quantity(1)
orders |= lines[:1]
else:
orders |= super().create(vals)
return orders
def write(self, values):
merge_needed = 'note' in values or 'topping_ids_1' in values or 'topping_ids_2' in values or 'topping_ids_3' in values
+12 -14
View File
@@ -27,20 +27,18 @@ class ResPartner(models.Model):
partner.iap_enrich_info = False
partner.iap_search_domain = False
@api.model
def create(self, vals):
partner = super(ResPartner, self).create(vals)
if vals.get('iap_enrich_info') or vals.get('iap_search_domain'):
# Not done with inverse method so we do not need to search
# for existing <res.partner.iap>
self.env['res.partner.iap'].sudo().create({
'partner_id': partner.id,
'iap_enrich_info': vals.get('iap_enrich_info'),
'iap_search_domain': vals.get('iap_search_domain'),
})
return partner
@api.model_create_multi
def create(self, vals_list):
partners = super().create(vals_list)
# Not done with inverse method so we do not need to search
# for existing <res.partner.iap>
partner_iap_vals_list = [{
'partner_id': partner.id,
'iap_enrich_info': vals.get('iap_enrich_info'),
'iap_search_domain': vals.get('iap_search_domain'),
} for partner, vals in zip(partners, vals_list) if vals.get('iap_enrich_info') or vals.get('iap_search_domain')]
self.env['res.partner.iap'].sudo().create(partner_iap_vals_list)
return partners
def write(self, vals):
super(ResPartner, self).write(vals)
+17 -15
View File
@@ -200,12 +200,13 @@ class MaintenanceEquipment(models.Model):
('serial_no', 'unique(serial_no)', "Another asset already exists with this serial number!"),
]
@api.model
def create(self, vals):
equipment = super(MaintenanceEquipment, self).create(vals)
if equipment.owner_user_id:
equipment.message_subscribe(partner_ids=[equipment.owner_user_id.partner_id.id])
return equipment
@api.model_create_multi
def create(self, vals_list):
equipments = super().create(vals_list)
for equipment in equipments:
if equipment.owner_user_id:
equipment.message_subscribe(partner_ids=[equipment.owner_user_id.partner_id.id])
return equipments
def write(self, vals):
if vals.get('owner_user_id'):
@@ -331,16 +332,17 @@ class MaintenanceRequest(models.Model):
if not self.user_id or not self.equipment_id or (self.user_id and not self.equipment_id.technician_user_id):
self.user_id = self.category_id.technician_user_id
@api.model
def create(self, vals):
@api.model_create_multi
def create(self, vals_list):
# context: no_log, because subtype already handle this
request = super(MaintenanceRequest, self).create(vals)
if request.owner_user_id or request.user_id:
request._add_followers()
if request.equipment_id and not request.maintenance_team_id:
request.maintenance_team_id = request.equipment_id.maintenance_team_id
request.activity_update()
return request
maintenance_requests = super().create(vals_list)
for request in maintenance_requests:
if request.owner_user_id or request.user_id:
request._add_followers()
if request.equipment_id and not request.maintenance_team_id:
request.maintenance_team_id = request.equipment_id.maintenance_team_id
maintenance_requests.activity_update()
return maintenance_requests
def write(self, vals):
# Overridden to reset the kanban_state to normal whenever
@@ -88,12 +88,14 @@ class Mailing(models.Model):
# ORM OVERRIDES
# --------------------------------------------------
@api.model
def create(self, values):
# Get subject from "sms_subject" field when SMS installed (used to build the name of record in the super 'create' method)
if values.get('mailing_type') == 'sms' and values.get('sms_subject'):
values['subject'] = values['sms_subject']
return super(Mailing, self).create(values)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
# Get subject from "sms_subject" field when SMS installed (used to
# build the name of record in the super 'create' method)
if vals.get('mailing_type') == 'sms' and vals.get('sms_subject'):
vals['subject'] = vals['sms_subject']
return super().create(vals_list)
# --------------------------------------------------
# BUSINESS / VIEWS ACTIONS
+33 -31
View File
@@ -765,37 +765,39 @@ class MrpProduction(models.Model):
production.date_planned_finished = new_date_planned_start + datetime.timedelta(hours=1)
return res
@api.model
def create(self, values):
# Remove from `move_finished_ids` the by-product moves and then move `move_byproduct_ids`
# into `move_finished_ids` to avoid duplicate and inconsistency.
if values.get('move_finished_ids', False):
values['move_finished_ids'] = list(filter(lambda move: move[2]['byproduct_id'] is False, values['move_finished_ids']))
if values.get('move_byproduct_ids', False):
values['move_finished_ids'] = values.get('move_finished_ids', []) + values['move_byproduct_ids']
del values['move_byproduct_ids']
if not values.get('name', False) or values['name'] == _('New'):
picking_type_id = values.get('picking_type_id') or self._get_default_picking_type()
picking_type_id = self.env['stock.picking.type'].browse(picking_type_id)
if picking_type_id:
values['name'] = picking_type_id.sequence_id.next_by_id()
else:
values['name'] = self.env['ir.sequence'].next_by_code('mrp.production') or _('New')
if not values.get('procurement_group_id'):
procurement_group_vals = self._prepare_procurement_group_vals(values)
values['procurement_group_id'] = self.env["procurement.group"].create(procurement_group_vals).id
production = super(MrpProduction, self).create(values)
(production.move_raw_ids | production.move_finished_ids).write({
'group_id': production.procurement_group_id.id,
'origin': production.name
})
production.move_raw_ids.write({'date': production.date_planned_start})
production.move_finished_ids.write({'date': production.date_planned_finished})
# Trigger move_raw creation when importing a file
if 'import_file' in self.env.context:
production._onchange_move_raw()
production._onchange_move_finished()
return production
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
# Remove from `move_finished_ids` the by-product moves and then move `move_byproduct_ids`
# into `move_finished_ids` to avoid duplicate and inconsistency.
if vals.get('move_finished_ids', False):
vals['move_finished_ids'] = list(filter(lambda move: move[2]['byproduct_id'] is False, vals['move_finished_ids']))
if vals.get('move_byproduct_ids', False):
vals['move_finished_ids'] = vals.get('move_finished_ids', []) + vals['move_byproduct_ids']
del vals['move_byproduct_ids']
if not vals.get('name', False) or vals['name'] == _('New'):
picking_type_id = vals.get('picking_type_id') or self._get_default_picking_type()
picking_type_id = self.env['stock.picking.type'].browse(picking_type_id)
if picking_type_id:
vals['name'] = picking_type_id.sequence_id.next_by_id()
else:
vals['name'] = self.env['ir.sequence'].next_by_code('mrp.production') or _('New')
if not vals.get('procurement_group_id'):
procurement_group_vals = self._prepare_procurement_group_vals(vals)
vals['procurement_group_id'] = self.env["procurement.group"].create(procurement_group_vals).id
productions = super().create(vals_list)
for production in productions:
(production.move_raw_ids | production.move_finished_ids).write({
'group_id': production.procurement_group_id.id,
'origin': production.name
})
production.move_raw_ids.write({'date': production.date_planned_start})
production.move_finished_ids.write({'date': production.date_planned_finished})
# Trigger move_raw creation when importing a file
if 'import_file' in self.env.context:
production._onchange_move_raw()
production._onchange_move_finished()
return productions
@api.ondelete(at_uninstall=False)
def _unlink_except_done(self):
+6 -5
View File
@@ -108,11 +108,12 @@ class MrpUnbuild(models.Model):
if unbuild.product_qty <= 0:
raise ValueError(_('Unbuild Order product quantity has to be strictly positive.'))
@api.model
def create(self, vals):
if not vals.get('name') or vals['name'] == _('New'):
vals['name'] = self.env['ir.sequence'].next_by_code('mrp.unbuild') or _('New')
return super(MrpUnbuild, self).create(vals)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if not vals.get('name') or vals['name'] == _('New'):
vals['name'] = self.env['ir.sequence'].next_by_code('mrp.unbuild') or _('New')
return super().create(vals_list)
@api.ondelete(at_uninstall=False)
def _unlink_except_done(self):
+5 -5
View File
@@ -6,11 +6,11 @@ from odoo import api, models
class Repair(models.Model):
_inherit = 'repair.order'
@api.model
def create(self, vals):
res = super().create(vals)
res.action_explode()
return res
@api.model_create_multi
def create(self, vals_list):
orders = super().create(vals_list)
orders.action_explode()
return orders
def write(self, vals):
res = super().write(vals)
+19 -18
View File
@@ -435,26 +435,27 @@ class PosConfig(models.Model):
result.append((config.id, "%s (%s)" % (config.name, last_session.user_id.name)))
return result
@api.model
def create(self, values):
IrSequence = self.env['ir.sequence'].sudo()
val = {
'name': _('POS Order %s', values['name']),
'padding': 4,
'prefix': "%s/" % values['name'],
'code': "pos.order",
'company_id': values.get('company_id', False),
}
# force sequence_id field to new pos.order sequence
values['sequence_id'] = IrSequence.create(val).id
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
IrSequence = self.env['ir.sequence'].sudo()
val = {
'name': _('POS Order %s', vals['name']),
'padding': 4,
'prefix': "%s/" % vals['name'],
'code': "pos.order",
'company_id': vals.get('company_id', False),
}
# force sequence_id field to new pos.order sequence
vals['sequence_id'] = IrSequence.create(val).id
val.update(name=_('POS order line %s', values['name']), code='pos.order.line')
values['sequence_line_id'] = IrSequence.create(val).id
pos_config = super(PosConfig, self).create(values)
pos_config.sudo()._check_modules_to_install()
pos_config.sudo()._check_groups_implied()
val.update(name=_('POS order line %s', vals['name']), code='pos.order.line')
vals['sequence_line_id'] = IrSequence.create(val).id
pos_configs = super().create(vals_list)
pos_configs.sudo()._check_modules_to_install()
pos_configs.sudo()._check_groups_implied()
# If you plan to add something after this, use a new environment. The one above is no longer valid after the modules install.
return pos_config
return pos_configs
def write(self, vals):
opened_session = self.mapped('session_ids').filtered(lambda s: s.state != 'closed')
+18 -16
View File
@@ -406,11 +406,12 @@ class PosOrder(models.Model):
for pos_order in self.filtered(lambda pos_order: pos_order.state not in ['draft', 'cancel']):
raise UserError(_('In order to delete a sale, it must be new or cancelled.'))
@api.model
def create(self, values):
session = self.env['pos.session'].browse(values['session_id'])
values = self._complete_values_from_session(session, values)
return super(PosOrder, self).create(values)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
session = self.env['pos.session'].browse(vals['session_id'])
vals = self._complete_values_from_session(session, vals)
return super().create(vals_list)
@api.model
def _complete_values_from_session(self, session, values):
@@ -936,17 +937,18 @@ class PosOrderLine(models.Model):
'refunded_orderline_id': self.id,
}
@api.model
def create(self, values):
if values.get('order_id') and not values.get('name'):
# set name based on the sequence specified on the config
config = self.env['pos.order'].browse(values['order_id']).session_id.config_id
if config.sequence_line_id:
values['name'] = config.sequence_line_id._next()
if not values.get('name'):
# fallback on any pos.order sequence
values['name'] = self.env['ir.sequence'].next_by_code('pos.order.line')
return super(PosOrderLine, self).create(values)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get('order_id') and not vals.get('name'):
# set name based on the sequence specified on the config
config = self.env['pos.order'].browse(vals['order_id']).session_id.config_id
if config.sequence_line_id:
vals['name'] = config.sequence_line_id._next()
if not vals.get('name'):
# fallback on any pos.order sequence
vals['name'] = self.env['ir.sequence'].next_by_code('pos.order.line')
return super().create(vals_list)
def write(self, values):
if values.get('pack_lot_line_ids'):
+39 -39
View File
@@ -199,52 +199,52 @@ class PosSession(models.Model):
['%s - %s' % (invoice.name, invoice.state) for invoice in
unposted_invoices]))
@api.model
def create(self, values):
config_id = values.get('config_id') or self.env.context.get('default_config_id')
if not config_id:
raise UserError(_("You should assign a Point of Sale to your session."))
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
config_id = vals.get('config_id') or self.env.context.get('default_config_id')
if not config_id:
raise UserError(_("You should assign a Point of Sale to your session."))
# journal_id is not required on the pos_config because it does not
# exists at the installation. If nothing is configured at the
# installation we do the minimal configuration. Impossible to do in
# the .xml files as the CoA is not yet installed.
pos_config = self.env['pos.config'].browse(config_id)
ctx = dict(self.env.context, company_id=pos_config.company_id.id)
# journal_id is not required on the pos_config because it does not
# exists at the installation. If nothing is configured at the
# installation we do the minimal configuration. Impossible to do in
# the .xml files as the CoA is not yet installed.
pos_config = self.env['pos.config'].browse(config_id)
ctx = dict(self.env.context, company_id=pos_config.company_id.id)
pos_name = self.env['ir.sequence'].with_context(ctx).next_by_code('pos.session')
if values.get('name'):
pos_name += ' ' + values['name']
pos_name = self.env['ir.sequence'].with_context(ctx).next_by_code('pos.session')
if vals.get('name'):
pos_name += ' ' + vals['name']
cash_payment_methods = pos_config.payment_method_ids.filtered(lambda pm: pm.is_cash_count)
statement_ids = self.env['account.bank.statement']
if self.user_has_groups('point_of_sale.group_pos_user'):
statement_ids = statement_ids.sudo()
for cash_journal in cash_payment_methods.mapped('journal_id'):
ctx['journal_id'] = cash_journal.id if pos_config.cash_control and cash_journal.type == 'cash' else False
st_values = {
'journal_id': cash_journal.id,
'user_id': self.env.user.id,
cash_payment_methods = pos_config.payment_method_ids.filtered(lambda pm: pm.is_cash_count)
statement_ids = self.env['account.bank.statement']
if self.user_has_groups('point_of_sale.group_pos_user'):
statement_ids = statement_ids.sudo()
for cash_journal in cash_payment_methods.mapped('journal_id'):
ctx['journal_id'] = cash_journal.id if pos_config.cash_control and cash_journal.type == 'cash' else False
st_vals = {
'journal_id': cash_journal.id,
'user_id': self.env.user.id,
'name': pos_name,
}
statement_ids |= statement_ids.with_context(ctx).create(st_vals)
update_stock_at_closing = pos_config.company_id.point_of_sale_update_stock_quantities == "closing"
vals.update({
'name': pos_name,
}
statement_ids |= statement_ids.with_context(ctx).create(st_values)
update_stock_at_closing = pos_config.company_id.point_of_sale_update_stock_quantities == "closing"
values.update({
'name': pos_name,
'statement_ids': [(6, 0, statement_ids.ids)],
'config_id': config_id,
'update_stock_at_closing': update_stock_at_closing,
})
'statement_ids': [(6, 0, statement_ids.ids)],
'config_id': config_id,
'update_stock_at_closing': update_stock_at_closing,
})
if self.user_has_groups('point_of_sale.group_pos_user'):
res = super(PosSession, self.with_context(ctx).sudo()).create(values)
sessions = super(PosSession, self.with_context(ctx).sudo()).create(vals_list)
else:
res = super(PosSession, self.with_context(ctx)).create(values)
res.action_pos_session_open()
return res
sessions = super(PosSession, self.with_context(ctx)).create(vals_list)
sessions.action_pos_session_open()
return sessions
def unlink(self):
for session in self.filtered(lambda s: s.statement_ids):
+7 -6
View File
@@ -481,14 +481,15 @@ class Project(models.Model):
self.browse(res[0]).type_ids += self.env['project.task.type'].sudo().create({'name': _('New')})
return res
@api.model
def create(self, vals):
@api.model_create_multi
def create(self, vals_list):
# Prevent double project creation
self = self.with_context(mail_create_nosubscribe=True)
project = super(Project, self).create(vals)
if project.privacy_visibility == 'portal' and project.partner_id:
project.message_subscribe(project.partner_id.ids)
return project
projects = super().create(vals_list)
for project in projects:
if project.privacy_visibility == 'portal' and project.partner_id:
project.message_subscribe(project.partner_id.ids)
return projects
def write(self, vals):
# directly compute is_favorite to dodge allow write access right
@@ -276,13 +276,14 @@ class ProjectTaskRecurrence(models.Model):
recurrence.recurrence_left -= 1
recurring_today._set_next_recurrence_date()
@api.model
def create(self, vals):
if vals.get('repeat_number'):
vals['recurrence_left'] = vals.get('repeat_number')
res = super(ProjectTaskRecurrence, self).create(vals)
res._set_next_recurrence_date()
return res
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get('repeat_number'):
vals['recurrence_left'] = vals.get('repeat_number')
recurrences = super().create(vals_list)
recurrences._set_next_recurrence_date()
return recurrences
def write(self, vals):
if vals.get('repeat_number'):
+6 -5
View File
@@ -75,11 +75,12 @@ class ProjectUpdate(models.Model):
# ---------------------------------
# ORM Override
# ---------------------------------
@api.model
def create(self, vals):
update = super().create(vals)
update.project_id.sudo().last_update_id = update
return update
@api.model_create_multi
def create(self, vals_list):
updates = super().create(vals_list)
for update in updates:
update.project_id.sudo().last_update_id = update
return updates
def unlink(self):
projects = self.project_id
@@ -7,29 +7,30 @@ from odoo import api, fields, models
class Employee(models.Model):
_inherit = 'hr.employee'
@api.model
def create(self, vals):
result = super(Employee, self).create(vals)
@api.model_create_multi
def create(self, vals_list):
employees = super().create(vals_list)
# We need to create timesheet entries for the global time off that are already created
# and are planned for after this employee creation date
# First we look for the global time off that are already planned after today
today = fields.Datetime.today()
global_leaves = result.resource_calendar_id.global_leave_ids.filtered(lambda l: l.date_from >= today)
work_hours_data = global_leaves._work_time_per_day()
lines_vals = []
for employee in employees:
global_leaves = employee.resource_calendar_id.global_leave_ids.filtered(lambda l: l.date_from >= today)
work_hours_data = global_leaves._work_time_per_day()
vals_list = []
for global_time_off in global_leaves:
for index, (day_date, work_hours_count) in enumerate(work_hours_data[global_time_off.id]):
vals_list.append(
global_time_off._timesheet_prepare_line_values(
index,
result,
work_hours_data[global_time_off.id],
day_date,
work_hours_count
for global_time_off in global_leaves:
for index, (day_date, work_hours_count) in enumerate(work_hours_data[global_time_off.id]):
lines_vals.append(
global_time_off._timesheet_prepare_line_values(
index,
employee,
work_hours_data[global_time_off.id],
day_date,
work_hours_count
)
)
)
self.env['account.analytic.line'].sudo().create(vals_list)
return result
self.env['account.analytic.line'].sudo().create(lines_vals)
return employees
+20 -15
View File
@@ -231,21 +231,26 @@ class PurchaseOrder(models.Model):
self.partner_id.sudo().write(partner_vals) # Because the purchase user doesn't have write on `res.partner`
return res
@api.model
def create(self, vals):
company_id = vals.get('company_id', self.default_get(['company_id'])['company_id'])
# Ensures default picking type and currency are taken from the right company.
self_comp = self.with_company(company_id)
if vals.get('name', 'New') == 'New':
seq_date = None
if 'date_order' in vals:
seq_date = fields.Datetime.context_timestamp(self, fields.Datetime.to_datetime(vals['date_order']))
vals['name'] = self_comp.env['ir.sequence'].next_by_code('purchase.order', sequence_date=seq_date) or '/'
vals, partner_vals = self._write_partner_values(vals)
res = super(PurchaseOrder, self_comp).create(vals)
if partner_vals:
res.sudo().write(partner_vals) # Because the purchase user doesn't have write on `res.partner`
return res
@api.model_create_multi
def create(self, vals_list):
orders = self.browse()
partner_vals_list = []
for vals in vals_list:
company_id = vals.get('company_id', self.default_get(['company_id'])['company_id'])
# Ensures default picking type and currency are taken from the right company.
self_comp = self.with_company(company_id)
if vals.get('name', 'New') == 'New':
seq_date = None
if 'date_order' in vals:
seq_date = fields.Datetime.context_timestamp(self, fields.Datetime.to_datetime(vals['date_order']))
vals['name'] = self_comp.env['ir.sequence'].next_by_code('purchase.order', sequence_date=seq_date) or '/'
vals, partner_vals = self._write_partner_values(vals)
partner_vals_list.append(partner_vals)
orders |= super(PurchaseOrder, self_comp).create(vals)
for order, partner_vals in zip(orders, partner_vals_list):
if partner_vals:
order.sudo().write(partner_vals) # Because the purchase user doesn't have write on `res.partner`
return orders
@api.ondelete(at_uninstall=False)
def _unlink_if_cancelled(self):
+11 -8
View File
@@ -88,14 +88,17 @@ class PurchaseOrder(models.Model):
po.requisition_id.action_done()
return res
@api.model
def create(self, vals):
purchase = super(PurchaseOrder, self).create(vals)
if purchase.requisition_id:
purchase.message_post_with_view('mail.message_origin_link',
values={'self': purchase, 'origin': purchase.requisition_id},
subtype_id=self.env['ir.model.data']._xmlid_to_res_id('mail.mt_note'))
return purchase
@api.model_create_multi
def create(self, vals_list):
orders = super().create(vals_list)
mt_note = self.env['ir.model.data']._xmlid_to_res_id('mail.mt_note')
for order in orders:
if order.requisition_id:
order.message_post_with_view(
'mail.message_origin_link',
values={'self': order, 'origin': order.requisition_id},
subtype_id=mt_note)
return orders
def write(self, vals):
result = super(PurchaseOrder, self).write(vals)
@@ -183,19 +183,20 @@ class PurchaseRequisitionLine(models.Model):
schedule_date = fields.Date(string='Scheduled Date')
supplier_info_ids = fields.One2many('product.supplierinfo', 'purchase_requisition_line_id')
@api.model
def create(self,vals):
res = super(PurchaseRequisitionLine, self).create(vals)
if res.requisition_id.state not in ['draft', 'cancel', 'done'] and res.requisition_id.is_quantity_copy == 'none':
supplier_infos = self.env['product.supplierinfo'].search([
('product_id', '=', vals.get('product_id')),
('partner_id', '=', res.requisition_id.vendor_id.id),
])
if not any(s.purchase_requisition_id for s in supplier_infos):
res.create_supplier_info()
if vals['price_unit'] <= 0.0:
raise UserError(_('You cannot confirm the blanket order without price.'))
return res
@api.model_create_multi
def create(self, vals_list):
lines = super().create(vals_list)
for line, vals in zip(lines, vals_list):
if line.requisition_id.state not in ['draft', 'cancel', 'done'] and line.requisition_id.is_quantity_copy == 'none':
supplier_infos = self.env['product.supplierinfo'].search([
('product_id', '=', vals.get('product_id')),
('partner_id', '=', line.requisition_id.vendor_id.id),
])
if not any(s.purchase_requisition_id for s in supplier_infos):
line.create_supplier_info()
if vals['price_unit'] <= 0.0:
raise UserError(_('You cannot confirm the blanket order without price.'))
return lines
def write(self, vals):
res = super(PurchaseRequisitionLine, self).write(vals)
+5 -4
View File
@@ -211,11 +211,12 @@ class Repair(models.Model):
if order.state not in ('draft', 'cancel'):
raise UserError(_('You can not delete a repair order once it has been confirmed. You must first cancel it.'))
@api.model
def create(self, vals):
@api.model_create_multi
def create(self, vals_list):
# We generate a standard reference
vals['name'] = self.env['ir.sequence'].next_by_code('repair.order') or '/'
return super(Repair, self).create(vals)
for vals in vals_list:
vals['name'] = self.env['ir.sequence'].next_by_code('repair.order') or '/'
return super().create(vals_list)
def button_dummy(self):
# TDE FIXME: this button is very interesting
+10 -8
View File
@@ -23,12 +23,14 @@ class ResCompany(models.Model):
'company_id': company.id
}).id
@api.model
def create(self, values):
company = super(ResCompany, self).create(values)
if not company.resource_calendar_id:
company.sudo()._create_resource_calendar()
@api.model_create_multi
def create(self, vals_list):
companies = super().create(vals_list)
companies_without_calendar = companies.filtered(lambda c: not c.resource_calendar_id)
if companies_without_calendar:
companies_without_calendar.sudo()._create_resource_calendar()
# calendar created from form view: no company_id set because record was still not created
if not company.resource_calendar_id.company_id:
company.resource_calendar_id.company_id = company.id
return company
for company in companies:
if not company.resource_calendar_id.company_id:
company.resource_calendar_id.company_id = company.id
return companies
+18 -11
View File
@@ -33,17 +33,24 @@ class ResourceMixin(models.AbstractModel):
string='Timezone', related='resource_id.tz', readonly=False,
help="This field is used in order to define in which timezone the resources will work.")
@api.model
def create(self, values):
if not values.get('resource_id'):
resource_vals = {'name': values.get(self._rec_name)}
tz = (values.pop('tz', False) or
self.env['resource.calendar'].browse(values.get('resource_calendar_id')).tz)
if tz:
resource_vals['tz'] = tz
resource = self.env['resource.resource'].create(resource_vals)
values['resource_id'] = resource.id
return super(ResourceMixin, self).create(values)
@api.model_create_multi
def create(self, vals_list):
resources_vals_list = []
calendar_ids = [vals['resource_calendar_id'] for vals in vals_list if vals.get('resource_calendar_id')]
calendars_tz = {calendar.id: calendar.tz for calendar in self.env['resource.calendar'].browse(calendar_ids)}
for vals in vals_list:
if not vals.get('resource_id'):
resource_vals = {'name': vals.get(self._rec_name)}
tz = vals.pop('tz', False) or calendars_tz.get(vals.get('resource_calendar_id'))
if tz:
resource_vals['tz'] = tz
resources_vals_list.append(resource_vals)
resources = self.env['resource.resource'].create(resources_vals_list)
resources_iter = iter(resources.ids)
for vals in vals_list:
if not vals.get('resource_id'):
vals['resource_id'] = next(resources_iter)
return super().create(vals_list)
def copy_data(self, default=None):
if default is None:
-99
View File
@@ -49,28 +49,22 @@
<record id="sale_order_line_1" model="sale.order.line">
<field name="order_id" ref="sale_order_1"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_25').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">3</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">295.00</field>
</record>
<record id="sale_order_line_2" model="sale.order.line">
<field name="order_id" ref="sale_order_1"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_delivery_02').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_delivery_02"/>
<field name="product_uom_qty">5</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">145.00</field>
</record>
<record id="sale_order_line_3" model="sale.order.line">
<field name="order_id" ref="sale_order_1"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_delivery_01').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_delivery_01"/>
<field name="product_uom_qty">2</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">65.00</field>
</record>
@@ -90,19 +84,15 @@
<record id="sale_order_line_4" model="sale.order.line">
<field name="order_id" ref="sale_order_2"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_1').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_1"/>
<field name="product_uom_qty">24</field>
<field name="product_uom" ref="uom.product_uom_hour"/>
<field name="price_unit">75.00</field>
</record>
<record id="sale_order_line_5" model="sale.order.line">
<field name="order_id" ref="sale_order_2"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_2').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_2"/>
<field name="product_uom_qty">30</field>
<field name="product_uom" ref="uom.product_uom_hour"/>
<field name="price_unit">38.25</field>
</record>
@@ -121,20 +111,14 @@
<record id="sale_order_line_6" model="sale.order.line">
<field name="order_id" ref="sale_order_3"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_1').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_1"/>
<field name="product_uom_qty">10</field>
<field name="product_uom" ref="uom.product_uom_hour"/>
<field name="price_unit">30.75</field>
</record>
<record id="sale_order_line_7" model="sale.order.line">
<field name="order_id" ref="sale_order_3"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_delivery_01').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_delivery_01"/>
<field name="product_uom_qty">1</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">70.00</field>
</record>
<record id="sale_order_4" model="sale.order">
@@ -151,38 +135,29 @@
<record id="sale_order_line_8" model="sale.order.line">
<field name="order_id" ref="sale_order_4"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_1').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_1"/>
<field name="product_uom_qty">16</field>
<field name="product_uom" ref="uom.product_uom_hour"/>
<field name="price_unit">75.00</field>
</record>
<record id="sale_order_line_9" model="sale.order.line">
<field name="order_id" ref="sale_order_4"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_delivery_02').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_delivery_02"/>
<field name="product_uom_qty">10</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">45.00</field>
</record>
<record id="sale_order_line_10" model="sale.order.line">
<field name="order_id" ref="sale_order_4"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.consu_delivery_02').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.consu_delivery_02"/>
<field name="product_uom_qty">3</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">150.00</field>
</record>
<record id="sale_order_line_11" model="sale.order.line">
<field name="order_id" ref="sale_order_4"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_delivery_01').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_delivery_01"/>
<field name="product_uom_qty">2</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">70.00</field>
</record>
<record id="sale_order_5" model="sale.order">
@@ -200,10 +175,7 @@
<record id="sale_order_line_12" model="sale.order.line">
<field name="order_id" ref="sale_order_5"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_delivery_02').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_delivery_02"/>
<field name="product_uom_qty">1</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">405.00</field>
</record>
@@ -222,10 +194,7 @@
<record id="sale_order_line_15" model="sale.order.line">
<field name="order_id" ref="sale_order_6"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_4').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_4"/>
<field name="product_uom_qty">1</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">750.00</field>
</record>
@@ -244,37 +213,26 @@
<record id="sale_order_line_16" model="sale.order.line">
<field name="order_id" ref="sale_order_7"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_25').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">5</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">295.00</field>
</record>
<record id="sale_order_line_17" model="sale.order.line">
<field name="order_id" ref="sale_order_7"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.consu_delivery_01').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.consu_delivery_01"/>
<field name="product_uom_qty">1</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">173.00</field>
</record>
<record id="sale_order_line_18" model="sale.order.line">
<field name="order_id" ref="sale_order_7"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_delivery_02').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_delivery_02"/>
<field name="product_uom_qty">1</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">40.00</field>
</record>
<record id="sale_order_line_19" model="sale.order.line">
<field name="order_id" ref="sale_order_7"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_delivery_01').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_delivery_01"/>
<field name="product_uom_qty">1</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">18.00</field>
</record>
@@ -293,19 +251,15 @@
<record id="sale_order_line_20" model="sale.order.line">
<field name="order_id" ref="sale_order_8"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_27').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_27"/>
<field name="product_uom_qty">2</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">110.50</field>
</record>
<record id="sale_order_line_21" model="sale.order.line">
<field name="order_id" ref="sale_order_8"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_12').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">2</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">120.50</field>
</record>
@@ -326,19 +280,15 @@
<record id="sale_order_line_22" model="sale.order.line">
<field name="order_id" ref="sale_order_9"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_27').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_27"/>
<field name="product_uom_qty">3</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">97.50</field>
</record>
<record id="sale_order_line_23" model="sale.order.line">
<field name="order_id" ref="sale_order_9"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_12').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">3</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">120.50</field>
</record>
@@ -358,19 +308,15 @@
<record id="sale_order_line_24" model="sale.order.line">
<field name="order_id" ref="sale_order_10"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_25').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">2</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">255.00</field>
</record>
<record id="sale_order_line_25" model="sale.order.line">
<field name="order_id" ref="sale_order_10"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_12').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">2</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">120.50</field>
</record>
@@ -390,19 +336,15 @@
<record id="sale_order_line_26" model="sale.order.line">
<field name="order_id" ref="sale_order_11"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_25').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">3</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">245.00</field>
</record>
<record id="sale_order_line_27" model="sale.order.line">
<field name="order_id" ref="sale_order_11"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_12').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">3</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">120.50</field>
</record>
@@ -422,19 +364,14 @@
<record id="sale_order_line_28" model="sale.order.line">
<field name="order_id" ref="sale_order_12"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_25').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">1</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">315.00</field>
</record>
<record id="sale_order_line_29" model="sale.order.line">
<field name="order_id" ref="sale_order_12"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_12').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">2</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">120.50</field>
</record>
@@ -453,19 +390,13 @@
<record id="sale_order_line_30" model="sale.order.line">
<field name="order_id" ref="sale_order_13"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_25').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">1</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">295.00</field>
</record>
<record id="sale_order_line_31" model="sale.order.line">
<field name="order_id" ref="sale_order_13"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_12').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">1</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">120.50</field>
</record>
@@ -484,19 +415,15 @@
<record id="sale_order_line_32" model="sale.order.line">
<field name="order_id" ref="sale_order_14"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_25').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">4</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">275.00</field>
</record>
<record id="sale_order_line_33" model="sale.order.line">
<field name="order_id" ref="sale_order_14"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_12').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">4</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">120.50</field>
</record>
@@ -515,19 +442,15 @@
<record id="sale_order_line_34" model="sale.order.line">
<field name="order_id" ref="sale_order_15"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_25').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">4</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">295.00</field>
</record>
<record id="sale_order_line_35" model="sale.order.line">
<field name="order_id" ref="sale_order_15"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_12').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">3</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">120.50</field>
</record>
@@ -546,19 +469,15 @@
<record id="sale_order_line_36" model="sale.order.line">
<field name="order_id" ref="sale_order_16"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_25').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">3</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">275.00</field>
</record>
<record id="sale_order_line_37" model="sale.order.line">
<field name="order_id" ref="sale_order_16"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_12').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">3</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">120.50</field>
</record>
@@ -577,19 +496,15 @@
<record id="sale_order_line_38" model="sale.order.line">
<field name="order_id" ref="sale_order_17"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_25').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">2</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">355.00</field>
</record>
<record id="sale_order_line_39" model="sale.order.line">
<field name="order_id" ref="sale_order_17"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_12').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">2</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">120.50</field>
</record>
@@ -608,19 +523,15 @@
<record id="sale_order_line_40" model="sale.order.line">
<field name="order_id" ref="sale_order_18"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_25').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">2</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">295.00</field>
</record>
<record id="sale_order_line_41" model="sale.order.line">
<field name="order_id" ref="sale_order_18"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_12').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">2</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">120.50</field>
</record>
@@ -729,28 +640,22 @@ Thanks!</field>
<record id="portal_sale_order_line_1" model="sale.order.line">
<field name="order_id" ref="portal_sale_order_1"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_25').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">3</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">295.00</field>
</record>
<record id="portal_sale_order_line_2" model="sale.order.line">
<field name="order_id" ref="portal_sale_order_1"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_delivery_02').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_delivery_02"/>
<field name="product_uom_qty">5</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">145.00</field>
</record>
<record id="portal_sale_order_line_3" model="sale.order.line">
<field name="order_id" ref="portal_sale_order_1"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_delivery_01').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_delivery_01"/>
<field name="product_uom_qty">2</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">65.00</field>
</record>
@@ -767,19 +672,15 @@ Thanks!</field>
<record id="portal_sale_order_line_4" model="sale.order.line">
<field name="order_id" ref="portal_sale_order_2"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_1').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_1"/>
<field name="product_uom_qty">24</field>
<field name="product_uom" ref="uom.product_uom_hour"/>
<field name="price_unit">75.00</field>
</record>
<record id="portal_sale_order_line_5" model="sale.order.line">
<field name="order_id" ref="portal_sale_order_2"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_2').get_product_multiline_description_sale()"/>
<field name="product_id" ref="product.product_product_2"/>
<field name="product_uom_qty">30</field>
<field name="product_uom" ref="uom.product_uom_hour"/>
<field name="price_unit">38.25</field>
</record>
-1
View File
@@ -5,7 +5,6 @@ from . import test_access_rights
from . import test_accrued_sale_orders
from . import test_onchange
from . import test_payment_flow
from . import test_performance
from . import test_reinvoice
from . import test_sale_flow
from . import test_sale_order
-15
View File
@@ -1,15 +0,0 @@
from odoo.tests import tagged
from odoo.addons.base.tests.common import PerformanceCommon
@tagged('post_install', '-at_install')
class TestSalePerformance(PerformanceCommon):
def test_batch_creation_sale_orders(self):
"""Enforce sale.order create overrides always support batch creation"""
self.assertModelCreateMulti('sale.order')
def test_batch_creation_sale_order_line(self):
"""Enforce sale.order.line create overrides always support batch creation"""
self.assertModelCreateMulti('sale.order.line')
@@ -127,11 +127,12 @@ class SaleOrderTemplateLine(models.Model):
self.product_uom_id = self.product_id.uom_id.id
self.name = self.product_id.get_product_multiline_description_sale()
@api.model
def create(self, values):
if values.get('display_type', self.default_get(['display_type'])['display_type']):
values.update(product_id=False, product_uom_qty=0, product_uom_id=False)
return super(SaleOrderTemplateLine, self).create(values)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get('display_type', self.default_get(['display_type'])['display_type']):
vals.update(product_id=False, product_uom_qty=0, product_uom_id=False)
return super().create(vals_list)
def write(self, values):
if 'display_type' in values and self.filtered(lambda line: line.display_type != values.get('display_type')):
@@ -65,11 +65,11 @@ class ProjectProductEmployeeMap(models.Model):
for map_entry in self:
map_entry.is_cost_changed = map_entry.employee_id and map_entry.cost != map_entry.employee_id.timesheet_cost
@api.model
def create(self, values):
res = super(ProjectProductEmployeeMap, self).create(values)
res._update_project_timesheet()
return res
@api.model_create_multi
def create(self, vals_list):
maps = super().create(vals_list)
maps._update_project_timesheet()
return maps
def write(self, values):
res = super(ProjectProductEmployeeMap, self).write(values)
+11 -10
View File
@@ -191,17 +191,18 @@ class Company(models.Model):
def _create_per_company_rules(self):
self.ensure_one()
@api.model
def create(self, vals):
company = super(Company, self).create(vals)
company.sudo()._create_per_company_locations()
company.sudo()._create_per_company_sequences()
company.sudo()._create_per_company_picking_types()
company.sudo()._create_per_company_rules()
self.env['stock.warehouse'].sudo().create({
@api.model_create_multi
def create(self, vals_list):
companies = super().create(vals_list)
for company in companies:
company.sudo()._create_per_company_locations()
company.sudo()._create_per_company_sequences()
company.sudo()._create_per_company_picking_types()
company.sudo()._create_per_company_rules()
self.env['stock.warehouse'].sudo().create([{
'name': company.name,
'code': self.env.context.get('default_code') or company.name[:5],
'company_id': company.id,
'partner_id': company.partner_id.id
})
return company
} for company in companies])
return companies
+8 -7
View File
@@ -139,13 +139,14 @@ class StockPackageLevel(models.Model):
'company_id': package_level.company_id.id,
})
@api.model
def create(self, vals):
result = super(StockPackageLevel, self).create(vals)
if vals.get('location_dest_id'):
result.mapped('move_line_ids').write({'location_dest_id': vals['location_dest_id']})
result.mapped('move_ids').write({'location_dest_id': vals['location_dest_id']})
return result
@api.model_create_multi
def create(self, vals_list):
package_levels = super().create(vals_list)
for package_level, vals in zip(package_levels, vals_list):
if vals.get('location_dest_id'):
package_level.move_line_ids.write({'location_dest_id': vals['location_dest_id']})
package_level.move_ids.write({'location_dest_id': vals['location_dest_id']})
return package_levels
def write(self, vals):
result = super(StockPackageLevel, self).write(vals)
+46 -42
View File
@@ -88,25 +88,24 @@ class PickingType(models.Model):
'res.company', 'Company', required=True,
default=lambda s: s.env.company.id, index=True)
@api.model
def create(self, vals):
if 'sequence_id' not in vals or not vals['sequence_id']:
if vals['warehouse_id']:
wh = self.env['stock.warehouse'].browse(vals['warehouse_id'])
vals['sequence_id'] = self.env['ir.sequence'].sudo().create({
'name': wh.name + ' ' + _('Sequence') + ' ' + vals['sequence_code'],
'prefix': wh.code + '/' + vals['sequence_code'] + '/', 'padding': 5,
'company_id': wh.company_id.id,
}).id
else:
vals['sequence_id'] = self.env['ir.sequence'].sudo().create({
'name': _('Sequence') + ' ' + vals['sequence_code'],
'prefix': vals['sequence_code'], 'padding': 5,
'company_id': vals.get('company_id') or self.env.company.id,
}).id
picking_type = super(PickingType, self).create(vals)
return picking_type
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if 'sequence_id' not in vals or not vals['sequence_id']:
if vals['warehouse_id']:
wh = self.env['stock.warehouse'].browse(vals['warehouse_id'])
vals['sequence_id'] = self.env['ir.sequence'].sudo().create({
'name': wh.name + ' ' + _('Sequence') + ' ' + vals['sequence_code'],
'prefix': wh.code + '/' + vals['sequence_code'] + '/', 'padding': 5,
'company_id': wh.company_id.id,
}).id
else:
vals['sequence_id'] = self.env['ir.sequence'].sudo().create({
'name': _('Sequence') + ' ' + vals['sequence_code'],
'prefix': vals['sequence_code'], 'padding': 5,
'company_id': vals.get('company_id') or self.env.company.id,
}).id
return super().create(vals_list)
def write(self, vals):
if 'company_id' in vals:
@@ -724,32 +723,37 @@ class Picking(models.Model):
"location_dest_id": self.location_dest_id
})
@api.model
def create(self, vals):
defaults = self.default_get(['name', 'picking_type_id'])
picking_type = self.env['stock.picking.type'].browse(vals.get('picking_type_id', defaults.get('picking_type_id')))
if vals.get('name', '/') == '/' and defaults.get('name', '/') == '/' and vals.get('picking_type_id', defaults.get('picking_type_id')):
if picking_type.sequence_id:
vals['name'] = picking_type.sequence_id.next_by_id()
@api.model_create_multi
def create(self, vals_list):
scheduled_dates = []
for vals in vals_list:
defaults = self.default_get(['name', 'picking_type_id'])
picking_type = self.env['stock.picking.type'].browse(vals.get('picking_type_id', defaults.get('picking_type_id')))
if vals.get('name', '/') == '/' and defaults.get('name', '/') == '/' and vals.get('picking_type_id', defaults.get('picking_type_id')):
if picking_type.sequence_id:
vals['name'] = picking_type.sequence_id.next_by_id()
# make sure to write `schedule_date` *after* the `stock.move` creation in
# order to get a determinist execution of `_set_scheduled_date`
scheduled_date = vals.pop('scheduled_date', False)
res = super(Picking, self).create(vals)
if scheduled_date:
res.with_context(mail_notrack=True).write({'scheduled_date': scheduled_date})
res._autoconfirm_picking()
# make sure to write `schedule_date` *after* the `stock.move` creation in
# order to get a determinist execution of `_set_scheduled_date`
scheduled_dates.append(vals.pop('scheduled_date', False))
# set partner as follower
if vals.get('partner_id'):
for picking in res.filtered(lambda p: p.location_id.usage == 'supplier' or p.location_dest_id.usage == 'customer'):
picking.message_subscribe([vals.get('partner_id')])
if vals.get('picking_type_id'):
for move in res.move_ids:
if not move.description_picking:
move.description_picking = move.product_id.with_context(lang=move._get_lang())._get_description(move.picking_id.picking_type_id)
pickings = super().create(vals_list)
return res
for picking, scheduled_date in zip(pickings, scheduled_dates):
if scheduled_date:
picking.with_context(mail_notrack=True).write({'scheduled_date': scheduled_date})
pickings._autoconfirm_picking()
for picking, vals in zip(pickings, vals_list):
# set partner as follower
if vals.get('partner_id'):
if picking.location_id.usage == 'supplier' or picking.location_dest_id.usage == 'customer':
picking.message_subscribe([vals.get('partner_id')])
if vals.get('picking_type_id'):
for move in picking.move_ids:
if not move.description_picking:
move.description_picking = move.product_id.with_context(lang=move._get_lang())._get_description(move.picking_id.picking_type_id)
return pickings
def write(self, vals):
if vals.get('picking_type_id') and any(picking.state != 'draft' for picking in self):
+32 -29
View File
@@ -170,40 +170,43 @@ class StockQuant(models.Model):
domain_operator = 'in'
return [('id', domain_operator, quant_query)]
@api.model
def create(self, vals):
@api.model_create_multi
def create(self, vals_list):
""" Override to handle the "inventory mode" and create a quant as
superuser the conditions are met.
"""
if self._is_inventory_mode() and any(f in vals for f in ['inventory_quantity', 'inventory_quantity_auto_apply']):
allowed_fields = self._get_inventory_fields_create()
if any(field for field in vals.keys() if field not in allowed_fields):
raise UserError(_("Quant's creation is restricted, you can't do this operation."))
quants = self.env['stock.quant']
is_inventory_mode = self._is_inventory_mode()
allowed_fields = self._get_inventory_fields_create()
for vals in vals_list:
if is_inventory_mode and any(f in vals for f in ['inventory_quantity', 'inventory_quantity_auto_apply']):
if any(field for field in vals.keys() if field not in allowed_fields):
raise UserError(_("Quant's creation is restricted, you can't do this operation."))
inventory_quantity = vals.pop('inventory_quantity', False) or vals.pop(
'inventory_quantity_auto_apply', False) or 0
# Create an empty quant or write on a similar one.
product = self.env['product.product'].browse(vals['product_id'])
location = self.env['stock.location'].browse(vals['location_id'])
lot_id = self.env['stock.lot'].browse(vals.get('lot_id'))
package_id = self.env['stock.quant.package'].browse(vals.get('package_id'))
owner_id = self.env['res.partner'].browse(vals.get('owner_id'))
quant = self._gather(product, location, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=True)
inventory_quantity = vals.pop('inventory_quantity', False) or vals.pop(
'inventory_quantity_auto_apply', False) or 0
# Create an empty quant or write on a similar one.
product = self.env['product.product'].browse(vals['product_id'])
location = self.env['stock.location'].browse(vals['location_id'])
lot_id = self.env['stock.lot'].browse(vals.get('lot_id'))
package_id = self.env['stock.quant.package'].browse(vals.get('package_id'))
owner_id = self.env['res.partner'].browse(vals.get('owner_id'))
quant = self._gather(product, location, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=True)
if quant:
quant = quant[0].sudo()
if quant:
quant = quant[0].sudo()
else:
quant = self.sudo().create(vals)
# Set the `inventory_quantity` field to create the necessary move.
quant.inventory_quantity = inventory_quantity
quant.user_id = vals.get('user_id', self.env.user.id)
quant.inventory_date = fields.Date.today()
quants |= quant
else:
quant = self.sudo().create(vals)
# Set the `inventory_quantity` field to create the necessary move.
quant.inventory_quantity = inventory_quantity
quant.user_id = vals.get('user_id', self.env.user.id)
quant.inventory_date = fields.Date.today()
return quant
res = super(StockQuant, self).create(vals)
if self._is_inventory_mode():
res._check_company()
return res
quant = super().create(vals)
quants |= quant
if self._is_inventory_mode():
quant._check_company()
return quants
def _load_records_create(self, values):
""" Add default location if import file did not fill it"""
+32 -29
View File
@@ -106,44 +106,47 @@ class Warehouse(models.Model):
}
}
@api.model
def create(self, vals):
# create view location for warehouse then create all locations
loc_vals = {'name': vals.get('code'), 'usage': 'view',
'location_id': self.env.ref('stock.stock_location_locations').id}
if vals.get('company_id'):
loc_vals['company_id'] = vals.get('company_id')
vals['view_location_id'] = self.env['stock.location'].create(loc_vals).id
sub_locations = self._get_locations_values(vals)
for field_name, values in sub_locations.items():
values['location_id'] = vals['view_location_id']
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
# create view location for warehouse then create all locations
loc_vals = {'name': vals.get('code'), 'usage': 'view',
'location_id': self.env.ref('stock.stock_location_locations').id}
if vals.get('company_id'):
values['company_id'] = vals.get('company_id')
vals[field_name] = self.env['stock.location'].with_context(active_test=False).create(values).id
loc_vals['company_id'] = vals.get('company_id')
vals['view_location_id'] = self.env['stock.location'].create(loc_vals).id
sub_locations = self._get_locations_values(vals)
for field_name, values in sub_locations.items():
values['location_id'] = vals['view_location_id']
if vals.get('company_id'):
values['company_id'] = vals.get('company_id')
vals[field_name] = self.env['stock.location'].with_context(active_test=False).create(values).id
# actually create WH
warehouse = super(Warehouse, self).create(vals)
# create sequences and operation types
new_vals = warehouse._create_or_update_sequences_and_picking_types()
warehouse.write(new_vals) # TDE FIXME: use super ?
# create routes and push/stock rules
route_vals = warehouse._create_or_update_route()
warehouse.write(route_vals)
warehouses = super().create(vals_list)
# Update global route with specific warehouse rule.
warehouse._create_or_update_global_routes_rules()
for warehouse, vals in zip(warehouses, vals_list):
# create sequences and operation types
new_vals = warehouse._create_or_update_sequences_and_picking_types()
warehouse.write(new_vals) # TDE FIXME: use super ?
# create routes and push/stock rules
route_vals = warehouse._create_or_update_route()
warehouse.write(route_vals)
# create route selectable on the product to resupply the warehouse from another one
warehouse.create_resupply_routes(warehouse.resupply_wh_ids)
# Update global route with specific warehouse rule.
warehouse._create_or_update_global_routes_rules()
# update partner data if partner assigned
if vals.get('partner_id'):
self._update_partner_data(vals['partner_id'], vals.get('company_id'))
# create route selectable on the product to resupply the warehouse from another one
warehouse.create_resupply_routes(warehouse.resupply_wh_ids)
# update partner data if partner assigned
if vals.get('partner_id'):
self._update_partner_data(vals['partner_id'], vals.get('company_id'))
self._check_multiwarehouse_group()
return warehouse
return warehouses
def write(self, vals):
if 'company_id' in vals:
+1 -1
View File
@@ -300,7 +300,7 @@ class TestInventory(TransactionCase):
after an adjustment.
"""
# Set product quantity to 42.
inventory_quant = self.env['stock.quant'].create(vals={
inventory_quant = self.env['stock.quant'].create({
'product_id': self.product1.id,
'location_id': self.stock_location.id,
'inventory_quantity': 42,
@@ -83,11 +83,12 @@ class StockLandedCost(models.Model):
if self.target_model != 'picking':
self.picking_ids = False
@api.model
def create(self, vals):
if vals.get('name', _('New')) == _('New'):
vals['name'] = self.env['ir.sequence'].next_by_code('stock.landed.cost')
return super().create(vals)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get('name', _('New')) == _('New'):
vals['name'] = self.env['ir.sequence'].next_by_code('stock.landed.cost')
return super().create(vals_list)
def unlink(self):
self.button_cancel()
@@ -43,12 +43,13 @@ class StockPicking(models.Model):
states={'done': [('readonly', True)], 'cancel': [('readonly', True)]},
help='Batch associated to this transfer', copy=False)
@api.model
def create(self, vals):
res = super().create(vals)
if vals.get('batch_id'):
res.batch_id._sanity_check()
return res
@api.model_create_multi
def create(self, vals_list):
pickings = super().create(vals_list)
for picking, vals in zip(pickings, vals_list):
if vals.get('batch_id'):
picking.batch_id._sanity_check()
return pickings
def write(self, vals):
batches = self.batch_id
@@ -152,14 +152,16 @@ class StockPickingBatch(models.Model):
# -------------------------------------------------------------------------
# CRUD
# -------------------------------------------------------------------------
@api.model
def create(self, vals):
if vals.get('name', '/') == '/':
if vals.get('is_wave'):
vals['name'] = self.env['ir.sequence'].next_by_code('picking.wave') or '/'
else:
vals['name'] = self.env['ir.sequence'].next_by_code('picking.batch') or '/'
return super().create(vals)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get('name', '/') == '/':
company_id = vals.get('company_id', self.env.company.id)
if vals.get('is_wave'):
vals['name'] = self.env['ir.sequence'].with_company(company_id).next_by_code('picking.wave') or '/'
else:
vals['name'] = self.env['ir.sequence'].with_company(company_id).next_by_code('picking.batch') or '/'
return super().create(vals_list)
def write(self, vals):
res = super().write(vals)
+6 -5
View File
@@ -17,12 +17,13 @@ class Attachment(models.Model):
key = fields.Char(help='Technical field used to resolve multiple attachments in a multi-website environment.')
website_id = fields.Many2one('website')
@api.model
def create(self, vals):
@api.model_create_multi
def create(self, vals_list):
website = self.env['website'].get_current_website(fallback=False)
if website and 'website_id' not in vals and 'not_force_website_id' not in self.env.context:
vals['website_id'] = website.id
return super(Attachment, self).create(vals)
for vals in vals_list:
if website and 'website_id' not in vals and 'not_force_website_id' not in self.env.context:
vals['website_id'] = website.id
return super().create(vals_list)
@api.model
def get_serving_groups(self):
+12 -10
View File
@@ -174,24 +174,26 @@ class Website(models.Model):
def _get_menu_ids(self):
return self.env['website.menu'].search([('website_id', '=', self.id)]).ids
@api.model
def create(self, vals):
self._handle_create_write(vals)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
self._handle_create_write(vals)
if 'user_id' not in vals:
company = self.env['res.company'].browse(vals.get('company_id'))
vals['user_id'] = company._get_public_user().id if company else self.env.ref('base.public_user').id
if 'user_id' not in vals:
company = self.env['res.company'].browse(vals.get('company_id'))
vals['user_id'] = company._get_public_user().id if company else self.env.ref('base.public_user').id
res = super(Website, self).create(vals)
res.company_id._compute_website_id()
res._bootstrap_homepage()
websites = super().create(vals_list)
websites.company_id._compute_website_id()
for website in websites:
website._bootstrap_homepage()
if not self.env.user.has_group('website.group_multi_website') and self.search_count([]) > 1:
all_user_groups = 'base.group_portal,base.group_user,base.group_public'
groups = self.env['res.groups'].concat(*(self.env.ref(it) for it in all_user_groups.split(',')))
groups.write({'implied_ids': [(4, self.env.ref('website.group_multi_website').id)]})
return res
return websites
def write(self, values):
public_user_to_change_websites = self.env['website']
+26 -21
View File
@@ -61,8 +61,8 @@ class Menu(models.Model):
res.append((menu.id, menu_name))
return res
@api.model
def create(self, vals):
@api.model_create_multi
def create(self, vals_list):
''' In case a menu without a website_id is trying to be created, we duplicate
it for every website.
Note: Particulary useful when installing a module that adds a menu like
@@ -72,27 +72,32 @@ class Menu(models.Model):
'''
self.clear_caches()
# Only used when creating website_data.xml default menu
if vals.get('url') == '/default-main-menu':
return super(Menu, self).create(vals)
if 'website_id' in vals:
return super(Menu, self).create(vals)
elif self._context.get('website_id'):
vals['website_id'] = self._context.get('website_id')
return super(Menu, self).create(vals)
else:
# create for every site
for website in self.env['website'].search([]):
w_vals = dict(vals, **{
menus = self.env['website.menu']
for vals in vals_list:
if vals.get('url') == '/default-main-menu':
menus |= super().create(vals)
continue
if 'website_id' in vals:
menus |= super().create(vals)
continue
elif self._context.get('website_id'):
vals['website_id'] = self._context.get('website_id')
menus |= super().create(vals)
continue
else:
# create for every site
w_vals = [dict(vals, **{
'website_id': website.id,
'parent_id': website.menu_id.id,
})
res = super(Menu, self).create(w_vals)
# if creating a default menu, we should also save it as such
default_menu = self.env.ref('website.main_menu', raise_if_not_found=False)
if default_menu and vals.get('parent_id') == default_menu.id:
res = super(Menu, self).create(vals)
return res # Only one record is returned but multiple could have been created
}) for website in self.env['website'].search([])]
new_menu = super().create(w_vals)[-1:] # take the last one
# if creating a default menu, we should also save it as such
default_menu = self.env.ref('website.main_menu', raise_if_not_found=False)
if default_menu and vals.get('parent_id') == default_menu.id:
new_menu = super().create(vals)
menus |= new_menu
# Only one record per vals is returned but multiple could have been created
return menus
def write(self, values):
res = super().write(values)
+4 -4
View File
@@ -108,11 +108,11 @@ class WebsiteRewrite(models.Model):
result.append((rewrite.id, name))
return result
@api.model
def create(self, vals):
res = super(WebsiteRewrite, self).create(vals)
@api.model_create_multi
def create(self, vals_list):
rewrites = super().create(vals_list)
self._invalidate_routing()
return res
return rewrites
def write(self, vals):
res = super(WebsiteRewrite, self).write(vals)
+6 -5
View File
@@ -229,11 +229,12 @@ class BlogPost(models.Model):
return True
return False
@api.model
def create(self, vals):
post_id = super(BlogPost, self.with_context(mail_create_nolog=True)).create(vals)
post_id._check_for_publication(vals)
return post_id
@api.model_create_multi
def create(self, vals_list):
posts = super(BlogPost, self.with_context(mail_create_nolog=True)).create(vals_list)
for post, vals in zip(posts, vals_list):
post._check_for_publication(vals)
return posts
def write(self, vals):
result = True
+41 -35
View File
@@ -532,28 +532,31 @@ class Post(models.Model):
if not self._check_recursion():
raise ValidationError(_('You cannot create recursive forum posts.'))
@api.model
def create(self, vals):
if 'content' in vals and vals.get('forum_id'):
vals['content'] = self._update_content(vals['content'], vals['forum_id'])
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if 'content' in vals and vals.get('forum_id'):
vals['content'] = self._update_content(vals['content'], vals['forum_id'])
post = super(Post, self.with_context(mail_create_nolog=True)).create(vals)
# deleted or closed questions
if post.parent_id and (post.parent_id.state == 'close' or post.parent_id.active is False):
raise UserError(_('Posting answer on a [Deleted] or [Closed] question is not possible.'))
# karma-based access
if not post.parent_id and not post.can_ask:
raise AccessError(_('%d karma required to create a new question.', post.forum_id.karma_ask))
elif post.parent_id and not post.can_answer:
raise AccessError(_('%d karma required to answer a question.', post.forum_id.karma_answer))
if not post.parent_id and not post.can_post:
post.sudo().state = 'pending'
posts = super(Post, self.with_context(mail_create_nolog=True)).create(vals_list)
# add karma for posting new questions
if not post.parent_id and post.state == 'active':
self.env.user.sudo().add_karma(post.forum_id.karma_gen_question_new)
post.post_notification()
return post
for post in posts:
# deleted or closed questions
if post.parent_id and (post.parent_id.state == 'close' or post.parent_id.active is False):
raise UserError(_('Posting answer on a [Deleted] or [Closed] question is not possible.'))
# karma-based access
if not post.parent_id and not post.can_ask:
raise AccessError(_('%d karma required to create a new question.', post.forum_id.karma_ask))
elif post.parent_id and not post.can_answer:
raise AccessError(_('%d karma required to answer a question.', post.forum_id.karma_answer))
if not post.parent_id and not post.can_post:
post.sudo().state = 'pending'
# add karma for posting new questions
if not post.parent_id and post.state == 'active':
self.env.user.sudo().add_karma(post.forum_id.karma_gen_question_new)
posts.post_notification()
return posts
@api.model
def _get_mail_message_access(self, res_ids, operation, model_name=None):
@@ -1077,20 +1080,22 @@ class Vote(models.Model):
}
return _karma_upd[old_vote][new_vote]
@api.model
def create(self, vals):
@api.model_create_multi
def create(self, vals_list):
# can't modify owner of a vote
if not self.env.is_admin():
vals.pop('user_id', None)
for vals in vals_list:
vals.pop('user_id', None)
vote = super(Vote, self).create(vals)
votes = super(Vote, self).create(vals_list)
vote._check_general_rights()
vote._check_karma_rights(vote.vote == '1')
for vote in votes:
vote._check_general_rights()
vote._check_karma_rights(vote.vote == '1')
# karma update
vote._vote_update_karma('0', vote.vote)
return vote
# karma update
vote._vote_update_karma('0', vote.vote)
return votes
def write(self, values):
# can't modify owner of a vote
@@ -1160,9 +1165,10 @@ class Tags(models.Model):
for tag in self:
tag.posts_count = len(tag.post_ids)
@api.model
def create(self, vals):
forum = self.env['forum.forum'].browse(vals.get('forum_id'))
if self.env.user.karma < forum.karma_tag_create:
raise AccessError(_('%d karma required to create a new Tag.', forum.karma_tag_create))
return super(Tags, self.with_context(mail_create_nolog=True, mail_create_nosubscribe=True)).create(vals)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
forum = self.env['forum.forum'].browse(vals.get('forum_id'))
if self.env.user.karma < forum.karma_tag_create:
raise AccessError(_('%d karma required to create a new Tag.', forum.karma_tag_create))
return super(Tags, self.with_context(mail_create_nolog=True, mail_create_nosubscribe=True)).create(vals_list)
+12 -9
View File
@@ -44,16 +44,19 @@ class ProductPricelist(models.Model):
website = self.env['website']
website._get_pl_partner_order.clear_cache(website)
@api.model
def create(self, data):
if data.get('company_id') and not data.get('website_id'):
# l10n modules install will change the company currency, creating a
# pricelist for that currency. Do not use user's company in that
# case as module install are done with OdooBot (company 1)
self = self.with_context(default_company_id=data['company_id'])
res = super(ProductPricelist, self).create(data)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get('company_id') and not vals.get('website_id'):
# l10n modules install will change the company currency, creating a
# pricelist for that currency. Do not use user's company in that
# case as module install are done with OdooBot (company 1)
# YTI FIXME: The fix is not at the correct place
# It be set when we actually create the pricelist
self = self.with_context(default_company_id=vals['company_id'])
pricelists = super().create(vals_list)
self.clear_cache()
return res
return pricelists
def write(self, data):
res = super(ProductPricelist, self).write(data)
+18 -15
View File
@@ -447,23 +447,26 @@ class Channel(models.Model):
""" % {'table_name': self._table}
self.env.cr.execute(query)
@api.model
def create(self, vals):
# Ensure creator is member of its channel it is easier for him to manage it (unless it is odoobot)
if not vals.get('channel_partner_ids') and not self.env.is_superuser():
vals['channel_partner_ids'] = [(0, 0, {
'partner_id': self.env.user.partner_id.id
})]
if not is_html_empty(vals.get('description')) and is_html_empty(vals.get('description_short')):
vals['description_short'] = vals['description']
channel = super(Channel, self.with_context(mail_create_nosubscribe=True)).create(vals)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
# Ensure creator is member of its channel it is easier for him to manage it (unless it is odoobot)
if not vals.get('channel_partner_ids') and not self.env.is_superuser():
vals['channel_partner_ids'] = [(0, 0, {
'partner_id': self.env.user.partner_id.id
})]
if not is_html_empty(vals.get('description')) and is_html_empty(vals.get('description_short')):
vals['description_short'] = vals['description']
if channel.user_id:
channel._action_add_members(channel.user_id.partner_id)
if 'enroll_group_ids' in vals:
channel._add_groups_members()
channels = super(Channel, self.with_context(mail_create_nosubscribe=True)).create(vals_list)
return channel
for channel in channels:
if channel.user_id:
channel._action_add_members(channel.user_id.partner_id)
if channel.enroll_group_ids:
channel._add_groups_members()
return channels
def write(self, vals):
# If description_short wasn't manually modified, there is an implicit link between this field and description.
+30 -27
View File
@@ -546,38 +546,41 @@ class Slide(models.Model):
# ORM Overrides
# ---------------------------------------------------------
@api.model
def create(self, values):
# Do not publish slide if user has not publisher rights
channel = self.env['slide.channel'].browse(values['channel_id'])
if not channel.can_publish:
# 'website_published' is handled by mixin
values['date_published'] = False
@api.model_create_multi
def create(self, vals_list):
channel_ids = [vals['channel_id'] for vals in vals_list]
can_publish_channel_ids = self.env['slide.channel'].browse(channel_ids).filtered(lambda c: c.can_publish).ids
for vals in vals_list:
# Do not publish slide if user has not publisher rights
if vals['channel_id'] not in can_publish_channel_ids:
# 'website_published' is handled by mixin
vals['date_published'] = False
if values.get('is_category'):
values['is_preview'] = True
values['is_published'] = True
if values.get('is_published') and not values.get('date_published'):
values['date_published'] = datetime.datetime.now()
if vals.get('is_category'):
vals['is_preview'] = True
vals['is_published'] = True
if vals.get('is_published') and not vals.get('date_published'):
vals['date_published'] = datetime.datetime.now()
slide = super(Slide, self).create(values)
slides = super().create(vals_list)
# avoid fetching external metadata when installing the module (i.e. for demo data)
# we also support a context key if you don't want to fetch the metadata when creating a slide
if any(values.get(url_param) for url_param in ['url', 'video_url', 'document_google_url', 'image_google_url']) \
and not self.env.context.get('install_mode') \
and not self.env.context.get('website_slides_skip_fetch_metadata'):
slide_metadata, _error = slide._fetch_external_metadata()
if slide_metadata:
# only update keys that are not set in the incoming values
slide.update({key: value for key, value in slide_metadata.items() if key not in values.keys()})
for slide, vals in zip(slides, vals_list):
# avoid fetching external metadata when installing the module (i.e. for demo data)
# we also support a context key if you don't want to fetch the metadata when creating a slide
if any(vals.get(url_param) for url_param in ['url', 'video_url', 'document_google_url', 'image_google_url']) \
and not self.env.context.get('install_mode') \
and not self.env.context.get('website_slides_skip_fetch_metadata'):
slide_metadata, _error = slide._fetch_external_metadata()
if slide_metadata:
# only update keys that are not set in the incoming vals
slide.update({key: value for key, value in slide_metadata.items() if key not in vals.keys()})
if not 'completion_time' not in values:
slide._on_change_document_binary_content()
if not 'completion_time' not in vals:
slide._on_change_document_binary_content()
if slide.is_published and not slide.is_category:
slide._post_publication()
return slide
if slide.is_published and not slide.is_category:
slide._post_publication()
return slides
def write(self, values):
if values.get('is_category'):
@@ -64,14 +64,13 @@ class Slide(models.Model):
if slide.slide_category == 'certification':
slide.slide_type = 'certification'
@api.model
def create(self, values):
rec = super(Slide, self).create(values)
if rec.survey_id:
rec.slide_category = 'certification'
if 'survey_id' in values:
rec._ensure_challenge_category()
return rec
@api.model_create_multi
def create(self, vals_list):
slides = super().create(vals_list)
slides_with_survey = slides.filtered('survey_id')
slides_with_survey.slide_category = 'certification'
slides_with_survey._ensure_challenge_category()
return slides
def write(self, values):
old_surveys = self.mapped('survey_id')
@@ -94,7 +93,7 @@ class Slide(models.Model):
old_certification_challenges = old_surveys.mapped('certification_badge_id').challenge_ids
old_certification_challenges.write({'challenge_category': 'certification'})
if not unlink:
certification_challenges = self.mapped('survey_id').mapped('certification_badge_id').challenge_ids
certification_challenges = self.survey_id.certification_badge_id.challenge_ids
certification_challenges.write({'challenge_category': 'slides'})
def _generate_certification_url(self):
@@ -61,12 +61,13 @@ class ResConfigSettings(models.TransientModel):
_logger.info('Please double-check your Twitter API Key and Secret!', exc_info=True)
raise UserError(_('Twitter authorization error! Please double-check your Twitter API Key and Secret!'))
@api.model
def create(self, vals):
TwitterConfig = super(ResConfigSettings, self).create(vals)
if vals.get('twitter_api_key') or vals.get('twitter_api_secret') or vals.get('twitter_screen_name'):
TwitterConfig._check_twitter_authorization()
return TwitterConfig
@api.model_create_multi
def create(self, vals_list):
configs = super().create(vals_list)
for config in configs:
if config.twitter_api_key or config.twitter_api_secret or config.twitter_screen_name:
config._check_twitter_authorization()
return configs
def write(self, vals):
TwitterConfig = super(ResConfigSettings, self).write(vals)
+1 -1
View File
@@ -621,7 +621,7 @@ class IrAttachment(models.Model):
for record_tuple in record_tuple_set:
(res_model, res_id) = record_tuple
self.check('create', values={'res_model':res_model, 'res_id':res_id})
return super(IrAttachment, self).create(vals_list)
return super().create(vals_list)
def _post_add_create(self):
pass
+5 -4
View File
@@ -65,12 +65,13 @@ class ir_cron(models.Model):
lastcall = fields.Datetime(string='Last Execution Date', help="Previous time the cron ran successfully, provided to the job through the context on the `lastcall` key")
priority = fields.Integer(default=5, help='The priority of the job, as an integer: 0 means higher priority, 10 means lower priority.')
@api.model
def create(self, values):
values['usage'] = 'ir_cron'
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
vals['usage'] = 'ir_cron'
if os.getenv('ODOO_NOTIFY_CRON_CHANGES'):
self._cr.postcommit.add(self._notifydb)
return super(ir_cron, self).create(values)
return super().create(vals_list)
@api.model
def default_get(self, fields_list):
+9 -9
View File
@@ -724,18 +724,18 @@ class Module(models.Model):
'to_buy': False
}
@api.model
def create(self, vals):
new = super(Module, self).create(vals)
module_metadata = {
'name': 'module_%s' % vals['name'],
@api.model_create_multi
def create(self, vals_list):
modules = super().create(vals_list)
module_metadata_list = [{
'name': 'module_%s' % module.name,
'model': 'ir.module.module',
'module': 'base',
'res_id': new.id,
'res_id': module.id,
'noupdate': True,
}
self.env['ir.model.data'].create(module_metadata)
return new
} for module in modules]
self.env['ir.model.data'].create(module_metadata_list)
return modules
# update the list of available packages
@assert_log_admin_access
+15 -13
View File
@@ -150,14 +150,15 @@ class IrSequence(models.Model):
use_date_range = fields.Boolean(string='Use subsequences per date_range')
date_range_ids = fields.One2many('ir.sequence.date_range', 'sequence_id', string='Subsequences')
@api.model
def create(self, values):
@api.model_create_multi
def create(self, vals_list):
""" Create a sequence, in implementation == standard a fast gaps-allowed PostgreSQL sequence is used.
"""
seq = super(IrSequence, self).create(values)
if values.get('implementation', 'standard') == 'standard':
_create_sequence(self._cr, "ir_sequence_%03d" % seq.id, values.get('number_increment', 1), values.get('number_next', 1))
return seq
seqs = super().create(vals_list)
for seq in seqs:
if seq.implementation == 'standard':
_create_sequence(self._cr, "ir_sequence_%03d" % seq.id, seq.number_increment or 1, seq.number_next or 1)
return seqs
def unlink(self):
_drop_sequences(self._cr, ["ir_sequence_%03d" % x.id for x in self])
@@ -356,15 +357,16 @@ class IrSequenceDateRange(models.Model):
for seq in self:
_alter_sequence(self._cr, "ir_sequence_%03d_%03d" % (seq.sequence_id.id, seq.id), number_increment=number_increment, number_next=number_next)
@api.model
def create(self, values):
@api.model_create_multi
def create(self, vals_list):
""" Create a sequence, in implementation == standard a fast gaps-allowed PostgreSQL sequence is used.
"""
seq = super(IrSequenceDateRange, self).create(values)
main_seq = seq.sequence_id
if main_seq.implementation == 'standard':
_create_sequence(self._cr, "ir_sequence_%03d_%03d" % (main_seq.id, seq.id), main_seq.number_increment, values.get('number_next_actual', 1))
return seq
seqs = super().create(vals_list)
for seq in seqs:
main_seq = seq.sequence_id
if main_seq.implementation == 'standard':
_create_sequence(self._cr, "ir_sequence_%03d_%03d" % (main_seq.id, seq.id), main_seq.number_increment, seq.number_next_actual or 1)
return seqs
def unlink(self):
_drop_sequences(self._cr, ["ir_sequence_%03d_%03d" % (x.sequence_id.id, x.id) for x in self])
+44 -30
View File
@@ -198,37 +198,51 @@ class Company(models.Model):
def cache_restart(self):
self.clear_caches()
@api.model
def create(self, vals):
if not vals.get('favicon'):
vals['favicon'] = self._get_default_favicon()
if not vals.get('name') or vals.get('partner_id'):
self.clear_caches()
return super(Company, self).create(vals)
partner = self.env['res.partner'].create({
'name': vals['name'],
'is_company': True,
'image_1920': vals.get('logo'),
'email': vals.get('email'),
'phone': vals.get('phone'),
'website': vals.get('website'),
'vat': vals.get('vat'),
'country_id': vals.get('country_id'),
})
# compute stored fields, for example address dependent fields
partner.flush()
vals['partner_id'] = partner.id
self.clear_caches()
company = super(Company, self).create(vals)
# The write is made on the user to set it automatically in the multi company group.
self.env.user.write({'company_ids': [Command.link(company.id)]})
@api.model_create_multi
def create(self, vals_list):
# add default favicon
for vals in vals_list:
if not vals.get('favicon'):
vals['favicon'] = self._get_default_favicon()
# Make sure that the selected currency is enabled
if vals.get('currency_id'):
currency = self.env['res.currency'].browse(vals['currency_id'])
if not currency.active:
currency.write({'active': True})
return company
# create missing partners
no_partner_vals_list = [
vals
for vals in vals_list
if vals.get('name') and not vals.get('partner_id')
]
if no_partner_vals_list:
partners = self.env['res.partner'].create([
{
'name': vals['name'],
'is_company': True,
'image_1920': vals.get('logo'),
'email': vals.get('email'),
'phone': vals.get('phone'),
'website': vals.get('website'),
'vat': vals.get('vat'),
'country_id': vals.get('country_id'),
}
for vals in no_partner_vals_list
])
# compute stored fields, for example address dependent fields
partners.flush()
for vals, partner in zip(no_partner_vals_list, partners):
vals['partner_id'] = partner.id
self.clear_caches()
companies = super().create(vals_list)
# The write is made on the user to set it automatically in the multi company group.
if companies:
self.env.user.write({
'company_ids': [Command.link(company.id) for company in companies],
})
# Make sure that the selected currencies are enabled
companies.currency_id.sudo().filtered(lambda c: not c.active).active = True
return companies
def write(self, values):
self.clear_caches()
+24 -23
View File
@@ -765,34 +765,35 @@ class ResConfigSettings(models.TransientModel, ResConfigModuleInstallationMixin)
return RedirectWarning(msg % values, action_id, _('Go to the configuration panel'))
return UserError(msg % values)
@api.model
def create(self, values):
@api.model_create_multi
def create(self, vals_list):
# Optimisation: saving a res.config.settings even without changing any
# values will trigger the write of all related values. This in turn may
# trigger chain of further recomputation. To avoid it, delete values
# that were not changed.
for field in self._fields.values():
if not (field.name in values and field.related and not field.readonly):
continue
# we write on a related field like
# qr_code = fields.Boolean(related='company_id.qr_code', readonly=False)
fname0, *fnames = field.related.split(".")
if fname0 not in values:
continue
for vals in vals_list:
for field in self._fields.values():
if not (field.name in vals and field.related and not field.readonly):
continue
# we write on a related field like
# qr_code = fields.Boolean(related='company_id.qr_code', readonly=False)
fname0, *fnames = field.related.split(".")
if fname0 not in vals:
continue
# determine the current value
field0 = self._fields[fname0]
old_value = field0.convert_to_record(
field0.convert_to_cache(values[fname0], self), self)
for fname in fnames:
old_value = next(iter(old_value), old_value)[fname]
# determine the current value
field0 = self._fields[fname0]
old_value = field0.convert_to_record(
field0.convert_to_cache(vals[fname0], self), self)
for fname in fnames:
old_value = next(iter(old_value), old_value)[fname]
# determine the new value
new_value = field.convert_to_record(
field.convert_to_cache(values[field.name], self), self)
# determine the new value
new_value = field.convert_to_record(
field.convert_to_cache(vals[field.name], self), self)
# drop if the value is the same
if old_value == new_value:
values.pop(field.name)
# drop if the value is the same
if old_value == new_value:
vals.pop(field.name)
return super(ResConfigSettings, self).create(values)
return super().create(vals_list)
+4 -4
View File
@@ -1162,13 +1162,13 @@ class UsersImplied(models.Model):
class GroupsView(models.Model):
_inherit = 'res.groups'
@api.model
def create(self, values):
user = super(GroupsView, self).create(values)
@api.model_create_multi
def create(self, vals_list):
groups = super().create(vals_list)
self._update_user_groups_view()
# actions.get_bindings() depends on action records
self.env['ir.actions.actions'].clear_caches()
return user
return groups
def write(self, values):
# determine which values the "user groups view" depends on
-21
View File
@@ -8,27 +8,6 @@ from odoo.tests.common import TransactionCase, HttpCase
from odoo import Command
class PerformanceCommon(TransactionCase):
def assertModelCreateMulti(self, model_name, vals_list=None):
"""Ensures model_name records can be created in batch.
:param str model_name: name of the model on which batch record creation should be verified
:param list vals_list: example list of values, if needed
"""
vals_list = vals_list or [dict(), dict()]
if not isinstance(vals_list, list):
raise ValueError("Invalid arguments for assertModelCreateMulti")
assert len(vals_list) > 1, "Batch creation cannot be tested with only one value."
def patched_create(self, values_list):
if len(values_list) != len(vals_list):
raise ValueError(f"Model {model_name} doesn't support batch records creation.")
# Do not create anything
return self
with patch('odoo.models.BaseModel.create', patched_create):
self.env[model_name].create(vals_list)
class TransactionCaseWithUserDemo(TransactionCase):
def setUp(self):
@@ -738,10 +738,10 @@ class TestAssetsBundleWithIRAMock(FileTouchable):
origin_create = IrAttachment.create
origin_unlink = IrAttachment.unlink
@api.model
def create(self, vals):
counter.update(['create'])
return origin_create(self, vals)
@api.model_create_multi
def create(self, vals_list):
counter.update(['create'] * len(vals_list))
return origin_create(self, vals_list)
def unlink(self):
counter.update(['unlink'])
+1
View File
@@ -401,6 +401,7 @@ def model_create_single(method):
record = model.create(vals)
records = model.create([vals, ...])
"""
_create_logger.warning("The model %s is not overriding the create method in batch", method.__module__)
wrapper = decorate(method, _model_create_single)
wrapper._api = 'model_create'
return wrapper