def switch_account_to_loan(self, account): loan = Loan() copy_attrs = ('id', 'number', 'label', 'type', 'currency', '_index', '_category', '_contract', '_id_element_contrat', 'owner_type') for attr in copy_attrs: setattr(loan, attr, getattr(account, attr)) loan.balance = -account.balance return loan
def get_revolving_attributes(self, account): loan = Loan() loan.id = account.id loan.label = '%s - %s' %(account.label, account.id) loan.currency = account.currency loan.url = account.url loan.available_amount = CleanDecimal('//tr[td[contains(text(), "Montant Maximum Autorisé") or contains(text(), "Montant autorisé")]]/td[2]')(self.doc) loan.used_amount = loan.used_amount = CleanDecimal('//tr[td[contains(text(), "Montant Utilisé") or contains(text(), "Montant utilisé")]]/td[2]')(self.doc) loan.available_amount = CleanDecimal(Regexp(CleanText('//tr[td[contains(text(), "Montant Disponible") or contains(text(), "Montant disponible")]]/td[2]'), r'(.*) au'))(self.doc) loan._has_cards = False loan.type = Account.TYPE_REVOLVING_CREDIT return loan
def get_list(self): accounts = [] for cpt in self.doc.xpath( '//div[contains(@class, " compte") and not(contains(@class, "compte_selected"))]' ): # ignore auto assurance accounts if 'aut' in cpt.get('class'): continue account = Account() account._history_link = Link( './ul/li/a[contains(@id, "consulter_solde") ' 'or contains(@id, "historique") ' 'or contains(@id, "contrat") ' 'or contains(@id, "assurance_vie_operations")]')(cpt) # this is to test if access to the accounts info is blocked for different reasons page = self.browser.open(account._history_link).page if isinstance(page, LoanPage): account = Loan() account._history_link = Link( './ul/li/a[contains(@id, "consulter_solde") ' 'or contains(@id, "historique") ' 'or contains(@id, "contrat") ' 'or contains(@id, "assurance_vie_operations")]')(cpt) if isinstance(page, LoanPage): account.id = CleanText( '(//p[@id="c_montantEmprunte"]//span[@class="valStatic"]//strong)[1]' )(cpt) account.label = CleanText( '(//p[@id="c_montantEmprunte"]//span[@class="valStatic"]//strong)[1]' )(cpt) account.type = Account.TYPE_LOAN account_history_page = self.browser.open( account._history_link).page account.total_amount = account_history_page.get_total_amount() account.next_payment_amount = account_history_page.get_next_payment_amount( ) account.next_payment_date = account_history_page.get_next_payment_date( ) account.account_label = account_history_page.get_account_label( ) account.subscription_date = account_history_page.get_subscription_date( ) account.maturity_date = account_history_page.get_maturity_date( ) if len(accounts) == 0: global_error_message = page.doc.xpath( '//div[@id="as_renouvellementMIFID.do_"]/div[contains(text(), "Bonjour")] ' '| //div[@id="as_afficherMessageBloquantMigration.do_"]//div[@class="content_message"] ' '| //p[contains(text(), "Et si vous faisiez de Fortuneo votre banque principale")] ' '| //div[@id="as_renouvellementMotDePasse.do_"]//p[contains(text(), "votre mot de passe")]' '| //div[@id="as_afficherSecuriteForteOTPIdentification.do_"]//span[contains(text(), "Pour valider ")]' ) if global_error_message: raise ActionNeeded(CleanText('.')(global_error_message[0])) local_error_message = page.doc.xpath( '//div[@id="error"]/p[@class="erreur_texte1"]') if local_error_message: raise BrowserUnavailable( CleanText('.')(local_error_message[0])) number = RawText('./a[contains(@class, "numero_compte")]')( cpt).replace(u'N° ', '') account.id = CleanText(None).filter(number).replace(u'N°', '') account._card_links = [] card_link = Link('./ul/li/a[contains(text(), "Carte bancaire")]', default='')(cpt) if len(card_link) > 0: account._card_links.append(card_link) account.label = CleanText( './a[contains(@class, "numero_compte")]/@title')(cpt) for pattern, type in self.ACCOUNT_TYPES.items(): if pattern in account._history_link: account.type = type break if account.type in { Account.TYPE_PEA, Account.TYPE_MARKET, Account.TYPE_LIFE_INSURANCE }: account._investment_link = Link( './ul/li/a[contains(@id, "portefeuille")]')(cpt) balance = self.browser.open( account._investment_link).page.get_balance(account.type) if account.type in {Account.TYPE_PEA, Account.TYPE_MARKET}: self.browser.investments[account.id] = list( self.browser.open( account._investment_link).page.get_investments( account)) else: balance = self.browser.open( account._history_link).page.get_balance() if account.type is not Account.TYPE_LOAN: account.coming = self.browser.open( account._history_link).page.get_coming() if account.type in {Account.TYPE_PEA, Account.TYPE_MARKET}: account.currency = self.browser.open( account._investment_link).page.get_currency() else: account.currency = account.get_currency(balance) account.balance = CleanDecimal(None, replace_dots=True).filter(balance) if account.type in (Account.TYPE_CHECKING, Account.TYPE_SAVINGS): # Need a token sent by SMS to customers account.iban = NotAvailable if (account.label, account.id, account.balance) not in [ (a.label, a.id, a.balance) for a in accounts ]: accounts.append(account) return accounts
def get_loan_attributes(self, account): loan = Loan() loan.total_amount = CleanDecimal('//div/span[contains(text(), "Capital initial")]/following-sibling::*[1]', replace_dots=True)(self.doc) owner_name = CleanText('//a[@class="lien-entete login"]/span')(self.doc) loan.name = ' '.join(owner_name.split()[1:]) loan.subscription_date = Date(Regexp(CleanText('//h4[span[contains(text(), "Date de départ du prêt")]]'), r'(\d{2}\/\d{2}\/\d{4})'), dayfirst=True)(self.doc) loan.maturity_date = Date(Regexp(CleanText('//h4[span[contains(text(), "Date de fin du prêt")]]'), r'(\d{2}\/\d{2}\/\d{4})'), dayfirst=True)(self.doc) loan.rate = Eval(lambda x: x / 100, CleanDecimal('//div/span[contains(text(), "Taux fixe")]/following-sibling::*[1]', replace_dots=True))(self.doc) loan.last_payment_amount = CleanDecimal('//div[@class="txt-detail " and not (@style)]//span[contains(text(), "Echéance du")]/following-sibling::span[1]')(self.doc) loan.last_payment_date = Date(Regexp(CleanText('//div[@class="txt-detail " and not (@style)]//span[contains(text(), "Echéance du")]'), r'(\d{2}\/\d{2}\/\d{4})'), dayfirst=True)(self.doc) loan.id = account.id loan.currency = account.currency loan.label = account.label loan.balance = account.balance loan.coming = account.coming loan.type = account.type loan._uncleaned_id = account._uncleaned_id loan._multiple_type = account._multiple_type return loan
def get_revolving_attributes(self, account): loan = Loan() loan.available_amount = CleanDecimal('//div/span[contains(text(), "Montant disponible")]/following-sibling::*[1]', replace_dots=True)(self.doc) loan.used_amount = CleanDecimal('//div/span[contains(text(), "Montant Utilisé")]/following-sibling::*[1]', replace_dots=True)(self.doc) loan.total_amount = CleanDecimal('//div/span[contains(text(), "Réserve accordée")]/following-sibling::*[1]', replace_dots=True)(self.doc) loan.last_payment_amount = CleanDecimal('//div/span[contains(text(), "Echéance Précédente")]/following-sibling::*[1]', replace_dots=True)(self.doc) loan.last_payment_date = Date(Regexp(CleanText('//div/span[contains(text(), "Echéance Précédente")]/following-sibling::*[2]'), r'(\d{2}\/\d{2}\/\d{4})'), dayfirst=True)(self.doc) owner_name = CleanText('//a[@class="lien-entete login"]/span')(self.doc) loan.name = ' '.join(owner_name.split()[1:]) loan.id = account.id loan.currency = account.currency loan.label = account.label loan.balance = account.balance loan.coming = account.coming loan.type = account.type loan._uncleaned_id = account._uncleaned_id loan._multiple_type = account._multiple_type return loan
def get_revolving_attributes(self, account): loan = Loan() loan.id = account.id loan.label = '%s - %s' % (account.label, account.id) loan.currency = account.currency loan.url = account.url loan.used_amount = CleanDecimal.US( '//tr[td[contains(text(), "Montant Utilisé") or contains(text(), "Montant utilisé")]]/td[2]' )(self.doc) loan.available_amount = CleanDecimal.US( Regexp( CleanText( '//tr[td[contains(text(), "Montant Disponible") or contains(text(), "Montant disponible")]]/td[2]' ), r'(.*) au'))(self.doc) loan.balance = -loan.used_amount loan._has_cards = False loan.type = Account.TYPE_REVOLVING_CREDIT return loan
def get_revolving_account(self, account): loan = Loan() loan.id = loan.number = account.id loan.label = account.label loan.type = account.type loan.ownership = account.ownership loan.currency = account.currency loan.balance = account.balance loan.coming = account.coming loan._internal_id = account._internal_id loan._prestation_id = account._prestation_id loan._loan_type = account._loan_type loan._is_json_histo = account._is_json_histo loan._parent_id = None if Dict('donnees/tabIdAllPrestations')(self.doc): for acc in Dict('donnees/tabPrestations')(self.doc): if CleanText(Dict('idPrestation'))(acc) == account._prestation_id: # coming if Dict('encoursFinMois', default=NotAvailable)(acc): loan.coming = eval_decimal_amount('encoursFinMois/valeur', 'encoursFinMois/posDecimale')(acc) # total amount if Dict('reserveAutorisee', default=NotAvailable)(acc): loan.total_amount = eval_decimal_amount('reserveAutorisee/valeur', 'reserveAutorisee/posDecimale')(acc) elif Dict('montantAutorise', default=NotAvailable)(acc): loan.total_amount = eval_decimal_amount('montantAutorise/valeur', 'montantAutorise/posDecimale')(acc) else: loan.total_amount = eval_decimal_amount('reserveMaximum/valeur', 'reserveMaximum/posDecimale')(acc) # available amount if Dict('montantDisponible', default=NotAvailable)(acc): loan.available_amount = eval_decimal_amount('montantDisponible/valeur', 'montantDisponible/posDecimale')(acc) else: loan.available_amount = eval_decimal_amount('reserveDispo/valeur', 'reserveDispo/posDecimale')(acc) # used amount if Dict('reserveUtilisee', default=NotAvailable)(acc): loan.used_amount = eval_decimal_amount('reserveUtilisee/valeur', 'reserveUtilisee/posDecimale')(acc) elif Dict('montantUtilise', default=NotAvailable)(acc): loan.available_amount = eval_decimal_amount('montantUtilise/valeur', 'montantUtilise/posDecimale')(acc) # next payment amount if Dict('prochaineEcheance', default=NotAvailable)(acc): loan.next_payment_amount = eval_decimal_amount('prochaineEcheance/valeur', 'prochaineEcheance/posDecimale')(acc) elif Dict('montantMensualite', default=NotAvailable)(acc): loan.next_payment_amount = eval_decimal_amount('montantMensualite/valeur', 'montantMensualite/posDecimale')(acc) loan.last_payment_amount = loan.next_payment_amount loan.duration = Dict('dureeNbMois')(acc) if Dict('dateMensualite', default=NotAvailable)(acc): loan.next_payment_date = datetime.datetime.strptime(Dict('dateMensualite')(acc), '%Y%m%d') self.set_parent_account_id(loan, acc) return loan return loan
def get_loan_account(self, account): assert account._prestation_id in Dict('donnees/tabIdAllPrestations')(self.doc), \ 'Loan with prestation id %s should be on this page ...' % account._prestation_id for acc in Dict('donnees/tabPrestations')(self.doc): if CleanText(Dict('idPrestation'))(acc) == account._prestation_id: loan = Loan() loan.id = loan.number = account.id loan.label = account.label loan.type = account.type loan.ownership = account.ownership loan.currency = Currency(Dict('capitalRestantDu/devise'))(acc) loan.balance = Eval(lambda x: x / 100, CleanDecimal(Dict('capitalRestantDu/valeur')))(acc) loan.coming = account.coming loan.total_amount = Eval(lambda x: x / 100, CleanDecimal(Dict('montantPret/valeur')))(acc) loan.next_payment_amount = Eval(lambda x: x / 100, CleanDecimal(Dict('montantEcheance/valeur')))(acc) loan.duration = Dict('dureeNbMois')(acc) loan.maturity_date = datetime.datetime.strptime(Dict('dateFin')(acc), '%Y%m%d') # We only know the next payment day (without the month or the year). But since we know that's # a monthly repayment, we can guess it. if CleanText(Dict('periodicite'))(acc) == 'MENSUELLE': repayment_day = CleanDecimal(Dict('jourEcheanceMensuelle'))(acc) if not repayment_day: loan.next_payment_date = NotAvailable else: now = datetime.datetime.now().date() next_payment_date = now.replace(day=repayment_day) if repayment_day < now.day: next_payment_date += relativedelta(months=1) loan.next_payment_date = next_payment_date else: self.logger.warning('Not handled periodicity: %s', CleanText(Dict('periodicite'))(acc)) self.set_parent_account_id(loan, acc) loan._internal_id = account._internal_id loan._prestation_id = account._prestation_id loan._loan_type = account._loan_type return loan
def iter_accounts(self): if self.accounts_list is None: self.accounts_list = [] # In case of password renewal, we need to go on ibans twice. self.ibans.go() ibans = self.page.get_ibans_dict() if self.ibans.is_here( ) else self.ibans.go().get_ibans_dict() # This page might be unavailable. try: ibans.update( self.transfer_init.go(json={ 'modeBeneficiaire': '0' }).get_ibans_dict('Crediteur')) except (TransferAssertionError, AttributeError): pass accounts = list(self.accounts.go().iter_accounts(ibans=ibans)) self.market_syn.go(json={}, method='POST') # do a post on the given URL market_accounts = self.page.get_list( ) # get the list of 'Comptes Titres' checked_accounts = set() for account in accounts: if self.is_loan(account): account = Loan.from_dict(account.to_dict()) if account.type in (Account.TYPE_MORTGAGE, Account.TYPE_CONSUMER_CREDIT): self.loan_details.go(data={'iban': account.id}, loan_type='creditPret') self.page.fill_loan_details(obj=account) elif account.type == Account.TYPE_REVOLVING_CREDIT: self.loan_details.go(data={'iban': account.id}, loan_type='creditConsoProvisio') self.page.fill_revolving_details(obj=account) elif account.type == Account.TYPE_LOAN: self.loan_details.go(data={'iban': account.id}, loan_type='creditPretPersoPro') self.page.fill_loan_details(obj=account) for market_acc in market_accounts: if all(( market_acc['securityAccountNumber'].endswith( account.number[-4:]), account.type in (Account.TYPE_MARKET, Account.TYPE_PEA), account.label == market_acc['securityAccountName'], not account.iban, )): if account.id in checked_accounts: # in this case, we have identified two accounts for the same CompteTitre raise DataError( 'we have two market accounts mapped to a same "CompteTitre" dictionary' ) checked_accounts.add(account.id) account.balance = market_acc.get( 'valorisation', account.balance) account.valuation_diff = market_acc['profitLoss'] break self.accounts_list.append(account) # Fetching capitalisation contracts from the "Assurances Vie" space (some are not in the BNP API): params = self.natio_vie_pro.go().get_params() try: self.capitalisation_page.go(params=params) except ServerError: self.logger.warning("An Internal Server Error occurred") else: if self.capitalisation_page.is_here( ) and self.page.has_contracts(): for account in self.page.iter_capitalisation(): # Life Insurance accounts may appear BOTH in the API and the "Assurances Vie" domain, # It is better to keep the API version since it contains the unitvalue: if account.number not in [ a.number for a in self.accounts_list ]: self.logger.warning( "We found an account that only appears on the old BNP website." ) self.accounts_list.append(account) else: self.logger.warning( "This account was skipped because it already appears in the API." ) return iter(self.accounts_list)
def get_list(self): accounts = [] for cpt in self.doc.xpath('//div[contains(@class, " compte") and not(contains(@class, "compte_selected"))]'): # ignore auto assurance accounts if 'aut' in cpt.get('class'): continue account = Account() account._history_link = Link('./ul/li/a[contains(@id, "consulter_solde") ' 'or contains(@id, "historique") ' 'or contains(@id, "contrat") ' 'or contains(@id, "assurance_vie_operations")]')(cpt) # this is to test if access to the accounts info is blocked for different reasons page = self.browser.open(account._history_link).page if isinstance(page, LoanPage): account = Loan() account._history_link = Link('./ul/li/a[contains(@id, "consulter_solde") ' 'or contains(@id, "historique") ' 'or contains(@id, "contrat") ' 'or contains(@id, "assurance_vie_operations")]')(cpt) if isinstance(page, LoanPage): account.id = CleanText('(//p[@id="c_montantEmprunte"]//span[@class="valStatic"]//strong)[1]')(cpt) account.label = CleanText('(//p[@id="c_montantEmprunte"]//span[@class="valStatic"]//strong)[1]')(cpt) account.type = Account.TYPE_LOAN account_history_page = page account.total_amount = account_history_page.get_total_amount() account.next_payment_amount = account_history_page.get_next_payment_amount() account.next_payment_date = account_history_page.get_next_payment_date() account.account_label = account_history_page.get_account_label() account.subscription_date = account_history_page.get_subscription_date() account.maturity_date = account_history_page.get_maturity_date() account.ownership = account_history_page.get_owner() if len(accounts) == 0: global_error_message = page.doc.xpath('//div[@id="as_renouvellementMIFID.do_"]/div[contains(text(), "Bonjour")] ' '| //div[@id="as_afficherMessageBloquantMigration.do_"]//div[@class="content_message"] ' '| //p[contains(text(), "Et si vous faisiez de Fortuneo votre banque principale")] ' '| //div[@id="as_renouvellementMotDePasse.do_"]//p[contains(text(), "votre mot de passe")]' '| //div[@id="as_afficherSecuriteForteOTPIdentification.do_"]//span[contains(text(), "Pour valider ")]') if global_error_message: if "Et si vous faisiez de Fortuneo votre banque principale" in CleanText(global_error_message)(self): self.browser.location('/ReloadContext', data={'action': 4}) return raise ActionNeeded(CleanText('.')(global_error_message[0])) local_error_message = page.doc.xpath('//div[@id="error"]/p[@class="erreur_texte1"]') if local_error_message: raise BrowserUnavailable(CleanText('.')(local_error_message[0])) account.id = account.number = CleanText('./a[contains(@class, "numero_compte")]/div')(cpt).replace(u'N° ', '') account._ca = CleanText('./a[contains(@class, "numero_compte")]/@rel')(cpt) account._card_links = [] card_link = Link('./ul/li/a[contains(text(), "Carte bancaire")]', default='')(cpt) if len(card_link) > 0: account._card_links.append(card_link) account.label = CleanText('./a[contains(@class, "numero_compte")]/@title')(cpt) for pattern, type in self.ACCOUNT_TYPES.items(): if pattern in account._history_link: account.type = type break investment_page = None if account.type in (Account.TYPE_PEA, Account.TYPE_MARKET, Account.TYPE_LIFE_INSURANCE): account._investment_link = Link('./ul/li/a[contains(@id, "portefeuille")]')(cpt) investment_page = self.browser.location(account._investment_link).page balance = investment_page.get_balance(account.type) if account.type in (Account.TYPE_PEA, Account.TYPE_MARKET): self.browser.investments[account.id] = list(self.browser.open(account._investment_link).page.get_investments(account)) else: balance = page.get_balance() if account.type is not Account.TYPE_LOAN: account.coming = page.get_coming() if account.type in (Account.TYPE_PEA, Account.TYPE_MARKET): account.currency = investment_page.get_currency() elif balance: account.currency = account.get_currency(balance) account.balance = CleanDecimal.French().filter(balance) if account.type in (Account.TYPE_CHECKING, Account.TYPE_SAVINGS): # Need a token sent by SMS to customers account.iban = NotAvailable if account.type is not Account.TYPE_LOAN: regexp = re.search(r'(m\. |mme\. )(.+)', CleanText('//span[has-class("mon_espace_nom")]')(self.doc), re.IGNORECASE) if regexp and len(regexp.groups()) == 2: gender = regexp.group(1).replace('.', '').rstrip() name = regexp.group(2) label = account.label if re.search(r'(m|mr|me|mme|mlle|mle|ml)\.? (.*)\bou (m|mr|me|mme|mlle|mle|ml)\b(.*)', label, re.IGNORECASE): account.ownership = AccountOwnership.CO_OWNER elif re.search(r'{} {}'.format(gender, name), label, re.IGNORECASE): account.ownership = AccountOwnership.OWNER else: account.ownership = AccountOwnership.ATTORNEY if (account.label, account.id, account.balance) not in [(a.label, a.id, a.balance) for a in accounts]: accounts.append(account) return accounts
def get_revolving_account(self, account): loan = Loan() loan.id = loan.number = account.id loan.label = account.label loan.type = account.type loan.currency = account.currency loan.balance = account.balance loan.coming = account.coming loan._internal_id = account._internal_id loan._prestation_id = account._prestation_id loan._loan_type = account._loan_type loan._is_json_histo = account._is_json_histo if Dict('donnees/tabIdAllPrestations')(self.doc): for acc in Dict('donnees/tabPrestations')(self.doc): if CleanText(Dict('idPrestation'))(acc) == account._prestation_id: # coming if Dict('encoursFinMois', default=NotAvailable)(acc): loan.coming = eval_decimal_amount('encoursFinMois/valeur', 'encoursFinMois/posDecimale')(acc) # total amount if Dict('reserveAutorisee', default=NotAvailable)(acc): loan.total_amount = eval_decimal_amount('reserveAutorisee/valeur', 'reserveAutorisee/posDecimale')(acc) elif Dict('montantAutorise', default=NotAvailable)(acc): loan.total_amount = eval_decimal_amount('montantAutorise/valeur', 'montantAutorise/posDecimale')(acc) else: loan.total_amount = eval_decimal_amount('reserveMaximum/valeur', 'reserveMaximum/posDecimale')(acc) # available amount if Dict('montantDisponible', default=NotAvailable)(acc): loan.available_amount = eval_decimal_amount('montantDisponible/valeur', 'montantDisponible/posDecimale')(acc) else: loan.available_amount = eval_decimal_amount('reserveDispo/valeur', 'reserveDispo/posDecimale')(acc) # used amount if Dict('reserveUtilisee', default=NotAvailable)(acc): loan.used_amount = eval_decimal_amount('reserveUtilisee/valeur', 'reserveUtilisee/posDecimale')(acc) elif Dict('montantUtilise', default=NotAvailable)(acc): loan.available_amount = eval_decimal_amount('montantUtilise/valeur', 'montantUtilise/posDecimale')(acc) # next payment amount if Dict('prochaineEcheance', default=NotAvailable)(acc): loan.next_payment_amount = eval_decimal_amount('prochaineEcheance/valeur', 'prochaineEcheance/posDecimale')(acc) elif Dict('montantMensualite', default=NotAvailable)(acc): loan.next_payment_amount = eval_decimal_amount('montantMensualite/valeur', 'montantMensualite/posDecimale')(acc) loan.last_payment_amount = loan.next_payment_amount loan.duration = Dict('dureeNbMois')(acc) return loan return loan
def get_loan_account(self, account): assert account._prestation_id in Dict('donnees/tabIdAllPrestations')(self.doc), \ 'Loan with prestation id %s should be on this page ...' % account._prestation_id for acc in Dict('donnees/tabPrestations')(self.doc): if CleanText(Dict('idPrestation'))(acc) == account._prestation_id: loan = Loan() loan.id = loan.number = account.id loan.label = account.label loan.type = account.type loan.currency = Currency(Dict('capitalRestantDu/devise'))(acc) loan.balance = Eval(lambda x: x / 100, CleanDecimal(Dict('capitalRestantDu/valeur')))(acc) loan.coming = account.coming loan.total_amount = Eval(lambda x: x / 100, CleanDecimal(Dict('montantPret/valeur')))(acc) loan.next_payment_amount = Eval(lambda x: x / 100, CleanDecimal(Dict('montantEcheance/valeur')))(acc) loan.duration = Dict('dureeNbMois')(acc) loan.maturity_date = datetime.datetime.strptime(Dict('dateFin')(acc), '%Y%m%d') loan._internal_id = account._internal_id loan._prestation_id = account._prestation_id loan._loan_type = account._loan_type return loan
def get_loan_account(self, account): assert account._prestation_id in Dict('donnees/tabIdAllPrestations')(self.doc), \ 'Loan with prestation id %s should be on this page ...' % account._prestation_id for acc in Dict('donnees/tabPrestations')(self.doc): if CleanText(Dict('idPrestation'))(acc) == account._prestation_id: loan = Loan() loan.id = loan.number = account.id loan.label = account.label loan.type = account.type loan.ownership = account.ownership loan.currency = Currency(Dict('capitalRestantDu/devise'))(acc) loan.balance = Eval( lambda x: x / 100, CleanDecimal(Dict('capitalRestantDu/valeur')))(acc) loan.coming = account.coming loan.total_amount = Eval( lambda x: x / 100, CleanDecimal(Dict('montantPret/valeur')))(acc) loan.next_payment_amount = Eval( lambda x: x / 100, CleanDecimal(Dict('montantEcheance/valeur')))(acc) loan.next_payment_date = self.guess_loan_monthly_repayment(acc) loan.duration = Dict('dureeNbMois')(acc) loan.maturity_date = datetime.datetime.strptime( Dict('dateFin')(acc), '%Y%m%d') self.set_parent_account_id(loan, acc) loan._internal_id = account._internal_id loan._prestation_id = account._prestation_id loan._loan_type = account._loan_type return loan