World Tax Planner Programmer's Documentation Calculations Overview Anthony Hornof - May 19, 1993 This documentation should assist the programmers in making additional modifications to calculations in the World Tax Planner. We will give an overview of: 1. The program files 2. The top-level procedures 3. Lower-level procedures 4. The main data structures used 5. The detailed calculation printout The "Planner" menu in the World Tax Planner gives the user two options, "Given Structures" and "Optimize International Money Flows." We will refer to these as "Planner" and "Optimal." Perhaps the staff in London refer to the first of the two more often as "Given." We will focus our discussion on the Planner rather than Optimal because the Planner is where all of the treaty, country-specific, and other tax calculations occur, even when they are called via Optimal. Though Optimal calls some of the same procedures as the Planner, it is a little less interesting (to someone programming calculations) because all that Optimal adds is a series of functions that call the Planner procedures over and over again with different country combinations. When modifying calculations, we made your changes and did your testing in using the Planner. Optimal will pick these changes up automatically. MAIN CALCULATION PROGRAM FILES ------------------------------ The main *.prg files used by the Planner include the following: givstruc.prg - The program that calls the planner() procedure. It contains the top level functions for the Planner module, such as setting up the interface screen and prompting for input. direct.prg - The procedure planner(), which is basically the top-level procedure for the Planner module, is in this program file. It in turn calls top-level procedures for calculating income flow from a host to 2 intermediaries to an investor. These procedures are also in this program file. Some lower-level procedures for a direct income flow are also in this program file. indirect.prg - This program file contains low-level procedures that are used to calculate the flow of income from a host to one intermediary to an investor (a "one-tier" calculation structure). 2tier.prg - This program file contains the low-level procedures used for calculating the income from a host to one intermediary to a second intermediary to an investor (a "two-tier" calculation structure). calcsht.prg - This program file is also interesting because it is used to print out the detailed calculation sheets. planner.prg - This program is a calculation tester that is not part of the actual system. We haven't even used it for testing recently and are not certain how well it works, but it could be quick and handy. TOP-LEVEL CALCULATION PROCEDURES -------------------------------- The "top-level" loop for the Planner is the planner() function in the direct.prg file. Reading through the code, it is clear to see where it calls the next-level procedures to calculate income flows. Direct_all(), for example, is called to calculate a direct flow from host to investor. For income flows with intermediaries, the case statements clearly direct the flow of program control based on income type (dividend versus interest/royalty) and whether it is a one-tier or two-tier structure. The next level of procedures that are called include dir1_div(), dir1_int(), dir2_div(), and dir2_int(). These are essentially at the same level in the hierarchy as direct_all(). Important: It is at this is the level that the "Optimal" portion of the World Tax Planner makes its entry into the "Planner" portion. The "Optimal" does not call planner() directly, but calls these functions instead. Of these procedures, direct_all() and dir1_div() appear first as you read through the code and have therefore been documented in the greatest detail. Once a programmer understands the calls made from these procedures, the other three are pretty clear. So they are in-line documented in less detail. The ordering of the calls to the lower level 3 procedures here is extremely important since some rules supercede others. The type of income specified in a structure of course dictates what type of actions will take place. We therefore tried to name our procedures based on the type of income they will be used to process. But we are not always consistent with the notation. For example, since interest and royalty income are treated very similarly, we often take "interest", "royalty", and "interest/royalty" to all mean the same thing whether written in full or abbreviated. Dir1_div() is therefore for dividends and dir1_int() is for interest but also for royalties. Though we often use "dir" to indicate that a function is used for all three types of income, this is not the case in "dir1_div()" and its partners. Here, I believe we used "dir" is in the names of these procedures to indicate that they are on the same functional level as direct_all(). LOWER-LEVEL CALCULATIONS ------------------------ Dir1_div() and the other procedures at this level have procedures inside of them that branch off and perform individual types of calculations based on special category numbers and other specifications. The names of these procedures contain obvious clues as to their functions. Sc_1() is for special category #1, for example These low-level calculation procedures are grouped together into the program files direct(), indirect(), and 2tier() roughly as described in the program file descriptions above. The sc_1() procedure contains a "do while" and "if-then" loop that recurs in these lower level procedures. What's happening here is that the program is flipping through the special category array (scarray[]) to determine if the country we are currently examining is in the list for special category #1. Scarray[] and other arrays are loaded in the treaty_info() procedure before calculations commence. We will now discuss these and other data structures used in the calculation module in greater detail. THE MAIN DATA STRUCTURES USED FOR CALCULATIONS ---------------------------------------------- Understanding a few of the arrays and *.dbf files used in the Planner calculations is critical. The most important of these are perhaps: 4 garray[] (also known as givenarray[]) scarray[] (similar to iscarray[]) invarray[] (also known as inv[]) dt000hst.dbf dtrtable.dbf sctable.dbf print_data[] (appears in calcsht.prg only) GARRAY[] AND INVARRAY[] ----------------------- Garray[x,y] is the first important one to understand since almost all calculations operate on this structure. This is the "given structure" array and it takes in the results of all relevant calculations throughout the lower-level calculation procedures. The y element is defined very well in the elements.ch file. The elements.ch file is a very important file for understanding the garray[] structure. It details the constants used by garray[] to access its elements. The x element of garray[x,y] is defined as follows: The x=1 line is for the host; the x=2 line is for intermediary 1 (if one exists); the x=3 line is for intermediary 2 (if one exists); the x=4 line is always blank. This array tracks all income aspects (as described in elements.ch) for each of these three countries. Invarray[x,y] is another important array used in calculations. It holds the final results of the calculations. The x=1 line is for the investor and the x=2 line is always blank. The y elements are best described in write_inv() in direct.prg - there is no elements.ch file as with garray[], but invarray[] is a much simpler array since there are fewer numbers associated with the investor. The y in garray[x,y] is currently dimensioned at 75 (in elements.ch) and the y in invarray[] at 22 (in direct.prg). The contents of the garray[] and invarray[] for each plan are copied into the user's dt000hst.dbf. (I use "000" here as the placeholder for the user number.) This is done in write_given() and write_inv() in direct.prg. Not only is the full host->intermediary1->intermediary2->investor written to the file, one country per line, but the direct host->investor is also written to the file one country per line. Even if the user specifies intermediaries, the program always does the calculations and records the results for a direct flow as well. Garray[] and invarray[] can hold only one host, two intermediaries, and one investor at a time. Dt000hst.dbf, however, can hold many series' of these calculations at a time, an entire "plan." 5 DTRTABLE.DBF AND SCTABLE.DBF ---------------------------- The sctable.dbf and dtrtable.dbf hold the special categories and treaty rates that are used in the calculations. Studying treaty_info() in direct.prg will help a programmer to learn how the data in these *.dbf files works its way into the program. Tax rates between countries are tracked in rates.dbf. Country1 is the destination country and country2 the source country. Evidently, any time that a record in rates.dbf represents a TREATY between two countries there is also a record in dtrtable.dbf assigning an "ftc" number. (The field is called "dtr_no" in dtrtable.dbf.) These treaty rates, also know as ftc's, make there way into the calculations in the Planner when treaty_info() in direct.prg calls find_rate() and does other activity to determine which ftc number (and therefore which tax rate) will be used in each country. These values are stored in the correct garray[] line for each country in the structure. The sctable.dbf contains the list of special categories. Usually there is a value associated with a special category. The sctable.dbf is loaded into scarray[] for all relevant countries in a plan. The subscripts in scarray[x,y,z] are used as follows: x is the country being considered; y is the number of sc's for that country; for z, 1=country, 2=code, 3=value. Three more special category notes: 1) The structure iscarray[x,y,z] is just like scarray[] except that x is always 1 and iscarray[] contains the investor special category data. 2) Sc.dbf merely holds a text description of each special category. 3) One subtlety in dt000hst.dbf is that each record actually holds the ftc number for the next country in line. The vars.ch file is good one to note. It connects all of the user-specific *.dbf files with the functions that are used to call them. The file names themselves are never used in the code, only these functions. THE DETAILED CALCULATION PRINTOUT --------------------------------- As we mentioned above, the garray[] and invarray[] are filled throughout the low-level calculation procedures. These two arrays are in turn loaded into dt000hst.dbf in write_given() and write_inv(). We will now discuss how dt000hst.dbf is printed out as a detailed calculation. 6 It happens in calcsht.prg. Print_data[x,y] is the critical array in this program. First, all of the calculation results are moved from dt000hst.dbf into print_data[x,y] line x=3 with calls to fill_host(), fill_int(), and fill_inv(). The ordering is not preserved exactly as the numbers move between data structures. Second, the English descriptions (such as "Corporate Tax Paid") that appear to the left on the detailed calculation printout are loaded from calcpr.dbf into print_data[x,y,z] line x=1. Third, the column position of where the calculation result should appear on the printout are loaded from calcpr.dbf into line x=2. Again, the ordering of the data in these data structures to not match exactly. In some cases, there are some last-minute logical checks made as calculation results are loaded to decide which data to use. And to repeat: There is not a precise but there is a rough one-to-one-to-one correspondence among these three structures: garray[], dt000hst.dbf, and print_data[]. Third, print_data[] is "printed out" to a holding file in print_rpt(). Print_rpt() is very important because this is where the ordering of the calculation lines on the page is fixed. This is where some work could be done to re-order the detailed calculation lines, perhaps by adding another layer of control to make the ordering more flexible. Lastly, the holding file is sent to the screen and/or the printer. The holding file is either disp000.dbf or print000.prn or both depending on the user's choice out output device. CONCLUSION ---------- Hopefully, this documentation will help a programmer to learn how to modify the calculation module of the World Tax Planner. The most recent two calculation modifications made have been N177-Singapore and N290-Australia. This document is based on what was learned during these tasks. Conducting a text search on all *.prg files for "N177" or "N290" will reveal every modification made to the World Tax Planner for these two fault reports. Perhaps studying these well-documented modifications along with this document will be the best guide to future enhancements.