def validate_iban(iban): iban = normalize_iban(iban) if not iban: raise ValidationError(_("There is no IBAN code.")) country_code = iban[:2].lower() if country_code not in _map_iban_template: raise ValidationError( _("The IBAN is invalid, it should begin with the country code")) iban_template = _map_iban_template[country_code] if len(iban) != len(iban_template.replace(' ', '')): raise ValidationError( _("The IBAN does not seem to be correct. You should have entered something like this %s\n" "Where B = National bank code, S = Branch code, C = Account No, k = Check digit" ) % iban_template) check_chars = iban[4:] + iban[:4] digits = int(''.join( str(int(char, 36)) for char in check_chars)) # BASE 36: 0..9,A..Z -> 0..35 if digits % 97 != 1: raise ValidationError( _("This IBAN does not pass the validation check, please verify it." ))
def _check_sale_line_type(self): for project in self: if project.billable_type == 'task_rate': if project.sale_line_id and not project.sale_line_id.is_service: raise ValidationError(_("A billable project should be linked to a Sales Order Item having a Service product.")) if project.sale_line_id and project.sale_line_id.is_expense: raise ValidationError(_("A billable project should be linked to a Sales Order Item that does not come from an expense or a vendor bill."))
def _create_payment_transaction(self, vals=None): for pay in self: if pay.payment_transaction_id: raise ValidationError( _('A payment transaction already exists.')) elif not pay.payment_token_id: raise ValidationError( _('A token is required to create a new payment transaction.' )) transactions = self.env['payment.transaction'] for pay in self: transaction_vals = pay._prepare_payment_transaction_vals() if vals: transaction_vals.update(vals) transaction = self.env['payment.transaction'].create( transaction_vals) transactions += transaction # Link the transaction to the payment. pay.payment_transaction_id = transaction return transactions
def _check_category_reference_uniqueness(self): """ Force the existence of only one UoM reference per category NOTE: this is a constraint on the all table. This might not be a good practice, but this is not possible to do it in SQL directly. """ category_ids = self.mapped('category_id').ids self._cr.execute( """ SELECT C.id AS category_id, count(U.id) AS uom_count FROM uom_category C LEFT JOIN uom_uom U ON C.id = U.category_id AND uom_type = 'reference' AND U.active = 't' WHERE C.id IN %s GROUP BY C.id """, (tuple(category_ids), )) for uom_data in self._cr.dictfetchall(): if uom_data['uom_count'] == 0: raise ValidationError( _("UoM category %s should have a reference unit of measure. If you just created a new category, please record the 'reference' unit first." ) % (self.env['uom.category'].browse( uom_data['category_id']).name, )) if uom_data['uom_count'] > 1: raise ValidationError( _("UoM category %s should only have one reference unit of measure." ) % (self.env['uom.category'].browse( uom_data['category_id']).name, ))
def set(self, model_name, field_name, value, user_id=False, company_id=False, condition=False): """ Defines a default value for the given field. Any entry for the same scope (field, user, company) will be replaced. The value is encoded in JSON to be stored to the database. :param user_id: may be ``False`` for all users, ``True`` for the current user, or any user id :param company_id: may be ``False`` for all companies, ``True`` for the current user's company, or any company id :param condition: optional condition that restricts the applicability of the default value; this is an opaque string, but the client typically uses single-field conditions in the form ``'key=val'``. """ if user_id is True: user_id = self.env.uid if company_id is True: company_id = self.env.user.company_id.id # check consistency of model_name, field_name, and value try: model = self.env[model_name] field = model._fields[field_name] field.convert_to_cache(value, model) json_value = json.dumps(value, ensure_ascii=False) except KeyError: raise ValidationError( _("Invalid field %s.%s") % (model_name, field_name)) except Exception: raise ValidationError( _("Invalid value for %s.%s: %s") % (model_name, field_name, value)) # update existing default for the same scope, or create one field = self.env['ir.model.fields']._get(model_name, field_name) default = self.search([ ('field_id', '=', field.id), ('user_id', '=', user_id), ('company_id', '=', company_id), ('condition', '=', condition), ]) if default: default.write({'json_value': json_value}) else: self.create({ 'field_id': field.id, 'user_id': user_id, 'company_id': company_id, 'condition': condition, 'json_value': json_value, }) return True
def _check_model(self): for action in self: if action.res_model not in self.env: raise ValidationError( _('Invalid model name %r in action definition.') % action.res_model) if action.src_model and action.src_model not in self.env: raise ValidationError( _('Invalid model name %r in action definition.') % action.src_model)
def _check_pattern(self): p = self.pattern.replace("\\\\", "X").replace("\{", "X").replace("\}", "X") findall = re.findall("[{]|[}]", p) # p does not contain escaped { or } if len(findall) == 2: if not re.search("[{][N]*[D]*[}]", p): raise ValidationError(_("There is a syntax error in the barcode pattern ") + self.pattern + _(": braces can only contain N's followed by D's.")) elif re.search("[{][}]", p): raise ValidationError(_("There is a syntax error in the barcode pattern ") + self.pattern + _(": empty braces.")) elif len(findall) != 0: raise ValidationError(_("There is a syntax error in the barcode pattern ") + self.pattern + _(": a rule can only contain one pair of braces.")) elif p == '*': raise ValidationError(_(" '*' is not a valid Regex Barcode Pattern. Did you mean '.*' ?"))
def _check_project_and_template(self): """ NOTE 'service_tracking' should be in decorator parameters but since ORM check constraints twice (one after setting stored fields, one after setting non stored field), the error is raised when company-dependent fields are not set. So, this constraints does cover all cases and inconsistent can still be recorded until the ORM change its behavior. """ for product in self: if product.service_tracking == 'no' and (product.project_id or product.project_template_id): raise ValidationError(_('The product %s should not have a project nor a project template since it will not generate project.') % (product.name,)) elif product.service_tracking == 'task_global_project' and product.project_template_id: raise ValidationError(_('The product %s should not have a project template since it will generate a task in a global project.') % (product.name,)) elif product.service_tracking in ['task_new_project', 'project_only'] and product.project_id: raise ValidationError(_('The product %s should not have a global project since it will generate a project.') % (product.name,))
def _check_grouping(self): warning = _( 'The Separator Format should be like [,n] where 0 < n :starting from Unit digit. ' '-1 will end the separation. e.g. [3,2,-1] will represent 106500 to be 1,06,500;' '[1,2,-1] will represent it to be 106,50,0;[3] will represent it as 106,500. ' 'Provided as the thousand separator in each case.') for lang in self: try: if not all( isinstance(x, int) for x in json.loads(lang.grouping)): raise ValidationError(warning) except Exception: raise ValidationError(warning)
def _check_product_recursion(self): for bom in self: if bom.product_id: if bom.bom_line_ids.filtered( lambda x: x.product_id == bom.product_id): raise ValidationError( _('BoM line product %s should not be same as BoM product.' ) % bom.display_name) else: if bom.bom_line_ids.filtered( lambda x: x.product_id.product_tmpl_id == bom. product_tmpl_id): raise ValidationError( _('BoM line product %s should not be same as BoM product.' ) % bom.display_name)
def _check_employee(self): for sheet in self: employee_ids = sheet.expense_line_ids.mapped('employee_id') if len(employee_ids) > 1 or (len(employee_ids) == 1 and employee_ids != sheet.employee_id): raise ValidationError( _('You cannot add expenses of another employee.'))
def _check_amount(self): # Allow to enter bank statement line with an amount of 0, # so that user can enter/import the exact bank statement they have received from their bank in Swerp if self.journal_id.type != 'bank' and self.currency_id.is_zero( self.amount): raise ValidationError( _('The amount of a cash transaction cannot be 0.'))
def _check_valid_attribute(self): if any(not line.value_ids or line.value_ids > line.attribute_id.value_ids for line in self): raise ValidationError( _('You cannot use this attribute with the following value.')) return True
def check_quantity(self): for quant in self: if float_compare(quant.quantity, 1, precision_rounding=quant.product_uom_id.rounding) > 0 and quant.lot_id and quant.product_id.tracking == 'serial': message_base = _('A serial number should only be linked to a single product.') message_quant = _('Please check the following serial number (name, id): ') message_sn = '(%s, %s)' % (quant.lot_id.name, quant.lot_id.id) raise ValidationError("\n".join([message_base, message_quant, message_sn]))
def _check_communication(self, payment_method_id, communication): super(AccountPayment, self)._check_communication(payment_method_id, communication) if payment_method_id == self.env.ref('account_check_printing.account_payment_method_check').id: if not communication: return if len(communication) > 60: raise ValidationError(_("A check memo cannot exceed 60 characters."))
def _check_lot_product(self): for line in self: if line.lot_id and line.product_id != line.lot_id.sudo( ).product_id: raise ValidationError( _('This lot %s is incompatible with this product %s' % (line.lot_id.name, line.product_id.display_name)))
def _check_filter_product(self): if self.filter == 'none' and self.product_id and self.location_id and self.lot_id: return if self.filter not in ('product', 'product_owner') and self.product_id: raise ValidationError( _('The selected product doesn\'t belong to that owner..')) if self.filter != 'lot' and self.lot_id: raise ValidationError(_('The selected lot number doesn\'t exist.')) if self.filter not in ('owner', 'product_owner') and self.partner_id: raise ValidationError( _('The selected owner doesn\'t have the proprietary of that product.' )) if self.filter != 'pack' and self.package_id: raise ValidationError( _('The selected inventory options are not coherent, the package doesn\'t exist.' ))
def _stripe_request(self, url, data=False, method="POST"): self.ensure_one() stripe_url = 'https://%s/' % (self._get_stripe_api_url()) url = urls.url_join(stripe_url, url) headers = { "AUTHORIZATION": "Bearer %s" % self.sudo().stripe_secret_key, "Stripe-Version": "2019-05-16", # SetupIntent need a specific version } resp = requests.request(method, url, data=data, headers=headers) # Stripe can send 4XX errors for payment failure (not badly-formed requests) # check if error `code` is present in 4XX response and raise only if not # cfr https://stripe.com/docs/error-codes # these can be made customer-facing, as they usually indicate a problem with the payment # (e.g. insufficient funds, expired card, etc.) # if the context key `stripe_manual_payment` is set then these errors will be raised as ValidationError, # otherwise, they will be silenced, and the will be returned no matter the status. # This key should typically be set for payments in the present and unset for automated payments # (e.g. through crons) if not resp.ok and self._context.get('stripe_manual_payment') and ( 400 <= resp.status_code < 500 and resp.json().get('error', {}).get('code')): try: resp.raise_for_status() except HTTPError: _logger.error(resp.text) stripe_error = resp.json().get('error', {}).get('message', '') error_msg = " " + (_( "Stripe gave us the following info about the problem: '%s'" ) % stripe_error) raise ValidationError(error_msg) return resp.json()
def _check_timesheet_generate(self): for holiday_status in self: if holiday_status.timesheet_generate: if not holiday_status.timesheet_project_id or not holiday_status.timesheet_task_id: raise ValidationError( _('Both the internal project and task are required to generate timesheet for the leaves.' ))
def _check_validity_dates(self): for leave_type in self: if leave_type.validity_start and leave_type.validity_stop and \ leave_type.validity_start > leave_type.validity_stop: raise ValidationError( _("End of validity period should be greater than start of validity period" ))
def _check_companies(self): if any( self.available_pricelist_ids.mapped( lambda pl: pl.company_id.id not in (False, self.company_id.id))): raise ValidationError( _("The selected pricelists must belong to no company or the company of the point of sale." ))
def _check_leave_timesheet_project_id_company(self): for company in self: if company.leave_timesheet_project_id: if company.leave_timesheet_project_id.sudo( ).company_id != company: raise ValidationError( _('The Internal Project of a company should be in that company.' ))
def _check_recursion_associate_member(self): level = 100 while self: self = self.associate_member if not level: raise ValidationError( _('You cannot create recursive associated members.')) level -= 1
def _check_company_payment(self): if self.env['account.journal'].search_count([ ('id', 'in', self.journal_ids.ids), ('company_id', '!=', self.company_id.id) ]): raise ValidationError( _("The method payments and the point of sale must belong to the same company." ))
def _check_activity_mixin(self): for action in self: if action.state == 'next_activity' and not issubclass( self.pool[action.model_id.model], self.pool['mail.thread']): raise ValidationError( _("A next activity can only be planned on models that use the chatter" ))
def _check_recursion(self): if any(item.base == 'pricelist' and item.pricelist_id and item.pricelist_id == item.base_pricelist_id for item in self): raise ValidationError( _('You cannot assign the Main Pricelist as Other Pricelist in PriceList Item' )) return True
def _check_sale_line_in_project_map(self): for timesheet in self: if timesheet.project_id and timesheet.so_line: # billed timesheet if timesheet.so_line not in timesheet.project_id.mapped( 'sale_line_employee_ids.sale_line_id' ) | timesheet.task_id.sale_line_id | timesheet.project_id.sale_line_id: raise ValidationError( _("This timesheet line cannot be billed: there is no Sale Order Item defined on the task, nor on the project. Please define one to save your timesheet line." ))
def _check_format(self): for lang in self: for pattern in lang._disallowed_datetime_patterns: if (lang.time_format and pattern in lang.time_format) or \ (lang.date_format and pattern in lang.date_format): raise ValidationError( _('Invalid date/time format directive specified. ' 'Please refer to the list of allowed directives, ' 'displayed when you edit a language.'))
def check_reserved_done_quantity(self): for move_line in self: if move_line.state == 'done' and not float_is_zero( move_line.product_uom_qty, precision_digits=self.env['decimal.precision']. precision_get('Product Unit of Measure')): raise ValidationError( _('A done move line should never have a reserved quantity.' ))
def _check_session_state(self): open_session = self.env['pos.session'].search_count([ ('config_id.rounding_method', '=', self.id), ('state', '!=', 'closed') ]) if open_session: raise ValidationError( _("You are not allowed to change the cash rounding configuration while a pos session using it is already opened." ))