From 00972f52311b3641c0bd4474334ff846501a3019 Mon Sep 17 00:00:00 2001 From: Dave Peticolas Date: Thu, 8 Jun 2000 19:51:16 +0000 Subject: [PATCH] Robert Merkel's patch to average-balance.scm. Bill Gribble's qif import patch. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@2443 57a11ea4-9604-0410-9ed3-97b8803252fd --- ChangeLog | 5 + po/gnucash.pot | 8 +- src/gnome/dialog-qif-import.c | 6 +- src/scm/qif-import/qif-dialog-utils.scm | 146 +++++++------- src/scm/qif-import/qif-file.scm | 25 ++- src/scm/qif-import/qif-guess-map.scm | 55 ++++-- src/scm/qif-import/qif-objects.scm | 62 +++--- src/scm/qif-import/qif-parse.scm | 25 ++- src/scm/qif-import/qif-to-gnc.scm | 241 +++++++++++++++--------- src/scm/report/average-balance.scm | 16 +- 10 files changed, 345 insertions(+), 244 deletions(-) diff --git a/ChangeLog b/ChangeLog index aba64b2bad..6de82ac27c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2000-06-08 Robert Graham Merkel + + * src/scm/report/average-balance.scm (average-balance-renderer): + added a condition to catch incorrectly entered dates without crashing. + 2000-06-07 Dave Peticolas * src/engine/Query.c: fixed a "dave is an idiot" bug in cropping diff --git a/po/gnucash.pot b/po/gnucash.pot index 261a8ece99..b4e15058d4 100644 --- a/po/gnucash.pot +++ b/po/gnucash.pot @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2000-06-04 17:16-0700\n" +"POT-Creation-Date: 2000-06-08 12:48-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -2977,8 +2977,8 @@ msgstr "" msgid "You must specify a currency." msgstr "" -#: src/gnome/dialog-qif-import.c:270 src/gnome/dialog-qif-import.c:619 -#: src/gnome/dialog-qif-import.c:676 src/gnome/dialog-qif-import.c:774 +#: src/gnome/dialog-qif-import.c:270 src/gnome/dialog-qif-import.c:622 +#: src/gnome/dialog-qif-import.c:679 src/gnome/dialog-qif-import.c:777 msgid "QIF File scheme code not loaded properly." msgstr "" @@ -2986,7 +2986,7 @@ msgstr "" msgid "QIF File already loaded. Reload with current settings?" msgstr "" -#: src/gnome/dialog-qif-import.c:704 src/gnome/dialog-qif-import.c:802 +#: src/gnome/dialog-qif-import.c:707 src/gnome/dialog-qif-import.c:804 msgid "Something is very wrong with QIF Importing." msgstr "" diff --git a/src/gnome/dialog-qif-import.c b/src/gnome/dialog-qif-import.c index 1263ccdf44..ba61573f5f 100644 --- a/src/gnome/dialog-qif-import.c +++ b/src/gnome/dialog-qif-import.c @@ -364,10 +364,11 @@ gnc_ui_qif_import_load_file_cb(GtkButton * button, gpointer user_data) { scm_protect_object(wind->imported_files); gettimeofday(&end, NULL); +#if 0 printf("QIF file load took %f ms total.\n", 1000.0*(end.tv_sec - start.tv_sec) + .001*(end.tv_usec - start.tv_usec)); - +#endif gettimeofday(&start, NULL); /* now update the Accounts and Categories pages in the notebook */ @@ -377,9 +378,11 @@ gnc_ui_qif_import_load_file_cb(GtkButton * button, gpointer user_data) { gettimeofday(&end, NULL); +#if 0 printf("QIF Category/account tab update took %f ms.\n", 1000.0*(end.tv_sec - start.tv_sec) + .001*(end.tv_usec - start.tv_usec)); +#endif gettimeofday(&end, NULL); @@ -785,7 +788,6 @@ update_categories_page(QIFImportWindow * wind) { hash_data); } - /* now get the list of strings to display in the clist widget */ /* gnc_unprotect_object(wind->cat_display_info); */ display_info = gh_call2(make_category_display, diff --git a/src/scm/qif-import/qif-dialog-utils.scm b/src/scm/qif-import/qif-dialog-utils.scm index 68621034cd..b1106465e1 100644 --- a/src/scm/qif-import/qif-dialog-utils.scm +++ b/src/scm/qif-import/qif-dialog-utils.scm @@ -35,13 +35,12 @@ (retval '())) ;; we want to make two passes here. The first pass picks the - ;; explicit Account descriptions and implicit "this" description - ;; out of each file. These are the best sources of info because - ;; we will have types and so on for them. The second pass picks - ;; out account-style L fields and investment security names from - ;; the transactions. Hopefully we'll have most of the accounts - ;; already located by that point. Otherwise, we have to guess - ;; them. + ;; explicit Account descriptions out of each file. These are the + ;; best sources of info because we will have types and so on for + ;; them. The second pass picks out account-style L fields and + ;; investment security names from the transactions. Hopefully + ;; we'll have most of the accounts already located by that point. + ;; Otherwise, we have to guess them. ;; guess-acct returns a list that's ;; (qif-name gnc-name gnc-type new-acct?) @@ -61,28 +60,7 @@ (list (qif-acct:type acct)) gnc-acct-info) (list 0 acct))))) - (qif-file:accounts file)) - - ;; then make an implicit account entry for the file - (if (and (qif-file:default-account file) - (qif-file:default-account-type file)) -; (not (eq? (qif-file:account-type file) GNC-STOCK-TYPE))) - (let ((entry (hash-ref acct-hash (qif-file:default-account file)))) - (if entry - ;; increment the xtn count in place - (list-set! entry 4 - (+ (list-ref entry 4) - (qif-file:default-acct-xtns file))) - ;; make a new hash table entry for the account - ;; make it a Bank account by default. - (hash-set! - acct-hash (qif-file:default-account file) - (append (qif-import:guess-acct - (qif-file:default-account file) - (list GNC-BANK-TYPE - GNC-CCARD-TYPE) - gnc-acct-info) - (list 0 #f))))))) + (qif-file:accounts file))) qif-files) ;; now make the second pass through the files, looking at the @@ -101,32 +79,30 @@ (qif-account-types #f) (entry #f)) - (if (string? action) - (set! action-sym (qif-parse:parse-action-field action))) - - (if (and stock-acct action-sym) + (if (and stock-acct (string? action)) ;; stock transactions are weird. there can be several ;; accounts associated with stock xtns: the security, ;; the brokerage, a dividend account, a long-term CG ;; account, a short-term CG account, an interest ;; account. Make sure all of the right ones get stuck ;; in the map. - (begin + (begin + (set! action-sym (qif-parse:parse-action-field action)) ;; first: figure out what the near-end account is. ;; it's generally the security account, but could be ;; an interest, dividend, or CG account. (case action-sym - ((buy buyx sell sellx reinvdiv reinvsh reinvsg - reinvlg shrsin) + ((buy buyx sell sellx reinvint reinvdiv reinvsh reinvsg + reinvlg shrsin stksplit) (set! qif-account stock-acct) (set! qif-account-types (list GNC-STOCK-TYPE GNC-MUTUAL-TYPE))) - ((div cgshort cglong intinc) + ((div cgshort cglong intinc miscinc miscexp xin xout) (set! qif-account from-acct) (set! qif-account-types (list GNC-BANK-TYPE GNC-CCARD-TYPE))) - ((divx cgshortx cglongx intincx) + ((divx cgshortx cglongx intincx miscincx miscexpx) (set! qif-account (qif-split:category (car (qif-xtn:splits xtn)))) @@ -137,73 +113,99 @@ (display action-sym) (newline))) ;; now reference the near-end account - (set! entry (hash-ref acct-hash qif-account)) - (if entry - (list-set! entry 4 - (+ 1 (list-ref entry 4))) - (hash-set! acct-hash qif-account - (append (qif-import:guess-acct - qif-account qif-account-types - gnc-acct-info) - (list 1 xtn)))) + (if qif-account + (begin + (set! entry (hash-ref acct-hash qif-account)) + (if entry + (list-set! entry 4 + (+ 1 (list-ref entry 4))) + (hash-set! acct-hash qif-account + (append (qif-import:guess-acct + qif-account qif-account-types + gnc-acct-info) + (list 1 xtn)))))) ;; now figure out the other end of the transaction. ;; the far end will be the brokerage for buy, sell, ;; etc, or the "L"-referenced account for buyx, ;; sellx, etc, or an equity account for ShrsIn + ;; miscintx and miscexpx are very, very "special" + ;; cases which I don't quite handle correctly yet. + (set! qif-account #f) (case action-sym ((buy sell) (set! qif-account from-acct) (set! qif-account-types (list GNC-BANK-TYPE GNC-CCARD-TYPE))) - ((buyx sellx) + ((buyx sellx xin xout) (set! qif-account (qif-split:category (car (qif-xtn:splits xtn)))) (set! qif-account-types (list GNC-BANK-TYPE GNC-CCARD-TYPE))) + ((stksplit) + (set! qif-account stock-acct) + (set! qif-account-types (list GNC-STOCK-TYPE + GNC-MUTUAL-TYPE))) ((cgshort cgshortx reinvsg reinvsh) (set! qif-account (default-cgshort-acct stock-acct)) (set! qif-account-types (list GNC-INCOME-TYPE))) + ((miscincx) + (set! qif-account + (qif-split:category + (car (qif-xtn:splits xtn)))) + (set! qif-account-types (list GNC-INCOME-TYPE))) + + ((miscexpx) + (set! qif-account + (qif-split:category + (car (qif-xtn:splits xtn)))) + (set! qif-account-types (list GNC-EXPENSE-TYPE))) + ((cglong cglongx reinvlg) (set! qif-account (default-cglong-acct stock-acct)) (set! qif-account-types (list GNC-INCOME-TYPE))) + ((intinc intincx reinvint) (set! qif-account (default-interest-acct stock-acct)) (set! qif-account-types (list GNC-INCOME-TYPE))) + ((div divx reinvdiv) (set! qif-account (default-dividend-acct stock-acct)) (set! qif-account-types (list GNC-INCOME-TYPE))) + ((shrsin) (set! qif-account (default-equity-account)) (set! qif-account-types (list GNC-EQUITY-TYPE))) + + ((miscinc miscexp) + ;; these reference a category on the other end + (set! qif-account #f)) + (else (display "HEY! HEY! action-sym = ") (display action-sym) (newline))) ;; now reference the far-end account - (set! entry (hash-ref acct-hash qif-account)) - (if entry - (list-set! entry 4 - (+ 1 (list-ref entry 4))) - (hash-set! acct-hash qif-account - (append (qif-import:guess-acct - qif-account qif-account-types - gnc-acct-info) - (list 1 xtn)))) - - ;; if there's a commission, it will reference - ;; a separate account on the far end. - - ) + (if qif-account + (begin + (set! entry (hash-ref acct-hash qif-account)) + (if entry + (list-set! entry 4 + (+ 1 (list-ref entry 4))) + (hash-set! acct-hash qif-account + (append (qif-import:guess-acct + qif-account qif-account-types + gnc-acct-info) + (list 1 xtn))))))) ;; non-stock transactions. these are a bit easier. ;; the near-end account (from) is always in the @@ -259,17 +261,17 @@ (vector->list acct-hash)) (list-set! gnc-acct-info 1 acct-hash) - + ;; sort by number of transactions with that account so the ;; most important are at the top - (set! retval (sort retval - (lambda (a b) - (or - (> (list-ref a 4) (list-ref b 4)) - (and - (eq? (list-ref a 4) (list-ref b 4)) - (string (list-ref a 4) (list-ref b 4)) + (and + (eq? (list-ref a 4) (list-ref b 4)) + (stringlist cat-hash)) (list-set! gnc-acct-info 2 cat-hash) - + ;; sort by number of transactions with that account so the ;; most important are at the top (set! retval (sort retval diff --git a/src/scm/qif-import/qif-file.scm b/src/scm/qif-import/qif-file.scm index 0ad60668c8..421e49d7e1 100644 --- a/src/scm/qif-import/qif-file.scm +++ b/src/scm/qif-import/qif-file.scm @@ -178,6 +178,10 @@ self current-xtn qstate-type) (set! first-xtn #f))) + (if (and (eq? qstate-type 'type:invst) + (not (qif-xtn:security-name current-xtn))) + (qif-xtn:set-security-name! current-xtn "")) + (if current-account-name (qif-xtn:set-from-acct! current-xtn current-account-name) @@ -201,6 +205,10 @@ ((#\D) (qif-class:set-description! current-xtn value)) + ;; R : tax copy designator (ignored for now) + ((#\R) + #t) + ;; end-of-record ((#\^) (qif-file:add-class! self current-xtn) @@ -264,7 +272,7 @@ ;; R : what is the tax rate (from some table? ;; seems to be an integer) ((#\R) - (qif-cat:set-tax-rate! current-xtn value)) + (qif-cat:set-tax-class! current-xtn value)) ;; B : budget amount. not really supported. ((#\B) @@ -305,13 +313,6 @@ ;; now reverse the transaction list so xtns are in the same order that ;; they were in the file. This is important in a few cases. (qif-file:set-xtns! self (reverse (qif-file:xtns self))) - - (set! end-time (gettimeofday)) - (display "QIF file read took ") - (display (+ (* 1000 (- (car end-time) (car start-time))) - (* .001 (- (cdr end-time) (cdr start-time))))) - (newline) - return-val)) @@ -393,7 +394,7 @@ (and ;; fields of categories. (check-and-parse-field - qif-cat:tax-rate qif-cat:set-tax-rate! + qif-cat:tax-class qif-cat:set-tax-class! qif-parse:check-number-format '(decimal comma) qif-parse:parse-number/format (qif-file:cats self) set-error) @@ -465,11 +466,7 @@ #t)) (set! end-time (gettimeofday)) - (display "QIF string parsing took ") - (display (+ (* 1000 (- (car end-time) (car start-time))) - (* .001 (- (cdr end-time) (cdr start-time))))) - (newline) - + (cond ((list? error) (list all-ok (errlist-to-string error))) (error diff --git a/src/scm/qif-import/qif-guess-map.scm b/src/scm/qif-import/qif-guess-map.scm index 2dbdbf5c88..2b143e9937 100644 --- a/src/scm/qif-import/qif-guess-map.scm +++ b/src/scm/qif-import/qif-guess-map.scm @@ -71,13 +71,15 @@ ;; (shortname fullname account) format. ;; - a hash of QIF account name to gnucash account info ;; - a hash of QIF category to gnucash account info - (let ((pref-filename (build-path (getenv "HOME") - ".gnucash" "qif-accounts-map")) + (let* ((pref-dir (build-path (getenv "HOME") ".gnucash")) + (pref-filename (build-path pref-dir "qif-accounts-map")) (results '())) ;; first, read the account map and category map from the ;; user's qif-accounts-map file. - (if (access? pref-filename R_OK) + (if (and (access? pref-dir F_OK) + (access? pref-dir X_OK) + (access? pref-filename R_OK)) (with-input-from-file pref-filename (lambda () (let ((qif-account-hash #f) @@ -98,9 +100,6 @@ (let* ((all-accounts (gnc:get-current-group)) (all-account-info (extract-all-account-info all-accounts #f))) (set! results (cons all-account-info results))) - -; (display " ** load prefs **")(newline) -; (write results)(newline) results)) @@ -115,10 +114,11 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (qif-import:save-map-prefs prefs) - (let ((pref-filename (build-path (getenv "HOME") - ".gnucash" "qif-accounts-map")) - (acct-map (cadr prefs)) - (cat-map (caddr prefs))) + (let* ((pref-dir (build-path (getenv "HOME") ".gnucash")) + (pref-filename (build-path pref-dir "qif-accounts-map")) + (acct-map (cadr prefs)) + (cat-map (caddr prefs)) + (save-ok #f)) (for-each (lambda (bin) (for-each @@ -135,17 +135,32 @@ (list-set! (cdr hashpair) 5 #f)) bin)) (vector->list cat-map)) - - (with-output-to-file pref-filename - (lambda () - (display ";;; qif-accounts-map") (newline) - (display ";;; automatically generated by GNUcash. DO NOT EDIT") - (newline) - (display ";;; map from QIF accounts to GNC accounts") (newline) - (write acct-map) (newline) - (display ";;; map from QIF categories to GNC accounts") (newline) - (write cat-map) (newline))))) + ;; test for the existence of the directory and create it + ;; if necessary + + ;; does the file exist? if not, create it; in either case, + ;; make sure it's a directory and we have write and execute + ;; permission. + (let ((perm (access? pref-dir F_OK))) + (if (not perm) + (mkdir pref-dir)) + (let ((stats (stat pref-dir))) + (if (and (eq? (stat:type stats) 'directory) + (access? pref-dir X_OK) + (access? pref-dir W_OK)) + (set! save-ok #t)))) + + (if save-ok + (with-output-to-file pref-filename + (lambda () + (display ";;; qif-accounts-map") (newline) + (display ";;; automatically generated by GNUcash. DO NOT EDIT") + (newline) + (display ";;; map from QIF accounts to GNC accounts") (newline) + (write acct-map) (newline) + (display ";;; map from QIF categories to GNC accounts") (newline) + (write cat-map) (newline)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/src/scm/qif-import/qif-objects.scm b/src/scm/qif-import/qif-objects.scm index 20571e0764..34a82d5962 100644 --- a/src/scm/qif-import/qif-objects.scm +++ b/src/scm/qif-import/qif-objects.scm @@ -25,7 +25,6 @@ '(path ;; where file was loaded default-account ;; guessed or specified default account name default-account-type ;; either GNC-BANK-TYPE or GNC-STOCK-TYPE - default-acct-xtns y2k-threshold currency ;; this is a string.. no checking accts-mentioned @@ -68,12 +67,6 @@ (define qif-file:set-currency! (simple-obj-setter 'currency)) -(define qif-file:default-acct-xtns - (simple-obj-getter 'default-acct-xtns)) - -(define qif-file:set-default-acct-xtns! - (simple-obj-setter 'default-acct-xtns)) - (define qif-file:accts-mentioned (simple-obj-getter 'accts-mentioned)) @@ -115,7 +108,6 @@ (qif-file:set-default-account! self account) (qif-file:set-currency! self currency) (qif-file:set-y2k-threshold! self 50) - (qif-file:set-default-acct-xtns! self 0) (qif-file:set-accts-mentioned! self '()) (qif-file:set-xtns! self '()) (qif-file:set-accounts! self '()) @@ -353,7 +345,9 @@ (simple-obj-setter 'budget)) (define (make-qif-acct) - (make-simple-obj )) + (let ((retval (make-simple-obj ))) + (qif-acct:set-type! retval "Bank") + retval)) (define qif-acct? (record-predicate )) @@ -408,7 +402,7 @@ (define (make-simple-class 'qif-cat - '(name description taxable expense-cat income-cat tax-rate budget-amt))) + '(name description taxable expense-cat income-cat tax-class budget-amt))) (define qif-cat:name (simple-obj-getter 'name)) @@ -440,11 +434,11 @@ (define qif-cat:set-income-cat! (simple-obj-setter 'income-cat)) -(define qif-cat:tax-rate - (simple-obj-getter 'tax-rate)) +(define qif-cat:tax-class + (simple-obj-getter 'tax-class)) -(define qif-cat:set-tax-rate! - (simple-obj-setter 'tax-rate)) +(define qif-cat:set-tax-class! + (simple-obj-setter 'tax-class)) (define qif-cat:budget-amt (simple-obj-getter 'budget-amt)) @@ -462,29 +456,23 @@ (simple-obj-print self)) (define (qif-file:add-xtn! self xtn) - (let ((from (qif-xtn:from-acct xtn))) - (if from - (if (not (member from (qif-file:accts-mentioned self))) - (qif-file:set-accts-mentioned! - self (cons from (qif-file:accts-mentioned self)))) - (let ((defs (qif-file:default-acct-xtns self))) - (qif-file:set-default-acct-xtns! self (+ 1 defs)) - (if (and (eq? 0 defs) - (not (member (qif-file:default-account self) - (qif-file:accts-mentioned self)))) - (qif-file:set-accts-mentioned! - self (cons (qif-file:default-account self) - (qif-file:accts-mentioned self))))))) - (for-each - (lambda (split) - (if (and (qif-split:category-is-account? split) - (not (member (qif-split:category split) - (qif-file:accts-mentioned self)))) - (qif-file:set-accts-mentioned! - self (cons (qif-split:category split) - (qif-file:accts-mentioned self))))) - (qif-xtn:splits xtn)) - + (let ((splits (qif-xtn:splits xtn))) + (for-each + (lambda (split) + (let ((accts (qif-split:accounts-affected split xtn)) + (mentioned (qif-file:accts-mentioned self))) + ;; add the near account to the mentioned-list + ;; but only for the first split + (if (and (eq? (car splits) split) + (not (member (car accts) mentioned))) + (qif-file:set-accts-mentioned! + self (cons (car accts) mentioned))) + ;; add the far account for each split + (set! mentioned (qif-file:accts-mentioned self)) + (if (not (member (cadr accts) mentioned)) + (qif-file:set-accts-mentioned! + self (cons (cadr accts) mentioned))))) + splits)) (qif-file:set-xtns! self (cons xtn (qif-file:xtns self)))) diff --git a/src/scm/qif-import/qif-parse.scm b/src/scm/qif-import/qif-parse.scm index d9921446fb..d6f781f4b8 100644 --- a/src/scm/qif-import/qif-parse.scm +++ b/src/scm/qif-import/qif-parse.scm @@ -130,6 +130,8 @@ (cond ((string=? mangled-string "bank") GNC-BANK-TYPE) + ((string=? mangled-string "port") + GNC-BANK-TYPE) ((string=? mangled-string "cash") GNC-CASH-TYPE) ((string=? mangled-string "ccard") @@ -188,9 +190,9 @@ 'div) ((divx) 'divx) - ((intinc aktzu) ;; zinsen + ((int intinc aktzu) ;; zinsen 'intinc) - ((intincx) + ((intx intincx) 'intincx) ((cglong) ;; Kapitalgewinnsteuer 'cglong) @@ -202,6 +204,12 @@ 'cgshortx) ((shrsin) 'shrsin) + ((xin) + 'xin) + ((xout) + 'xout) + ((stksplit) + 'stksplit) ((reinvdiv) 'reinvdiv) ((reinvint) @@ -212,9 +220,18 @@ 'reinvsh) ((reinvlg reinvkur) 'reinvlg) + ((miscinc) + 'miscinc) + ((miscincx) + 'miscincx) + ((miscexp) + 'miscexp) + ((miscexpx) + 'miscexpx) (else - action-symbol)))) - + (display "qif-parse:parse-action-field : unknown action field ") + (write read-value) (newline) + 'unknown)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; parse-cleared-field : in a C (cleared) field in a QIF transaction, diff --git a/src/scm/qif-import/qif-to-gnc.scm b/src/scm/qif-import/qif-to-gnc.scm index 9f058762d4..6fbf0f66fe 100644 --- a/src/scm/qif-import/qif-to-gnc.scm +++ b/src/scm/qif-import/qif-to-gnc.scm @@ -52,7 +52,7 @@ (gnc:account-begin-edit new-acct 1) ;; if this is a copy of an existing gnc account, -2 ;; copy the account properties + ;; copy the account properties (if (not make-new-acct) (begin (gnc:account-set-name @@ -206,13 +206,11 @@ (qif-file:xtns qif-file)) (qif-file:set-markable-xtns! qif-file markable-xtns))) qif-files-list) - + ;; iterate over files. Going in the sort order by number of ;; transactions should give us a small speed advantage. (for-each (lambda (qif-file) - ;; iterate over markable transactions. The non-transfer - ;; ones are already weeded out. (for-each (lambda (xtn) (if (not (qif-xtn:mark xtn)) @@ -221,7 +219,7 @@ ;; xtns that refer to the same xtn (qif-xtn:set-mark! xtn #t) (qif-import:mark-matching-xtns xtn qif-file qif-files-list) - + ;; create and fill in the GNC transaction (let ((gnc-xtn (gnc:transaction-create))) (gnc:transaction-init gnc-xtn) @@ -262,7 +260,7 @@ gnc-acct-hash mapping-data) (let ((splits (qif-xtn:splits qif-xtn)) (gnc-near-split (gnc:split-create)) - (near-split-total 0) + (near-split-total 0.0) (qif-cat-map (caddr mapping-data)) (qif-acct-map (cadr mapping-data)) (near-acct-info #f) @@ -292,7 +290,7 @@ (set! near-acct-name (list-ref near-acct-info 1)) (set! near-acct (hash-ref gnc-acct-hash near-acct-name)) - + ;; iterate over QIF splits. Each split defines one "far ;; end" for the transaction. (for-each @@ -304,6 +302,8 @@ (far-acct #f) (split-amt (qif-split:amount qif-split)) (memo (qif-split:memo qif-split))) + + (if (not split-amt) (set! split-amt 0.0)) ;; fill the splits in (near first). This handles files in ;; multiple currencies by pulling the currency value from the @@ -342,7 +342,6 @@ (gnc:transaction-append-split gnc-xtn gnc-near-split) (gnc:account-insert-split near-acct gnc-near-split)) - ;; STOCK TRANSACTIONS: the near/far accounts depend on the ;; "action" encoded in the Number field. It's generally the ;; security account (for buys, sells, and reinvests) but can @@ -351,6 +350,7 @@ (share-price (qif-xtn:share-price qif-xtn)) (num-shares (qif-xtn:num-shares qif-xtn)) (split-amt (qif-split:amount (car (qif-xtn:splits qif-xtn)))) + (qif-accts #f) (qif-near-acct #f) (qif-far-acct #f) (far-acct-info #f) @@ -358,92 +358,95 @@ (far-acct #f) (gnc-far-split (gnc:split-create))) + (if (not share-price) (set! share-price 0.0)) + (if (not num-shares) (set! num-shares 0.0)) + (if (not split-amt) (set! split-amt 0.0)) + ;; I don't think this should ever happen, but I want ;; to keep this check just in case. (if (> (length splits) 1) (begin (display "qif-import:qif-xtn-to-gnc-xtn : ") (display "splits in stock transaction!") (newline))) + + (set! qif-accts + (qif-split:accounts-affected (qif-xtn:splits qif-xtn) + qif-xtn)) - ;; the near split: where is the money going TO? - (case action-sym - ((buy buyx sell sellx reinvdiv reinvsg reinvsh reinvlg shrsin) - (set! qif-near-acct qif-security)) - ((div cgshort cglong intinc) - (set! qif-near-acct (qif-xtn:from-acct qif-xtn))) - ((divx cgshortx cglongx intincx) - (set! qif-near-acct - (qif-split:category (car (qif-xtn:splits qif-xtn))))) - (else - (display "HEY! HEY! action-sym = ") - (display action-sym) (newline))) + (set! qif-near-acct (car qif-accts)) + (set! qif-far-acct (cadr qif-accts)) - ;; the far split: where is the money coming from? - (case action-sym - ((buy sell) - (set! qif-far-acct (qif-xtn:from-acct qif-xtn))) - ((buyx sellx) - (set! qif-far-acct - (qif-split:category (car (qif-xtn:splits qif-xtn))))) - ((cgshort cgshortx reinvsg reinvsh) - (set! qif-far-acct - (default-cgshort-acct qif-security))) - ((cglong cglongx reinvlg) - (set! qif-far-acct - (default-cglong-acct qif-security))) - ((intinc intincx reinvint) - (set! qif-far-acct - (default-interest-acct qif-security))) - ((div divx reinvdiv) - (set! qif-far-acct - (default-dividend-acct qif-security))) - ((shrsin) - (set! qif-far-acct - (default-equity-account))) - (else - (display "HEY! HEY! action-sym = ") - (display action-sym) (newline))) - + ;; translate the QIF account names into Gnucash accounts + (if (and qif-near-acct qif-far-acct) + (begin + (set! near-acct-info + (or (hash-ref qif-acct-map qif-near-acct) + (hash-ref qif-cat-map qif-near-acct))) + (set! near-acct-name + (list-ref near-acct-info 1)) + (set! near-acct (hash-ref gnc-acct-hash near-acct-name)) + + (set! far-acct-info + (or (hash-ref qif-acct-map qif-far-acct) + (hash-ref qif-cat-map qif-far-acct))) + (set! far-acct-name + (list-ref far-acct-info 1)) + (set! far-acct (hash-ref gnc-acct-hash far-acct-name)))) + ;; the amounts and signs: are shares going in or out? ;; are amounts currency or shares? (case action-sym - ((buy buyx reinvdiv reinvsg reinvsh reinvlg shrsin) + ((buy buyx reinvint reinvdiv reinvsg reinvsh reinvlg shrsin) (gnc:split-set-share-price gnc-near-split share-price) (gnc:split-set-share-price gnc-far-split share-price) (gnc:split-set-share-amount gnc-near-split num-shares) (gnc:split-set-share-amount gnc-far-split (- num-shares))) + ((sell sellx) (gnc:split-set-share-price gnc-near-split share-price) (gnc:split-set-share-price gnc-far-split share-price) (gnc:split-set-share-amount gnc-near-split (- num-shares)) (gnc:split-set-share-amount gnc-far-split num-shares)) - ((cgshort cgshortx cglong cglongx intinc intincx div divx) + + ((cgshort cgshortx cglong cglongx intinc intincx div divx + miscinc miscincx miscexp miscexpx xin) (gnc:split-set-base-value gnc-near-split split-amt currency) - (gnc:split-set-base-value gnc-far-split (- split-amt) currency))) - - (set! near-acct-info - (hash-ref qif-acct-map qif-near-acct)) - (set! near-acct-name - (list-ref near-acct-info 1)) - (set! near-acct (hash-ref gnc-acct-hash near-acct-name)) - - (set! far-acct-info - (hash-ref qif-acct-map qif-far-acct)) - (set! far-acct-name - (list-ref far-acct-info 1)) - (set! far-acct (hash-ref gnc-acct-hash far-acct-name)) - + (gnc:split-set-base-value gnc-far-split (- split-amt) currency)) + + ((xout) + (gnc:split-set-base-value gnc-near-split (- split-amt) currency) + (gnc:split-set-base-value gnc-far-split split-amt currency)) + + ;; stock splits are a pain in the butt: QIF just specifies + ;; the split ratio, not the number of shares in and out, + ;; so we have to fetch the number of shares from the + ;; security account + ((stksplit) + (let* ((splitratio (/ num-shares 10)) + (in-shares + (gnc:account-get-share-balance near-acct)) + (out-shares (* in-shares splitratio))) + (gnc:split-set-share-price gnc-near-split + (/ share-price splitratio)) + (gnc:split-set-share-price gnc-far-split share-price) + (gnc:split-set-share-amount gnc-near-split out-shares) + (gnc:split-set-share-amount gnc-far-split (- in-shares)))) + (else + (display "symbol = " ) (write action-sym) (newline))) + (let ((cleared (qif-split:matching-cleared (car (qif-xtn:splits qif-xtn))))) (if (or (eq? 'cleared cleared) (eq? 'reconciled cleared)) (gnc:split-set-reconcile gnc-far-split #\c))) - (gnc:transaction-append-split gnc-xtn gnc-near-split) - (gnc:account-insert-split near-acct gnc-near-split) - - (gnc:transaction-append-split gnc-xtn gnc-far-split) - (gnc:account-insert-split far-acct gnc-far-split))) + (if (and qif-near-acct qif-far-acct) + (begin + (gnc:transaction-append-split gnc-xtn gnc-near-split) + (gnc:account-insert-split near-acct gnc-near-split) + + (gnc:transaction-append-split gnc-xtn gnc-far-split) + (gnc:account-insert-split far-acct gnc-far-split))))) ;; set properties of the whole transaction (apply gnc:transaction-set-date gnc-xtn (qif-xtn:date qif-xtn)) @@ -475,37 +478,35 @@ (qif-split:set-mark! split #t) (qif-split:set-matching-cleared! split - (qif-import:mark-matching-split split xtn qif-file qif-files)) + (qif-import:mark-matching-split + split xtn qif-file qif-files)) (qif-split:set-mark! split #t))))) (qif-xtn:splits xtn)) (qif-xtn:set-mark! xtn #t)) (define (qif-import:mark-matching-split split xtn qif-file qif-files) - (let ((near-acct-name #f) - (far-acct-name (qif-split:category split)) - (date (qif-xtn:date xtn)) - (amount (- (qif-split:amount split))) - (memo (qif-split:memo split)) - (bank-xtn? (not (qif-xtn:security-name xtn))) - (cleared? #f) - (done #f)) + (let* ((near-acct-name #f) + (far-acct-name (qif-split:category split)) + (date (qif-xtn:date xtn)) + (amount (- (qif-split:amount split))) + (memo (qif-split:memo split)) + (security-name (qif-xtn:security-name xtn)) + (action (qif-xtn:number xtn)) + (bank-xtn? (not security-name)) + (cleared? #f) + (done #f)) - ;; FIXME security stuff (if bank-xtn? (let ((near (qif-xtn:from-acct xtn))) + (set! far-acct-name (qif-split:category split)) (if near (set! near-acct-name near) (set! near-acct-name (qif-file:default-account qif-file)))) - (set! near-acct-name (qif-xtn:security-name xtn))) + (let ((qif-accts + (qif-split:accounts-affected split xtn))) + (set! near-acct-name (car qif-accts)) + (set! far-acct-name (cadr qif-accts)))) -;; (display "mark-matching-split : near-acct = ") -;; (write near-acct-name) -;; (display " far-acct = ") -;; (write far-acct-name) -;; (display " date = ") -;; (write date) -;; (newline) - ;; this is the grind loop. Go over every unmarked split of every ;; unmarked transaction of every file that has any transactions from ;; the far-acct-name. @@ -578,3 +579,71 @@ ;; is the memo the same? (is this true?) ;; ignore it for now )) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; (qif-split:accounts-affected split xtn) +;; Get the near and far ends of a split, returned as a list +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define (qif-split:accounts-affected split xtn) + (let ((near-acct-name #f) + (far-acct-name #f) + (security (qif-xtn:security-name xtn)) + (action (qif-xtn:number xtn))) + + ;; for non-security transactions, the near account is the + ;; acct in which the xtn is, and the far is the account + ;; linked by the category line. + + (if (not security) + ;; non-security transactions + (begin + (set! near-acct-name (qif-xtn:from-acct xtn)) + (set! far-acct-name (qif-split:category split))) + + ;; security transactions : the near end is either the + ;; brokerage, the stock, or the category + (let ((action-sym (qif-parse:parse-action-field action))) + (case action-sym + ((buy buyx sell sellx reinvint reinvdiv reinvsg reinvsh + reinvlg shrsin stksplit) + (set! near-acct-name security)) + ((div cgshort cglong intinc miscinc miscexp xin xout) + (set! near-acct-name (qif-xtn:from-acct xtn))) + ((divx cgshortx cglongx intincx miscintx miscexpx) + (set! near-acct-name + (qif-split:category (car (qif-xtn:splits xtn))))) + (else + (set! near-acct-name (qif-xtn:from-acct xtn)) + (display "HEY! HEY! action-sym = ") + (display action-sym) (newline))) + + ;; the far split: where is the money coming from? + ;; Either the brokerage account, the category, + ;; or an external account + (case action-sym + ((buy sell) + (set! far-acct-name (qif-xtn:from-acct xtn))) + ((buyx sellx miscinc miscincx miscexp miscexpx xin xout) + (set! far-acct-name + (qif-split:category (car (qif-xtn:splits xtn))))) + ((stksplit) + (set! far-acct-name security)) + ((cgshort cgshortx reinvsg reinvsh) + (set! far-acct-name + (default-cgshort-acct security))) + ((cglong cglongx reinvlg) + (set! far-acct-name + (default-cglong-acct security))) + ((intinc intincx reinvint) + (set! far-acct-name + (default-interest-acct security))) + ((div divx reinvdiv) + (set! far-acct-name + (default-dividend-acct security))) + ((shrsin) + (set! far-acct-name + (default-equity-account)))))) + + (list near-acct-name far-acct-name))) + \ No newline at end of file diff --git a/src/scm/report/average-balance.scm b/src/scm/report/average-balance.scm index 342a27a3fa..8e57ef3e61 100644 --- a/src/scm/report/average-balance.scm +++ b/src/scm/report/average-balance.scm @@ -338,12 +338,17 @@ (gncq (gnc:malloc-query)) (slist '())) - (if (null? accounts) - (set! rept-text + (cond ((null? accounts) + (set! rept-text (list "" (string-db 'lookup 'no-account) - "")) - (begin + ""))) + ((gnc:timepair-le enddate begindate) + (set! rept-text + (list "" + (string-db 'lookup 'dates-reversed) + ""))) + (else (begin ; Grab account names (set! acctname @@ -401,7 +406,7 @@ (system (string-append "echo \"" preplot "plot '" fn "'" plotstr - "\"|gnuplot -persist " )))))) + "\"|gnuplot -persist " ))))))) (append prefix (if (null? accounts) @@ -426,6 +431,7 @@ (string-db 'store 'gain "Gain") (string-db 'store 'loss "Loss") (string-db 'store 'no-account "You have not selected an account.") + (string-db 'store 'dates-reversed "Please choose appropriate dates - the \"To\" date should be *after* the \"From\" date.") (string-db 'store 'period-ending "Period Ending") (string-db 'store 'report-for "Report for %s.") (string-db 'store 'report-for-and "Report for %s and all subaccounts.")