4 Customizing Tax Calculation

This chapter describes how to extend the Oracle Communications Billing and Revenue Management (BRM) tax calculation features, including the Vertex Data Manager.

See "About Calculating Taxes" for information on calculating taxes.

How BRM Calculates Taxes

The PCM_OP_RATE_EVENT opcode is the main tax calculation opcode.

For each rated event, this opcode reads the PIN_FLD_RATES_USED array in the input flist to determine what rates to apply. This rate information determines how the taxable amount is treated.

Based on the information it collects, PCM_OP_RATE_EVENT does the following:

  • If taxation occurs during rating, it calls the PCM_OP_RATE_TAX_CALC opcode.

  • If taxation occurs during billing, it calls the PCM_OP_BILL_CYCLE_TAX opcode. PCM_OP_BILL_CYCLE_TAX calls PCM_OP_RATE_TAX_CALC to perform the tax calculation.

  • If the event is nontaxable, it does nothing.

PCM_OP_RATE_EVENT also calls the PCM_OP_RATE_POL_TAX_LOC policy opcode to determine whether custom processing or default processing is used to determine the tax-related locales.

  • If default processing is used, PCM_OP_RATE_EVENT retrieves the locales from the database.

  • If custom processing is used, control is handed to the PCM_OP_RATE_POL_TAX_LOC policy opcode, which determines which locales to use.

The locales are used during the tax calculation process to determine jurisdiction. BRM stores up to four tax locales for the current account, session, and event.

PCM_OP_RATE_EVENT also checks the PIN_FLD_EXEMPTIONS array in /account objects to determine whether all or part of the purchase amount is exempt from taxes.

PCM_OP_RATE_EVENT returns a revised set of objects for the event. This can include PIN_FLD_TAXES and PIN_FLD_EXEMPTIONS arrays to indicate tax amounts that were calculated immediately by PCM_OP_RATE_TAX_CALC.

See "Retrieving Tax Location Data" for more information on the tax locales and how to customize their retrieval.

Calculating Taxes

PCM_OP_RATE_TAX_CALC performs tax calculations when taxes are calculated during real-time rating or during billing.

  • To calculate taxes during real-time rating, PCM_OP_RATE_TAX_CALC is called by PCM_OP_RATE_EVENT.

  • To calculate taxes during billing, PCM_OP_RATE_TAX_CALC is called by PCM_OP_BILL_CYCLE_TAX.

PCM_OP_RATE_TAX_CALC determines the taxation Data Manager (DM) or custom taxation method to be used for an event. It sends the input flist to the DM or the custom tax calculation method for calculation. It receives the information it needs to calculate taxes from the following input fields:

  • The tax code of the BRM product mapped to a product code that is recognized by the taxation software. The tax code also identifies the taxation DM or the custom tax calculation method to be used.

  • The purchase amount to be taxed from the PIN_FLD_TAXES array. Each element of the PIN_FLD_TAXES array represents a separate tax calculation method.

    Note:

    If the tax calculation software or custom policy is not specified in the tax code, taxes are not calculated.
  • The locations that are involved in the transaction to be taxed. This includes ship-from, ship-to, order origin, and order accept addresses for sales and use taxation.

    Note:

    For telecommunications taxation, the address fields contain additional information (NPA-NXX or geocodes) for origin, termination, and charge-to numbers.
  • The date and time of the transaction from the PIN_FLD_START_T and PIN_FLD_END_T fields. PIN_FLD_START_T is used to compute PIN_FLD_ELAPSED_TIME or duration (that is, the difference between the end time and start time).

  • Tax exemption information, including exemption information based on tax jurisdiction, from the PIN_FLD_EXEMPTIONS array.

  • The tax supplier ID from the PIN_FLD_TAX_SUPPLIER field.

  • Other optional values such as the account's bill object in the PIN_FLD_BILL_OBJ field and telecommunications values such as incorporated, residence, and regulated flags.

PCM_OP_RATE_TAX_CALC returns an output flist with a revised PIN_FLD_TAXES array containing the tax data that the tax calculation software or the custom tax calculation method returns. The calculated taxes are sorted by jurisdiction.

Tax Calculation Error Handling

PCM_OP_RATE_TAX_CALC checks for the following errors:

  • Missing or nonvalid PIN_FLD_TAX_CODE field.

  • Nonvalid PIN_FLD_TAXPKG_TYPE field, which is derived from PIN_FLD_TAX_CODE field and the taxcodes_map file.

  • Missing or nonvalid tax database entry, such as vertex_db in the Connection Manager (CM) configuration file (pin.conf).

Tax Calculation Policy Opcodes

PCM_OP_RATE_TAX_CALC calls the following policy opcodes that you can customize to modify the tax data or to use custom tax calculation:

See "About Customizing BRM Taxation" for more information about customizing tax calculation.

Calculating Taxes without Recording Them

If the PCM_OPFLG_CALC_ONLY flag is set, PCM_OP_RATE_TAX_CALC performs the tax calculation and returns the tax rate and amount. The tax data is not written to the database, however.

Performing Address or VAT Certificate Validation

You can call PCM_OP_RATE_TAX_CALC in jurisdiction-check-only mode during account creation to perform address or VAT certificate number validation. You specify jurisdiction-check-only mode by using the PIN_FLD_COMMAND input field. The following modes are supported:

  • If PIN_FLD_COMMAND is set to 1, it sends an address to the taxation DM for verification and additionally returns the geocode and county information in the PIN_FLD_NAMEINFO array if the address was successfully validated.

  • If PIN_FLD_COMMAND is set to 2, it sends a VAT certificate number to the tax DM for validation.

In jurisdiction-check-only mode, PCM_OP_RATE_TAX_CALC returns 1 if the jurisdiction is valid and 0 if it is not.

Calculating Taxes during Billing

To calculate taxes during billing, PCM_OP_RATE_EVENT calls PCM_OP_BILL_CYCLE_TAX.

PCM_OP_BILL_CYCLE_TAX performs these steps:

  1. If a transaction is not already open, opens one.

    If PCM_OPFLG_CALC_ONLY is set, the transaction is opened with the flag PCM_TRANS_OPEN_READONLY.

  2. Creates an /event/billing/cycle/tax object with the taxable amount if there were any deferred taxes.

    The output flist contains the POID of the created /event/billing/cycle/tax object.

  3. Calls PCM_OP_RATE_TAX_CALC to perform the actual tax calculation.

  4. If PCM_OP_BILL_CYCLE_TAX was called with the PCM_OPFLG_CALC_ONLY flag set, it still performs the tax calculation but does not create the /event/billing/cycle/tax object.

    Instead, this opcode's output flist contains the PIN_FLD_RESULTS array, an flist with the information that would have been used to create the /event/billing/cycle/tax object.

  5. Sets the /event/billing/cycle/tax object status to inactive.

  6. Commits the transaction if one was opened in step 1.

About Customizing BRM Taxation

You can customize BRM tax calculation in the following ways:

Retrieving Tax Calculation Data

Use the following policy opcodes to retrieve tax data from the BRM database:

Retrieving a List of Tax Codes

To retrieve a list of tax codes, use the PCM_OP_RATE_POL_GET_TAXCODE policy opcode. You can customize this policy opcode to return additional cached tax code information.

