Freeside:1.9:Documentation:Developer:Tax data vendor support
Freeside contains facilities for vendor supplied tax calculation data. During the billing process customers are associated with a vendor geocoded location, and each package of a given customer is mapped onto the vendor's concept of one or more taxable products. The taxes are then calculated, assigned to the invoice, and stored with sufficient information for later reporting of which individual taxes were billed in which districts.
A number of tables are used to accomplish this. Here are the tables used most directly with some description and notes.
- cust_tax_location - maps a place onto a geocode
The primary key of a row in this table is passed through tax calculation routines to assist in identifying a location for tax puposes.
- tax_class - identifies a category of tax (i.e. sales tax)
- part_pkg_taxrate - automatic (data vendor) mapping via geocode and product of packages (part_pkg) onto tax_class keys
- cust_tax_exempt - deprecated; do not use
- cust_tax_exempt_pkg - information about exemptions for those taxes with an initial amount excluded
- tax_rate - the description of individual taxes (rates, fees, exempted amounts, basis, etc)
taxline method returns a listref of a name and an amount. Here is where new ways of calculating taxes can be implemented tax_on_tax method returns a list of tax classes which are candidates for being taxed by this tax
- tax_rate_location - maps a geocode onto place name, required for reporting purposes
impermissible to delete; use disabled flag
- part_pkg_taxproduct - identifies a product (i.e. international long distance charges) subject to taxation
- part_pkg_taxoverride - manual (user) mapping of packages (part_pkg) onto tax_classes
Additionally the following tables are worth noting for their relationships to the tax subsystem.
- cust_bill_pkg_tax_rate_location - table contains data on actual tax amounts collected via invoicing
- usage_class - specifies a type of usage (i.e. international)
part_pkg records have associated part_pkg_option records with names of the form usage_taxproductnum_X where X is a primary key value of usage_class primary key, setup or recur. the option value is the taxproductnum
- cust_bill_pkg_tax_location - analogous to cust_bill_pkg_tax_rate_location for internal (cust_main_county) tax scheme
Overview of tax calcuation
Once the cust_tax_location is known, for any given invoice line item (cust_bill_pkg) the 'private' method FS::cust_main::_gather_taxes is called. This determines the associated pkgpart and calls its part_pkg_taxoverride method. Should that yield no tax_class rows the part_pkg_taxrate method is called to determine tax_class values associated with the cust_bill_pkg. The part_pkg_taxrate method relies on the taxproductnum (key of part_pkg_taxproduct, compare with taxclass in cust_main_county) stored in the part_pkg (default) or a part_pkg_option row associated with the part_pkg. You will need to ensure that FS::part_pkg::part_pkg_taxrate returns the correct part_pkg_taxrate rows. The taxclassnum values of those rows (OR'd), together with the geocode are used to select the tax_rate rows.
After the tax_rate (compare with cust_main_county) rows for each customer package have been collated, determine which taxes apply to these taxes (tax_on_tax). Loop through the resultant list of taxes (tax_rate) and the corresponding package information (cust_bill_pkg or a currency amount) and calculate the tax (FS::tax_rate::taxline), creating new cust_bill_pkg and cust_bill_pkg_tax_rate_location records. Each cust_bill_pkg passed to FS::tax_rate::taxline is guaranteed to have only a single amount value (setup OR recur OR a particular usage class).
In order to cause Freeside to perform the above calculations you will need to import the data from the vendor. Freeside presently offers two different styles of import. The first is an import by uploading a set of files through the user's web browser. The second is a download from the vendor's site. Which is presented in the UI is controlled by the taxdatadirectdownload global configuration value. The latter is an extension of the former.
For the upload of files you will need to choose one or more values to represent the name(s) of the format (vendor) and modify httemplate/misc/tax-import.cgi to support the correct number of files and the format. Similarly the httemplate/misc/tax-fetch_and_import.cgi will require addition of the format name(s). Each of the tables cust_tax_location, tax_class, part_pkg_taxrate, tax_rate, tax_rate_location, and part_pkg_taxproduct has a data_override column which will also receive this name of the vendor or format. The packages corresponding to the tables (except part_pkg_taxproduct) each contains a batch_import method. You will need to write the format handling code in that method for the file containing your vendor's data. You may need to add a similar routine to part_pkg_taxproduct depending on your vendor's data layout.
The FS::tax_rate package also contains the method process_batch_import to handle the processing of an entire set uploaded files. It is (presently) specific to the vendor CCH and will need to be modified for your vendor(s). Similarly the process_download_and_update method is specific to CCH and will require modification to support that feature for your vendor.
Finally the httptemplate/misc/tax-fetch_and_replace.cgi, which is not reachable via menus, offers a facility for wiping out the tax data tables and repopulating them while retaining the information about which taxes are disabled and what products are assigned to which part_pkg fows. If you wish to support this facility you will need to add your format names to that file and modify the FS::tax_rate::process_batch_reload method. It is currenly specific to CCH data.
Steps required to support a vendor's tax data:
- Choose one or more names for the vendor
- Modify httemplate/misc/tax-import.cgi and or httemplate/misc/tax-fetch_and_import
- Add format support callbacks for batch_import to FS/FS/cust_tax_location.pm to populate that table
- Add format support callbacks for batch_import to FS/FS/tax_class.pm to populate that table
- Add format support callbacks for batch_import to FS/FS/part_pkg_taxrate.pm to populate that table
- Add format support callbacks for batch_import to FS/FS/tax_rate.pm to populate that table
- Add format support callbacks for batch_import to FS/FS/tax_rate_location.pm to populate that table
- Add a batch_import to FS/FS/part_pkg_taxproduct to populate that table
- Modify process_batch_import and process_download_and_update in FS/FS/tax_rate.pm to handle entire vendor dataset
- Ensure that geocode in FS/FS/cust_main correctly identifies a customer's location
- Add any necessary customer editing bits required for geocoding
- Modify part_pkg_taxrate in FS/FS/pkg_part to return appropriate rows from your vendor's data
- Modify tax_line in FS/FS/tax_rate if required to handle any new sorts of tax calculation
- Modify tax_on_tax in FS/FS/tax_rate to indentify taxes which are applied to taxes