Other FPI Links: FPI Client Guide
Downloads: FPIClientSDK.zip | FPIServerSDK.zip


 

Financial Posting Interface 1.1 - Server Guide

© 2002 Quik Sense Software

By Scott K. Maxwell

The Financial Posting Interface allows any application to post transactions to any FPI-compliant account manager. This document will tell you how to add FPI to your account manager.

FPI was created by Quik Sense Software as a generic way to post transactions to account managers and to update those transactions if necessary. I created FPI primarily to interface my Quik Budget product to account managers. Through FPI, users can create and modify transactions in Quik Budget and the same transactions will be created and modified in the user's account manager of choice. This avoids the problem of having to enter the transaction into multiple applications. However, FPI is not for Quik Budget alone.Through FPI any application can post transactions with no knowledge of the internal workings of the current account manager.

This document is aimed at account manager authors who are interested in making their applications FPI compliant.

Features of FPI

FPI plug-ins can:

  • Be built into your application or distributed as a separate plug-in.
  • Use resources and do UI interaction. The client specifies whether or not UI is allowed.
  • Query the name, creator ID and application type of the client. It can use this information to modify its behavior or to refuse to start.
  • Register themselves as the the default account manager for the system. This facilitates auto-discovery.

Clients can:

  • Interact with any FPI application with no knowledge of the specific application.
  • Get a list of accounts, transaction types and classes.
  • Query the next check number for any given account.
  • Set the last check number used for any given account.
  • Get a list of categories and sub-categories. FPI supports an unlimited nesting level for sub-categories.
  • Query the base currency. This can be used to verify that both apps are using the same home currency.
  • Post transactions. The FPI application returns a 32-bit UID if it was able to complete the post.
  • Query transactions. This is done via the UID generated by the Post method so the client will only be looking at transactions that it created.
  • Modify transactions. This is also done via the UID generated by Post.

Getting the FPI Server SDK

All of the code necessary for implementing FPI plug-ins is available in the FPI Server SDK at http://quiksense.com/FPI/FPIServerSDK.zip. You probably want to extract the SDK into your main project directory. You will need to add RegisterPlugIn.c to your project.source code.

How the Plug-in Works

An FPI plug-in is built as a PalmOS code resource. It is maintained as a separate project from your main application but it can share code files with your main app and CodeWarrior can be setup to automatically build the plug-in as a sub-project of your main app. It can access the resources of your main application but there is no easy way (that I know of) for the plug-in to access your main apps code. FPI plug-ins generally range between 12K and 16K in size.

Although FPI is implemented in C++, you can add FPI support to your application even if your account manager is written completely in C. The only change you will need to make to your main source code is to call the RegisterAccountManager() function. That function is written in ANSI C. Alternatively, you could distribute FPI support as a separate PRC and make no changes to your main app but that could lead to versioning issues later so I don't really advise that approach.

An account manager plug-in is built as a code resource of type 'FPAM', resource number zero. If you build the plug-in as a standalone PRC, it should be of type 'FPAM' with the same creator ID as your main app. If you build it into your main app, the RegisterAccountManager() function will create a small database of type 'FPAM' with the creator ID of your main app and will store the type/creator of your main application database in record 0. Call this in your app startup code so that your application will automatically register as the default account manager whenever it is run.

FPI clients will open the first database of type 'FPAM'. If it is a resource database, the client will attempt to use that database as the plug-in. If not, it reads the first 8 bytes from record zero to discover the type/creator of the actual plug-in database.

What is in the FPI Server SDK

When you first extract the files from the FPI Server SDK, it may look a bit intimidating. Don't worry. It is mostly sample code. The SDK includes the following projects:

  1. Plug-In Test.mcp. This is a sample FPI client application that you can use to test and debug your client. It automatically builds the Sample Account Manager and SamplePlug-In projects as sub-projects and the debugger automatically loads SamplePlugIn.prc. You will probably want to change that to build and debug your plug-in instead.
  2. SamplePlug-In.mcp. An example of a complete plug-in. Please feel free to use any of this code that you like.
  3. Sample Account Manager.mcp. A very simple sample account manager. It does not actually do anything except create the databases need to try the SamplePlug-In. You can look at this to see how to add your plug-in as a sub-project of your main application.
  4. MyPlug-In.mcp. An FPI plug-in skeleton. Just add code to the stubs and your plug-in will be done.