The PCM_OP_RATE_POL_GET_TAXCODE policy opcode takes an account POID as input and performs these functions:

  • Obtains the database number from the POID.

  • Searches the CMs in-memory cache for tax codes.

  • Returns an array of tax code names in the output flist.

The PCM_OP_RATE_POL_GET_TAXCODE policy opcode returns a list of the tax code names cached from the taxcodes_map file by the CM during initialization.

Retrieving a List of Tax Suppliers

To retrieve a list of tax suppliers, use the PCM_OP_RATE_POL_GET_TAX_SUPPLIER policy opcode. You can customize this policy opcode by modifying the fields on the output flist. You can specify which fields are validated by adding or removing them from the input flist.

The PCM_OP_RATE_POL_GET_TAX_SUPPLIER policy opcode takes an account POID as input and performs these functions:

  • Obtains the database number from the POID.

  • Performs a global search for tax suppliers.

  • Returns a list of tax suppliers with all the relevant fields in the output flist.

See "About Tax Suppliers" for more information on tax suppliers.

Retrieving Tax Supplier Data

To retrieve tax supplier data, use the PCM_OP_RATE_POL_MAP_TAX_SUPPLIER policy opcode. You can customize this policy opcode to change how a tax supplier is derived for a specific BRM event.

This policy opcode can function in either of two ways:

  • If a tax_supplier_map file is used with a corresponding entry in the CM pin.conf file, this policy opcode searches the tax_supplier_map file by company ID based on the Product Name and Ship To categories. If a matching entry is found, it returns that entry from the tax_supplier_map file. If no matching entry exists, the policy opcode returns NULL as the address of the flist.

  • If the tax_supplier_map file does not exist or the CM pin.conf entry does not specify using a tax_supplier_map file, this policy opcode tries to find the tax_supplier object POID in the PIN_FLD_PRODUCTS array of the account object.

The PCM_OP_RATE_POL_MAP_TAX_SUPPLIER policy opcode also retrieves the utility flag, which is used for telecommunication (telco) taxation, from the PIN_FLD_REGULATED_FLAG field of the /profile/tax_supplier object and returns it on the output flist.

Retrieving Tax Location Data

To customize the way PCM_OP_RATE_EVENT obtains the locations for tax jurisdictions, use the PCM_OP_RATE_POL_TAX_LOC policy opcode. This policy opcode returns the locations for an event, which are then used to establish jurisdictions for tax calculation.

Note:

For a telephony event, the locations contain additional information, which is enclosed in square ([]) brackets.

For example, you can obtain the value for the PIN_FLD_ORDER_ACCEPT field from a different source. Additionally, you can provide a geocode instead of an NPA/NXX for telephony events.

The PCM_OP_RATE_POL_TAX_LOC policy opcode takes an account POID as input and returns these fields:

  • PIN_FLD_SHIP_TO: The ship-to address; for telephony events, the call termination number.

  • PIN_FLD_SHIP_FROM: The ship-from address; for telephony events, the call origination number.

  • PIN_FLD_ORDER_ACCEPT: The order accept address; for telephony events, the charge-to number.

  • PIN_FLD_ORDER_ORIGIN: The order origin address.

It returns them in four strings with this syntax:

city; state_abbreviation;zipcode; country;[code,location,international_indicator]
  

where:

  • code is the geocode or NPA/NXX.

  • location specifies the type of code:

    0 - Address

    1 - Geocode

    2 - NPA/NXX

  • international_indicator specifies the type of call:

    1 - North America numbering plan

    2 - North America originated, overseas terminated

    3 - North America originated, overseas terminated and billed

    4 - IOC North America originated, overseas terminated

    5 - Overseas originated, North America terminated

    6 - IOC North America originated, overseas terminated and billed

    7 - Overseas originated, overseas terminated

For example:

1  PIN_FLD_SHIP_TO      STR [0] "Cupertino; CA; 95014; USA;[408572,2,1]"
1  PIN_FLD_SHIP_FROM    STR [0] "Englewood; CO; 80112; USA;[060050006000,1,1]"
1  PIN_FLD_ORDER_ORIGIN STR [0] "Englewood; CO; 80112; USA;[060050006000,1,1]"
1  PIN_FLD_ORDER_ACCEPT STR [0] "Englewood; CO; 80112; USA;[060050006000,1,1]"
1  PIN_FLD_LOCATION_MODE ENUM [0] 1
1  PIN_FLD_INTERNATIONAL_IND INT [0] 1
  

By default, the PCM_OP_RATE_POL_TAX_LOC policy opcode uses the sources for locations described in Table 4-1:

Table 4-1 PCM_OP_RATE_POL_TAX_LOC Source Locations

Location Default Source

PIN_FLD_SHIP_TO

The account billing address, obtained from the PIN_FLD_NAMEINFO array of the /account object.

PIN_FLD_SHIP_FROM

Same as PIN_FLD_ORDER_ACCEPT.

PIN_FLD_ORDER_ACCEPT

The value for the fm_rate_pol provider_loc entry in the CM pin.conf file. For information on the default PIN_FLD_ORDER_ACCEPT location, see the fm_rate_pol provider_loc entry in the CM pin.conf file.

PIN_FLD_ORDER_ORIGIN

Same as PIN_FLD_ORDER_ACCEPT.


Using Custom Tax Rates

If your business uses a relatively uncomplicated tax calculation method, you may not need to use a tax calculation software package. You can use custom tax rates instead. In simple cases, you can implement taxation using built-in features that do not require programming. See "Calculating Flat Taxes by Using the taxcodes_map File" for more information.

If your business requires a more complex tax structure but does not require the full capabilities of one of the taxation packages, you can implement custom tax rates by modifying the two taxation policy opcodes: PCM_OP_CUST_POL_TAX_INIT and PCM_OP_CUST_POL_TAX_CALC.

The PCM_OP_CUST_POL_TAX_INIT policy opcode caches tax rate information from the file specified by the taxcodes_map entry in the CM pin.conf file. PCM_OP_CUST_POL_TAX_CALC caches the entries in this file in which the Tax Pkg value is U (user code). It ignores all the other entries including the tax codes Vertex tax calculation software.

If no tax calculation software is configured, the PCM_OP_CUST_POL_TAX_INIT policy opcode calls the PCM_OP_CUST_POL_TAX_CALC policy opcode to use the custom tax rates in the cache instead of calling a taxation DM. The PCM_OP_CUST_POL_TAX_CALC policy opcode performs the actual tax calculation.

