QIF imports and stock ticker symbols

David Hampton hampton@employees.org
Mon, 16 Apr 2001 16:27:08 -0700


I initially tried to create an implementation where the stock
name/ticker symbol values were stored as part each <qif-file> object,
but I couldn't find any way to access the <qif-file> object from the
routine qif-import:update-stock-hash().  I gave up on that approach
and created an implementation with a single stock name/ticker symbol
map attached to the druid window object, and passed this value into
the necessary routines.  This code is working fine, and has been
tested for both missing map entries (which shouldn't happen), and map
entries that don't specify a ticker symbol (which happen whenever
quicken doesn't have a ticker symbol).  I've attached diffs from the
1.5.5 release.


David


Index: src/gnome/druid-qif-import.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome/druid-qif-import.c,v
retrieving revision 1.29
diff -u -c -r1.29 druid-qif-import.c
*** src/gnome/druid-qif-import.c	2001/04/03 21:42:09	1.29
--- src/gnome/druid-qif-import.c	2001/04/16 22:59:49
***************
*** 87,92 ****
--- 87,93 ----
    SCM       gnc_acct_info;
    SCM       stock_hash;
    SCM       new_stocks;
+   SCM       ticker_map;
  
    SCM       imported_account_group;
    SCM       match_transactions;
***************
*** 139,144 ****
--- 140,146 ----
    GtkObject       * wobj;
    SCM  load_map_prefs;
    SCM  mapping_info;
+   SCM  create_ticker_map;
    int  i;
  
    char * pre_page_names[NUM_PRE_PAGES] = {
***************
*** 173,178 ****
--- 175,181 ----
    retval->memo_map_info     =  SCM_BOOL_F;
    retval->stock_hash        =  SCM_BOOL_F;
    retval->new_stocks        =  SCM_BOOL_F;
+   retval->ticker_map        =  SCM_BOOL_F;
    retval->imported_account_group   = SCM_BOOL_F;
    retval->match_transactions = SCM_BOOL_F;
    retval->selected_transaction = 0;
***************
*** 230,235 ****
--- 233,241 ----
    retval->cat_map_info     = gh_list_ref(mapping_info, gh_int2scm(2));
    retval->memo_map_info    = gh_list_ref(mapping_info, gh_int2scm(3));
    retval->stock_hash       = gh_list_ref(mapping_info, gh_int2scm(4));
+ 
+   create_ticker_map = gh_eval_str("make-ticker-map");
+   retval->ticker_map = gh_call0(create_ticker_map);
    
    scm_protect_object(retval->imported_files);
    scm_protect_object(retval->selected_file);
***************
*** 242,247 ****
--- 248,254 ----
    scm_protect_object(retval->acct_map_info);
    scm_protect_object(retval->stock_hash);
    scm_protect_object(retval->new_stocks);
+   scm_protect_object(retval->ticker_map);
    scm_protect_object(retval->imported_account_group);
    scm_protect_object(retval->match_transactions);
    
***************
*** 287,292 ****
--- 294,300 ----
    scm_unprotect_object(window->acct_map_info);
    scm_unprotect_object(window->stock_hash);
    scm_unprotect_object(window->new_stocks);
+   scm_unprotect_object(window->ticker_map);
    scm_unprotect_object(window->imported_account_group);
    scm_unprotect_object(window->match_transactions);
  
***************
*** 560,567 ****
      scm_protect_object(wind->selected_file);      
      
      /* load the file */
!     load_return = gh_call2(qif_file_load,  gh_car(imported_files),
!                            scm_filename);
      
      /* a list returned is (#f error-message) for an error, 
       * (#t error-message) for a warning, or just #f for an 
--- 568,575 ----
      scm_protect_object(wind->selected_file);      
      
      /* load the file */
!     load_return = gh_call3(qif_file_load, gh_car(imported_files),
!                            scm_filename, wind->ticker_map);
      
      /* a list returned is (#f error-message) for an error, 
       * (#t error-message) for a warning, or just #f for an 
***************
*** 1325,1332 ****
      /* if we need to look at stocks, do that, otherwise import
       * xtns and go to the duplicates page */
      scm_unprotect_object(wind->new_stocks);
!     wind->new_stocks = gh_call2(update_stock, wind->stock_hash, 
!                                 wind->acct_map_info);
      scm_protect_object(wind->new_stocks);
      
      if(wind->new_stocks != SCM_BOOL_F) {
--- 1333,1340 ----
      /* if we need to look at stocks, do that, otherwise import
       * xtns and go to the duplicates page */
      scm_unprotect_object(wind->new_stocks);
!     wind->new_stocks = gh_call3(update_stock, wind->stock_hash,
! 				wind->ticker_map, wind->acct_map_info);
      scm_protect_object(wind->new_stocks);
      
      if(wind->new_stocks != SCM_BOOL_F) {
***************
*** 1380,1387 ****
    int show_matches;
  
    scm_unprotect_object(wind->new_stocks);
!   wind->new_stocks =  gh_call2(update_stock, wind->stock_hash, 
!                                wind->acct_map_info);
    scm_protect_object(wind->new_stocks);
    
    if(wind->new_stocks != SCM_BOOL_F) {
--- 1388,1395 ----
    int show_matches;
  
    scm_unprotect_object(wind->new_stocks);
!   wind->new_stocks =  gh_call3(update_stock, wind->stock_hash, 
! 			       wind->ticker_map, wind->acct_map_info);
    scm_protect_object(wind->new_stocks);
    
    if(wind->new_stocks != SCM_BOOL_F) {
Index: src/scm/qif-import/qif-dialog-utils.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/scm/qif-import/qif-dialog-utils.scm,v
retrieving revision 1.24
diff -u -c -r1.24 qif-dialog-utils.scm
*** src/scm/qif-import/qif-dialog-utils.scm	2001/02/23 22:20:34	1.24
--- src/scm/qif-import/qif-dialog-utils.scm	2001/04/16 22:59:51
***************
*** 587,593 ****
  ;;  new stocks or #f if none.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  
! (define (qif-import:update-stock-hash stock-hash acct-hash)
    (let ((names '()))
      (hash-fold 
       (lambda (qif-name map-entry p)
--- 587,593 ----
  ;;  new stocks or #f if none.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  
! (define (qif-import:update-stock-hash stock-hash ticker-map acct-hash)
    (let ((names '()))
      (hash-fold 
       (lambda (qif-name map-entry p)
***************
*** 625,637 ****
                     
                     ;; we know nothing about this security.. we need to 
                     ;; ask about it
!                    (begin 
                       (set! names (cons stock-name names))
                       (hash-set! 
                        stock-hash stock-name 
                        (gnc:commodity-create stock-name
                                              GNC_COMMODITY_NS_NYSE
!                                             stock-name
                                              ""
                                              100000))))))
           #f))
--- 625,639 ----
                     
                     ;; we know nothing about this security.. we need to 
                     ;; ask about it
!                    (let ((ticker-symbol (qif-ticker-map:lookup-ticker ticker-map stock-name)))
!                      (if (not ticker-symbol)
! 			 (set! ticker-symbol stock-name))
                       (set! names (cons stock-name names))
                       (hash-set! 
                        stock-hash stock-name 
                        (gnc:commodity-create stock-name
                                              GNC_COMMODITY_NS_NYSE
!                                             ticker-symbol
                                              ""
                                              100000))))))
           #f))
Index: src/scm/qif-import/qif-file.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/scm/qif-import/qif-file.scm,v
retrieving revision 1.25
diff -u -c -r1.25 qif-file.scm
*** src/scm/qif-import/qif-file.scm	2001/03/01 23:55:24	1.25
--- src/scm/qif-import/qif-file.scm	2001/04/16 22:59:51
***************
*** 17,23 ****
  ;;  just store the fields "raw".
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  
! (define (qif-file:read-file self path)
    (false-if-exception
     (let* ((qstate-type #f)
            (current-xtn #f)
--- 17,23 ----
  ;;  just store the fields "raw".
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  
! (define (qif-file:read-file self path ticker-map)
    (false-if-exception
     (let* ((qstate-type #f)
            (current-xtn #f)
***************
*** 88,93 ****
--- 88,95 ----
                         (set! current-xtn (make-qif-cat)))
                        ((account)
                         (set! current-xtn (make-qif-acct)))
+                       ((type:security)
+                        (set! current-xtn (make-qif-stock-symbol)))
                        ((option:autoswitch)
                         (set! ignore-accounts #t))
                        ((clear:autoswitch)
***************
*** 322,327 ****
--- 324,358 ----
                          (display "qif-file:read-file : unknown Cat slot ")
                          (display tag) 
                          (display " .. continuing anyway") (newline))))
+ 
+                    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+                     ;; Security transactions 
+                    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+                     ((type:security)
+                      (case tag
+                        ;; N : stock name 
+                        ((#\N)
+                         (qif-stock-symbol:set-name! current-xtn value))
+                        
+                        ;; S : ticker symbol 
+                        ((#\S)
+                         (qif-stock-symbol:set-symbol! current-xtn value))
+                        
+                        ;; T : type 
+                        ((#\T)
+                         (qif-stock-symbol:set-type! current-xtn value))
+                        
+                        ;; end-of-record
+                        ((#\^)
+                         (qif-ticker-map:add-ticker! ticker-map current-xtn)
+                         (set! current-xtn (make-qif-stock-symbol)))
+                        
+                        (else
+                         (display "qif-file:read-file : unknown Security slot ")
+                         (display tag) 
+                         (display " .. continuing anyway.")
+                         (newline))))
+                     
                      
                      ;; trying to sneak one by, eh? 
                      (else 
Index: src/scm/qif-import/qif-objects.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/scm/qif-import/qif-objects.scm,v
retrieving revision 1.15
diff -u -c -r1.15 qif-objects.scm
*** src/scm/qif-import/qif-objects.scm	2001/02/23 22:20:35	1.15
--- src/scm/qif-import/qif-objects.scm	2001/04/16 22:59:52
***************
*** 578,580 ****
--- 578,654 ----
  
  (define qif-map-entry:set-display?!
    (simple-obj-setter <qif-map-entry> 'display?))
+ 
+ 
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ ;;  <qif-stock-symbol>
+ ;;  [N] stock name     : string 
+ ;;  [S] ticker symbol  : string 
+ ;;  [T] type           : string 
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ 
+ (define <qif-stock-symbol>
+   (make-simple-class
+    'qif-stock-symbol
+    '(name symbol type)))
+ 
+ (define qif-stock-symbol:name
+   (simple-obj-getter <qif-stock-symbol> 'name))
+ 
+ (define qif-stock-symbol:set-name! 
+   (simple-obj-setter <qif-stock-symbol> 'name))
+ 
+ (define qif-stock-symbol:symbol
+   (simple-obj-getter <qif-stock-symbol> 'symbol))
+ 
+ (define qif-stock-symbol:set-symbol! 
+   (simple-obj-setter <qif-stock-symbol> 'symbol))
+ 
+ (define qif-stock-symbol:type
+   (simple-obj-getter <qif-stock-symbol> 'type))
+ 
+ (define qif-stock-symbol:set-type! 
+   (simple-obj-setter <qif-stock-symbol> 'type))
+ 
+ (define (qif-stock-symbol:print self)
+   (simple-obj-print self))
+ 
+ (define (make-qif-stock-symbol)
+   (make-simple-obj <qif-stock-symbol>))
+ 
+ 
+ 
+ 
+ (define <qif-ticker-map>
+   (make-simple-class
+    'qif-ticker-map
+    '(stocks)))
+ 
+ (define qif-ticker-map:ticker-map
+   (simple-obj-getter <qif-ticker-map> 'stocks))
+ 
+ (define qif-ticker-map:set-ticker-map!
+   (simple-obj-setter <qif-ticker-map> 'stocks))
+ 
+ (define (make-ticker-map) 
+   (let ((self (make-simple-obj <qif-ticker-map>)))
+     (qif-ticker-map:set-ticker-map! self '())
+     self))
+ 
+ (define (qif-ticker-map:add-ticker! ticker-map stock-symbol)
+   (qif-ticker-map:set-ticker-map!
+    ticker-map
+    (cons stock-symbol (qif-ticker-map:ticker-map ticker-map))))
+ 
+ (define (qif-ticker-map:lookup-ticker ticker-map name)
+   (let ((retval #f))
+     (for-each 
+      (lambda (symbol)
+        (if (string=? name (qif-stock-symbol:name symbol))
+ 	   (begin
+ 	     (set! retval (qif-stock-symbol:symbol symbol))
+ 	     (if (string=? retval "")
+ 		 (set! retval #f)))))
+      (qif-ticker-map:ticker-map ticker-map))
+     retval))
+