The actual code is split up into seven sub-directories as follows:

FPI Plug-In Test - Code for the test app.

  1. FPI-Test.rsrc. Resources for the test app.
  2. PlugInTest.pch. Precompiled headers for the test app..
  3. Test.cpp. All of the code for the test app. This is a good example of how to implement an FPI client.

MyPlug-In - Code for the skeleton plug-in.

  1. FPIAccountManager.h/.cpp. Skeleton for the FPIAccountManager class.
  2. FPITransaction.h/.cpp. Skeleton for the FPITransactionHandle class.

SamplePlug-In - Code for the complete sample plug-in and account manager.

  1. FPIAccountManager.h. Example of a complete FPIAccountManager class definition.
  2. FPIAccountManager.cpp. Constructor/destructor and initialization for the FPIAccountManager.
  3. FPIAccount.h/.cpp. All of the account manipulation methods of the FPIAccountManager class.
  4. FPICategory.h/.cpp. All of the category manipulation methods of the FPIAccountManager class.
  5. FPIClass.h/.cpp. All of the class manipulation methods of the FPIAccountManager class.
  6. FPICurrency.h/.cpp. All of the currency manipulation methods of the FPIAccountManager class.
  7. FPITransaction.h/.cpp. Complete example of an FPITransactionHandle class.
  8. Sample App.cpp. Bare bones account manager. All it does is create the databases needed by the plug-in and register the plug-in. Use this as an example of how to add the plug-in as a sub-project of your own main app.

AccountManagerBase - You will only need to deal with RegisterPlugIn.h/.c if you use the skeleton or sample plug-in.

  1. RegisterPlugIn.h/.c. These are the only two files you will need to add to your main application. Call RegisterAccountManager() from your startup code if you are building the plug-in into your app.
  2. PlugIn.pch. Precompiled header file for the plugin. Include this in your plug-in project. This is already done for you in both the sample plug-in and the skeleton.
  3. FPIAccountManagerInterface.h. This file defines the FPI interface and must be included within the definition of your FPIAccountManager class. This is already done for you in both the sample plug-in and the skeleton.
  4. FPIPlugInGlue.h. Glue code to connect the plug-in to the FPIAccountManager object. This must also be included within the definition of your FPIAccountManager class. This is already done for you in both the sample plug-in and the skeleton.
  5. FPIPlugInGlue.cpp. The actual glue code defined in FPIPlugInGlue.h. Just include this file in your plug-in project. This is already done for you in both the sample plug-in and the skeleton.
  6. FPITransactionInterface.h. Defines the FPITransactionHandle interface. It must be included within the definition of your FPITransactionHandle class. This is already done for you in both the sample plug-in and the skeleton.

ClientCode - Code that is used by both the plug-in and by FPI clients

  1. AccountManagerPlugIn.h. The base class for FPI account manager plug-ins.
  2. AccountManagerClient.h/.cpp. The client's sub-class of AccountManagerPlugIn. It includes all of the necessary glue to connect the client to the plug-in. This can be used in your plug-in to provide chaining to Quik Budget. You can see how this is done in both the skeleton and the sample plug-in.
  3. FFP.h/.cpp. Definition of the FFP class. See FFP below for details.
  4. FinancialAppClasses.h. Definitions of all of the current financial application types. See details below.

PlugInBase - Base code for generic plug-ins. You can use this base code to create your own C++ plug-ins.