To use custom tax rates:

  1. Define tax rates in a text file.

    You can use the default file (BRM_Home/sys/cm/taxcodes_map) as a starting place. See "Calculating Flat Taxes by Using the taxcodes_map File" for information about the file.

  2. If you change the name or location of the taxcodes_map file, modify the taxcodes_map entry in the CM configuration file (BRM_Home/sys/cm/pin.conf) to point to the new name and location.

  3. Modify the source file for the PCM_OP_CUST_POL_TAX_INIT policy opcode (BRM_SDK_Home/source/sys/fm_cust_pol/fm_cust_pol_tax_init.c) to implement your customizations.

    1. If you plan to load tax code data in a different format than is used by default in the taxcodes_map file, define a data structure in fm_cust_pol_tax_init.c for your custom tax rates.

    2. Perform any other customizations required in fm_cust_pol_tax_init.c to implement your custom tax features.

  4. If necessary for your customizations, modify the source file for the PCM_OP_CUST_POL_TAX_CALC policy opcode (BRM_SDK_Home/source/sys/fm_cust_pol_tax_calc.c).

  5. Compile fm_cust_pol_tax_init.c and fm_cust_pol_tax_calc.c by using the makefile in the BRM_SDK_Home/source/sys/fm_cust_pol directory.

  6. Copy the compiled shared library files to BRM_Home/lib, replacing the existing versions.

  7. Open the CM configuration file (pin.conf) and ensure that the following entries in the fm_module section are enabled (not commented out):

    - cm fm_module BRM_Home/lib/fm_cust.a fm_cust_config - pin
    - cm fm_module BRM_Home/lib/fm_cust_pol.a fm_cust_pol_config fm_cust_pol_tax_init pin
      
    

    Note:

    The example above shows the entries for AIX systems. The file name extension is .so for Solaris, Linux, and HP-UX IA64 systems.
  8. Stop and restart the CM.

    See the discussion of starting and stopping the BRM system in BRM System Administrator's Guide, for more information.

Retrieving Additional Tax Data from Vertex Communications Tax Q Series

When you perform tax calculation by using Vertex Communications Tax Q Series, it returns tax data in an input flist to the BRM API. The tax data is then processed and stored in the BRM database. For a list of data that Vertex Communications Tax Q Series returns to the BRM API by default, see "Default Tax Data Returned by Vertex Communications Tax Q Series" for more information.

You can also customize BRM to request and store additional data from Vertex Communications Tax Q Series by performing the following:

  1. Requesting additional data from Vertex Communications Tax Q Series.

    See "Requesting Additional Data from Vertex Communications Tax Q Series" for more information.

  2. Retrieving the additional tax data returned by Vertex Communications Tax Q Series.

    See "Requesting Additional Data from Vertex Communications Tax Q Series" for more information.

  3. Storing the additional tax data in the BRM database.

    See "Storing the Requested Vertex Tax Data in the BRM Database" for more information.

Default Tax Data Returned by Vertex Communications Tax Q Series

Vertex Communications Tax Q Series makes its attributes available to other applications through data handles. BRM uses tax data from the following two data handles only:

  • The Register Transaction data handle, which defines tax transaction attributes.

  • The Register Transaction Tax Detail data handle, which defines tax jurisdiction attributes.

Vertex Communications Tax Q Series sends tax attributes to the BRM API in the following input flist structures:

  • PIN_FLD_TAXES input flist array: Contains the result of a tax calculation at the transaction level.

  • PIN_FLD_TAXES.PIN_FLD_SUBTOTAL input flist array: Contains the result of a tax calculation at the jurisdiction level, such as at the Federal level or at the State level. Within each jurisdiction, the taxes are broken into subtypes, such as 911 and DEAF.

Table 4-2 shows the tax attributes that are sent to the BRM API by default and the flist structure in which the attribute is passed:

Table 4-2 Default BRM Tax Attributes and flist Structure

Vertex Communications Tax Q Series Data Handle Vertex Communications Tax Q Series Attributes BRM Input Flist Structure

Register Transaction data handle

  • eCtqAttribChargeToLocationMode

  • eCtqAttribChargeToPostalCode

  • eCtqAttribTaxedGeoCodeOverrideCode

  • eCtqAttribInvoiceDate

  • eCtqAttribBilledLines

  • eCtqAttribInvoiceNumber

  • eCtqAttribServiceCode

  • eCtqAttribCategoryCode

  • eCtqAttribCreditCode

  • eCtqAttribDescriptionFlag

  • eCtqAttribTaxedGeoCodeIncorporatedCode

  • eCtqAttribFederalExemptFlag

  • eCtqAttribStateExemptFlag

  • eCtqAttribCountyExemptFlag

  • eCtqAttribCityExemptFlag

  • eCtqAttribWriteJournal

Note: The eCtqAttribWriteJournal attribute is retrieved from the Register Subsystem data handle.

PIN_FLD_TAXES array

Register Transaction Tax Detail data handle

  • eCtqAttribTrunksTaxed

  • eCtqAttribTaxCode

  • eCtqAttribLinkTaxAmount

  • eCtqAttribRowCount

PIN_FLD_TAXES.PIN_FLD_SUBTOTAL array


For more information about Vertex Communications Tax Q Series data handles and attributes, see the Vertex Communications Tax Q Series documentation.

Requesting Additional Data from Vertex Communications Tax Q Series

You can request additional tax data from Vertex Communications Tax Q Series by customizing the PCM_OP_RATE_POL_PRE_TAX policy opcode. Vertex Communications Tax Q Series returns the requested tax data in the input flist to the PCM_OP_RATE_POL_POST_TAX policy opcode.

To request additional tax data:

  • Customize the PCM_OP_RATE_POL_PRE_TAX policy opcode to request data from the following two Vertex data handles: Register Transaction data handle and Register Transaction Tax Detail data handle.

  • Add custom output flist fields to the PCM_OP_RATE_POL_PRE_TAX policy opcode. To request additional tax data, add the flist fields shown in bold below to the PIN_FLD_RESULTS output flist array:

    0 PIN_FLD_RESULTS           ARRAY [0] allocated 20, used 1
    1   PIN_FLD_TAXES                 [0] allocated 20, used 1
    2     PIN_FLD_FIELD_NAMES   ARRAY [ArrayIndexValue] allocated 20, used 2
    3       PIN_FLD_TYPE         ENUM [0] VertexDataType
    1   PIN_FLD_SUBTOTAL              [0] allocated 20, used 1
    2     PIN_FLD_FIELD_NAMES   ARRAY [ArrayIndexValue] allocated 20, used 2
    3       PIN_FLD_TYPE         ENUM [0] VertexDataType
      
    

    where:

    The PIN_FLD_TAXES structure specifies that you are requesting data from the Vertex Register Transaction data handle. All elements under this array must reference attributes from the Register Transaction data handle only.

    The PIN_FLD_SUBTOTAL structure specifies that you are requesting data from the Vertex Register Transaction Tax Detail data handle. All elements under this array must reference attributes from the Register Transaction Tax Detail data handle only.

    ArrayIndexValue specifies the Vertex Communications Tax Q Series attribute ID that you are requesting. For example, set the PIN_FLD_FIELD_NAMES array index to 304 to request the eCtqAttribTrunksTaxed attribute.

    VertexDataType specifies the Vertex data type ID for the Vertex Communications Tax Q Series attribute you are requesting. Supported Vertex data types include the following:

    • eCtqInt

    • eCtqString

    • eCtqBool

    • eCtqFloat

    • eCtqDouble

    • eCtqLong

    • eCtqDate

For example, the following shows custom output flist fields for requesting additional tax data:

0 PIN_FLD_RESULTS                ARRAY [0] allocated 20, used 1 
1   PIN_FLD_TAXES                      [0] allocated 20, used 1 
2     PIN_FLD_FIELD_NAMES        ARRAY [271] allocated 20, used 2 
3       PIN_FLD_TYPE              ENUM [0] 3 
1   PIN_FLD_SUBTOTAL                   [0] allocated 20, used 1 
2     PIN_FLD_FIELD_NAMES        ARRAY [285] allocated 20, used 2 
3       PIN_FLD_TYPE              ENUM [0] 10 

