def iter_investment(self): for line in self.document.xpath('//table[contains(@class, "ca-data-table")]/descendant::tr[count(td)>=7]'): for sub in line.xpath('./td[@class="info-produit"]'): sub.drop_tree() cells = line.findall('td') if cells[self.COL_ID].find('div/a') is None: continue inv = Investment() inv.label = unicode(cells[self.COL_ID].find('div/a').text.strip()) inv.code = cells[self.COL_ID].find('div/br').tail.strip().split(u'\xa0')[0] inv.quantity = self.parse_decimal(cells[self.COL_QUANTITY].find('span').text) inv.valuation = self.parse_decimal(cells[self.COL_VALUATION].text) inv.diff = self.parse_decimal(cells[self.COL_DIFF].text_content()) if "%" in cells[self.COL_UNITPRICE].text and "%" in cells[self.COL_UNITVALUE].text: inv.unitvalue = inv.valuation / inv.quantity inv.unitprice = (inv.valuation - inv.diff) / inv.quantity else: inv.unitprice = self.parse_decimal(cells[self.COL_UNITPRICE].text) inv.unitvalue = self.parse_decimal(cells[self.COL_UNITVALUE].text) date = cells[self.COL_UNITVALUE].find('span').text if ':' in date: inv.vdate = ddate.today() else: day, month = map(int, date.split('/', 1)) date_guesser = LinearDateGuesser() inv.vdate = date_guesser.guess_date(day, month) yield inv
def iter_investment(self): cleaner = CleanText().filter for line in self.doc.xpath( '//div[@class="supportTable"]//table/tbody/tr'): tds = line.findall('td') if len(tds) < 4: continue inv = Investment() if self.doc.xpath( '//div[@id="table-evolution-contrat"]//table/tbody/tr[1]/td[1]' ): inv.vdate = Date(dayfirst=True).filter(CleanText().filter( self.doc.xpath( '//div[@id="table-evolution-contrat"]//table/tbody/tr[1]/td[1]' ))) else: inv.vdate = NotAvailable inv.label = cleaner(tds[self.COL_LABEL]) inv.code = cleaner(tds[self.COL_CODE]) inv.valuation = Decimal( FrenchTransaction.clean_amount(cleaner( tds[self.COL_VALUATION]))) inv.portfolio_share = Decimal( FrenchTransaction.clean_amount( cleaner(tds[self.COL_PORTFOLIO_SHARE]))) / 100 yield inv
def iter_investment(self): item = self.doc.xpath(u'//table[@summary="Liste des échéances"]/tfoot/tr/td[@class="tot _c1 d _c1"]')[0] total = CleanDecimal(Regexp(CleanText('.'), '(.*) .*'), default=1, replace_dots=True)(item) item_xpath = u'((//table[@summary="Liste des échéances"])[1]/tbody/tr)[position() < last() and not(contains(./td[1]/@class, "tittot"))]' obj = None for tr in self.doc.xpath(item_xpath): tds = tr.xpath('./td') if len(tds) > 3: if obj is not None: obj.portfolio_share = (obj.valuation / total).quantize(Decimal('.0001')) yield obj obj = Investment() obj.label = CleanText('.')(tds[0]) obj.vdate = date.today() # * En réalité derniere date de valorisation connue obj.unitvalue = CleanDecimal('.', replace_dots=True)(tds[2]) obj.valuation = CleanDecimal('.', replace_dots=True)(tds[5]) obj.quantity = CleanDecimal('.', replace_dots=True)(tds[4]) elif obj is not None: obj.quantity += CleanDecimal('.', replace_dots=True)(tds[1]) obj.valuation += CleanDecimal('.', replace_dots=True)(tds[2]) if obj is not None: obj.portfolio_share = (obj.valuation / total).quantize(Decimal('.0001')) yield obj
def get_transactions_from_detail(self, account): for label, page in account._history_pages: amounts = page.doc.xpath( '//span[contains(text(), "Montant")]/following-sibling::span') if len(amounts) == 3: amounts.pop(0) for table in page.doc.xpath('//table'): t = Transaction() t.date = Date(CleanText( page.doc.xpath( '//span[contains(text(), "Date d\'effet")]/following-sibling::span' )), dayfirst=True)(page) t.label = label t.amount = CleanDecimal(replace_dots=True).filter(amounts[0]) amounts.pop(0) t._is_coming = False t.investments = [] for tr in table.xpath('./tbody/tr'): i = Investment() i.label = CleanText().filter(tr.xpath('./td[1]')) i.vdate = Date(CleanText(tr.xpath('./td[2]')), dayfirst=True)(tr) i.unitvalue = CleanDecimal(replace_dots=True).filter( tr.xpath('./td[3]')) i.quantity = CleanDecimal(replace_dots=True).filter( tr.xpath('./td[4]')) i.valuation = CleanDecimal(replace_dots=True).filter( tr.xpath('./td[5]')) t.investments.append(i) yield t
def get_accounts_list(self): data = {'clang': self.LANG, 'ctcc': self.CTCC, 'login': self.username, 'session': self.sessionId} for dispositif in self.accountsp.open(data=data).get_list(): if dispositif['montantBrutDispositif'] == 0: continue a = Account() a.id = dispositif['codeDispositif'] a.type = Account.TYPE_MARKET a.balance = Decimal(dispositif["montantBrutDispositif"]).quantize(Decimal('.01')) a.label = dispositif['titreDispositif'] a.currency = u"EUR" # Don't find any possbility to get that from configuration. a._investments = [] for fund in dispositif['listeFonds']: if fund['montantValeurEuro'] == 0: continue i = Investment() i.id = i.code = dispositif['codeEntreprise'] + dispositif["codeDispositif"] + fund["codeSupport"] i.label = fund['libelleSupport'] i.unitvalue = Decimal(fund["montantValeur"]).quantize(Decimal('.01')) i.valuation = Decimal(fund["montantValeurEuro"]).quantize(Decimal('.01')) i.quantity = i.valuation / i.unitvalue i.vdate = parse_date(fund['dateValeur'], dayfirst=True) a._investments.append(i) yield a
def get_investments(self, account): for line in self.doc.xpath('//table[@id="tableau_support"]/tbody/tr'): cols = line.findall('td') inv = Investment() inv.id = re.search( 'cdReferentiel=(.*)', cols[self.COL_LABEL].find('a').attrib['href']).group(1) inv.code = re.match('^[A-Z]+[0-9]+(.*)$', inv.id).group(1) inv.label = CleanText(None).filter(cols[self.COL_LABEL]) inv.quantity = self.parse_decimal(cols[self.COL_QUANTITY]) inv.unitprice = self.parse_decimal(cols[self.COL_UNITPRICE]) inv.unitvalue = self.parse_decimal(cols[self.COL_UNITVALUE]) inv.vdate = Date(CleanText(cols[self.COL_DATE], default=NotAvailable), dayfirst=True, default=NotAvailable)(self.doc) inv.valuation = self.parse_decimal(cols[self.COL_VALUATION]) inv.diff = self.parse_decimal(cols[self.COL_PERF]) diff_percent = self.parse_decimal(cols[self.COL_PERF_PERCENT]) inv.diff_percent = diff_percent / 100 if diff_percent else NotAvailable if is_isin_valid(inv.code): inv.code_type = Investment.CODE_TYPE_ISIN yield inv
def get_deposit_investment(self): COL_LABEL = 0 COL_QUANTITY = 3 COL_UNITVALUE = 4 COL_VALUATION = 5 for tr in self.doc.xpath( '//table[@class="datas"]/tr[not(@class="entete")]'): cols = tr.findall('td') inv = Investment() inv.label = CleanText('.')(cols[COL_LABEL].xpath('.//a')[0]) inv.code = CleanText('./text()')(cols[COL_LABEL]) inv.quantity = MyDecimal('.')(cols[COL_QUANTITY]) inv.unitvalue = MyDecimal().filter( CleanText('.')(cols[COL_UNITVALUE]).split()[0]) if inv.unitvalue is not NotAvailable: inv.vdate = Date(dayfirst=True, default=NotAvailable)\ .filter(Regexp(CleanText('.'), '(\d{2})/(\d{2})/(\d{4})', '\\3-\\2-\\1', default=NotAvailable)(cols[COL_UNITVALUE])) or \ Date(dayfirst=True, default=NotAvailable)\ .filter(Regexp(CleanText('//tr[td[span[b[contains(text(), "Estimation du contrat")]]]]/td[2]'), '(\d{2})/(\d{2})/(\d{4})', '\\3-\\2-\\1', default=NotAvailable)(cols[COL_UNITVALUE])) inv.valuation = MyDecimal('.')(cols[COL_VALUATION]) yield inv
def get_transactions_from_detail(self, account): for label, page in account._history_pages: amounts = page.doc.xpath('//span[contains(text(), "Montant")]/following-sibling::span') if len(amounts) == 3: amounts.pop(0) for table in page.doc.xpath('//table'): t = Transaction() t.date = Date(CleanText(page.doc.xpath('//span[contains(text(), "Date d\'effet")]/following-sibling::span')), dayfirst=True)(page) t.label = label t.amount = CleanDecimal(replace_dots=True).filter(amounts[0]) amounts.pop(0) t._is_coming = False t.investments = [] sum_amount = 0 for tr in table.xpath('./tbody/tr'): i = Investment() i.label = CleanText().filter(tr.xpath('./td[1]')) i.vdate = Date(CleanText(tr.xpath('./td[2]')), dayfirst=True)(tr) i.unitvalue = CleanDecimal(replace_dots=True).filter(tr.xpath('./td[3]')) i.quantity = CleanDecimal(replace_dots=True).filter(tr.xpath('./td[4]')) i.valuation = CleanDecimal(replace_dots=True).filter(tr.xpath('./td[5]')) sum_amount += i.valuation t.investments.append(i) if t.label == 'prélèvement': t.amount = sum_amount yield t
def iter_investment(self): item = self.doc.xpath( u'//table[@summary="Liste des échéances"]/tfoot/tr/td[@class="tot _c1 d _c1"]' )[0] total = CleanDecimal(Regexp(CleanText('.'), '(.*) .*'), default=1, replace_dots=True)(item) item_xpath = u'((//table[@summary="Liste des échéances"])[1]/tbody/tr)[position() < last() and not(contains(./td[1]/@class, "tittot"))]' obj = None for tr in self.doc.xpath(item_xpath): tds = tr.xpath('./td') if len(tds) > 3: if obj is not None: obj.portfolio_share = (obj.valuation / total).quantize( Decimal('.0001')) yield obj obj = Investment() obj.label = CleanText('.')(tds[0]) obj.vdate = date.today( ) # * En réalité derniere date de valorisation connue obj.unitvalue = CleanDecimal('.', replace_dots=True)(tds[2]) obj.valuation = CleanDecimal('.', replace_dots=True)(tds[5]) obj.quantity = CleanDecimal('.', replace_dots=True)(tds[4]) elif obj is not None: obj.quantity += CleanDecimal('.', replace_dots=True)(tds[1]) obj.valuation += CleanDecimal('.', replace_dots=True)(tds[2]) if obj is not None: obj.portfolio_share = (obj.valuation / total).quantize( Decimal('.0001')) yield obj
def parse(self, el): i = Investment() i.label = Field('label')(self) i.code = CleanText(TableCell('code'))(self) i.quantity = MyDecimal(TableCell('quantity'))(self) i.valuation = Field('amount')(self) i.vdate = Field('date')(self) self.env['investments'] = [i]
def parse(self, el): i = None if CleanText(TableCell('code'))(self): i = Investment() i.label = Field('label')(self) i.code = unicode(TableCell('code')(self)[0].xpath('./text()[last()]')[0]).strip() i.quantity = MyDecimal(TableCell('quantity'))(self) i.valuation = Field('amount')(self) i.vdate = Field('date')(self) self.env['investments'] = [i] if i else []
def iter_investment(self): cleaner = CleanText().filter for line in self.doc.xpath('//div[@class="supportTable"]//table/tbody/tr'): tds = line.findall('td') if len(tds) < 4: continue inv = Investment() if self.doc.xpath('//div[@id="table-evolution-contrat"]//table/tbody/tr[1]/td[1]'): inv.vdate = Date(dayfirst=True).filter(CleanText().filter( self.doc.xpath('//div[@id="table-evolution-contrat"]//table/tbody/tr[1]/td[1]'))) else: inv.vdate = NotAvailable inv.label = cleaner(tds[self.COL_LABEL]) inv.code = cleaner(tds[self.COL_CODE]) inv.valuation = Decimal(FrenchTransaction.clean_amount( cleaner(tds[self.COL_VALUATION]))) inv.portfolio_share = Decimal(FrenchTransaction.clean_amount( cleaner(tds[self.COL_PORTFOLIO_SHARE]))) / 100 yield inv
def get_investments(self, link): invests = [] doc = self.browser.get_document(self.browser.openurl(link)) for table in doc.xpath('//div[@class="block" and not(@style)]//table'): for tr in table.xpath('./tr')[1:]: tds = tr.xpath('./td') inv = Investment() inv.label = self.parser.tocleanstring(tds[0]) inv.vdate = Date(self.parser.tocleanstring(tds[1])) inv.unitprice = Decimal(tds[2]) inv.quantity = Decimal(tds[3]) inv.valuation = Decimal(tds[4]) invests.append(inv) return invests
def iter_investment(self): for tr in self.doc.xpath(u'//table[@class="boursedetail"]/tr[@class and not(@class="total")]'): inv = Investment() libelle = CleanText('.')(tr.xpath('./td[1]')[0]).split(' ') inv.label, inv.code = self.split_label_code(libelle) inv.quantity = self.parse_decimal(tr.xpath('./td[2]')[0]) inv.unitvalue = self.parse_decimal(tr.xpath('./td[3]')[0]) date = CleanText('.')(tr.xpath('./td[4]')[0]) inv.vdate = Date(dayfirst=True).filter(date) if date and date != '-' else NotAvailable inv.valuation = self.parse_decimal(tr.xpath('./td[5]')[0]) inv.diff_percent = self.parse_decimal(tr.xpath('./td[6]')[0], percentage=True) yield inv
def iter_investment(self): for line in self.document.xpath( '//table[contains(@class, "ca-data-table")]/descendant::tr[count(td)>=7]' ): for sub in line.xpath('./td[@class="info-produit"]'): sub.drop_tree() cells = line.findall('td') if cells[self.COL_ID].find('div/a') is None: continue inv = Investment() inv.label = unicode(cells[self.COL_ID].find('div/a').text.strip()) inv.code = cells[self.COL_ID].find('div/br').tail.strip().split( u'\xa0')[0] inv.quantity = self.parse_decimal( cells[self.COL_QUANTITY].find('span').text) inv.valuation = self.parse_decimal(cells[self.COL_VALUATION].text) inv.diff = self.parse_decimal(cells[self.COL_DIFF].text_content()) if "%" in cells[self.COL_UNITPRICE].text and "%" in cells[ self.COL_UNITVALUE].text: inv.unitvalue = inv.valuation / inv.quantity inv.unitprice = (inv.valuation - inv.diff) / inv.quantity else: inv.unitprice = self.parse_decimal( cells[self.COL_UNITPRICE].text) inv.unitvalue = self.parse_decimal( cells[self.COL_UNITVALUE].text) date = cells[self.COL_UNITVALUE].find('span').text if ':' in date: inv.vdate = ddate.today() else: day, month = map(int, date.split('/', 1)) date_guesser = LinearDateGuesser() inv.vdate = date_guesser.guess_date(day, month) yield inv
def iter_investment(self, account, invs=None): if account.id not in self.investments and invs is not None: self.investments[account.id] = [] for inv in invs: i = Investment() i.label = "%s - %s" % (inv['classification'], inv['description']) i.code = inv['isin'] i.quantity = CleanDecimal().filter(inv['nombreParts']) i.unitprice = CleanDecimal().filter(inv['prixMoyenAchat']) i.unitvalue = CleanDecimal().filter(inv['valeurCotation']) i.valuation = CleanDecimal().filter(inv['montantEuro']) i.vdate = Date().filter(inv['datePosition']) i.diff = CleanDecimal().filter(inv['performanceEuro']) self.investments[account.id].append(i) return self.investments[account.id]
def iter_investment(self, account, invs=None): if account.id not in self.investments and invs is not None: self.investments[account.id] = [] for inv in invs: i = Investment() i.label = "%s - %s" % (inv['classification'], inv['description']) i.code = inv['isin'] i.code_type = Investment.CODE_TYPE_ISIN i.quantity = CleanDecimal().filter(inv['nombreParts']) i.unitprice = CleanDecimal().filter(inv['prixMoyenAchat']) i.unitvalue = CleanDecimal().filter(inv['valeurCotation']) i.valuation = CleanDecimal().filter(inv['montantEuro']) i.vdate = Date().filter(inv['datePosition']) i.diff = CleanDecimal().filter(inv['performanceEuro']) self.investments[account.id].append(i) return self.investments[account.id]
def iter_investment(self): for tr in self.doc.xpath( u'//table[@class="boursedetail"]/tr[@class and not(@class="total")]' ): inv = Investment() libelle = CleanText('.')(tr.xpath('./td[1]')[0]).split(' ') inv.label, inv.code = self.split_label_code(libelle) diff = self.parse_decimal(tr.xpath('./td[6]')[0]) inv.quantity = self.parse_decimal(tr.xpath('./td[2]')[0]) inv.unitvalue = self.parse_decimal(tr.xpath('./td[3]')[0]) date = CleanText('.')(tr.xpath('./td[4]')[0]) inv.vdate = Date(dayfirst=True).filter( date) if date and date != '-' else NotAvailable inv.unitprice = self.calc(inv.unitvalue, diff) inv.valuation = self.parse_decimal(tr.xpath('./td[5]')[0]) inv.diff = self.get_diff(inv.valuation, self.calc(inv.valuation, diff)) yield inv
def get_investments(self, account): for line in self.doc.xpath('//table[@id="tableau_support"]/tbody/tr'): cols = line.findall('td') inv = Investment() inv.id = re.search('cdReferentiel=(.*)', cols[self.COL_LABEL].find('a').attrib['href']).group(1) inv.code = re.match('^[A-Z]+[0-9]+(.*)$', inv.id).group(1) inv.label = CleanText(None).filter(cols[self.COL_LABEL]) inv.quantity = self.parse_decimal(cols[self.COL_QUANTITY]) inv.unitprice = self.parse_decimal(cols[self.COL_UNITPRICE]) inv.unitvalue = self.parse_decimal(cols[self.COL_UNITVALUE]) inv.vdate = Date(CleanText(cols[self.COL_DATE], default=NotAvailable), default=NotAvailable)(self.doc) inv.valuation = self.parse_decimal(cols[self.COL_VALUATION]) inv.diff = self.parse_decimal(cols[self.COL_PERF]) diff_percent = self.parse_decimal(cols[self.COL_PERF_PERCENT]) inv.diff_percent = diff_percent / 100 if diff_percent else NotAvailable if is_isin_valid(inv.code): inv.code_type = Investment.CODE_TYPE_ISIN yield inv
def iter_investment(self, account, invs=None): if account.id not in self.investments and invs is not None: self.investments[account.id] = [] for inv in invs: i = Investment() # If nothing is given to make the label, we use the ISIN instead # We let it crash if the ISIN is not available either. if all([inv['classification'], inv['description']]): i.label = "%s - %s" % (inv['classification'], inv['description']) else: i.label = Coalesce().filter(( inv['classification'], inv['description'], inv['isin'], )) i.code = inv['isin'] if not is_isin_valid(i.code): i.code = NotAvailable i.code_type = NotAvailable if u'Solde Espèces' in i.label: i.code = 'XX-liquidity' else: i.code_type = Investment.CODE_TYPE_ISIN i.quantity = CleanDecimal(default=NotAvailable).filter( inv['nombreParts']) i.unitprice = CleanDecimal(default=NotAvailable).filter( inv['prixMoyenAchat']) i.unitvalue = CleanDecimal(default=NotAvailable).filter( inv['valeurCotation']) i.valuation = CleanDecimal().filter(inv['montantEuro']) # For some invests the vdate returned is None # Consequently we set the default value at NotAvailable i.vdate = Date(default=NotAvailable).filter( inv['datePosition']) i.diff = CleanDecimal(default=NotAvailable).filter( inv['performanceEuro']) self.investments[account.id].append(i) return self.investments[account.id]
def get_deposit_investment(self): COL_LABEL = 0 COL_QUANTITY = 3 COL_UNITVALUE = 4 COL_VALUATION = 5 for tr in self.doc.xpath('//table[@class="datas"]/tr[not(@class="entete")]'): cols = tr.findall('td') inv = Investment() inv.label = CleanText('.')(cols[COL_LABEL].xpath('.//a')[0]) inv.code = CleanText('./text()')(cols[COL_LABEL]) inv.quantity = MyDecimal('.')(cols[COL_QUANTITY]) inv.unitvalue = MyDecimal().filter(CleanText('.')(cols[COL_UNITVALUE]).split()[0]) if inv.unitvalue is not NotAvailable: inv.vdate = Date(dayfirst=True, default=NotAvailable)\ .filter(Regexp(CleanText('.'), '(\d{2})/(\d{2})/(\d{4})', '\\3-\\2-\\1', default=NotAvailable)(cols[COL_UNITVALUE])) or \ Date(dayfirst=True, default=NotAvailable)\ .filter(Regexp(CleanText('//tr[td[span[b[contains(text(), "Estimation du contrat")]]]]/td[2]'), '(\d{2})/(\d{2})/(\d{4})', '\\3-\\2-\\1', default=NotAvailable)(cols[COL_UNITVALUE])) inv.valuation = MyDecimal('.')(cols[COL_VALUATION]) yield inv
def get_accounts_list(self): data = { 'clang': self.LANG, 'ctcc': self.CTCC, 'login': self.username, 'session': self.sessionId } for dispositif in self.accountsp.go(data=data).get_list(): if dispositif['montantBrutDispositif'] == 0: continue a = Account() a.id = dispositif['codeDispositif'] a.type = Account.TYPE_MARKET a.balance = Decimal(dispositif["montantBrutDispositif"]).quantize( Decimal('.01')) a.label = dispositif['titreDispositif'] a.currency = u"EUR" # Don't find any possbility to get that from configuration. a._investments = [] for fund in dispositif['listeFonds']: if fund['montantValeurEuro'] == 0: continue i = Investment() i.id = i.code = dispositif['codeEntreprise'] + dispositif[ "codeDispositif"] + fund["codeSupport"] i.label = fund['libelleSupport'] i.unitvalue = Decimal(fund["montantValeur"]).quantize( Decimal('.01')) i.valuation = Decimal(fund["montantValeurEuro"]).quantize( Decimal('.01')) i.quantity = i.valuation / i.unitvalue i.vdate = parse_date(fund['dateValeur'], dayfirst=True) a._investments.append(i) yield a
def get_history(self): tr = None for page in self.doc: for n, row in enumerate(page): if len(row) != 7: continue label = ' '.join(row[self.COL_LABEL]) if row[self.COL_TR_AMOUNT]: if tr is not None: if n == 0 and label == tr.label: self.logger.debug('%r seems to continue on next page', tr) continue yield tr tr = None if not label: # this pdf is really cryptic... # we assume blue rows are a new transaction # but if no label, it doesn't appear in the website json continue tr = Transaction() tr.type = Transaction.TYPE_BANK tr.raw = tr.label = label tr.amount = CleanDecimal(replace_dots=True).filter(''.join(row[self.COL_TR_AMOUNT])) elif not row[self.COL_DATE]: if not tr: # ignore transactions with the empty label, see above continue if label == 'Investissement': tr.amount = abs(tr.amount) elif label == 'Désinvestissement': tr.amount = -abs(tr.amount) else: assert False, 'unhandled line %s' % label assert not any(len(cell) for cell in row[self.COL_LABEL+1:]), 'there should be only the label' else: if not tr: continue inv = Investment() inv.label = label inv.valuation = CleanDecimal(replace_dots=True).filter(row[self.COL_VALUATION]) if tr.amount < 0: inv.valuation = -inv.valuation inv.vdate = Date(dayfirst=True).filter(''.join(row[self.COL_DATE])) tr.date = inv.vdate inv.quantity = CleanDecimal(replace_dots=True, default=NotAvailable).filter(''.join(row[self.COL_QUANTITY])) if inv.quantity and tr.amount < 0: inv.quantity = -inv.quantity inv.unitvalue = CleanDecimal(replace_dots=True, default=NotAvailable).filter(''.join(row[self.COL_UNITVALUE])) tr.investments.append(inv) if tr: yield tr
def get_history(self): sign = 0 tr = None for page in self.doc: first_in_page = True for row in page: if len(row) != 7: first_in_page = False continue label = ' '.join(row[0]) if label == 'Investissement': sign = 1 first_in_page = False continue elif label == u'Désinvestissement': sign = -1 first_in_page = False continue global_amount = ''.join(row[2]) if global_amount: if first_in_page and tr and tr.raw == label: # this must be the continuation of the previous page first_in_page = False continue first_in_page = False if tr is not None: # flush use_invest_date(tr) yield tr # amount is "brut", unlike invest amounts ("net")... sign = 0 tr = None if not label: # this pdf is really cryptic... # we assume blue rows are a new transaction # but if no label, it doesn't appear in the website json continue tr = Transaction() # the amount is always positive... do not set it to avoid mistakes tr.type = Transaction.TYPE_BANK tr.label = tr.raw = label tr.investments = [] continue first_in_page = False date = ''.join(row[1]) assert date if tr is None: # ignore transactions with the empty label, see above continue assert sign inv = Investment() inv.label = label inv.vdate = Date(dayfirst=True).filter(date) inv.quantity = CleanDecimal(replace_dots=True, default=NotAvailable).filter( ''.join(row[5])) if inv.quantity is not NotAvailable: inv.quantity *= sign inv.unitvalue = CleanDecimal(replace_dots=True, default=NotAvailable).filter( ''.join(row[4])) inv.valuation = CleanDecimal(replace_dots=True, default=NotAvailable).filter( ''.join(row[3])) if inv.valuation is not NotAvailable: inv.valuation *= sign tr.investments.append(inv) # flush if tr is not None: use_invest_date(tr) yield tr
def get_history(self): tr = None for page in self.doc: for n, row in enumerate(page): if len(row) != 7: continue label = ' '.join(row[self.COL_LABEL]) if row[self.COL_TR_AMOUNT]: if tr is not None: if n == 0 and label == tr.label: self.logger.debug( '%r seems to continue on next page', tr) continue yield tr tr = None if not label: # this pdf is really cryptic... # we assume blue rows are a new transaction # but if no label, it doesn't appear in the website json continue tr = Transaction() tr.type = Transaction.TYPE_BANK tr.raw = tr.label = label tr.amount = CleanDecimal(replace_dots=True).filter(''.join( row[self.COL_TR_AMOUNT])) elif not row[self.COL_DATE]: if not tr: # ignore transactions with the empty label, see above continue if label == 'Investissement': tr.amount = abs(tr.amount) elif label == 'Désinvestissement': tr.amount = -abs(tr.amount) else: assert False, 'unhandled line %s' % label assert not any( len(cell) for cell in row[self.COL_LABEL + 1:]), 'there should be only the label' else: if not tr: continue inv = Investment() inv.label = label inv.valuation = CleanDecimal(replace_dots=True).filter( row[self.COL_VALUATION]) if tr.amount < 0: inv.valuation = -inv.valuation inv.vdate = Date(dayfirst=True).filter(''.join( row[self.COL_DATE])) tr.date = inv.vdate inv.quantity = CleanDecimal( replace_dots=True, default=NotAvailable).filter( ''.join(row[self.COL_QUANTITY])) if inv.quantity and tr.amount < 0: inv.quantity = -inv.quantity inv.unitvalue = CleanDecimal( replace_dots=True, default=NotAvailable).filter( ''.join(row[self.COL_UNITVALUE])) tr.investments.append(inv) if tr: yield tr