diff --git a/modules/boursorama/browser.py b/modules/boursorama/browser.py index 2ad2b305ce519ea635671aaa025df3f965ca3e4c..ce69ff9c44e2573c75c3b0b1f5d161597af9fb05 100644 --- a/modules/boursorama/browser.py +++ b/modules/boursorama/browser.py @@ -35,7 +35,7 @@ Account, AccountNotFound, TransferError, TransferInvalidAmount, TransferInvalidEmitter, TransferInvalidLabel, TransferInvalidRecipient, AddRecipientStep, Rate, TransferBankError, AccountOwnership, RecipientNotFound, - AddRecipientTimeout, TransferDateType, Emitter, + AddRecipientTimeout, TransferDateType, Emitter, TransactionType, ) from weboob.capabilities.base import empty, find_object from weboob.capabilities.contact import Advisor @@ -51,7 +51,7 @@ TransferAccounts, TransferRecipients, TransferCharac, TransferConfirm, TransferSent, AddRecipientPage, StatusPage, CardHistoryPage, CardCalendarPage, CurrencyListPage, CurrencyConvertPage, AccountsErrorPage, NoAccountPage, TransferMainPage, PasswordPage, NewTransferRecipients, - NewTransferAccounts, + NewTransferAccounts, CardSumDetailPage, ) from .transfer_pages import TransferListPage, TransferInfoPage @@ -96,6 +96,7 @@ class BoursoramaBrowser(RetryLoginBrowser, TwoFactorBrowser): budget_transactions = URL('/budget/compte/(?P.*)/mouvements.*', HistoryPage) other_transactions = URL('/compte/cav/(?P.*)/mouvements.*', HistoryPage) saving_transactions = URL('/compte/epargne/csl/(?P.*)/mouvements.*', HistoryPage) + card_summary_detail_transactions = URL(r'/contre-valeurs-operation/.*', CardSumDetailPage) saving_pep = URL('/compte/epargne/pep', PEPPage) incident = URL('/compte/cav/(?P.*)/mes-incidents.*', IncidentPage) @@ -456,6 +457,25 @@ def get_regular_transactions(self, account, coming): for transaction in self.page.iter_history(): yield transaction + def get_html_past_card_transactions(self, account): + """ Get card transactions from parent account page """ + + self.otp_location('%s/mouvements' % account.parent.url.rstrip('/')) + for tr in self.page.iter_history(is_card=False): + # get card summaries + if ( + tr.type == TransactionType.CARD_SUMMARY + and account.number in tr.label # in case of several cards per parent account + ): + tr.amount = - tr.amount + yield tr + + # for each summaries, get detailed transactions + self.location(tr._card_sum_detail_link) + for detail_tr in self.page.iter_history(): + detail_tr.date = tr.date + yield detail_tr + # Note: Checking accounts have a 'Mes prélèvements à venir' tab, # but these transactions have no date anymore so we ignore them. @@ -497,8 +517,8 @@ def get_card_transactions(self, account, coming): if self.get_card_transaction(coming, tr): yield tr - for tr in self.page.iter_history(is_card=True): - if self.get_card_transaction(coming, tr): + if not coming: + for tr in self.get_html_past_card_transactions(account): yield tr def get_invest_transactions(self, account, coming): diff --git a/modules/boursorama/pages.py b/modules/boursorama/pages.py index eb32c967cac7738ce13b5b2cb05b4630de55020c..034588d09d7fe3d020cf04a530d1c0708b67cdeb 100644 --- a/modules/boursorama/pages.py +++ b/modules/boursorama/pages.py @@ -700,6 +700,11 @@ def obj_date(self): return date + def obj__card_sum_detail_link(self): + if Field('type')(self) == Transaction.TYPE_CARD_SUMMARY: + return Attr('.//div', 'data-action-url')(self.el) + return NotAvailable + def validate(self, obj): # TYPE_DEFERRED_CARD transactions are already present in the card history # so we only return TYPE_DEFERRED_CARD for the coming: @@ -740,6 +745,25 @@ def get_calendar_link(self): return Link('//a[contains(text(), "calendrier")]')(self.doc) +class CardSumDetailPage(LoggedPage, HTMLPage): + @otp_pagination + @method + class iter_history(ListElement): + item_xpath = '//li[contains(@class, "deffered")]' # this quality website's got all-you-can-eat typos! + + class item(ItemElement): + klass = Transaction + + obj_amount = CleanDecimal.French('.//div[has-class("list-operation-item__amount")]') + obj_raw = Transaction.Raw(CleanText('.//div[has-class("list-operation-item__label-name")]')) + obj_id = Attr('.', 'data-id') + obj__is_coming = False + + def obj_type(self): + # to override CARD typing done by obj.raw + return Transaction.TYPE_DEFERRED_CARD + + class CardHistoryPage(LoggedPage, CsvPage): ENCODING = 'latin-1' FMTPARAMS = {'delimiter': str(';')}