Retrieving Additional Tax Data

The additional data you request from Vertex Communications Tax Q Series is returned in the input flist of the PCM_OP_RATE_POL_POST_TAX policy opcode. You can customize the BRM API to retrieve the tax data from the input flist fields and process it according to your business needs.

Vertex Communications Tax Q Series returns the additional data in the following PCM_OP_RATE_POL_POST_TAX policy opcode input flist structure under the PIN_FLD_TAXES array or the PIN_FLD_TAXES.PIN_FLD_SUBTOTAL array:

  • If passed in the PIN_FLD_TAXES array, the data is for one tax transaction. This information is from the Register Transaction data handle.

  • If passed in the PIN_FLD_TAXES.PIN_FLD_SUBTOTAL array, the tax data is for one jurisdiction. This information is from the Register Transaction Tax Detail data handle.

    1  PIN_FLD_FIELD_NAMES           ARRAY [ArrayIndexValue] allocated 20, used 3
    2    PIN_FLD_TYPE                      ENUM [0] VertexDataType
    2    PIN_FLD_VERTEX_CTQ_BRMDataType   INT [0] BRMTaxData
      
    

    where:

    ArrayIndexValue specifies the Vertex Communications Tax Q Series attribute ID. For example, enter 295 to request data from the eCtqAttribTaxedGeoCode attribute.

    VertexDataType specifies the data type ID of the Vertex Communications Tax Q Series attribute. For example, enter 3 for the eCtqInt data type.

    BRMTaxData is the tax data from the specified Vertex Communications Tax Q Series attribute.

    PIN_FLD_VERTEX_CTQ_BRMDataType is the name of the input flist field that contains the tax data. Table 4-3 specifies the name of the BRM input flist field that corresponds to each Vertex data type.

    Table 4-3 BRM Input flist for Vertex Data Type

    BRM Data Type Vertex Data Type

    INT

    eCtqInt

    STR

    eCtqString

    BOOL

    eCtqBool

    FLOAT

    eCtqFloat

    DOUBLE

    eCtqDouble

    LONG

    eCtqLong

    STR

    Important: This field will contain the date in Vertex Communications Tax Q Series format (CCYYMMDD). This is different from the mapping for custom input fields, in which eCtqDate is mapped to PIN_FLD_VERTEX_CTQ_TIMESTAMP.

    eCtqDate


For example, the following shows a simple input flist for the PCM_OP_RATE_POL_POST_TAX policy opcode. The flist fields for the additional tax data are shown in bold.

# number of field entries allocated 20, used 2
0 PIN_FLD_POID                  POID [0] 0.0.0.1 /account 27225 0
0 PIN_FLD_EVENT_OBJ             POID [0] 0.0.0.1 /event/billing/cycle/tax 11111 0
0 PIN_FLD_TAXES                ARRAY [0] allocated 20, used 3
1   PIN_FLD_TAXPKG_TYPE         ENUM [0] 0
1   PIN_FLD_TAX              DECIMAL [0] 0.70
1   PIN_FLD_FIELD_NAMES         ARRAY [295] allocated 20, used 3  // Array index = eCtqAttribTaxedGeoCode
2     PIN_FLD_TYPE              ENUM [0] 10
2     PIN_FLD_VERTEX_CTQ_STR     STR [0] "123456789"
1   PIN_FLD_SUBTOTAL           ARRAY [0] allocated 20, used 10
2     PIN_FLD_TAX            DECIMAL [0] 0.70
2     PIN_FLD_TYPE              ENUM [0] 0
2     PIN_FLD_NAME               STR [0] "US; CA; Sunnyvale; ; 94086"
2     PIN_FLD_AMOUNT_GROSS   DECIMAL [0] 19.88
2     PIN_FLD_PERCENT        DECIMAL [0] 0.035000
2     PIN_FLD_AMOUNT_TAXED   DECIMAL [0] 19.88
2     PIN_FLD_AMOUNT_EXEMPT  DECIMAL [0] 0.00
2     PIN_FLD_SUBTYPE           ENUM [0] 0
2     PIN_FLD_DESCR              STR [0] "Excise"
2     PIN_FLD_LOCATION_MODE     ENUM [0] 0
2     PIN_FLD_FIELD_NAMES       ARRAY [304] allocated 20, used 3  // Array index = eCtqAttribTrunksTaxed
3       PIN_FLD_TYPE            ENUM [0] 3
3       PIN_FLD_VERTEX_CTQ_INT   INT [0] 1
  

Each PIN_FLD_TAXES array element results in a single balance impact. All tax data from the PIN_FLD_TAXES array element is stored in the BRM /event object in the PIN_FLD_BAL_IMPACTS array.

Each PIN_FLD_TAXES.PIN_FLD_SUBTOTAL array element results in a single balance impact for a jurisdiction. All tax data for that jurisdiction is stored in the BRM /event object in the PIN_FLD_TAX_JURISDICTIONS array.

Note:

In some cases, a Vertex attribute may be missing from the input flist of the PCM_OP_RATE_POL_POST_TAX policy opcode. This could be due to an exception condition. For example:
  • If taxes do not apply because of an undefined service code. In this case, the PIN_FLD_SUBTOTAL array will have a zero tax amount, but none of the additional output fields.

  • If BRM requested a non-applicable attribute. For example, if BRM requested the eCtqAttribOriginGeoCode attribute when calculating taxes for a wireless service based on the PPU location passed in as a ZIP code.

Storing the Requested Vertex Tax Data in the BRM Database

All additional Vertex Communications Tax Q Series data that you request is returned in the PCM_OP_RATE_POL_POST_TAX policy opcode input flist. To customize the policy opcode to store the additional data in the BRM database:

Creating a Custom Storable Class for Vertex Tax Data

To store the additional data from Vertex Communications Tax Q Series, create a custom tax storable class, such as /custom/tax/ctq_output. The structure of the custom tax storable class should be similar to the following flist:

Note:

Make sure you define all fields in the custom tax storable class.
PIN_FLD_POID
PIN_FLD_ACCOUNT_OBJ
PIN_FLD_EVENT_OBJ
   PIN_FLD_CUSTOM_TAX_BAL_IMPACTS           ARRAY
      PIN_FLD_CUSTOM_TAX_TAXED_GEO_CODE     STR
...
   PIN_FLD_CUSTOM_TAX_TAX_JURISDICTIONS     ARRAY
      PIN_FLD_ELEMENT_ID                    INT
      PIN_FLD_CUSTOM_TAX_TRUNKS_TAXED       INT
  

See "Creating Custom Fields and Storable Classes" in BRM Developer's Guide for more information on how to create custom storable classes and custom BRM fields.

Storing Vertex Tax Data in Your Custom Storable Class