Utility - Various utility functions to make life easier.

  1. NewDel.h. Definitions of the C++ operators new and delete.
  2. PHandle.h/.cpp. A C++ class to handle MemHandles. This class is provided entirely for your convenience and is not needed by the plug-in.
  3. PSimpleRecordHandle.h/.cpp. A C++ class to handle database records. Includes methods for locking records, creating new records, reading data from records and writing to records. Also includes methods for modifying packed record data directly including replacing packed strings with strings of a different length. The record is released appropriately whenever Lock, Unlock or the destructor is called. See the sample plug-in for example of usage. This class is provided entirely for your convenience and is not needed by the plug-in.
  4. StartupCommon.c. This file does not actually contain any functions. It merely puts a wrapper around the StartupCommon.c file in your PalmOS Support folder so that the C++ compiler will build it properly. StartupCommon.c includes definitions of functions such as _lmul_ and _ldiv_ which the compiler expects to be included in your project.

Plug-In Test

When you extract the SDK, the test app is setup to build the sample account manager and plug-in. You may want to play with this a bit just to see how it works.

  1. Build the project and hit F5 to upload it to the emulator.
  2. It will complain that it couldn't find a valid plug-in. That is because the plug-in could not find its databases. Go to the app launcher and run 'SampleAccountManger'. It will simply create its databases and return to the app launcher.
  3. Start FPI-Test again. Now it will startup properly.
  4. Notice that there are popup lists for accounts and transaction types.
  5. Enter a transaction. If you enter a category or class, it will be added to the list. Use a ':' to separate sub-categories.
  6. Exit FPI-Test and restart it. You will see that the transaction has been repopulated properly.

Implementation Strategy

This is what I believe to be the simplest way to implement a plug-in:

  1. Extract the FPI Server SDK into your main project directory.
  2. Have a look at both MyPlug-In and SamplePlug-In. Decide whether you'd prefer to implement your plug-in from scratch or simply modify the sample. Add whichever one you want to use as a starting point to your main project as a sub-project. See the next topic for instructions if you don't know how to do this.
  3. If you are starting with the MyPlug-In project you will want to modify Plug-In Test. First remove the 2 sample projects from the targets tab. Next add your plug-in as a sub-project as described in the next topic. However, do not click in the right-hand column to include the code resource. That seems to make debugging difficult in CodeWarrior. Instead, open the project settings and scroll down to the Debugger:Other Executables section. Remove the lines for the sample plug-in and add Obj\MyPlug-In.prc.
  4. Implement the Setup and Cleanup code
  5. Implement the Account Methods. You should now be able to build the test app and see a list of accounts from your account manager.
  6. If you support them transaction types, implement the Transaction Number Methods and test.
  7. If you support transaction classes, implement the Class Methods and test.
  8. Implement the Category Methods and test.
  9. If you support payees, implement the Payee Methods and test.
  10. Implement Master Currency and test. FPI-Test should now show your master currency on the Currency line.
  11. Implement a Minimal Post and test.
  12. Implement GetTransaction.
  13. Implement Change and test. You should now be able to post complete transactions to your account manager.
  14. Implement Get. The transaction should now repopulate properly when you start FPI-Test.
  15. Implement Delete and test.
  16. Implement AddSplit.
  17. Grab a pint at the local pub to celebrate.

Adding a Sub-Project in CodeWarrior (Building the plug-in into your main app)

To ensure that your main application and plug-in stay in sync, you will want to add the plug-in to your main project as a sub-project. Here is how:

  1. Change to the Targets tab in CodeWarrior. You should see your project target with a '+' next to it. Click on the '+' to expand it and you will see the plug-in project. Click the '+' next to that and click on the bullseye icon next to the first target. Ignore the 'Headers' target. Also click in the right-hand column next to that target to add a dot. This last step causes the .tmp file from the plug-in to be included as a code resource in your main app. This appears not to work on some versions of CodeWarrior. If you do not see the .tmp file in the Segments view, just compile the plug-in and drag-and-drop the .tmp file directly into your main project.
  2. You may need to add the .tmp extension to your CodeWarrior File Mappings. To do this, go to the File Mappings tab and set File Type to blank, Extension to .tmp, Compiler to Rez and Flags to Resource File. Then hit the Add button. Don't forget to hit Add. If you simply hit OK, CodeWarrior will not add the extension.

