def iter_transfer_recipients(self, account): if account._perimeter != self.current_perimeter: self.go_perimeter(account._perimeter) self.transfer_init_page.go(sag=self.sag) if self.page.get_error() == 'Fonctionnalité Indisponible': self.location(self.accounts_url.format(self.sag)) return for rcpt in self.page.iter_emitters(): if rcpt.id == account.id: break else: # couldn't find the account as emitter return # set of recipient id to not return or already returned seen = set([account.id]) for rcpt in self.page.iter_recipients(): if (rcpt.id in seen) or (rcpt.iban and not is_iban_valid(rcpt.iban)): # skip seen recipients and recipients with invalid iban continue seen.add(rcpt.id) yield rcpt
def check_account(self, account): self.assertTrue(account.id, 'account %r has no id' % account) self.assertTrue(account.label, 'account %r has no label' % account) self.assertFalse( empty(account.balance) and empty(account.coming), 'account %r should have balance or coming' % account) self.assertTrue(account.type, 'account %r is untyped' % account) self.assertTrue(account.currency, 'account %r has no currency' % account) self.assertIsNot(account.number, NotLoaded) if account.iban: self.assertTrue( is_iban_valid(account.iban), 'account %r IBAN is invalid: %r' % (account, account.iban)) if account.type in (account.TYPE_LOAN, ): self.assertLessEqual( account.balance, 0, 'loan %r should not have positive balance' % account) elif account.type == account.TYPE_CHECKING: self.assertTrue(account.iban, 'account %r has no IBAN' % account) elif account.type == account.TYPE_CARD: if not account.parent: self.backend.logger.warning( 'card account %r has no parent account', account) else: self.assertEqual( account.parent.type, account.TYPE_CHECKING, 'parent account of %r should have checking type' % account)
def get_iban(self): iban = '' # according to re module doc, list returned by re.findall always # be in the same order as they are in the source text for part in re.findall(r'([A-Z0-9]{4})\1\1', extract_text(self.data), flags=re.MULTILINE): # findall will find something like # ['FRXX', '1234', ... , '9012', 'FRXX', '1234', ... , '9012'] iban += part iban = iban[:len(iban) // 2] # we suppose that all iban are French iban iban_last_part = re.findall(r'([A-Z0-9]{3})\1\1Titulaire', extract_text(self.data), flags=re.MULTILINE) assert len( iban_last_part ) == 1, 'There should have something like 123123123Titulaire' iban += iban_last_part[0] if is_iban_valid(iban): return iban self.logger.warning('IBAN %s is not valid', iban) return NotAvailable
def create_transfer(self, account, recipient, transfer): transfer = Transfer() transfer.currency = FrenchTransaction.Currency('.//tr[td[contains(text(), "Montant")]]/td[not(@class)] | \ .//tr[th[contains(text(), "Montant")]]/td[not(@class)]')(self.doc) transfer.amount = CleanDecimal('.//tr[td[contains(text(), "Montant")]]/td[not(@class)] | \ .//tr[th[contains(text(), "Montant")]]/td[not(@class)]', replace_dots=True)(self.doc) transfer.account_iban = account.iban if recipient.category == u'Externe': for word in Upper(CleanText(u'.//tr[th[contains(text(), "Compte à créditer")]]/td[not(@class)]'))(self.doc).split(): if is_iban_valid(word): transfer.recipient_iban = word break else: raise TransferError('Unable to find IBAN (original was %s)' % recipient.iban) else: transfer.recipient_iban = recipient.iban transfer.account_id = unicode(account.id) transfer.recipient_id = unicode(recipient.id) transfer.exec_date = Date(CleanText('.//tr[th[contains(text(), "En date du")]]/td[not(@class)]'), dayfirst=True)(self.doc) transfer.label = (CleanText(u'.//tr[td[contains(text(), "Motif de l\'opération")]]/td[not(@class)]')(self.doc) or CleanText(u'.//tr[td[contains(text(), "Libellé")]]/td[not(@class)]')(self.doc) or CleanText(u'.//tr[th[contains(text(), "Libellé")]]/td[not(@class)]')(self.doc)) transfer.account_label = account.label transfer.recipient_label = recipient.label transfer._account = account transfer._recipient = recipient transfer.account_balance = account.balance return transfer
def iter_accounts(self, ibans): for f in self.path('data.infoUdc.familleCompte.*'): for a in f.get('compte'): iban = ibans.get(a.get('key')) if iban is not None and not is_iban_valid(iban): iban = rib2iban(rebuild_rib(iban)) acc = Account.from_dict({ 'id': a.get('key'), 'label': a.get('libellePersoProduit') or a.get('libelleProduit'), 'currency': a.get('devise'), 'type': self.LABEL_TO_TYPE.get(' '.join(a.get('libelleProduit').split())) or \ self.FAMILY_TO_TYPE.get(f.get('idFamilleCompte')) or Account.TYPE_UNKNOWN, 'balance': a.get('soldeDispo'), 'coming': a.get('soldeAVenir'), 'iban': iban, 'number': a.get('value') }) # softcap not used TODO don't pass this key when backend is ready # deferred cb can disappear the day after the appear, so 0 as day_for_softcap acc._bisoftcap = { 'deferred_cb': { 'softcap_day': 1000, 'day_for_softcap': 0, 'date_field': 'rdate' } } yield acc
def iter_transfer_recipients(self, account): # perimeters have their own recipients self.go_to_perimeter(account._perimeter) self.transfer_init_page.go() if self.page.get_error() == 'Fonctionnalité Indisponible': self.accounts.go() return for emitter_acc in self.page.iter_emitters(): if emitter_acc.id == account.id: break else: # couldn't find the account as emitter return # set of recipient id to not return or already returned seen = set([account.id]) for rcpt in self.page.iter_recipients(): if (rcpt.id in seen) or (rcpt.iban and not is_iban_valid(rcpt.iban)): # skip seen recipients and recipients with invalid iban continue seen.add(rcpt.id) yield rcpt
def iter_accounts(self, ibans): for f in self.path('data.infoUdc.familleCompte.*'): for a in f.get('compte'): iban = ibans.get(a.get('key')) if iban is not None and not is_iban_valid(iban): iban = rib2iban(rebuild_rib(iban)) yield Account.from_dict({ 'id': a.get('key'), 'label': a.get('libellePersoProduit') or a.get('libelleProduit'), 'currency': a.get('devise'), 'type': self.LABEL_TO_TYPE.get(a.get('libelleProduit')) or self.FAMILY_TO_TYPE.get(f.get('idFamilleCompte')) or Account.TYPE_UNKNOWN, 'balance': a.get('soldeDispo'), 'coming': a.get('soldeAVenir'), 'iban': iban, 'number': a.get('value') })
def obj_iban(self): iban = Map(Dict('key'), Env('ibans')(self), default=NotAvailable)(self) if not empty(iban): if not is_iban_valid(iban): iban = rib2iban(rebuild_rib(iban)) return iban return None
def get_iban(self): match = re.search(r'Tm \[\((FR[0-9]{2} [A-Z0-9 ]+)\)\]', self.doc.decode('ISO8859-1')) if not match: return NotAvailable iban = match.group(1).replace(' ', '') assert is_iban_valid(iban) return iban
class Item(MyRecipient): obj_id = obj_iban = CleanText('./div[1]/div[1]/span[1]') obj_bank_name = CleanText('./div[1]/div[2]/span[1]') obj_category = u'Externe' def obj_label(self): first_label = CleanText('./div[1]/div[3]/span[1]')(self) second_label = CleanText('./div[1]/div[3]/span[2]')(self) return first_label if first_label == second_label else ( '%s %s' % (first_label, second_label)).strip() validate = lambda self, obj: empty(self.obj_iban( self)) or is_iban_valid(self.obj_iban(self))
def add_recipient(self, recipient, **params): """ Add a recipient to the connection. :param iban: iban of the new recipient. :type iban: :class:`str` :param label: label of the new recipient. :type label: :class`str` :raises: :class:`BrowserQuestion` :raises: :class:`AddRecipientError` :rtype: :class:`Recipient` """ if not is_iban_valid(recipient.iban): raise RecipientInvalidIban('Iban is not valid.') if not recipient.label: raise RecipientInvalidLabel('Recipient label is mandatory.') return self.new_recipient(recipient, **params)
def get_account_iban(self, account_index, account_category, weboob_account_id): """ Fetch an IBAN for a given account It may fail from time to time (error 500 or 403) """ params = { 'compteIdx': int(account_index), 'grandeFamilleCode': int(account_category), } try: self.account_iban.go(params=params) except (ClientError, ServerError): self.logger.warning('Request to IBAN failed for account id "%s"', weboob_account_id) return NotAvailable iban = self.page.get_iban() if is_iban_valid(iban): return iban return NotAvailable
def iter_accounts(self): for classeur in self.doc.get('donnees', {}).get('classeurs', {}): title = classeur['title'] for compte in classeur.get('comptes', []): a = Account() a.label = CleanText().filter(compte['libelle']) a._id = compte['id'] a.type = self.obj_type(a.label) a.number = compte['iban'].replace(' ', '') # for some account that don't have Iban the account number is store under this variable in the Json if not is_iban_valid(a.number): a.iban = NotAvailable else: a.iban = a.number # id based on iban to match ids in database. a.id = a.number[4:-2] if len(a.number) == 27 else a.number a._agency = compte['agenceGestionnaire'] a._title = title yield a
def get_account_iban(self, account_index, account_category, weboob_account_id): """ Fetch an IBAN for a given account It may fail from time to time (error 500 or 403) """ params = { 'compteIdx': int(account_index), 'grandeFamilleCode': int(account_category), } try: self.account_iban.go(space=self.space, params=params) except (ClientError, ServerError): self.logger.warning('Request to IBAN failed for account id "%s"', weboob_account_id) return NotAvailable iban = self.page.get_iban() if is_iban_valid(iban): return iban return NotAvailable
def check_account(self, account): self.assertTrue(account.id, 'account %r has no id' % account) self.assertTrue(account.label, 'account %r has no label' % account) self.assertFalse(empty(account.balance) and empty(account.coming), 'account %r should have balance or coming' % account) self.assertTrue(account.type, 'account %r is untyped' % account) self.assertTrue(account.currency, 'account %r has no currency' % account) self.assertIsNot(account.number, NotLoaded) if account.iban: self.assertTrue(is_iban_valid(account.iban), 'account %r IBAN is invalid: %r' % (account, account.iban)) if account.type in (account.TYPE_LOAN,): self.assertLessEqual(account.balance, 0, 'loan %r should not have positive balance' % account) elif account.type == account.TYPE_CHECKING: self.assertTrue(account.iban, 'account %r has no IBAN' % account) elif account.type == account.TYPE_CARD: if not account.parent: self.backend.logger.warning('card account %r has no parent account', account) else: self.assertEqual(account.parent.type, account.TYPE_CHECKING, 'parent account of %r should have checking type' % account)
def check_account(self, account): self.assertTrue(account.id, 'account %r has no id' % account) self.assertTrue(account.label, 'account %r has no label' % account) self.assertFalse( empty(account.balance) and empty(account.coming), 'account %r should have balance or coming' % account) self.assertTrue(account.type, 'account %r is untyped' % account) self.assertTrue(account.currency, 'account %r has no currency' % account) if account.iban: self.assertTrue( is_iban_valid(account.iban), 'account %r IBAN is invalid: %r' % (account, account.iban)) if account.type in (account.TYPE_LOAN, ): self.assertLessEqual( account.balance, 0, 'loan %r should not have positive balance' % account) elif account.type == account.TYPE_CHECKING: self.assertTrue(account.iban, 'account %r has no IBAN' % account)
def get_iban(self): iban = u'' # according to re module doc, list returned by re.findall always # be in the same order as they are in the source text for part in re.findall(r'([A-Z0-9]{4})\1\1', extract_text(self.data), flags=re.MULTILINE): # findall will find something like # ['FRXX', '1234', ... , '9012', 'FRXX', '1234', ... , '9012'] iban += part iban = iban[:len(iban)/2] # we suppose that all iban are French iban iban_last_part = re.findall(r'([A-Z0-9]{3})\1\1Titulaire', extract_text(self.data), flags=re.MULTILINE) assert len(iban_last_part) == 1, 'There should have something like 123123123Titulaire' iban += iban_last_part[0] if is_iban_valid(iban): return iban self.logger.warning('IBAN %s is not valid', iban) return NotAvailable
def iter_accounts(self, ibans): for f in self.path('data.infoUdc.familleCompte.*'): for a in f.get('compte'): iban = ibans.get(a.get('key')) if iban is not None and not is_iban_valid(iban): iban = rib2iban(rebuild_rib(iban)) acc = Account.from_dict({ 'id': a.get('key'), 'label': a.get('libellePersoProduit') or a.get('libelleProduit'), 'currency': a.get('devise'), 'type': self.LABEL_TO_TYPE.get(' '.join(a.get('libelleProduit').split())) or \ self.FAMILY_TO_TYPE.get(f.get('idFamilleCompte')) or Account.TYPE_UNKNOWN, 'balance': a.get('soldeDispo'), 'coming': a.get('soldeAVenir'), 'iban': iban, 'number': a.get('value') }) # softcap not used TODO don't pass this key when backend is ready # deferred cb can disappear the day after the appear, so 0 as day_for_softcap acc._bisoftcap = {'deferred_cb': {'softcap_day': 1000, 'day_for_softcap': 0, 'date_field': 'rdate'}} yield acc
def create_transfer(self, account, recipient, transfer): transfer = Transfer() transfer.currency = FrenchTransaction.Currency( './/tr[td[contains(text(), "Montant")]]/td[not(@class)] | \ .//tr[th[contains(text(), "Montant")]]/td[not(@class)]' )(self.doc) transfer.amount = CleanDecimal( './/tr[td[contains(text(), "Montant")]]/td[not(@class)] | \ .//tr[th[contains(text(), "Montant")]]/td[not(@class)]', replace_dots=True)(self.doc) transfer.account_iban = account.iban if recipient.category == u'Externe': for word in Upper( CleanText( u'.//tr[th[contains(text(), "Compte à créditer")]]/td[not(@class)]' ))(self.doc).split(): if is_iban_valid(word): transfer.recipient_iban = word break else: raise TransferError('Unable to find IBAN (original was %s)' % recipient.iban) else: transfer.recipient_iban = recipient.iban transfer.account_id = unicode(account.id) transfer.recipient_id = unicode(recipient.id) transfer.exec_date = Date(CleanText( './/tr[th[contains(text(), "En date du")]]/td[not(@class)]'), dayfirst=True)(self.doc) transfer.label = CleanText( u'.//tr[td[contains(text(), "Motif de l\'opération")]]/td[not(@class)] | \ .//tr[td[contains(text(), "Libellé")]]/td[not(@class)]' )(self.doc) transfer.account_label = account.label transfer.recipient_label = recipient.label transfer._account = account transfer._recipient = recipient transfer.account_balance = account.balance return transfer
def get_iban(self): text = extract_text(self.content) iban = re.search(r'IBAN([A-Z]{2}\d+)', text).group(1) assert is_iban_valid(iban), 'did not parse IBAN properly' return iban
def obj_iban(self): return self.obj_id(self) if is_iban_valid(self.obj_id(self)) else NotAvailable
def validate(self, obj): # Some international external recipients show those infos: # INT - CA - 0815304220511006 - CEGEP CANADA # Skipping those for the moment. return not obj.iban or is_iban_valid(obj.iban)
def validate(self, el): # For the moment, we skip this kind of recipient: # {"nomBeneficiaire":"Aircraft Guaranty Holdings LLC","idBeneficiaire":"00002##00002##FRSTUS44XXX##130018430","ibanNumCompte":"130018430","typeIban":"0","bic":"FRSTUS44XXX","statut":"1","numListe":"00002","typeBeneficiaire":"INTER","devise":"USD","tauxConversion":"1.047764","nbDecimale":"2","typeFrais":"","adresseBeneficiaire":"","nomBanque":"Frost National Bank","adresseBanque":"100 West Houston Street San Antonio, Texas 78205 USA ","canalActivation":"1","libelleStatut":"Activé"} return is_iban_valid(el.iban)
def obj_iban(self): # for some account that don't have Iban the account number is store under this variable in the Json number = Field('number')(self) if not is_iban_valid(number): return NotAvailable return number
def get_iban(self): text = extract_text(self.doc) iban = re.search(r'IBAN([A-Z]{2}\d+)', text).group(1) assert is_iban_valid(iban), 'did not parse IBAN properly' return iban
def condition(self): return Field('id')(self) != Env('account_id')( self) and is_iban_valid(Field('iban')(self))
def condition(self): return Field('id')(self) != Env('account_id')(self) and is_iban_valid(Field('iban')(self))
def condition(self): iban = Field('iban')(self) if iban: return is_iban_valid(iban) # some internal accounts don't show iban return True