To store the additional Vertex Communications Tax Q Series tax data in your custom tax storable class, customize the PCM_OP_RATE_POL_POST_TAX policy opcode as follows:

  1. Add the following compiler directives to include Vertex Communications Tax Q Series compiler definitions and copy these files from the Vertex Communications Tax Q Series installation directory to the directory in which the policy source code resides.

    #include "stda.h"
    #include "ctqa.h"
      
    
  2. In the policy source code directory, modify Makefile to add the -DPORT_UNIXANSI Compiler option.

    For example, you can use the CFLAGS variable as follows:

    CFLAGS += -DPORT_UNIXANSI
      
    
  3. Create a new flist instance of your custom tax storable class and set PIN_FLD_EVENT_OBJ of this instance in the /event object.

  4. In your custom tax storable class:

    • Add a PIN_FLD_CUSTOM_TAX_BAL_IMPACTS array element for each PIN_FLD_TAXES element passed in the PCM_OP_RATE_POL_POST_TAX input flist.

    • In the PIN_FLD_CUSTOM_TAX_BAL_IMPACTS element, set each custom tax storable class field to its corresponding value from the PIN_FLD_TAXES input flist array. For example, set the PIN_FLD_CUSTOM_TAX_TAXED_GEO_CODE storable class field to the value in the PIN_FLD_VERTEX_CTQ_STR input flist field.

    • Add a PIN_FLD_CUSTOM_TAX_TAX_JURISDICTIONS array element for each PIN_FLD_TAXES.PIN_FLD_SUBTOTAL element passed in the PCM_OP_RATE_POL_POST_TAX input flist.

    • In the PIN_FLD_CUSTOM_TAX_TAX_JURISDICTIONS element, set each custom tax storable class field to its corresponding value from the PIN_FLD_SUBTOTAL input flist array. For example, set the PIN_FLD_CUSTOM_TAX_TRUNKS_TAXED storable class field to the value in the PIN_FLD_VERTEX_CTQ_INT input flist field.

    • Link each PIN_FLD_CUSTOM_TAX_TAX_JURISDICTIONS element to its corresponding parent PIN_FLD_CUSTOM_TAX_BAL_IMPACTS element by using the PIN_FLD_ELEMENT_ID field.

      Note:

      BRM uses this same method to link PIN_FLD_TAX_JURISDICTIONS elements to corresponding parent PIN_FLD_BAL_IMPACTS elements in the /event object.
  5. Create an instance of your custom tax storable class in the BRM database by calling the PCM_OP_CREATE_OBJ opcode.

  6. Drop the PIN_FLD_FIELD_NAMES arrays from the PCM_OP_RATE_POL_POST_TAX policy opcode output flist, because they are no longer needed.

    Note:

    • In the rare case that no taxes are computed, the policy input flist will include a single PIN_FLD_TAXES element set to 0 and no PIN_FLD_SUBTOTAL elements. Likewise, when a jurisdiction check is performed to validate the account address, the policy input flist will not include a PIN_FLD_TAXES element. In both cases, you do not need to create a new instance of your custom tax storable class.

    • For event-time taxation, the PCM_OP_RATE_POL_POST_TAX policy opcode input flist does not include the PIN_FLD_EVENT_OBJ field.

    • For reporting purposes, you can relate a taxed event's default tax fields with the additional tax fields by using the /event POID as the join criterion between the /event object and your custom tax object.

Modifying Tax Data Before Calculating Taxes

Use the PCM_OP_RATE_POL_PRE_TAX policy opcode to modify data before you send the data to the taxation DM for calculating taxes.

In the default implementation, this policy opcode is called by PCM_OP_RATE_TAX_CALC before determining the tax package to use for tax calculation.

By default, the PCM_OP_RATE_POL_PRE_TAX policy opcode returns the input flist as the output flist. You can customize the policy opcode to perform these functions:

  • Identify the geocode for an address and provide it to the taxation DM.

  • Add a tax exemption to the input flist before sending the flist to the taxation DM.

  • Change the tax exemption from a percentage to a set amount. For example, deduct x amount from the taxable amount because the first x amount is exempt from taxes.

In addition, the policy opcode source file contains commented code for enhancements available to Vertex Communications Tax Q Series users.

Customizing Vertex Communications Tax Q Series to Override ZIP Codes

For Vertex Communications Tax Q Series, the PCM_OP_RATE_POL_PRE_TAX policy source file contains commented code to instruct the Vertex Communications Tax Q Series taxation software to override the ZIP code. This enables the Vertex DM to charge taxes for non-telephony events by using Vertex Communications Tax Q Series.

To customize Vertex Communications Tax Q Series to override ZIP codes:

  1. Open the PCM_OP_RATE_POL_PRE_TAX policy source file with a text editor.

  2. Uncomment the code.

  3. Define the OVERRIDE_BY_ZIP symbol.

  4. Save and close the file.

  5. Recompile the policy opcode.

Customizing Vertex Communications Tax Q Series to Provide Custom Input Tax Data

For Communications Tax Q Series, you can modify the PCM_OP_RATE_POL_PRE_TAX policy opcode source code to use a customized input flist to the taxation DM for tax data. The taxation DM checks the input flist. If it includes the PIN_FLD_STATUS_FLAGS field with the value 1, the DM sets all custom fields included in the flist and then calls the tax package to calculate taxes.

Note:

When you create the customized flist, make sure that you express the field values on the basis of Vertex field data types. Add the correct data type and value for each Vertex attribute that you want to customize. If you want to see your customized flist, you can use PIN_ERR_LOG_FLIST in debug mode.

To customize the PCM_OP_RATE_POL_PRE_TAX policy opcode:

  1. Open BRM_SDK_Home/source/sys/fm_rate_pol/fm_rate_pol_pre_tax.c file.

  2. Add the code from "Source Code for Customizing PCM_OP_RATE_POL_PRE_TAX" to the fm_rate_pol_pre_tax() function after the OVERRIDE_BY_ZIP section.

  3. Add optional fields to customize the tax calculation process (the source code includes a comment about how to add new fields).

  4. Define the USE_VERTEX_Q_SERIES symbol.

  5. Add stda.h and ctqa.h to the Include section of the file.

  6. Set the value of customized_flag to 1, if it is not already set to that value.

  7. Save and close the file.

  8. Copy the stda.h and ctqa.h files from the Vertex_Home/inc directory to the BRM_SDK_Home/source/sys/fm_rate_pol directory.

  9. To the Makefile, add CFLAGS += -DPORT_UNIXANSI.

  10. Recompile the policy opcode.

Source Code for Customizing PCM_OP_RATE_POL_PRE_TAX

