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
| Object | Purpose | Key Fields |
|---|---|---|
| Group__c (TypeId = 0) | The tax group container | Name, TypeId__c, Brand__c |
| Tax__c | An individual tax record within a group | Percentage__c, Brand__c, StartDate__c, EndDate__c, TaxProfile__c |
| TaxProfileAssignment__c | Links tax profiles to specific contexts | TaxProfile__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:
| Object | Field | What It Controls |
|---|---|---|
| Item__c | TaxGroup__c | Tax applied to a specific inventory item |
| Addon__c | TaxGroup__c | Tax applied to an addon / optional extra |
| CustomType__c | TaxGroup__c | Default tax for all services of a custom type |
| FeeAssignment__c | TaxGroup__c | Tax applied to fee calculations |
| BoardBasisAssignment__c (Meal Plan Assignment) | TaxGroup__c | Tax 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__cobject is shared with other group types in Kaptio. Tax groups are distinguished byTypeId = 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
- Navigate to Setup → Kaptio → Tax Group Manager
- Click New Tax Group
- Enter a descriptive name (e.g., “US Federal + State Tax”, “EU VAT Standard”, “Zero-Rated”)
- 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:
- Open the tax group in the Tax Group Manager
- Add a new tax record
- Configure the following fields:
| Field | Required | Description |
|---|---|---|
| Percentage__c | Yes | The tax rate as a number (e.g., 10 for 10%) |
| Brand__c | No | Limits this tax record to a specific brand / business unit |
| StartDate__c | No | The date from which this tax rate is effective |
| EndDate__c | No | The date after which this tax rate no longer applies |
| TaxProfile__c | No | Links 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 item | Item__c record | Item record detail page → TaxGroup__c field |
| An addon / optional extra | Addon__c record | Addon record detail page → TaxGroup__c field |
| All services of a type | CustomType__c record | Custom Type record detail page → TaxGroup__c field |
| A fee | FeeAssignment__c record | Fee Assignment record detail page → TaxGroup__c field |
| A meal plan / board basis | BoardBasisAssignment__c record | Board 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
| Priority | Level | Description |
|---|---|---|
| 1 (highest) | Addon | If the service line is an addon and the Addon__c record has a TaxGroup__c value, use it |
| 2 | Item | If the service line references an Item__c record with a TaxGroup__c value, use it |
| 3 (lowest) | CustomType | Fall 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:
- The effective tax rate — the sum of all
Tax__cpercentages in the group - 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 Record | Percentage |
|---|---|
| Federal Tax | 10% |
| State Tax | 5% |
| Effective Rate | 15% |
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__crecords 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__crecords matching the booking’s brand (or with no brand specified) are included.
Quick Reference
| Task | Where To Do It |
|---|---|
| Create a new tax group | Setup → Kaptio → Tax Group Manager |
| Add / edit tax rates within a group | Tax Group Manager → select the group → add/edit Tax__c records |
| Assign a tax group to a service item | Item__c record → TaxGroup__c lookup field |
| Assign a tax group to an addon | Addon__c record → TaxGroup__c lookup field |
| Assign a default tax group for a service type | CustomType__c record → TaxGroup__c lookup field |
| Assign a tax group to a fee | FeeAssignment__c record → TaxGroup__c lookup field |
| Assign a tax group to a meal plan | BoardBasisAssignment__c record → TaxGroup__c lookup field |
| Check which tax group a service line is using | Trace the resolution chain: Addon → Item → CustomType |
| Handle a tax rate change | Add a new Tax__c record with the new rate and start date; set an end date on the old record |
| Make a service tax-exempt | Create a zero-rate tax group and assign it |
| Apply different tax rates per brand | Set 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:
| Object | API Name | Role in Tax System |
|---|---|---|
| Tax Group | Group__c (TypeId = 0) | Container for tax records |
| Tax | Tax__c | Individual tax rate with percentage, date range, brand, and profile |
| Tax Profile Assignment | TaxProfileAssignment__c | Links a tax profile to a tax group for granular scoping |
| Item | Item__c | Inventory item; has TaxGroup__c lookup for item-level tax |
| Addon | Addon__c | Optional extra / addon; has TaxGroup__c lookup (highest priority) |
| Custom Type | CustomType__c | Service type category; has TaxGroup__c lookup (fallback) |
| Fee Assignment | FeeAssignment__c | Fee configuration; has TaxGroup__c lookup for fee-level tax |
| Board Basis Assignment | BoardBasisAssignment__c | Meal 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 / Page | Responsibility |
|---|---|
| TaxService | Core service class for tax operations — retrieving tax groups, calculating tax amounts, and managing tax data |
| TaxGroupManagerController | Apex controller for the Tax Group Manager Visualforce page — handles CRUD operations on tax groups and tax records |
| GroupsSelector | SOQL selector for Group__c records — provides query methods filtered by TypeId and other criteria |
| PUtils | Pricing utility class — contains getTaxGroupId() which implements the addon → item → custom type resolution logic |
| PQuery | Pricing query class — retrieves tax-related data as part of pricing calculations |
| Calculator | Core pricing calculator — contains applyTax() with the inclusive/exclusive tax formulas |
| DynamicPriceQuery | Handles tax group resolution for dynamically priced services |
| PackagePriceQuery | Handles tax group resolution for package-priced services |
| CustomPriceQuery | Handles tax group resolution for custom-priced services |
| PriceLineFactory | Creates price line records including tax amount fields |
| SalesInvoiceOutputDto | Data transfer object for sales invoices — includes tax breakdown fields |
| ItineraryCostingsService | Itinerary costing calculations — applies tax groups when computing service costs |
| TaxGroupManager.page | Visualforce page providing the Tax Group Manager UI (Setup → Kaptio → Tax Group Manager) |
See Also
- Currency & FX Configuration — Setting up currencies and exchange rates, which interact with tax calculations
- Organization Structure Guide — Business units and brands, which can filter tax records
- Foundation: Currency & Tax — Broader foundation guide covering currency and tax setup together