Tax Groups in Kaptio

To be Reviewed

Detailed walkthrough of how tax groups work in Kaptio — object model, setup steps, resolution logic, and calculation formulas. Aimed at consultants and support engineers.

Version 15 min read | March 5, 2026 Gallery

Overview

A tax group in Kaptio is a container that holds one or more tax records. It is not a tax rate itself — it is the grouping mechanism that lets you define multiple tax percentages (for example, federal tax + state tax + local levy) that all apply to a single service.

Tax groups are represented by the Group__c object with TypeId = 0. Each group contains one or more Tax__c records, and each tax record defines a percentage, an effective date range, and optionally a brand and tax profile.

When to use tax groups:

  • You need to apply more than one tax percentage to a service (e.g., a 10% federal tax and a 5% state tax)
  • Different services need different tax configurations (e.g., accommodation is taxed differently from transfers)
  • Tax rates change over time and you need date-based tax records
  • Different brands or channels require different tax calculations

Object Model

The tax system in Kaptio is built on three core objects and several lookup relationships.

Core Objects

ObjectPurposeKey Fields
Group__c (TypeId = 0)The tax group containerName, TypeId__c, Brand__c
Tax__cAn individual tax record within a groupPercentage__c, Brand__c, StartDate__c, EndDate__c, TaxProfile__c
TaxProfileAssignment__cLinks tax profiles to specific contextsTaxProfile__c, TaxGroup__c

Lookup Relationships

The TaxGroup__c lookup field appears on several objects, allowing you to assign a tax group at different levels of the product hierarchy:

ObjectFieldWhat It Controls
Item__cTaxGroup__cTax applied to a specific inventory item
Addon__cTaxGroup__cTax applied to an addon / optional extra
CustomType__cTaxGroup__cDefault tax for all services of a custom type
FeeAssignment__cTaxGroup__cTax applied to fee calculations
BoardBasisAssignment__c (Meal Plan Assignment)TaxGroup__cTax applied to meal plan / board basis assignments

Relationship Diagram

Group__c (TypeId = 0)
  └── Tax__c (one or more per group)
        └── TaxProfileAssignment__c (optional profile scoping)

Item__c ────────────────┐
Addon__c ───────────────┤
CustomType__c ──────────┤──── TaxGroup__c (lookup to Group__c)
FeeAssignment__c ───────┤
BoardBasisAssignment__c ┘

Key point: The Group__c object is shared with other group types in Kaptio. Tax groups are distinguished by TypeId = 0. When querying or filtering, always include the TypeId filter to avoid mixing tax groups with other group types.


Setup Steps

Setting up tax groups is a three-step process: create the group, define the tax records inside it, and then assign the group to the services that need it.

Step 1: Create Tax Groups

  1. Navigate to Setup → Kaptio → Tax Group Manager
  2. Click New Tax Group
  3. Enter a descriptive name (e.g., “US Federal + State Tax”, “EU VAT Standard”, “Zero-Rated”)
  4. Save the group

The Tax Group Manager is a custom Visualforce page (TaxGroupManager.page) managed by TaxGroupManagerController. It provides a streamlined interface for creating and managing groups without navigating standard Salesforce record pages.

Tip: Use a naming convention that makes the tax group’s purpose immediately clear. Include the region or market and the type of tax. For example: “UK VAT 20%”, “AU GST + Tourism Levy”, “Canada Federal + Provincial”.

Step 2: Define Tax Records

Within each tax group, create one or more Tax__c records:

  1. Open the tax group in the Tax Group Manager
  2. Add a new tax record
  3. Configure the following fields:
FieldRequiredDescription
Percentage__cYesThe tax rate as a number (e.g., 10 for 10%)
Brand__cNoLimits this tax record to a specific brand / business unit
StartDate__cNoThe date from which this tax rate is effective
EndDate__cNoThe date after which this tax rate no longer applies
TaxProfile__cNoLinks to a tax profile for more granular scoping