Making the Plug-In Your Own

Whether you choose to start from the sample plug-in or the skeleton, there is one thing you have to do to make the plug-in your own. Change the creatorID to match your main app. Even though the plug-in will ultimately be built in to your main app, you will need to make this change so that you can debug the plug-in through the PRC.

Registering Your Plug-in

If you build the plug-in into your main application database, you need to register it when your application is run. This will allow clients to find your plug-in. To register your plug-in, just call RegisterAccountManager() from your startup code. That will create a small glue database called FPAM-PlugIn that contains the type/creator for your app.

The only problem with having the plug-in built into your application is that if the user runs your app from VFS, your plug-in will not be in RAM for clients to use. Fortunately, there is a solution. In the switch statement in your PilotMain, simply add these lines:

case sysAppLaunchCmdCardLaunch:

	CopyAccountManagerPlugIn();

	return 0;

Notice the return 0. You are not supposed to actually run your application when you receive sysAppLaunchCmdCardLaunch. Your application will be launched again immediately with the normal launch code.

Now when your app is launched from a card, this will copy the code resource for the plug-in to its own database so that it remains resident, even when the main application no longer is. It also temporarily sets a feature so that the RegisterAccountManager function will not overwrite the plug-in. If the user moves your app back to main RAM, RegisterAccountManager will automatically replace the plug-in with the small glue database, thus reclaiming the memory.

Setup and Cleanup

Here is a basic description of the life cycle of an FPI plug-in:

  1. Client creates a new FPIAccountManager object.
  2. Client sets the client variables of the FPIAccountManager.
  3. Client calls the Init method of the FPIAccountManager. The FPIAccountManager opens its databases and verifies that everything is ready to go.
  4. Client checks to see if the plug-in was initialized successfully. If not, it deletes it.
  5. Client uses the plug-in.
  6. As the client app shuts down, it deletes the FPIAccountManager. The destructor gets called and the FPIAccountManager closes all of its databases and releases its resources.

Since FPIAccountManager is a sub-class of AccountManagerPlugIn, we have to start by calling the AccountManagerPlugIn constructor:

	AccountManagerPlugIn(	UInt32 creator,
const char *appName,
const char *appVersion,
const char *shortName,
bool supportsTransactionNumber,
bool allowAnythingInTransactionNumber,
bool supportsClasses);
  • 'creator' specifies the creator ID of your application.
  • 'appName' is the pretty name of your application.
  • 'appVersion' is a string representing the current version of your app.
  • 'shortName' should be no more than 6 characters. This is a short name that can appear on a button or tab.
  • 'supportsTransactionNumber' indicates whether or not your app supports transaction numbers or types.
  • 'allowAnythingInTransactionNumber' indicates whether of not your app can handle random text for the transaction number string or not. false indicates that only predefined types are allowed.
  • 'supportsClasses' indicates whether or not your app supports transaction classes. Some account managers support both categories and classes

You should not do any work in the constructor. Just zero any pointers or DmOpenRef objects and call InitVTable(). The client will need to setup a few more things in the plug-in before you actually initialize it.

You should open your databases and verify that everything is in working order in the Init method. If you encounter a problem and the plug-in cannot be fully initialized, set the m_valid member to false.

In the destructor you will need to free any resources you have used and close your databases.

Info from the Client

The client will provide the plug-in with a bit of info about itself and its expectations. This info may be queried with the following methods:

UInt32		ClientCreatorID();
const char* ClientAppDBName();
bool UIIsOkay();
bool ClientHandles(UInt16 c); DmOpenRef DB();