#ifdef USE_VERTEX_Q_SERIES
/***************************************************************************
      /*****************************************************************
      * FOLLOWING MANDATORY FIELDS SHOULD BE FILLED WITH CORRECT VALUES.
      * YOU CAN CUSTOMIZE THE MANDATORY AND OPTIONAL FIELDS.
      * HERE IS THE LIST OF MAPPING FIELDS.
      * VERTEX DATATYPE => MAPPING FIELD              =>PORTAL DATATYPE
      *
      * eCtqString    =>PIN_FLD_VERTEX_CTQ_STR        =>PIN_FLDT_STR
      * eCtqInt       =>PIN_FLD_VERTEX_CTQ_INT        =>PIN_FLDT_INT
      * eCtqFloat     =>PIN_FLD_VERTEX_CTQ_FLOAT      =>PIN_FLDT_DECIMAL
      * eCtqDouble    =>PIN_FLD_VERTEX_CTQ_DOUBLE     =>PIN_FLDT_DECIMAL
      * eCtqLong      =>PIN_FLD_VERTEX_CTQ_LONG       =>PIN_FLDT_DECIMAL
      * eCtqDate      =>PIN_FLD_VERTEX_CTQ_DATE       =>PIN_FLDT_TSTAMP
      * eCtqTime      =>PIN_FLD_VERTEX_CTQ_TIME       =>PIN_FLDT_TSTAMP
      * eCtqTimestamp =>PIN_FLD_VERTEX_CTQ_TIMESTAMP  =>PIN_FLDT_TSTAMP
      * eCtqBool      =>PIN_FLD_VERTEX_CTQ_BOOL       =>PIN_FLD_INT
      * eCtqChar      =>PIN_FLD_VERTEX_CTQ_CHAR       =>PIN_FLDT_STR
      * eCtqEnum      =>PIN_FLD_VERTEX_CTQ_ENUM       =>PIN_FLDT_ENUM
      *
      * YOU CAN ADD ONE FIELD LIKE THE FOLLOWING FLIST FORMAT.
      0 PIN_FLD_TAXES         ARRAY [] allocated 24, used 24
      1 PIN_FLD_FIELD_NAMES   ARRAY [] allocated 20, used 2
              2     PIN_FLD_TYPE             ENUM [0]
              2     PIN_FLD_VERTEX_CTQ_STR    STR [0]
      * USE PROPER MAPPING FIELD TO SET VALUE OF VERTEX FIELD.
      * IF YOU ADD SOME STRING FIELD(eCtqString),THEN SET VALUE FOR THAT FIELD
      * USING PIN_FLD_VERTEX_CTQ_STR.FOR DETAILS,SEE THE ABOVE TABLES.
      *
      *
      * TO OVERRIDE DETAILED TAX INFORMATION (ATTRIBUTES THAT SET IN
      * REGTAX HANDEL IN VERTEX) SUCH AS TAX CODE, TAX TYPE, RATE, AND
      * TAX AUTHROITY, THE FIELD VALUES NEED TO SPECIFY UNDER THE
      * TAX_INPUT ARRAY, WITH INDEX STARTS FROM 1.
      * EX:
      *  0 PIN_FLD_TAXES         ARRAY [] allocated 24, used 24
      *  ....
      *  1     PIN_FLD_TAX_INPUT     ARRAY [1] allocated 20, used 4
      *  2         PIN_FLD_FIELD_NAMES   ARRAY [340] allocated 20, used 2
      *  3             PIN_FLD_TYPE           ENUM [0] 10
      *  3             PIN_FLD_VERTEX_CTQ_STR    STR [0] "40"
      *  2         PIN_FLD_FIELD_NAMES   ARRAY [339] allocated 20, used 2
      *  3             PIN_FLD_TYPE           ENUM [0] 10
      *  3             PIN_FLD_VERTEX_CTQ_STR    STR [0] "0"
      *  2         PIN_FLD_FIELD_NAMES   ARRAY [341] allocated 20, used 2
      *  3             PIN_FLD_TYPE           ENUM [0] 10
      *  3             PIN_FLD_VERTEX_CTQ_STR    STR [0] "X"
      *  2         PIN_FLD_FIELD_NAMES   ARRAY [224] allocated 20, used 2
      *  3             PIN_FLD_TYPE           ENUM [0] 6
      *  3             PIN_FLD_VERTEX_CTQ_DOUBLE DECIMAL [0] 0
      *
      *
      * CUSTOMIZED FIELDS ARE SET INSIDE THE TAXES ARRAY ELEMENTS. WHEN THE 
      * CUSTOMIZATION FLAG IS SET, ONLY CUSTOMIZED FIELDS (FIELD_NAMES
      * UNDER TAXES AND FIELD_NAMES UNDER TAX_INPUT) ARE CONSIDERED. REST 
      * OF THE FIELDS ARE NEGLECTED.      
******************************************************************/
      pin_flist_t     *cust_flistp = NULL;
      pin_flist_t     *field_name_flistp = NULL;
      tCtqAttribType  attribute_type = eCtqHandle ;
      time_t          now_t = 0;
      pin_decimal_t   *value_decimal = NULL;
      int32           value_int = 0;
      char            temp_buf[255] = { '\0' };
      pin_cookie_t    cookie = NULL;
      pin_flist_t     *t_flistp = NULL;
      pin_flist_t     *ti_flistp = NULL;
      int32           elemid = 0;
  
      int32           customized_flag = 1;/* SET TO 1 FOR CUSTOMIZATION */
  
      /*****************************************************************
       * IMPORTANT:SET customized_flag to 1 IF YOU WANT TO CUSTOMIZE THE
       * VERTEX FIELDS.
       *****************************************************************/
      PIN_FLIST_FLD_SET(cust_flistp, PIN_FLD_STATUS_FLAGS,
              (void *)&customized_flag, ebufp);
              while ((t_flistp = PIN_FLIST_ELEM_GET_NEXT(ret_flistp, PIN_FLD_TAXES, 
              &elemid, 1, &cookie, ebufp)) != (pin_flist_t*)NULL) {
  
              cust_flistp = PIN_FLIST_CREATE(ebufp);
  
      /* FIELD:eCtqAttribCategoryCode NATURE:Mandatory Field */
  
      field_name_flistp = PIN_FLIST_ELEM_ADD(cust_flistp, PIN_FLD_FIELD_NAMES,
              eCtqAttribCategoryCode, ebufp);
      attribute_type = eCtqString;
      temp_buf[0]='\0';
      strcpy(temp_buf ,"04") ;
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_TYPE,
              (void *)&attribute_type,ebufp);
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_VERTEX_CTQ_STR,
              (void *)temp_buf,ebufp);
  
      /* FIELD:eCtqAttribServiceCode NATURE:Mandatory Field */
  
      field_name_flistp = PIN_FLIST_ELEM_ADD(cust_flistp, PIN_FLD_FIELD_NAMES,
              eCtqAttribServiceCode, ebufp);
  
      attribute_type = eCtqString;
      temp_buf[0]='\0';
      strcpy(temp_buf,"01" );
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_TYPE,
              (void *)&attribute_type,ebufp);
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_VERTEX_CTQ_STR,
              (void *)temp_buf,ebufp);
  
      /* FIELD:eCtqAttribOriginGeoCode NATURE:Mandatory Field */
  
      field_name_flistp = PIN_FLIST_ELEM_ADD(cust_flistp, PIN_FLD_FIELD_NAMES,
              eCtqAttribOriginGeoCode, ebufp);
      attribute_type = eCtqString;
      temp_buf[0]='\0';
      strcpy(temp_buf ,"390290740" );
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_TYPE,
              (void *)&attribute_type,ebufp);
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_VERTEX_CTQ_STR,
              (void *)temp_buf,ebufp);
  
      /* FIELD:eCtqAttribTerminationGeoCode NATURE:Mandatory Field */
  
      field_name_flistp = PIN_FLIST_ELEM_ADD(cust_flistp, PIN_FLD_FIELD_NAMES,
              eCtqAttribTerminationGeoCode, ebufp);
  
      attribute_type = eCtqString;
      temp_buf[0]='\0';
      strcpy(temp_buf,"390296350") ;
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_TYPE,
              (void *)&attribute_type,ebufp);
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_VERTEX_CTQ_STR,(void *)temp_buf,
              ebufp);
  
      /* FIELD:eCtqAttribInvoiceDate NATURE:Mandatory Field */
  
      field_name_flistp = PIN_FLIST_ELEM_ADD(cust_flistp, PIN_FLD_FIELD_NAMES,
              eCtqAttribInvoiceDate, ebufp);
      attribute_type=eCtqDate;
      now_t = pin_virtual_time((time_t *)NULL);
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_TYPE,
              (void *)&attribute_type,ebufp);
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_VERTEX_CTQ_DATE,&now_t,
              ebufp);
  
      /* FIELD:eCtqAttribTaxableAmount NATURE:Mandatory Field */
  
      field_name_flistp = PIN_FLIST_ELEM_ADD(cust_flistp, PIN_FLD_FIELD_NAMES,
              eCtqAttribTaxableAmount, ebufp);
      attribute_type = eCtqDouble;
      value_decimal = pbo_decimal_from_str("100.00",ebufp);
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_TYPE,
              (void *)&attribute_type,ebufp);
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_VERTEX_CTQ_DOUBLE,
              (void *)value_decimal,ebufp);
  
  
      /**********************************************************************
       * YOU CAN ADD OPTIONAL FIELDS LIKE BELOW FLIST
       *
       * field_name_flistp = PIN_FLIST_ELEM_ADD(cust_flistp,
              PIN_FLD_FIELD_NAMES,eCtqAttribBilledLines, ebufp);
       * attribute_type = eCtqInt;
       * PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_TYPE,
              (void *)&attribute_type,ebufp);
       * int value_int = 01
       * PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_VERTEX_CTQ_INT,
              (void *)&value_int,ebufp);
       **********************************************************************/
       field_name_flistp = PIN_FLIST_ELEM_ADD(cust_flistp, PIN_FLD_FIELD_NAMES,
              eCtqAttribBilledLines, ebufp);
       attribute_type = eCtqInt;
       value_int = 01;
       PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_TYPE,
              (void *)&attribute_type,ebufp);
       PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_VERTEX_CTQ_INT,
              (void *)&value_int,ebufp);
      field_name_flistp = PIN_FLIST_ELEM_ADD(cust_flistp, PIN_FLD_FIELD_NAMES,
              eCtqAttribSaleResaleCode, ebufp);
      attribute_type = eCtqString;
      temp_buf[0]='\0';
      strcpy(temp_buf ,"S" );
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_TYPE,
              (void *)&attribute_type,ebufp);
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_VERTEX_CTQ_STR,
              temp_buf,ebufp);
  
      field_name_flistp = PIN_FLIST_ELEM_ADD(cust_flistp, PIN_FLD_FIELD_NAMES,
              eCtqAttribChargeToGeoCode, ebufp);
      attribute_type = eCtqString;
      temp_buf[0]='\0';
      strcpy(temp_buf ,"390296350" );
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_TYPE,
              (void *)&attribute_type,ebufp);
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_VERTEX_CTQ_STR,
              temp_buf,ebufp);
  
      field_name_flistp = PIN_FLIST_ELEM_ADD(cust_flistp, PIN_FLD_FIELD_NAMES,
              eCtqAttribCallMinutes, ebufp);
      attribute_type = eCtqDouble;
      value_decimal = pbo_decimal_from_str("10.0",ebufp);
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_TYPE,
              (void *)&attribute_type,ebufp);
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_VERTEX_CTQ_DOUBLE,
              (void *)value_decimal,ebufp);
  
      field_name_flistp = PIN_FLIST_ELEM_ADD(cust_flistp, PIN_FLD_FIELD_NAMES,
              eCtqAttribUserArea, ebufp);
      attribute_type = eCtqString;
      temp_buf[0]='\0';
      strcpy(temp_buf ,"Interstate/Toll");
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_TYPE,
              (void *)&attribute_type,ebufp);
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_VERTEX_CTQ_STR,temp_buf,
              ebufp);
  
      field_name_flistp = PIN_FLIST_ELEM_ADD(cust_flistp, PIN_FLD_FIELD_NAMES,
              eCtqAttribInvoiceNumber, ebufp);
      attribute_type = eCtqString;
      temp_buf[0]='\0';
      strcpy(temp_buf ,"DEMO-002");
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_TYPE,
              (void *)&attribute_type,ebufp);
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_VERTEX_CTQ_STR,temp_buf,
              ebufp);
  
        /**********************************************************************
         * YOU CAN OPTIONALLY OVERRIDE DETAILED TAX INFORMATION 
         * (ATTRIBUTES THAT SET IN REGTAX HANDEL IN VERTEX) SUCH AS 
         * TAX CODE, TAX TYPE, RATE, AND TAX AUTHROITY, THE FIELD 
         * VALUES NEED TO SPECIFY UNDER THE TAX_INPUT ARRAY, WITH 
         * INDEX STARTS FROM 1.                                            
         ***********************************************************************          /
  
          ti_flistp = PIN_FLIST_ELEM_ADD(cust_flistp, PIN_FLD_TAX_INPUT, 1,
          ebufp);
          field_name_flistp = PIN_FLIST_ELEM_ADD(ti_flistp, PIN_FLD_FIELD_NAMES,
          eCtqAttribTaxType, ebufp);
          attribute_type = eCtqString;
          temp_buf[0]='\0';
          strcpy(temp_buf,"40") ;
          PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_TYPE,
          (void *)&attribute_type,ebufp);
          PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_VERTEX_CTQ_STR,(void *)
          temp_buf, ebufp);
  
          field_name_flistp = PIN_FLIST_ELEM_ADD(ti_flistp, PIN_FLD_FIELD_NAMES,
          eCtqAttribTaxAuthority, ebufp);
          attribute_type = eCtqString;
          temp_buf[0]='\0';
          strcpy(temp_buf,"0") ;
          (field_name_flistp,PIN_FLD_TYPE,
          (void *)&attribute_type,ebufp);
          PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_VERTEX_CTQ_STR,(void *)
          temp_buf, ebufp);
  
          field_name_flistp = PIN_FLIST_ELEM_ADD(ti_flistp, PIN_FLD_FIELD_NAMES,
          eCtqAttribTaxCode, ebufp);
          attribute_type = eCtqString;
          temp_buf[0]='\0';
          strcpy(temp_buf,"X") ;
          PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_TYPE, 
          (void *)&attribute_type,ebufp);
          PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_VERTEX_CTQ_STR,(void *)
          temp_buf, ebufp);
  
      field_name_flistp = PIN_FLIST_ELEM_ADD(ti_flistp, PIN_FLD_FIELD_NAMES,
      eCtqAttribRate, ebufp);
      attribute_type = eCtqDouble;
      value_decimal = pbo_decimal_from_str("0.0",ebufp);
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_TYPE,
      void *)&attribute_type,ebufp);
      PIN_FLIST_FLD_SET(field_name_flistp,PIN_FLD_VERTEX_CTQ_DOUBLE, 
      (void *)value_decimal,ebufp);
  
  
      PIN_ERR_LOG_FLIST(PIN_ERR_LEVEL_DEBUG,
              "op_rate_pol_pre_tax customized flist", cust_flistp);
      PIN_FLIST_CONCAT(ret_flistp,cust_flistp,ebufp);
      if (value_decimal) {
              pbo_decimal_destroy(&value_decimal);
      }
  
      PIN_FLIST_DESTROY_EX(&cust_flistp,NULL);
***************************************************************************/
#endif

