#!/usr/bin/env python3 from os.path import basename from beangulp import Ingest from beangulp import mimetypes from beangulp.importers import csvbase from beangulp.testing import main from beancount.core.data import Transaction, Posting from deelnemers import deelnemers participants = deelnemers() class RaboAmount(csvbase.Amount): def __init__(self, col): super().__init__(col, subs={"\\+": "", ",": "."}) class Importer(csvbase.Importer): encoding = "iso-8859-15" date = csvbase.Date("Datum", "%Y-%m-%d") payee = csvbase.Columns("Naam tegenpartij", "Tegenrekening IBAN/BBAN", sep="; ") narration = csvbase.Columns( "Omschrijving-1", "Omschrijving-2", "Omschrijving-3", sep=" " ) amount = RaboAmount("Bedrag") balance = RaboAmount("Saldo na trn") def identify(self, filepath): mimetype, encoding = mimetypes.guess_type(filepath) if mimetype != "text/csv": return False with open(filepath, "rb") as fd: head = fd.read(1024) return head.startswith( b'"IBAN/BBAN","Munt","BIC","Volgnr","Datum","Rentedatum","Bedrag","Saldo na trn","Tegenrekening IBAN/BBAN"' ) def filename(self, filepath): return "rabobank." + basename(filepath) def guess_contra(entry): posting = entry.postings[0] def have_keyword(*keywords): l_description = entry.narration.lower() return any(kw in l_description for kw in keywords) if entry.payee == "Kosten" or ( entry.payee == "Rabobank; NL89RABO0111741386" and entry.narration.startswith("Kosten") ): return "Uitgaven:Bankkosten" if entry.payee == "Stichting Bitlair; NL09RABO3159222187": return "Activa:Spaarrekening" if ( entry.payee == "Symbiose Beheer B.V.; NL84ABNA0630587221" and posting.units.number < -3400 ): return "Uitgaven:Huur" if ( entry.payee == "Stichting EventInfra; NL59RABO0312574800" and entry.narration == "Verhuur opslagruimte " ): return "Activa:Debiteuren:EventInfra" if ( entry.payee == "JONGE ONDERZOEKERS AMERS; NL30ABNA0119774844" and 590 < posting.units.number < 700 ): return "Activa:Debiteuren:DJO" if ( entry.payee == "Furthermore B.V.; NL06REVO8135470894" and 600 < posting.units.number < 800 ): return "Activa:Debiteuren:UnicornDept" if entry.payee == "Gebr. Schurman GmbH; DE68441600141300702500": return "Uitgaven:Bar:Mate" if entry.payee == "Sligro ZB 5037": return "Uitgaven:Bar:Snacks" if entry.payee == "STATIEGELD NEDERLAND; NL59ABNA0100073913": return "Uitgaven:Bar" if entry.narration.startswith("Decla") and posting.units.number < 0: return "Passiva:Declaraties" if have_keyword( "deposit", "revbank", " bar ", "kassa vulling", "desposit", "(RB QR)", "rev-bank", " bank", "elena transfer", "barsaldo", ): return "Passiva:RevBank" if entry.payee == "Stichting Mollie Payments; NL70CITI2032329018": return "Passiva:RevBank" for p in participants: if ( hasattr(p, "maandbedrag") and hasattr(p, "ibans") and p.maandbedrag == posting.units.number and any(iban in entry.payee for iban in p.ibans) ): return f"Activa:Debiteuren:Deelnemers:{p.nickname.title().replace('_', '')}" return None def classify_hook(extracted_entries_list, ledger_entries): def _classify(entry): if not isinstance(entry, Transaction): return entry contra = guess_contra(entry) posting = entry.postings[0] entry.postings.append( Posting( contra or "Inkomsten:TODO", -posting.units, posting.cost, posting.price, None if contra else "!", None, ) ) return entry return [ (filename, [_classify(entry) for entry in entries], account, importer) for filename, entries, account, importer in extracted_entries_list ] if __name__ == "__main__": importers = [Importer("Activa:Betaalrekening", "EUR")] hooks = [classify_hook] main = Ingest(importers, hooks) main()