Skip to main content
Version: 3.x

Taxclassrates

Version
3.x
Updated
View markdown

The tax rates of one geographic zone, one rate per tax class.

Storage kind: derived · Column: none

It sits on a geography record — a country, state, county or city — and edits that zone's row in #__configbox_tax_class_rates for every tax class that exists. You will not add one to a new model: it is specific to the four geography models, and taxclasstype is what tells it which.

Settings

SettingMeaning
taxclasstype'country' | 'state' | 'county' | 'city' — which zone column keys the rates

taxclasstype decides the key column (country_id, state_id, county_id, city_id) used in both the join and the write. It must match the model the property is on; nothing checks that, and a mismatch writes rates against the wrong zone.

The label is suppressed (doesShowAdminLabel() returns false) — the rendered grid carries its own headings.

The record shape follows the data

The property does not map to one column. getSelectsForGetRecord() and getJoinsForGetRecord() loop over ConfigboxPrices::getTaxClasses() and emit one join and two selects per tax class, aliased tcr_<id>, producing record keys:

KeyHolds
tax_rate_tcr_<taxClassId>the percentage rate
tax_code_tcr_<taxClassId>the reporting code

So the number of values is not fixed by the definition — it follows the tax classes that exist. Generated artifacts describe the property, not the per-class values, because the per-class values are not knowable from the definition alone. A consumer must read the tax classes first.

Writing is delete-then-insert

store() deletes every rate row for this zone and re-inserts one per tax class where either the rate or the code was submitted. Consequences worth knowing:

  • A save that does not carry the fields clears the zone's rates. Unlike multiselect, this type does not distinguish absent from empty — there is no "no instruction" path. Partial updates through the API must include them.
  • A tax class with an empty rate and an empty code gets no row at all, rather than a zero row. Absent means "no rate for this class here", and the calculation reads it that way.
  • The delete step is skipped when $data->id is 0, since a zone being created has nothing to clear; the insert step runs either way. In practice the id is always set by then — KenedoModel::store() writes the new key onto the data object before it calls any property's store() — so rates can be entered on the same save that creates the zone.

German-locale decimal commas are converted to dots on the way in, for de-DE, de-AT and de-CH only. Other locales that use a comma are not covered.

Being derived, it contributes no column to the base table and storeExternally does not apply.

@see multiselect.md — the other type whose values live in another table @see ../com_configbox_calculation_engine.md @see ../../admin-guide/commerce/set-up-taxes.md — tax classes and zones from the operator's side