Modifying Tax Data after Calculating Taxes

You can customize the PCM_OP_RATE_POL_POST_TAX policy opcode to modify any data in the output returned by the tax calculation software after tax calculation. For example, you can modify the policy opcode to perform these functions:

  • Change how the CM logs any messages that are returned from the external taxation DMs.

  • Add a surcharge to the tax amount in the output flist returned from the taxation DM, as shown in the following example:

    void fm_rate_pol_post_tax(...)
    {
    /* loop through array of incoming taxes */
      while(t_flistp = PIN_FLIST_ELEM_GET_NEXT(in_flistp, PIN_FLD_TAXES,
          &elemid, 1, &cookie, ebufp)) != (pin_flist_t*)NULL) {
         /* add a surcharge to the SUBTOTAL array */
          cnt = PIN_FLIST_ELEM_COUNT(t_flist, PIN_FLD_SUBTOTAL, ebufp))
          s_flistp = PIN_FLIST_ELEM_ADD(t_flistp, PIN_FLD_SUBTOTAL, cnt++, ebufp);
    ...
         /* add the entries to the SUBTOTAL array */
          PIN_FLIST_FLD_SET(s_flistp, PIN_FLD_TAX, (void*)&tax, ebufp);
          PIN_FLIST_FLD_SET(s_flistp, PIN_FLD_SUBTYPE, (void*)&taxType, ebufp);
    ...
      }
    }
      
    