None of these methods is available until the client calls the Init method so don't try to use them in your constructor.

  • ClientCreatorID and ClientAppDBName can be useful if you want to be able to tell users what application created a particular transaction.
  • UIIsOkay returns true if it is safe to display a user interface. WARNING: Never display UI if this flag is false.
  • ClientHandles allows you to check to see what classes of financial data the client handles. You can use this information to determine whether or not you should chain to another plug-in. For instance, Quik Budget passes BUDGETMANAGER_CLASS. Your plug-in can test for this and if the client is not handling BUDGETMANAGER_CLASS, your plug-in can pass the transaction on through to the QB plug-in if present. You can see how this works in both the skeleton and the sample plug-in. See Financial App Classes for more information.
  • DB returns the DmOpenRef of the plug-in. You can use this in conjunction with DmOpenDatabaseInfo to get information about your plug-in database. You may need to do this if you are using resources. See Using Resources.

Account Methods

So that the client can get information about your accounts, you need to implement:

UInt16		AccountIndexOf(const char *name);

const char*	GetAccountName(UInt16 index);

UInt16		AccountCount();
const char** GetAccountList(UInt16 _All_RscID, UInt16 _None_RscID);

The client will need to get an index of the account in order to use the transaction number methods or to set the selection value for a list of accounts. AccountIndexOf should take a name and return a list index. If the account does not exist, it should return EOF (0xffff). GetAccountName should convert that index back into a name. The memory is managed by the plug-in.

AccountCount returns the number of valid accounts.

GetAccountList returns a list of the valid accounts. If no valid accounts exist, return NULL. The client can pass this list directly to LstSetChoices.
WARNING: The client is expected to do MemPtrFree on the block of data returned by GetAccountList when the data is no longer needed. Be sure to use MemPtrNew to allocate the memory you need for this.

Transaction Number/Type Methods

Many account managers support transaction numbers and types. FPI allows this to be set by passing a single string to the Post and Change methods. If that string is a number, it is assumed to be a check number. If a string, it is the transaction type. If empty or NULL, it is unspecified. So that the client can get a list of valid transaction types, you need to implement:

Int32		GetAccountNextCheckNumber(UInt16 acctIndex);

void		SetAccountLastCheckNumber(UInt16 acctIndex, Int32 last);

UInt16		TransactionNumberStringCount(UInt16 acctIndex);

const char**	GetTransactionNumberList(UInt16 acctIndex);

Each of these methods takes a parameter called acctIndex. This is the index returned by AccountIndexOf.

GetAccountNextCheckNumber should return the next check number for the specified account. If you do not support this feature, just return zero.

The client may also call SetAccountLastCheckNumber to update the value. If you do not support this feature, just do nothing.

TransactionNumberStringCount returns the number of transaction types for the given account.

GetTransactionNumberList returns a list of transaction type strings for the given account. If no valid transaction types exist, return NULL. The client can pass this list directly to LstSetChoices.
WARNING: The client is expected to do MemPtrFree on the block of data returned by GetTransactionNumberList when the data is no longer needed. Be sure to use MemPtrNew to allocate the memory you need for this.

Category Methods

FPI supports infinitely nested category structures. To accomodate this, each of the category methods takes a root string. The prototypes look like this:

bool		HasCategories(const char *root=NULL);

UInt16		CategoryCount(const char *root=NULL);

const char**	GetCategoryList(const char *root=NULL);

If the client passes NULL to any of these methods, you should return data based on the root categories. If the client passes a root string, the return values should refer to sub-categories of that root. For instance, this call should return the number of sub-categories of "Dining":

UInt16 count = CategoryCount("Dining"); 

If no valid categories or sub-categories exist, the GetCategoryList should return NULL.

FPI 1.1 adds three more category methods:

UInt16		CompleteCategoryCount();

const char**	GetCompleteCategoryList();

const char*	GetCategoryName(UInt16 index);

These are used to handle complete, indented lists of categories. GetCompleteCategoryList() will typically return a list that looks something like this:

Auto

  Fuel

  Wash

Dining

  Breakfast

  Lunch

  Dinner

Gifts

Groceries

GetCategoryName takes an index into this list and returns the fully qualified category name. In the above example, GetCategoryName(2) would return "Auto:Fuel". The account manager is responsible for managing the memory used for this string data. Typically, the account manager will have a single buffer it uses for building the category string and it reuses the buffer every time this method is called.