Multiple tax records in one group: When a tax group contains multiple Tax__c records, their percentages are summed during calculation. For example, if a group has a 10% federal tax record and a 5% state tax record, the effective rate is 15%.

Date ranges: If you set start and end dates, the system only applies the tax record when the service date falls within the range. This is how you handle rate changes — create a new tax record with the new rate and a start date, and set an end date on the old one.

Brand filtering: If a tax record has a Brand__c value, it only applies when the booking is under that brand. Leave it blank to apply across all brands.

Step 3: Assign Tax Groups to Services

Assign the tax group to the appropriate objects using the TaxGroup__c lookup field:

To tax this…Set TaxGroup__c on…Where to find it
A specific inventory itemItem__c recordItem record detail page → TaxGroup__c field
An addon / optional extraAddon__c recordAddon record detail page → TaxGroup__c field
All services of a typeCustomType__c recordCustom Type record detail page → TaxGroup__c field
A feeFeeAssignment__c recordFee Assignment record detail page → TaxGroup__c field
A meal plan / board basisBoardBasisAssignment__c recordBoard Basis Assignment record detail page → TaxGroup__c field

Gotcha: If you assign a tax group at both the Item level and the CustomType level, the system uses the most specific match. See the Resolution section below for the full priority order.


Tax Group Resolution

When a service line in a booking needs a tax group, the system resolves which group to use by checking multiple levels in priority order. This logic lives in PUtils.getTaxGroupId().

Resolution Priority Order

PriorityLevelDescription
1 (highest)AddonIf the service line is an addon and the Addon__c record has a TaxGroup__c value, use it
2ItemIf the service line references an Item__c record with a TaxGroup__c value, use it
3 (lowest)CustomTypeFall back to the CustomType__c record’s TaxGroup__c value

How It Works in Practice

The resolution is a simple first-match lookup. The system checks each level in order and stops at the first one that returns a non-null tax group ID.

Example 1 — Addon with its own tax group: A “Travel Insurance” addon has TaxGroup__c set to “Insurance Premium Tax 12%”. Even though the parent item and custom type also have tax groups, the addon-level group wins.

Example 2 — Item-level tax: An accommodation item has TaxGroup__c set to “Hotel Tax 8%”. No addon is involved. The system skips the addon check (not applicable), finds the item-level tax group, and uses it.

Example 3 — CustomType fallback: A transfer service has no tax group on the item or addon. The custom type “Transfer” has TaxGroup__c set to “Standard VAT 20%”. The system falls back to this.

Example 4 — No tax group found: If none of the three levels have a tax group assigned, no tax is applied to the service line.

Troubleshooting tip: If a service line is showing unexpected tax (or no tax), check the resolution chain in order: addon → item → custom type. The first non-null value wins. A common mistake is setting a tax group on the custom type and expecting it to override an item-level assignment — it won’t.


Calculation Logic

Once a tax group is resolved, the system calculates the tax amount using formulas in Calculator.applyTax(). The two key variables are:

  1. The effective tax rate — the sum of all Tax__c percentages in the group
  2. The tax mode — inclusive (tax is included in the displayed price) or exclusive (tax is added on top)

Summing Percentages

When a tax group contains multiple Tax__c records, their percentages are summed into a single effective rate before calculation.

Tax RecordPercentage
Federal Tax10%
State Tax5%
Effective Rate15%

Exclusive Tax (Tax Added On Top)

The displayed price does not include tax. Tax is calculated and added separately.

Formula:

tax_amount = amount × (rate / 100)

Example: A service costs $100 with a 15% exclusive tax:

tax_amount = 100 × (15 / 100) = $15.00
total_with_tax = $100 + $15 = $115.00

Inclusive Tax (Tax Included in Price)

The displayed price already includes tax. The system back-calculates the tax portion.

Formula:

tax_amount = amount - (amount / (1 + rate / 100))

