ofx and generic import infrastructure

Benoit Grégoire bock@step.polymtl.ca
Wed, 20 Nov 2002 20:37:29 -0500


> Err... are you saying that the destination account matching *has* to be on
> the same page as on the transaction matching/duplicate detection? If that
> is what you want to say, then I definitely disagree... those are two
> different tasks and I can easily imagine those happening in different
> windows (or druid pages or whatever). Maybe you prefer to have both
> happening in one window (and I prefer the other) -- but if you think that
> there are important reasons for the one-window concept, can you elaborate
> more on that?

Ok, here is an example.  You regularly go to one of those  mega-stores where 
you can buy everything form Bread to computers, such as WalMart where you can 
buy grocery, audiovisual, computers, clothes, etc.  Monday you buy your 
groceries, Friday you got your paycheck and decide buy new TV.  The next week 
you download your credit card statement.  You now have two transactions with 
the EXACT same description, but only differing in the date and amount.  Since 
your groceries and TV are unlikely to go into the same expense account, you 
MUST have a way to override the destination account on a per transaction 
basis. 

Unless you mean for the first page to have one line per transaction, I don't 
see how you could handle it on your previous druid page.  The strings for 
which you would be picking an account would be identical (hence you could 
only select one account).  So, since you need to double check anyway and have 
an interface to override the selection, it seems kind of silly to have two 
separate, successive interfaces to do it.  Destination account matching 
(unlike source account matching) is dynamic in nature.  I changes over time, 
and there are a whole bunch of punctual exceptions.  

The WallMart example is not an isolated case, here are a few other stores 
where you would buy stuff that would not normally go in the same expense 
account.
-Drug stores (cosmetics, grocery and medication).  Here at least everyone are 
mandated by law to have medication insurance that will reimburse part of the 
price of prescription drugs.  Most people will handle this as a separate 
expense account.
-Hardware stores:  Furniture, construction materials and various household 
products.
-Electronics stores:  Furniture (Refrigerator, washing machines), Audiovisual 
and computers
-Basically any large surface store will have this problem to some extent.  And 
at least here in North America, that is where people buy most of their stuff.

> :-) Not really. My "Reconcile window invocation" happens in
>
> src/import-export/hbci/gnc-hbci-getbalance.c line 169. Not really much
> code, is it? :-) In the current HBCI implementation, the user simply gets a
> dialog window popping up in his face (line 148) asking "Reconcile now?
> Yes/No", and if the user answers yes,  the reconcile window is opened by
> recnWindowWithBalance from RecnWindow.h. That's all there is.

Darn, no code to steal :(  Unfortunately for me in OFX and QIF you can receive 
several balances in the same file.  Popping the same dialog four times in a 
row (once for each account) might trigger aggressive reactions by the user...  
So a smoother solution will have to be implemented for OFX and QIF.  But the 
smooth solution would require (ouch, it hurts to say this) a druid, to add a 
page after transaction matching.

> > Now, I've taken a lot of heat in the past for the event based, "pop in
> > your face" design of the current generic importer.  Derek and Christian
> > want it to be druid based.
>
> Ok, this point is still up for discussion, but there are several issues
> with it, and since you asked, I'm just going to state those:
>
> * One thing that keeps buggin me about the gnc_import_add_trans function is
> that it operates on static, hidden GUI data, which is obvious by the fact
> that it only takes one argument, the Transaction to add. IMHO the natural
> question here is "this thing adds transaction TO WHERE?" What I definitely
> would prefer here is a function like
>
> void gnc_import_add_trans(GenericImporter *importer, Transaction *trans);
>
> and having the additional function
>
> GenericImporter *gnc_import_importer_new (GtkWidget *parent);
>
> and so on. Note that this point is still totally independent from the
> Druid/One-Window discussion. It is, however, clearly not independent from
> the point you raised about different programming styles colliding here. :-)

I don't actually mind if it's done like this, but I think it's only moving the 
problem from one place to several place, which is usually a bad thing.  If 
the structure is created from outside the matcher, I will need to keep a 
static or global variable in the OFX module, so that each time a 
ofx_proc_trans_cb is called from LibOFX, the transactions will go to the same 
matcher.  Which implies that we will also have to define a 
gnc_import_importer_complete_cb(GenericImporter *importer) to tell the OFX 
module (and every other module now that I think of it) that the matcher has 
been closed by the user and should now be destroyed.  (Since there is is 
never any way the protocol specific module can know when the user has 
finished processing all transactions and closed the matcher).

One benefit however (as we discussed a few weeks ago) would be to allow OFX, 
QIF and HBCI imports to occur simultaneously, but each in their own window.  
IMHO it's not worth moving matcher creation and destruction outside the 
matcher and into each and every module, but I would not oppose a patch that 
does it (as long as it doesn't break OFX obviously).  

> * Same point (different programming styles): I would kindly ask you that if
> you define function prototypes in a header file, *please* put the
> implementation in a .c file *of the same name*. Otherwise the header file
> IMHO is almost useless -- I still have to grep for the actual
> implementation of that function, which is quite a bummer. Of course this
> can lead to the fact that you create a whole lot of header files, and maybe
> some of those are almost empty -- but IMHO this is totally valid and only
> reflects the *actual* *real* function interdependencies/ program structure.
> Note that this point can perfectly be done during the next days, since it
> shouldn't change the behaviour of the code at all.

I don't really understand the benefit.  To have a coherent and easy to 
understand API for the generic import infrastructure, I think all public 
functions should be in a single header file, so that this file can be 
included by the protocol specific module.  I've split the file to allow for 
easier reading and faster recompiles (it used to be a single file).  I think 
one header for each C file is usefull if you want to have prototypes for 
private functions (in which case you have one header per c file with the 
private function, and that header includes the header with the public 
functions), but I've never seen that anywhere in GnuCash.  In GnuCash all 
header files represent an API, and every c file have more functions that it's 
header file.  And I've never seen an API anywhere that forces the client to 
include a whole bunch of header files each containing one or two functions in 
order to use the API.  

I do however see your point about program structure, but I meant that to be 
reflected by the the c files.  I could write the filename where the function 
is implemented in the comments above the function.  I can't help but to think 
that If we split the headers in separate files and in the end we do a druid 
interface, the protocol module will have to include at least one header per 
page, which would be kind of funny :)

> confirming that). In other words: You shouldn't feel disappointed because
> nobody else is editing the files you do -- instead, this has just proven to
> be the most effective way of dividing up the work, especially in OpenSource
> projects. Not doing so (i.e. editing the *same* files) immediately requires
> a whole different level of
> understanding and communication, which IMHO might be necessary for a big,
> multi-purpose API (OpenHBCI) but not really for one part inside a big
> application. Gee. I'm pretty sure we'll come to a nicely working
> application in the end. Thanks for your comments.

Well, from that point of view, I think you are right.  But it would still have 
been nice to have negative comments on the API design while it was only that: 
a design document.  I might have ignored some of it, but i could have 
justified it as i went.  I received only thumbs up for the design document, 
and started receiving negative feedback only once I had working code, which 
was kind of demoralizing...

Oh well, the hard part is behind us in any case.  Once destination matching is 
implemented, I'll be able to turn my attention back to LibOFX, for which I 
have big projects (And since GnuCash is my testbed, it will also gain OFX and 
QIF export, and possibly OFC import in the process...)  Hopefully then we 
will soon have true interoperability between open source financial software!