Error Handling: By default, the PCM_OP_RATE_POL_POST_TAX policy opcode returns the input flist as the output flist, without the PIN_FLD_MESSAGES array. It also logs any messages returned from the taxation DM as specified in the tax_return_loglevel entry of the CM pin.conf file.

The PCM_OP_RATE_POL_POST_TAX policy opcode default implementation handles errors as follows:

  • Logs messages as specified in the tax_return_loglevel entry in the CM pin.conf file. The default is to log only warnings.

  • If an error occurs while reading the tax_return_loglevel entry, sets the error buffer to INVALID_CONF.

Using Geocodes to Calculate Taxes

A geocode is a geographic code that is used to determine a tax jurisdiction. Different tax calculation software packages use different geocode systems and update them frequently. To use geocodes to calculate taxes, you need to modify the PCM_OP_RATE_POL_PRE_TAX policy opcode to query the geocoder and obtain the geocode for an account during account creation. The geocoder maps the address or postal code of the account to a unique geocode.

If a geocode is available during tax calculation, the tax package uses it to calculate the tax. If a geocode is not available, the tax calculation software chooses the geocode with the highest tax rate from a list of geocodes it finds for that account address.

Note:

The tax calculation software itself cannot map an address to a unique geocode.

To use geocodes to calculate taxes:

  1. Using Storable Class Editor, create a /profile storable class and add the PIN_FLD_GEOCODE field to it.

    See "Creating Custom Fields and Storable Classes" in BRM Developer's Guide for more information.

    If you have configured more than one tax calculation package, create an array that contains separate PIN_FLD_GEOCODE fields for the tax calculation package. The index values should represent the tax packages:

    • 0 specifies a custom tax package.

    • 3 specifies the Sales Tax Q Series package.

    • 4 specifies the Communications Tax Q Series package.

  2. Modify the PCM_OP_CUST_POL_VALID_NAMEINFO policy opcode to store the geocode in the new PIN_FLD_GEOCODE field of the /profile object if the address was validated successfully.

  3. Implement the PCM_OP_RATE_POL_PRE_TAX policy opcode to perform the following functions:

    • Obtain the geocode from the /profile object.

    • Set the geocode in the PIN_FLD_SHIP_TO or PIN_FLD_SHIP_FROM field in the taxes array in the input flist to the taxation DM.

      For example, the opcode should change this field value:

      PIN_FLD_SHIP_TO STR [0] "Cupertino; CA; 95012; US; []"
        
      

      to include the geocode in the square brackets []:

      PIN_FLD_SHIP_TO STR [0] "Cupertino; CA; 95012; US; [050850860]"
        
      
  4. Set the location mode to geocode by supplying 1 as the value for the PIN_FLD_LOCATION_MODE field in the PIN_FLD_TAXES array of the input flist.

    When you set the location mode to geocode, the taxation DM passes the geocode instead of the address to the tax calculation module.

    For example:

    PIN_FLD_LOCATION_MODE  ENUM[0] 1
      
    

After calculating the taxes, the taxation DM returns the jurisdiction (address and geocode) where tax rates were applied in the PIN_FLD_TAXES array of the output flist:

PIN_FLD_NAME STR[0] "US: CA: Santa Clara: Cupertino: 95012 : [050850860]"

Adding Tax Information to Accounts

To add tax information to an account, use the PCM_OP_CUST_SET_TAXINFO opcode. This opcode adds or updates values for the following fields in the taxinfo array of an /account object:

  • PIN_FLD_VAT_CERT

  • PIN_FLD_EXEMPTIONS

  • PIN_FLD_INCORPORATED_FLAG

  • PIN_FLD_RESIDENCE_FLAG

For example, when an account is created and a VAT certificate number or exemption information is provided, PCM_OP_CUST_SET_TAXINFO is called. PCM_OP_CUST_SET_TAXINFO performs these functions:

  • Modifies existing data or adds information to the PIN_FLD_TAXINFO array of the /account object by using the field values provided in the input flist.

  • If a VAT certificate number is not provided, replaces the value of PIN_FLD_VAT_CERT in the account object with an empty ("") string.

  • If exemption information is not provided, deletes the PIN_FLD_EXEMPTIONS array.

  • If the field values provided in the input flist contain the PIN_FLD_INCORPORATED_FLAG or PIN_FLD_RESIDENCE_FLAG flag, adds or updates these values in the account object.

Validating Tax Information

To customize how tax information is validated, use the PCM_OP_CUST_POL_VALID_TAXINFO policy opcode. This policy opcode validates the VAT certificate number to prevent nonvalid numbers, which cause failures in tax calculations.

By default, the PCM_OP_CUST_POL_VALID_TAXINFO policy opcode checks for the VAT certificate data and performs these functions:

  • If the VAT certificate number provided is a string, zero in length, returns the validation result PASS.

  • If the following tax_valid entry in the CM pin.conf file is not set or is set to 0, returns the validation result FAIL.

    #Enables or disables validation of the VAT certificate number. 
    #1 means Enable; 0, which is the default, means Disable.
    - fm_cust_pol  tax_valid 0 
      
    
  • If the tax_valid entry in the CM pin.conf file is set to 1, invokes the PCM_OP_RATE_TAX_CALC opcode to validate the VAT certificate number by passing the special command flag PIN_FLD_COMMAND set to PIN_CUST_TAX_VAL_VAT_CERT. If you have implemented custom tax calculation, you will need to validate the VAT certificate number only if the PIN_FLD_COMMAND input field is set to PIN_CUST_TAX_VAL_VAT_CERT.

For more information, see "About the PREP and VALID Opcodes" in BRM Developer's Guide.

For example, instead of calling the PCM_OP_RATE_TAX_CALC opcode, you can query your custom VAT validation function by rewriting the function do_vat_cert_validation in the PCM_OP_CUST_POL_VALID_TAXINFO policy opcode source file.