WARNING: As with the Account and Transaction Number methods, the client is expected to do MemPtrFree on the block of data returned by GetCategoryList and GetCompleteCategoryList when the data is no longer needed. Be sure to use MemPtrNew to allocate the memory you need for this.

Class Methods

Classes are similar to categories but they are not usually nested. Classes seem to be supported by about half of the account managers currently available for the Palm platform. If you support classes, you need to implement the following:

UInt16		ClassCount();

const char**	GetClassList();

WARNING: As with the Account and Transaction Number methods, the client is expected to do MemPtrFree on the block of data returned by GetClassList when the data is no longer needed. Be sure to use MemPtrNew to allocate the memory you need for this.

Payee Methods

From FPI's point of view, payees are simply lists of names. Some account managers have a separate list of payees for each category. If you support payees, you need to implement the following:

UInt16		PayeeCount(const char *category);

const char**	GetPayeeList(const char *category);

WARNING: As with the Account and Transaction Number methods, the client is expected to do MemPtrFree on the block of data returned by GetPayeeList when the data is no longer needed. Be sure to use MemPtrNew to allocate the memory you need for this.

Master Currency

Some clients will want to find out what your app's master currency is. Quik Budget uses this to make sure that it is using the same master currency as the account manager and warns the user if there is a mismatch. If you support currencies, you should implement:

bool		GetMasterCurrency(char *symbol, char *code=0)

The client is expected to provide 6-byte buffers for both symbol and code. Be sure you don't write more than 5 bytes plus a NULL.

Financial Fixed-Point

FPI uses Financial Fixed-Point (FFP) to specify all amounts. Include FFP.h in any .c/.cpp files that need to use FFP.

Internally, FFP consists of an Int32 and a UInt16. The UInt16 specifies how many decimals of precision are needed. This will almost always be either zero or two. $20.00 is represented as an Int32 of 2000 and a UInt16 of 2. 2000 lira is represented as an Int32 of 2000 and a UInt16 of 0. This allows for a good range of values, very high precision and good performance. You can create FFP objects from either integers or doubles.

To create an FFP object representing $98.47, you would do this:

FFP amount(9847,2);	// Constructor taking an Int32

Or:

FFP amount(98.47,2);	// Constructor taking a double

You can query the value with 4 methods:

  • double AsDouble() const; // Returns the value as a double
  • Int32 Value() const; // Returns the value stored in the Int32 portion
  • UInt16 Decimals() const; // Returns the number of decimal places to shift the Int32
  • char *AsString(char *buf, char decimalPoint='.') const; // Prints the value to the buffer

Minimal Post

Clients use the Post method to send transactions to your app. Here is an example:

if (accountManager.Valid()) {	// Make sure we have a valid plug-in
FFP amount(-2000,2); // -$20.00 UInt32 uid = accountManager->Post( 0, //Link ID "Checking", //Account name 0, //Transfer account name TimGetSeconds(), //Time of transaction "Kentucky Fried Chicken", //Comment "Large family bucket", //Note "ATM", //Transaction number or type "Dining", //Category "Personal", //Class false, //Cleared false, //Private amount, //Amount 1.0, //Exchange rate "$", //Currency symbol "USD", //Currency code fpiShowUIIfIncomplete); //UI flag }

If the post is successful, it should return a unique ID that can be used by the client to retrieve the transaction again later. If the post fails, it should return 0.

The Post method and the Change method are very similar. Post is used to create new transactions and Change is used to modify existing transactions. Although, you could do all of the work in the Post method, I would recommend that you not do that. Instead, do the bare minimum amount of work necessary to create the transaction here and then call the Change method. The Change method takes all of the same parameters as Post with the exception of the UIFlag at the end. You may want to assign default values to any of the parameters the client left blank before calling the Change method.

Have a look at the Post method in the sample plug-in to see how to have the Post method call Change.

The final parameter will usually be fpiShowUIIfIncomplete. This flag is a suggestion. You never need to show UI but you should never show UI if this flag is set to fpiShowUINever or if UIIsOkay returns false.

GetTransaction and the FPITransactionHandle object

When a client wants to query or modify an existing transaction, it must first get a handle to the transaction record. The client does this by instantiating a glue object called AMTransaction. The AMTransaction object calls the FPIAccountManager::GetTransaction method and passes the unique ID that it previously received from the Post method. The GetTransaction method should use the UID to find the transaction record. If the record does not exist, GetTransaction returns NULL. Otherwise it creates an FPITransactionHandle object and returns a pointer to it. You can see examples of this in both the skeleton and the sample plug-in.

The FPITransactionHandle object exists as long as the clients AMTransaction object does. The AMTransaction destructor deletes the FPITransactionHandle object. FPITransactionHandle is responsible for freeing all resources it needed to allocate.

TIP: If you have pack and unpack functions, you may want to have the FPITransactionHandle object contain a copy of your unpacked structure. The constructor can then call the unpack function so that the transaction data is in an easy to use form. If the client calls the Change method, you can simply write the changes to the unpacked structure and set a dirty flag. Then in your destructor, you can repack the transaction if it is dirty and move it if the sort location has changed.

Change

The Change method looks almost identical to the Post method. It works very much like DmSetRecordInfo or DmSetDatabaseInfo. The client will pass in valid pointers for everything that needs to be updated. Any NULL parameters are left as is.

The first parameter is a link ID. If not 0, this is a unique ID for the account manager to store if you want to directly access the matching client record. If your plug-in does not know how to handle records from the client app, you should probably just ignore this. In the case of Quik Budget, the link ID is always the unique ID of the QB transaction that corresponds to this post. When QB posts transactions to an account manager, you always end up with the transaction existing in both the account manager and in QB. You can use the ClientHandles(BUDGETMANAGER_CLASS) call to see if the linkID is coming from Quik Budget.

The second parameter is account. If the account does not exist, it is up to the account manager to decide what to do. You could create the account. If UI is allowed, you could ask the user if they want to create the account. Or you could just quit and return a unique ID of zero to indicate failure. The last option is probably the most common.

The transferToAccount is specified if the transaction is a transfer.

comment is often used for payee.

The transaction number or type is used to indicate a check number, transaction number, or type of transaction such as 'ATM', 'Withdrawal', 'Deposit', etc.

Category capability varies greatly among account managers. Some only have a single level of categories. Others allow for a second level or even unlimited levels of nested categories. In FPI, these are always represented as a single string with the different levels separated by a colon. For instance, "Dining:Lunch" would indicate the Lunch sub-category of Dining. It is entirely up to the account manager how it will handle categories. If the category has more levels than the account manager represents, you could just chop off the extra levels, create a new category containing the whole string or simply fail and return a 0. The last option is pretty unfriendly, though.

Some account managers support transaction classes as well as categories. This is often used to specify 'Business' and 'Personal' or to specify the name of the person who spent the money.

A negative amount indicates money spent, charged or withdrawn and a positive value indicates money deposited or credited. Expense amounts are always specified in Financial Fixed-Point as detailed above.

The exchange rate is always a double representing the number to multiply the amount by to get the total in the native currency. If the native currency is US$, the transaction currency is British Pounds and the amount is 10 pounds, an exchange rate of 1.6 would indicate US$16.00.

The client may specify both the symbol and the code of the currency as different account managers and different users prefer to use one over the other. The symbol is the common symbol used for that currency such as '$'. The code is the 3-letter code used to indicate the currency such as 'USD'. If you only use one or the other, you should probably check for a match against both strings.

If the client specifies a category, class or currency that does not exist in your account manager, you should create it if possible.

If the client is not Quik Budget, you should probably chain through to the Quik Budget plug-in. An example of how to do this is in both the skeleton and the sample plug-in.

Return the unique ID of the transaction. If for some reason (i.e. account doesn't exist) you had to delete the transaction, return zero.

Get

Once a client has a valid FPITransactionHandle, it can use the Get method to retrieve the details. Get allows the client to query all of the information that was set in the Post and Change methods and has almost exactly the same prototype. The main difference is that everything is a pointer. For instance, instead of:

const char *comment
Get expects:
const char **comment

This is very similar to the way DmRecordInfo and DmDatabaseInfo work. The client simply passes in valid pointers for the items it wishes to retrieve and NULL for those it doesn't need.

Important: The string data is managed by the FPITransactionHandle object so be sure to free any strings you had to allocate when the destructor is called.

Delete

Delete should remove the transaction and add the money back in to the account.

AddSplit

Once the client has created a transaction, it may want to add splits to it. This is done with the AddSplit method. Here is an example of the client code:

if (accountManager.Valid()) {	// Make sure we have a valid plug-in.

	FFP amount(-6.92,2);	// -$6.92

	UInt32 uid = accountManager->Post(

		0,				//Link ID

		"Checking",			//Account name

		0,				//Transfer account name

		TimGetSeconds(),		//Time of transaction

		"Safeway",			//Comment

		"Bread, Cheese, Mushrooms",	//Note

		"1520",				//Check number

		"Groceries",			//Category

		"Personal",			//Class

		false,				//Cleared

		false,				//Private

		amount);			//Amount

	if (uid) {

		AMTransaction amTran(accountManager,uid,true);
if (amTran.Valid()) { amount.Set(-3.08,2); uid = amTran.AddSplit( 0, // Link ID "Paper towels", // Split note "Household", // Category "Personal", // Class amount); // Amount of split } }
}

The resulting transaction would be for $10 (6.92+3.08) and contain a split with two parts. Whenever you add a split, the original transaction becomes split 1 and the first AddSplit becomes split two.

Notice that the AddSplit method takes a linkID and returns a unique ID. The reason for this is that each split can be accessed independently. For example, Quik Budget does not have true split support so the QB AddSplit method simply creates another transaction. An account manager with true split support could keep a separate QB link ID for each split. An account manager with true splits could return a different unique ID for each split by ORing the 24-bit transaction uid with an 8-bit split uid.

Using Resources

Before you use resources, be sure to check the FPIAccountManager::UIIsOkay() method. If the value is true, you will need to ensure that your resource database is on top.

PalmOS looks for resources first in the most recently opened resource database. When an FPI plug-in is loaded, the client reopens its own database to put its resources on top. To get your resources back on top, you will need to reopen your plug-in database. The safest way to do this is:

  1. Use the FPIAccountManager::DB() method to get a DmOpenRef to your plug-in database.
  2. Pass that value to DmOpenDatabaseInfo() to get the card number and LocalID of your database.
  3. Use DmOpenDatabase() to open it.
  4. Use the resources.
  5. Close the database. Don't forget to do this!

Financial App Classes

Although this document has focused on creating an FPI Account Manager plug-in, the ultimate goal is to create a variety of plug-in APIs that can be used to link many classes of financial application. You can see the current list of application classes in FinancialAppClasses.h. Your plug-in can query the FPIAccountManager::HandlesClass() method to see if the client handles a class of data that you know how to interact with. For instance, if you create a loan manager, you may want the loan manager to interact with your account manager. By checking FPIAccountManager::HandlesClass(LOANMANAGER_CLASS), your account manager could determine that a Post was coming from a loan manager and store the link ID so that it can write any changes back to the loan manager.

Both the skeleton and the sample plug-in already include code to chain to Quik Budget. Please do this if at all possible. The Quik Budget plug-in also chains to the account manager if present. Quik Budget will, of course, only do this if !FPIAccountManager::HandlesClass(ACCOUNTMANAGER_CLASS).

At the time of this writing, only this account manager interface has been written. This interface is also used by budget managers. If you are interested in defining interfaces for any other classes of financial application, we would be happy to assist in defining the API.


Copyright © 2002, Quik Sense Software

 

Google
WWW http://www.quiksense.com

Home | Links | Consulting | Privacy Statement | Email us

Copyright © 1999-2006 Quik Sense Software. All rights reserved.