def _process_onchange_acc_number(self, acc_number, country): res = {} if not acc_number or country != self.env.ref('base.es'): return res # pragma: no cover bank_obj = self.env['res.bank'] acc_number = normalize_iban(acc_number) if len(acc_number) > 20: # It's an IBAN account try: validate_iban(acc_number) bank = bank_obj.search([('code', '=', acc_number[4:8])], limit=1) number = pretty_iban(acc_number) except exceptions.ValidationError: res['warning_message'] = _('IBAN account is not valid') return res else: number = self.check_bank_account(acc_number) if number == 'invalid-size': res['warning_message'] = _( 'Bank account should have 20 digits.') return res elif number == 'invalid-dc': res['warning_message'] = _('Invalid bank account.') return res bank = bank_obj.search([('code', '=', number[:4])], limit=1) res['acc_number'] = number res['bank_id'] = bank.id return res
def check_iban(self, iban): try: if iban: validate_iban(iban) return True else: return False except ValidationError: return False
def _validate_qr_iban(self, qr_iban): # Check first if it's a valid IBAN. validate_iban(qr_iban) # We sanitize first so that _check_qr_iban_range() can extract correct IID from IBAN to validate it. sanitized_qr_iban = sanitize_account_number(qr_iban) # Now, check if it's valid QR-IBAN (based on its IID). if not self._check_qr_iban_range(sanitized_qr_iban): raise ValidationError(_("QR-IBAN '%s' is invalid.") % qr_iban) return True
def _match_partner_bank( self, partner, iban, bic, chatter_msg, create_if_not_found=False): assert iban, 'iban is a required arg' assert partner, 'partner is a required arg' partner = partner.commercial_partner_id iban = iban.replace(' ', '').upper() rpbo = self.env['res.partner.bank'] rbo = self.env['res.bank'] try: validate_iban(iban) except Exception as e: chatter_msg.append(_( "IBAN <b>%s</b> is not valid, so it has been ignored.") % iban) return False company_id = self._context.get('force_company') or\ self.env.user.company_id.id bankaccount = rpbo.search([ '|', ('company_id', '=', False), ('company_id', '=', company_id), ('sanitized_acc_number', '=', iban), ('partner_id', '=', partner.id)], limit=1) if bankaccount: return bankaccount elif create_if_not_found: bank_id = False if bic: bic = bic.replace(' ', '').upper() bank = rbo.search([('bic', '=', bic)], limit=1) if bank: bank_id = bank.id else: bank = rbo.create({ 'bic': bic, 'name': bic, # TODO: see if we could do better }) bank_id = bank.id partner_bank = rpbo.create({ 'partner_id': partner.id, 'acc_number': iban, 'bank_id': bank_id, }) chatter_msg.append(_( "The bank account <b>IBAN %s</b> has been automatically " "added on the supplier " "<a href=# data-oe-model=res.partner data-oe-id=%d>%s</a>") % ( iban, partner.id, partner.display_name)) return partner_bank else: chatter_msg.append(_( "The analysis of the business document returned " "<b>IBAN %s</b> as bank account, but there is no such " "bank account in Odoo linked to partner " "<a href=# data-oe-model=res.partner data-oe-id=%d>%s</a> and " "the option to automatically create bank " "accounts upon import is disabled.") % (iban, partner.id, partner.display_name))
def retrieve_acc_type(self, acc_number, bank_account=None): if bank_account: bank_type = bank_account.bank_id.type if bank_type != "normal": return bank_type try: # if normal we want iban and others to run validate_iban(acc_number) return "iban" except ValidationError: return super(ResPartnerBank, self).retrieve_acc_type(acc_number)
def _onchange_set_l10n_ch_postal(self): try: validate_iban(self.bank_acc_number) is_iban = True except ValidationError: is_iban = False if is_iban: self.l10n_ch_postal = self.env['res.partner.bank']._retrieve_l10n_ch_postal(sanitize_account_number(self.bank_acc_number)) else: self.l10n_ch_postal = self.bank_acc_number
def _check_values(self, acquirer, iban, phone=None): validate_iban(iban) # TO CHECK: should we restrict to country code from iban country? sanitized_number = None if acquirer.sepa_direct_debit_sms_enabled: if not phone: raise ValidationError(_('No phone number provided.')) sanitized_number = phone_sanitize_numbers([phone], None, None).get(phone, {}).get('sanitized') if not sanitized_number: raise ValidationError(_('Incorrect phone number.')) return (iban, sanitized_number)
def _constraint_acc_number(self): for acc in self: if acc.bank_id.validation_regex and not re.compile(acc.bank_id.validation_regex, re.IGNORECASE) \ .match(acc.acc_number): raise ValidationError( _("Account number does not meet the expected pattern for " + acc.bank_id.name)) if acc.acc_type == 'iban': validate_iban(acc.acc_number) elif acc.acc_type == 'mobile': validate_mobile_money(acc.acc_number)
def create_account(self): self.ensure_one() validate_iban(self.acc_number) bank_account = self.env["res.partner.bank"].create( { "acc_number": self.acc_number, "bank_id": self.bank_id.id, "partner_id": self.employee_id.partner_id.id, "acc_type": "iban", } ) self.employee_id.write({"bank_account_id": bank_account.id}) return {"type": "ir.actions.act_window_close"}
def _check_journal_bank_account(self, journal, account_number): res = super(AccountBankStatementImport, self)._check_journal_bank_account(journal, account_number) if not res: e_acc_num = journal.bank_account_id.sanitized_acc_number e_acc_num = e_acc_num.replace(" ", "") validate_iban(e_acc_num) country_code = e_acc_num[:2].lower() iban_template = _map_iban_template[country_code].replace(" ", "") e_acc_num = "".join( [c for c, t in zip(e_acc_num, iban_template) if t == "C"]) res = (e_acc_num == account_number) return res
def _match_partner_bank(self, partner, iban, bic, chatter_msg, create_if_not_found=False): assert iban, 'iban is a required arg' assert partner, 'partner is a required arg' partner = partner.commercial_partner_id iban = iban.replace(' ', '').upper() rpbo = self.env['res.partner.bank'] rbo = self.env['res.bank'] try: validate_iban(iban) except Exception as e: chatter_msg.append( _("IBAN <b>%s</b> is not valid, so it has been ignored.") % iban) return False company_id = self._context.get('force_company') or\ self.env.user.company_id.id bankaccount = rpbo.search([ '|', ('company_id', '=', False), ('company_id', '=', company_id), ('sanitized_acc_number', '=', iban), ('partner_id', '=', partner.id) ], limit=1) if bankaccount: return bankaccount elif create_if_not_found: bank_id = False if bic: bic = bic.replace(' ', '').upper() bank = rbo.search([('bic', '=', bic)], limit=1) if bank: bank_id = bank.id else: bank = rbo.create({ 'bic': bic, 'name': bic, # TODO: see if we could do better }) bank_id = bank.id partner_bank = rpbo.create({ 'partner_id': partner.id, 'acc_number': iban, 'bank_id': bank_id, }) chatter_msg.append( _("The bank account <b>IBAN %s</b> has been automatically " "added on the supplier <b>%s</b>") % (iban, partner.name)) return partner_bank
def validate_qr_iban(qr_iban): # Check first if it's a valid IBAN. validate_iban(qr_iban) # We sanitize first so that _check_qr_iban_range() can extract correct IID from IBAN to validate it. sanitized_qr_iban = sanitize_account_number(qr_iban) if sanitized_qr_iban[:2] != 'CH': raise ValidationError( _("QR-IBAN numbers are only available in Switzerland.")) # Now, check if it's valid QR-IBAN (based on its IID). if not check_qr_iban_range(sanitized_qr_iban): raise ValidationError(_("QR-IBAN '%s' is invalid.") % qr_iban) return True
def _auto_init(self): # A l'installation du module il faut déterminer si le type des comptes bancaires existants cr = self._cr cr.execute( "SELECT 1 FROM information_schema.columns " "WHERE table_name = 'res_partner_bank' AND column_name = 'acc_type'" ) acc_type_exists = bool(cr.fetchall()) res = super(ResPartnerBank, self)._auto_init() if not acc_type_exists: # Initialisation des comptes bancaires existants cr.execute("SELECT id, acc_number FROM res_partner_bank") for acc_id, acc_number in cr.fetchall(): try: validate_iban(acc_number) except ValidationError: cr.execute( "UPDATE res_partner_bank SET acc_type = 'bank' WHERE id = %s", (acc_id, )) return res
def sepa_direct_debit_s2s_form_process(self, data): if not data.get('mandate_id'): iban = sanitize_account_number(data['iban']) # will raise a ValidationError given an invalid format validate_iban(iban) partner_id = int(data.get('partner_id')) mandate = self._create_or_find_mandate(iban, partner_id) else: mandate = self.env['sdd.mandate'].browse(data['mandate_id']) # since we're in a sudoed env, we need to add a few checks if mandate.partner_id.id != data['partner_id']: raise AccessError(_('Identity mismatch')) payment_token = self.env['payment.token'].sudo().create({ 'sdd_mandate_id': mandate.id, 'name': data['iban'], 'acquirer_ref': mandate.name, 'acquirer_id': int(data['acquirer_id']), 'partner_id': int(data['partner_id']), }) return payment_token
def sepa_direct_debit_s2s_form_process(self, data): partner_id = int(data['partner_id']) if not data.get('mandate_id'): iban = sanitize_account_number(data['iban']) same_iban_acc = self.env['res.partner.bank'].search( [('sanitized_acc_number', '=', iban), ('company_id', '=', self.env.company.id)], limit=1) if same_iban_acc: raise ValidationError( _("This account is not available. Please log in to continue." )) # will raise a ValidationError given an invalid format validate_iban(iban) mandate = self._create_or_find_mandate(iban, partner_id) else: partner = self.env['res.partner'].browse(partner_id).sudo() mandate = self.env['sdd.mandate'].browse(data['mandate_id']) # since we're in a sudoed env, we need to add a few checks if mandate.partner_id != partner.commercial_partner_id: raise AccessError(_('Identity mismatch')) iban_mask = 'X' * (len(data['iban']) - 4) + data['iban'][-4:] payment_token = self.env['payment.token'].sudo().create({ 'sdd_mandate_id': mandate.id, 'name': _('Direct Debit: ') + iban_mask, 'acquirer_ref': mandate.name, 'acquirer_id': int(data['acquirer_id']), 'partner_id': partner_id, }) return payment_token
def check_iban(self, iban=""): try: validate_iban(iban) return True except ValidationError: return False
def _validate_bank_account(self, value): try: res_partner_bank.validate_iban(value) except ValidationError: raise FormValidationError(_("Please give a correct IBAN number."))
def _match_partner_bank( self, partner, iban, bic, chatter_msg, create_if_not_found=False ): assert iban, "iban is a required arg" assert partner, "partner is a required arg" partner = partner.commercial_partner_id iban = iban.replace(" ", "").upper() rpbo = self.env["res.partner.bank"] rbo = self.env["res.bank"] try: validate_iban(iban) except Exception: chatter_msg.append( _("IBAN <b>%s</b> is not valid, so it has been ignored.") % iban ) return False company_id = self._context.get("force_company") or self.env.company.id bankaccount = rpbo.search( [ "|", ("company_id", "=", False), ("company_id", "=", company_id), ("sanitized_acc_number", "=", iban), ("partner_id", "=", partner.id), ], limit=1, ) if bankaccount: return bankaccount elif create_if_not_found: bank_id = False if bic: bic = bic.replace(" ", "").upper() bank = rbo.search([("bic", "=", bic)], limit=1) if bank: bank_id = bank.id else: bank = rbo.create( {"bic": bic, "name": bic} # TODO: see if we could do better ) bank_id = bank.id partner_bank = rpbo.create( {"partner_id": partner.id, "acc_number": iban, "bank_id": bank_id} ) chatter_msg.append( _( "The bank account <b>IBAN %s</b> has been automatically " "added on the supplier " "<a href=# data-oe-model=res.partner data-oe-id=%d>%s</a>" ) % (iban, partner.id, partner.display_name) ) return partner_bank else: chatter_msg.append( _( "The analysis of the business document returned " "<b>IBAN %s</b> as bank account, but there is no such " "bank account in Odoo linked to partner " "<a href=# data-oe-model=res.partner data-oe-id=%d>%s</a> and " "the option to automatically create bank " "accounts upon import is disabled." ) % (iban, partner.id, partner.display_name) )