Example: A service is priced at $115 inclusive of 15% tax:

tax_amount = 115 - (115 / (1 + 15 / 100))
           = 115 - (115 / 1.15)
           = 115 - 100
           = $15.00
net_amount = $115 - $15 = $100.00

Edge Cases

  • Zero-rate tax group: If the effective rate is 0%, no tax is applied. This is useful for explicitly marking a service as tax-exempt (rather than leaving the tax group unassigned, which might indicate a configuration gap).
  • Date-filtered records: Only Tax__c records whose date range covers the service date are included in the sum. If no records match the date, the effective rate is 0%.
  • Brand-filtered records: Only Tax__c records matching the booking’s brand (or with no brand specified) are included.

Quick Reference

TaskWhere To Do It
Create a new tax groupSetup → Kaptio → Tax Group Manager
Add / edit tax rates within a groupTax Group Manager → select the group → add/edit Tax__c records
Assign a tax group to a service itemItem__c recordTaxGroup__c lookup field
Assign a tax group to an addonAddon__c recordTaxGroup__c lookup field
Assign a default tax group for a service typeCustomType__c recordTaxGroup__c lookup field
Assign a tax group to a feeFeeAssignment__c recordTaxGroup__c lookup field
Assign a tax group to a meal planBoardBasisAssignment__c recordTaxGroup__c lookup field
Check which tax group a service line is usingTrace the resolution chain: Addon → Item → CustomType
Handle a tax rate changeAdd a new Tax__c record with the new rate and start date; set an end date on the old record
Make a service tax-exemptCreate a zero-rate tax group and assign it
Apply different tax rates per brandSet the Brand__c field on individual Tax__c records within the group

Salesforce Objects

Full list of Salesforce objects involved in the tax group system:

ObjectAPI NameRole in Tax System
Tax GroupGroup__c (TypeId = 0)Container for tax records
TaxTax__cIndividual tax rate with percentage, date range, brand, and profile
Tax Profile AssignmentTaxProfileAssignment__cLinks a tax profile to a tax group for granular scoping
ItemItem__cInventory item; has TaxGroup__c lookup for item-level tax
AddonAddon__cOptional extra / addon; has TaxGroup__c lookup (highest priority)
Custom TypeCustomType__cService type category; has TaxGroup__c lookup (fallback)
Fee AssignmentFeeAssignment__cFee configuration; has TaxGroup__c lookup for fee-level tax
Board Basis AssignmentBoardBasisAssignment__cMeal plan / board basis; has TaxGroup__c lookup

Code References

The tax group logic spans several Apex classes. Use this table to find the relevant code when debugging or extending tax functionality.

Class / PageResponsibility
TaxServiceCore service class for tax operations — retrieving tax groups, calculating tax amounts, and managing tax data
TaxGroupManagerControllerApex controller for the Tax Group Manager Visualforce page — handles CRUD operations on tax groups and tax records
GroupsSelectorSOQL selector for Group__c records — provides query methods filtered by TypeId and other criteria
PUtilsPricing utility class — contains getTaxGroupId() which implements the addon → item → custom type resolution logic
PQueryPricing query class — retrieves tax-related data as part of pricing calculations
CalculatorCore pricing calculator — contains applyTax() with the inclusive/exclusive tax formulas
DynamicPriceQueryHandles tax group resolution for dynamically priced services
PackagePriceQueryHandles tax group resolution for package-priced services
CustomPriceQueryHandles tax group resolution for custom-priced services
PriceLineFactoryCreates price line records including tax amount fields
SalesInvoiceOutputDtoData transfer object for sales invoices — includes tax breakdown fields
ItineraryCostingsServiceItinerary costing calculations — applies tax groups when computing service costs
TaxGroupManager.pageVisualforce page providing the Tax Group Manager UI (Setup → Kaptio → Tax Group Manager)

See Also

Back to Gallery