Taxclassrates
- Version
- 4.0 preview
- Updated
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
| Setting | Meaning |
|---|---|
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:
| Key | Holds |
|---|---|
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->idis0, 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'sstore()— 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