;; ;; members-payments.scm ;; ;; Adding payment information to member records from bank account statement. ;; ;; ISC License ;; ;; Copyright 2023 Brmlab, z.s. ;; Dominik Pantůček ;; ;; Permission to use, copy, modify, and/or distribute this software ;; for any purpose with or without fee is hereby granted, provided ;; that the above copyright notice and this permission notice appear ;; in all copies. ;; ;; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL ;; WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ;; WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE ;; AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR ;; CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS ;; OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, ;; NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ;; CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ;; (declare (unit members-payments)) (module members-payments ( member-payments-total members-payments-process member-balance member-total-balance ) (import scheme (chicken base) (chicken string) (chicken io) (chicken irregex) (chicken sort) (chicken process-context) (chicken pathname) bank-account member-record members-base bank-fio dictionary member-fees period configuration) ;; Exchange rates (define exchange-rates-lookup-table (make-period-lookup-table '(((2010 1) 25)))) ;; Lookup CZK/EUR (define (lookup-eur-rate) (car (lookup-by-period exchange-rates-lookup-table))) ;; Extract probable member-id from transaction (define (transaction-extract-member-id transaction) (if (equal? (bank-transaction-type transaction) "Poplatek") #f (let* ((varsym-id0 (if (*jendasap-compat*) ;; JendaSAP - whole string (bank-transaction-varsym transaction) (string->number (bank-transaction-varsym transaction)))) (varsym-id (or varsym-id0 (let* ((msg (bank-transaction-message transaction)) (ci (substring-index "," msg)) (vs (if ci (substring msg 0 ci) msg))) (string->number vs))))) varsym-id))) ;; Special comparator with JendaSAP hack (define (compare-member-id member-id bank-varsym) (if (*jendasap-compat*) (equal? bank-varsym (number->string member-id)) (eq? member-id bank-varsym))) ;; Merges bank account statement into members payment keys. The ;; payment key will be a list of transactions. (define (members-payments-process-bank mb ba) (let loop ((mb mb) (transactions (bank-account-transactions ba))) (if (null? transactions) mb (let* ((transaction (car transactions)) (varsym-id (transaction-extract-member-id transaction))) (loop (members-base-update mb (lambda (mr) (compare-member-id (member-id mr) varsym-id)) (lambda (mr) (member-record-add-payment mr transaction))) (cdr transactions)))))) ;; Reads the payments (define (load-accounts-list apikeys) (map (compose car string-split) (read-lines (open-input-file apikeys)))) ;; Loads all accounts - it expects .csv files in given directory. (define (load-accounts accounts-list dir) (map (lambda (acc) (bank-fio-parse (make-pathname dir (string-append acc ".csv")))) accounts-list)) ;; If apikeys is not #f, loads the account numbers, loads bank ;; accounts and processes transactions. (define (members-payments-process mb apikeys-file dir) (if apikeys-file (let* ((accounts (load-accounts (load-accounts-list apikeys-file) dir))) (map member-sort-payments (foldl members-payments-process-bank mb accounts))) mb)) ;; Adds all balances - payments are converted to CZK in member-payments-total (define (member-sort-payments mr) (dict-set mr 'payments (sort (dict-ref mr 'payments '()) (lambda (a b) (string