FormTrait uses trait:short, trait:short
Builds the shipper tariff edit form (hosted in a dedicated AJAX modal on `ShipperPresenter`).
The shipper is always server-side context ($this->shipperId, set in the constructor of
ShipperTariffEdit), never
a form field. Pricing is generation based: history is immutable, bands may be open-ended,
and prices are kept per currency.
Saving goes through AdminComponentFormTrait::createAdminComponentForm()
with a custom $afterSave hook (buildAfterSave()) and never redirects the page.
Table of Contents
Properties
- $shipperTariffBandErrors : array<int, string>
- Band validation errors collected while building; `saveShipperTariffForm()` uses them to decide whether saving is allowed at all.
- $shipperTariffBandWarnings : array<int, string>
- $shipperTariffCurrentAxisDates : array{prices: ?string, payments: ?string}|null
- Date of the currently valid generation of each axis (per-request cache), see {@see getShipperTariffCurrentAxisDates()}.
-
$shipperTariffGenerationPrefill
: array{bands: list
>, payments: array }|null - Prefill for a newly added generation; computed once per request and applied to every empty container that `onCreate` meets.
Methods
- canRemoveShipperTariffGeneration() : bool
- Tells whether a generation may be removed: only a new or scheduled one (from today's midnight on). The currently valid one may not, because deleting it would make an older generation take over, a silent return to old prices.
- getShipperTariffBandIssues() : array<int, array{type: string, from: string, to: string}>
- Returns the strips between bands, as `['overlap' => range]` or `['gap' => range]` keyed by the index of the band before which the strip is rendered. It is computed on a sorted copy but returns the index in the submitted order, so the template reorders nothing.
- getShipperTariffGenerationBadgeKey() : string
- Returns the badge key of the card header. With migrated data the axes diverge (the price list is valid from another date than the matrix), giving two "current" cards, so the badge says which axis the card holds.
- getShipperTariffGenerationState() : string
- Returns `current` (valid now), `scheduled` or `history`, for the badge and card color.
- getShipperTariffGenerationSummary() : array{bands: int, currencies: int, methods: int}
- Returns the card header summary: number of bands, number of currencies with at least one price, and number of available payment methods.
- isShipperTariffGenerationDateLocked() : bool
- Tells whether the "valid from" field is locked: for history (fully read-only) and for the currently valid generation, whose values are editable but whose date is a fact; repricing from another date is a new generation. A disabled input is not posted, the build takes the date from `origDateFrom`.
- isShipperTariffGenerationOpenByDefault() : bool
- Tells whether the card's `<details>` is open by default: a new generation (empty `origDateFrom`) is open because it is being worked on; all others (valid, scheduled, history) are collapsed.
- isShipperTariffGenerationReadOnly() : bool
- Tells whether a generation is read-only. Only superseded history is: a generation before today's midnight that a newer one has replaced on its axis. The currently valid generation (even dated in the past) is editable, and a new one (empty `origDateFrom`) is always editable.
- restoreShipperTariffGenerationDisplay() : void
- Restores the display of fields that do not survive a POST followed by an AJAX redraw. The template calls it via `{do}` first in every generation card (before totals are computed).
- shipperTariffCurrencyHasPrice() : bool
- Tells whether the currency has a price in at least one band of this generation. Used only by {@see getShipperTariffGenerationSummary()} for the currency count; the template lists all currencies for every band regardless.
- createComponentEditForm() : Form
- isTargetAllowed() : bool
- Returns whether the logged-in user may open the given admin target. For visibility (tiles, autocomplete, buttons); it does not throw.
- requirePrivilege() : void
- Throws 403 when the logged-in user lacks the given admin privilege.
- resolvePageTarget() : string|null
- Returns the RBAC key of the target page: `<presenter>:<action>`, e.g. `:Admin:System:User:show`.
- resolveSupplyKindDefaultId() : int|null
- addShipperTariffBandControls() : void
- Fields of one weight band inside a generation (currency becomes a table row in the template).
- addShipperTariffGenerationMultiplier() : void
- Adds the outer `generations` multiplier, the nested `bands` multiplier and the fixed payment matrix.
- addShipperTariffMainFields() : void
- addShipperTariffPaymentMatrixControls() : void
- Adds the payment matrix of a generation: a fixed 2D loop (methods x currencies), not a multiplier, because both axes are code lists that admins do not create in this form.
- addShipperTariffTranslationFields() : void
- applyShipperTariffGenerations() : void
- Rebuilds both time series of the tariff from the submitted generations.
- buildAfterSave() : callable
- Builds the post-save action (`AdminComponentFormTrait` hook); never redirects the page for AJAX.
- buildShipperTariffBandDefaultRows() : array<int, array<string, mixed>>
- Builds the band rows of one generation, sorted by `weightFrom` and renumbered (sorting happens on load only).
- buildShipperTariffEntity() : ShipperTariff
- buildShipperTariffGenerationDefaultRows() : array<int, array<string, mixed>>
- Maps the existing series to default rows of the outer multiplier.
- buildShipperTariffGenerationRowForDate() : array<string, mixed>
- Builds the row of one generation (bands plus payment matrix) for a specific date; shared by {@see buildShipperTariffGenerationDefaultRows()} and {@see duplicateShipperTariffGeneration()}.
- buildShipperTariffPaymentMatrixRow() : array<string, mixed>
- Maps the payment matrix cells of one generation to `pmAvailable_<mid>`, `pmPrice_<mid>_<cid>` and `pmFreeFrom_<mid>_<cid>`. Shared by {@see buildShipperTariffGenerationDefaultRows()} (existing generation) and {@see resolveShipperTariffGenerationPrefill()} (prefill of a new one).
-
collectShipperTariffBands()
: array<int, array{weightFrom: string, weightTo: ?string, row: array
}> - Extracts and validates the bands of one generation. The returned order is the submitted order, not the sorted one: validation runs on a sorted copy so that error messages can name the exact range while the user's rows are not rearranged.
- decimalOrNull() : string|null
- NOTE: this is not a duplicate of {@see \App\Core\Utils\Helpers\Decimal::fromInput()}. It quantizes to a given number of decimal places (`$scale`) instead of normalizing input. The scale differs per column (weight vs. shipping price), so it does not belong in the shared helper, which deliberately knows no scale so it cannot be unified across modules by accident.
- duplicateShipperTariffGeneration() : Container|null
- Handles the "duplicate" action in the card header: copies the whole stored generation (bands and matrix) into a new generation so the admin only adjusts the date and prices.
- entityReference() : Shipper
- Builds a thin shipper reference (the hydrator assembles the entity from the id).
- fillShipperTariffGenerationContainer() : void
- Fills a generation container with row data (format of {@see buildShipperTariffGenerationRowForDate()}) so that it also works on a submitted form; the only reliable path for the AJAX actions "add generation" (prefill) and "duplicate".
- getShipperTariffCurrentAxisDates() : array{prices: ?string, payments: ?string}
- Returns the date of the currently valid generation of each axis separately (the greatest `date_from <= now`) in the `Y-m-d H:i:s` format that the hidden `origDateFrom` carries.
- isOwnEditFormSubmit() : bool
- Tells whether this request is a POST submit of this very `editForm`. The `_do` value carries the full component path, so a component created after the key switch has a different path and safely gets defaults.
- isShipperTariffGenerationEmpty() : bool
- Detects a new empty container by the absence of data, not by index: `onCreate` runs for all generation containers on every request, including history and half-edited generations after a redraw. Empty `origDateFrom` alone is not enough (a new generation has it empty even after the admin typed something), so all fields the prefill would overwrite are checked too.
- isShipperTariffHistoric() : bool
- loadShipperTariffSelectData() : void
- Loads the form axes (regions, VAT rates, currencies, payment methods) once per request; called from `createComponentEditForm()` before the fields and defaults are built.
- prefillNewShipperTariffGeneration() : void
- Prefills a newly added generation with the data of the currently valid one. Leaves `validFrom` and `origDateFrom` alone: empty `origDateFrom` marks a new generation for rendering and the immutability guard, and `validFrom` must be chosen deliberately by the admin.
- redrawTariffModal() : void
- Redraws the host snippet `tariffEditHost` after an AJAX validation or save failure. The component renders again with the same submitted form (inline field errors) plus flash, and the modal stays open.
- resolveShipperTariffGenerationDate() : DateTime|null
- Converts `validFrom` to a `DateTime`. Empty means effective immediately (now). A past date would write into history, so it is an error, not a silent shift to today.
-
resolveShipperTariffGenerationPrefill()
: array{bands: list
>, payments: array } - Resolves the prefill data of a new generation. Bands and the payment matrix are looked up separately because they are two independent time series ({@see ShipperTariff}).
- resolveShipperTariffPrefillDate() : DateTime|null
- Resolves the generation date for the prefill: the greatest `date_from <= now` (the currently valid generation), or the nearest future one when the whole price list is only scheduled.
- saveShipperTariffForm() : bool
- setShipperTariffFormDefaults() : void
- shipperTariffBandContainers() : array<int, Container>
- shipperTariffControlValue() : mixed
- Returns a container control's value without type juggling over `IComponent` (which has no `getValue()`).
- shipperTariffPaymentMethodRef() : PaymentMethod
- Builds a thin payment method reference (the hydrator assembles the entity from the id).
- shipperTariffValuesToArray() : array<string, mixed>
- Converts a form container (`ArrayHash` from the multiplier) to a plain array so that typed offsets can be used. Anything other than an array or `ArrayHash` is an empty row.
- translateShipperTariff() : string
- validateShipperTariffBandCoverage() : void
- Validates band invariants within one generation: at most one open band, the open band must be the topmost, no overlaps (error) and ideally no gaps (warning only, a carrier may legitimately not ship every weight).
Properties
$shipperTariffBandErrors
Band validation errors collected while building; `saveShipperTariffForm()` uses them to decide whether saving is allowed at all.
private
array<int, string>
$shipperTariffBandErrors
= []
$shipperTariffBandWarnings
private
array<int, string>
$shipperTariffBandWarnings
= []
warnings (gaps between bands); flashed, do not block saving
$shipperTariffCurrentAxisDates
Date of the currently valid generation of each axis (per-request cache), see {@see getShipperTariffCurrentAxisDates()}.
private
array{prices: ?string, payments: ?string}|null
$shipperTariffCurrentAxisDates
= null
$shipperTariffGenerationPrefill
Prefill for a newly added generation; computed once per request and applied to every empty container that `onCreate` meets.
private
array{bands: list>, payments: array}|null
$shipperTariffGenerationPrefill
= null
Methods
canRemoveShipperTariffGeneration()
Tells whether a generation may be removed: only a new or scheduled one (from today's midnight on). The currently valid one may not, because deleting it would make an older generation take over, a silent return to old prices.
public
canRemoveShipperTariffGeneration(Container $generation) : bool
Parameters
- $generation : Container
Return values
boolgetShipperTariffBandIssues()
Returns the strips between bands, as `['overlap' => range]` or `['gap' => range]` keyed by the index of the band before which the strip is rendered. It is computed on a sorted copy but returns the index in the submitted order, so the template reorders nothing.
public
getShipperTariffBandIssues(Container $generation) : array<int, array{type: string, from: string, to: string}>
Parameters
- $generation : Container
Return values
array<int, array{type: string, from: string, to: string}>getShipperTariffGenerationBadgeKey()
Returns the badge key of the card header. With migrated data the axes diverge (the price list is valid from another date than the matrix), giving two "current" cards, so the badge says which axis the card holds.
public
getShipperTariffGenerationBadgeKey(Container $generation) : string
Parameters
- $generation : Container
Return values
stringgetShipperTariffGenerationState()
Returns `current` (valid now), `scheduled` or `history`, for the badge and card color.
public
getShipperTariffGenerationState(Container $generation) : string
Parameters
- $generation : Container
Return values
stringgetShipperTariffGenerationSummary()
Returns the card header summary: number of bands, number of currencies with at least one price, and number of available payment methods.
public
getShipperTariffGenerationSummary(Container $generation) : array{bands: int, currencies: int, methods: int}
Parameters
- $generation : Container
Return values
array{bands: int, currencies: int, methods: int}isShipperTariffGenerationDateLocked()
Tells whether the "valid from" field is locked: for history (fully read-only) and for the currently valid generation, whose values are editable but whose date is a fact; repricing from another date is a new generation. A disabled input is not posted, the build takes the date from `origDateFrom`.
public
isShipperTariffGenerationDateLocked(Container $generation) : bool
Parameters
- $generation : Container
Return values
boolisShipperTariffGenerationOpenByDefault()
Tells whether the card's `<details>` is open by default: a new generation (empty `origDateFrom`) is open because it is being worked on; all others (valid, scheduled, history) are collapsed.
public
isShipperTariffGenerationOpenByDefault(Container $generation) : bool
Parameters
- $generation : Container
Return values
boolisShipperTariffGenerationReadOnly()
Tells whether a generation is read-only. Only superseded history is: a generation before today's midnight that a newer one has replaced on its axis. The currently valid generation (even dated in the past) is editable, and a new one (empty `origDateFrom`) is always editable.
public
isShipperTariffGenerationReadOnly(Container $generation) : bool
The Api immutability guard enforces the same rule.
Parameters
- $generation : Container
Return values
boolrestoreShipperTariffGenerationDisplay()
Restores the display of fields that do not survive a POST followed by an AJAX redraw. The template calls it via `{do}` first in every generation card (before totals are computed).
public
restoreShipperTariffGenerationDisplay(Container $generation) : void
Disabled fields are not submitted and defaults are applied on GET only, so after any AJAX action (duplicate, add or remove band) they would render empty:
- the locked date of the valid generation is restored from the hidden
origDateFrom; - read-only history has disabled selects (VAT) and checkboxes, so the whole row is restored from stored data (its POST is ignored on build anyway).
Posted values of editable fields are never overwritten.
Parameters
- $generation : Container
shipperTariffCurrencyHasPrice()
Tells whether the currency has a price in at least one band of this generation. Used only by {@see getShipperTariffGenerationSummary()} for the currency count; the template lists all currencies for every band regardless.
public
shipperTariffCurrencyHasPrice(Container $generation, int $currencyId) : bool
Parameters
- $generation : Container
- $currencyId : int
Return values
boolcreateComponentEditForm()
protected
createComponentEditForm() : Form
Return values
FormisTargetAllowed()
Returns whether the logged-in user may open the given admin target. For visibility (tiles, autocomplete, buttons); it does not throw.
protected
isTargetAllowed(string|null $key) : bool
IMPORTANT: fail-closed like requirePrivilege(): an empty key and a presenter
without isAllowed() both mean no. A component that skips this question lists the
target to everyone.
Parameters
- $key : string|null
Return values
boolrequirePrivilege()
Throws 403 when the logged-in user lacks the given admin privilege.
protected
requirePrivilege(string $key) : void
Call it as the first statement of a mutating signal, before loading data, so the check cannot be bypassed by something being written first.
Parameters
- $key : string
resolvePageTarget()
Returns the RBAC key of the target page: `<presenter>:<action>`, e.g. `:Admin:System:User:show`.
protected
static resolvePageTarget(object|null $page) : string|null
Same interpretation as Menu::filterByPrivileges(), BasePresenter::authorizeListing() and PrivilegeCheckTrait::checkCurrentPrivilege(). The key is derived from the page target only, never from a file or class name.
Returns null when the page is missing or has no presenter, so there is nothing to allow.
Parameters
- $page : object|null
-
AdminPageentity (hydrated, hence justobject)
Return values
string|nullresolveSupplyKindDefaultId()
protected
resolveSupplyKindDefaultId(SupplyKindManager $manager, array<int, mixed> $options[, string|null $preferredKey = null ]) : int|null
Parameters
- $manager : SupplyKindManager
- $options : array<int, mixed>
-
select options (
SupplyKindManager::findSelectOptions()) - $preferredKey : string|null = null
Return values
int|nulladdShipperTariffBandControls()
Fields of one weight band inside a generation (currency becomes a table row in the template).
private
addShipperTariffBandControls(Container $container) : void
Parameters
- $container : Container
addShipperTariffGenerationMultiplier()
Adds the outer `generations` multiplier, the nested `bands` multiplier and the fixed payment matrix.
private
addShipperTariffGenerationMultiplier(Form $form) : void
IMPORTANT: the redraw closure is shared and always redraws the outer generations snippet,
also for the nested band buttons. A nested multiplier cannot have its own snippet (it would
sit inside the outer one and its name could not be a literal per index).
Parameters
- $form : Form
addShipperTariffMainFields()
private
addShipperTariffMainFields(Form $form) : void
Parameters
- $form : Form
addShipperTariffPaymentMatrixControls()
Adds the payment matrix of a generation: a fixed 2D loop (methods x currencies), not a multiplier, because both axes are code lists that admins do not create in this form.
private
addShipperTariffPaymentMatrixControls(Container $generation) : void
pmAvailable_<mid> gates the whole method row across currencies; payment method
availability is a tariff property, not a currency one.
Parameters
- $generation : Container
addShipperTariffTranslationFields()
private
addShipperTariffTranslationFields(Form $form) : void
Parameters
- $form : Form
applyShipperTariffGenerations()
Rebuilds both time series of the tariff from the submitted generations.
private
applyShipperTariffGenerations(ArrayHash<string|int, mixed> $values, ShipperTariff $tariff) : void
Superseded history (older than the currently valid generation of its axis) is carried over as
the original entities; it must be returned to the collection, otherwise orphanRemoval
deletes it. Editable generations are rebuilt from scratch as a snapshot: every band x currency
with a price and every method x currency combination (even unavailable ones) is written.
IMPORTANT: the currently valid generation is editable; only history already replaced by a
newer generation is locked. The date of the valid generation cannot be changed (the input is
disabled, the build takes it from origDateFrom); repricing from a date is a new generation.
Parameters
- $values : ArrayHash<string|int, mixed>
- $tariff : ShipperTariff
buildAfterSave()
Builds the post-save action (`AdminComponentFormTrait` hook); never redirects the page for AJAX.
private
buildAfterSave() : callable
save(AJAX): closes the modal.update(AJAX): keeps the modal open and redraws the component (fresh$editedShipperTariff, see saveShipperTariffForm()); always also redraws the tariff list and flash.- non-AJAX fallback: full redirect to the tariffs tab.
Return values
callablebuildShipperTariffBandDefaultRows()
Builds the band rows of one generation, sorted by `weightFrom` and renumbered (sorting happens on load only).
private
buildShipperTariffBandDefaultRows(array<int, ShipperTariffPrice> $prices) : array<int, array<string, mixed>>
Parameters
- $prices : array<int, ShipperTariffPrice>
Return values
array<int, array<string, mixed>>buildShipperTariffEntity()
private
buildShipperTariffEntity(ArrayHash<string|int, mixed> $values) : ShipperTariff
Parameters
- $values : ArrayHash<string|int, mixed>
Tags
Return values
ShipperTariffbuildShipperTariffGenerationDefaultRows()
Maps the existing series to default rows of the outer multiplier.
private
buildShipperTariffGenerationDefaultRows(ShipperTariff $tariff) : array<int, array<string, mixed>>
Rows are grouped by date_from (both series separately but into the same generation, as they
share the date; a generation with only a payment matrix and no bands must still be shown).
Generations are ordered date_from descending (newest first) and future (scheduled) ones are
shown too. Each row is built by buildShipperTariffGenerationRowForDate(), shared with
duplicateShipperTariffGeneration().
Parameters
- $tariff : ShipperTariff
Return values
array<int, array<string, mixed>>buildShipperTariffGenerationRowForDate()
Builds the row of one generation (bands plus payment matrix) for a specific date; shared by {@see buildShipperTariffGenerationDefaultRows()} and {@see duplicateShipperTariffGeneration()}.
private
buildShipperTariffGenerationRowForDate(ShipperTariff $tariff, string $dateKey, array<int, ShipperTariffPrice> $prices, array<int, PaymentMethodPrice> $payments) : array<string, mixed>
Parameters
- $tariff : ShipperTariff
- $dateKey : string
- $prices : array<int, ShipperTariffPrice>
- $payments : array<int, PaymentMethodPrice>
Return values
array<string, mixed>buildShipperTariffPaymentMatrixRow()
Maps the payment matrix cells of one generation to `pmAvailable_<mid>`, `pmPrice_<mid>_<cid>` and `pmFreeFrom_<mid>_<cid>`. Shared by {@see buildShipperTariffGenerationDefaultRows()} (existing generation) and {@see resolveShipperTariffGenerationPrefill()} (prefill of a new one).
private
buildShipperTariffPaymentMatrixRow(array<int, PaymentMethodPrice> $paymentPrices) : array<string, mixed>
Parameters
- $paymentPrices : array<int, PaymentMethodPrice>
Return values
array<string, mixed>collectShipperTariffBands()
Extracts and validates the bands of one generation. The returned order is the submitted order, not the sorted one: validation runs on a sorted copy so that error messages can name the exact range while the user's rows are not rearranged.
private
collectShipperTariffBands(array<string, mixed> $generation, string $dateKey) : array<int, array{weightFrom: string, weightTo: ?string, row: array}>
Parameters
- $generation : array<string, mixed>
- $dateKey : string
Tags
Return values
array<int, array{weightFrom: string, weightTo: ?string, row: arraydecimalOrNull()
NOTE: this is not a duplicate of {@see \App\Core\Utils\Helpers\Decimal::fromInput()}. It quantizes to a given number of decimal places (`$scale`) instead of normalizing input. The scale differs per column (weight vs. shipping price), so it does not belong in the shared helper, which deliberately knows no scale so it cannot be unified across modules by accident.
private
decimalOrNull(mixed $value, int $scale) : string|null
Parameters
- $value : mixed
- $scale : int
Return values
string|nullduplicateShipperTariffGeneration()
Handles the "duplicate" action in the card header: copies the whole stored generation (bands and matrix) into a new generation so the admin only adjusts the date and prices.
private
duplicateShipperTariffGeneration(Container $generation) : Container|null
Defaults are built from the stored $this->editedShipperTariff filtered by this card's
origDateFrom, not from the POST: readonly/disabled history fields are not fully posted.
The redraw is not part of this method; the onClick handler in
addShipperTariffGenerationMultiplier() calls it separately, so the method can run
outside an attached presenter, where redrawControl() has nothing to redraw.
Parameters
- $generation : Container
Return values
Container|nullentityReference()
Builds a thin shipper reference (the hydrator assembles the entity from the id).
private
entityReference(int $shipperId) : Shipper
Parameters
- $shipperId : int
Return values
ShipperfillShipperTariffGenerationContainer()
Fills a generation container with row data (format of {@see buildShipperTariffGenerationRowForDate()}) so that it also works on a submitted form; the only reliable path for the AJAX actions "add generation" (prefill) and "duplicate".
private
fillShipperTariffGenerationContainer(Container $generation, array<string, mixed> $row) : void
A plain setValues($row) is not enough: Multiplier::setValues() only stores the bands values
and builds copies later in createCopies(), which on a submitted form builds them from the
HTTP data; a new container has none, so no bands appear. Bands are therefore created
explicitly with addCopy($i) plus setValues($bandRow) on every copy.
Parameters
- $generation : Container
- $row : array<string, mixed>
getShipperTariffCurrentAxisDates()
Returns the date of the currently valid generation of each axis separately (the greatest `date_from <= now`) in the `Y-m-d H:i:s` format that the hidden `origDateFrom` carries.
private
getShipperTariffCurrentAxisDates() : array{prices: ?string, payments: ?string}
null means the axis has no valid generation.
Return values
array{prices: ?string, payments: ?string}isOwnEditFormSubmit()
Tells whether this request is a POST submit of this very `editForm`. The `_do` value carries the full component path, so a component created after the key switch has a different path and safely gets defaults.
private
isOwnEditFormSubmit() : bool
Return values
boolisShipperTariffGenerationEmpty()
Detects a new empty container by the absence of data, not by index: `onCreate` runs for all generation containers on every request, including history and half-edited generations after a redraw. Empty `origDateFrom` alone is not enough (a new generation has it empty even after the admin typed something), so all fields the prefill would overwrite are checked too.
private
isShipperTariffGenerationEmpty(Container $generation) : bool
Parameters
- $generation : Container
Return values
boolisShipperTariffHistoric()
private
isShipperTariffHistoric(DateTime|null $dateFrom, DateTime $todayMidnight) : bool
Parameters
- $dateFrom : DateTime|null
- $todayMidnight : DateTime
Return values
boolloadShipperTariffSelectData()
Loads the form axes (regions, VAT rates, currencies, payment methods) once per request; called from `createComponentEditForm()` before the fields and defaults are built.
private
loadShipperTariffSelectData() : void
The shipper options are not loaded because the shipper is server-side context.
prefillNewShipperTariffGeneration()
Prefills a newly added generation with the data of the currently valid one. Leaves `validFrom` and `origDateFrom` alone: empty `origDateFrom` marks a new generation for rendering and the immutability guard, and `validFrom` must be chosen deliberately by the admin.
private
prefillNewShipperTariffGeneration(Container $generation) : void
Parameters
- $generation : Container
redrawTariffModal()
Redraws the host snippet `tariffEditHost` after an AJAX validation or save failure. The component renders again with the same submitted form (inline field errors) plus flash, and the modal stays open.
private
redrawTariffModal() : void
resolveShipperTariffGenerationDate()
Converts `validFrom` to a `DateTime`. Empty means effective immediately (now). A past date would write into history, so it is an error, not a silent shift to today.
private
resolveShipperTariffGenerationDate(array<string, mixed> $generation, DateTime $todayMidnight) : DateTime|null
Parameters
- $generation : array<string, mixed>
- $todayMidnight : DateTime
Tags
Return values
DateTime|nullresolveShipperTariffGenerationPrefill()
Resolves the prefill data of a new generation. Bands and the payment matrix are looked up separately because they are two independent time series ({@see ShipperTariff}).
private
resolveShipperTariffGenerationPrefill(ShipperTariff $tariff) : array{bands: list>, payments: array}
Parameters
- $tariff : ShipperTariff
Return values
array{bands: listresolveShipperTariffPrefillDate()
Resolves the generation date for the prefill: the greatest `date_from <= now` (the currently valid generation), or the nearest future one when the whole price list is only scheduled.
private
resolveShipperTariffPrefillDate(array<int, DateTime> $dates, DateTime $now) : DateTime|null
Empty input (a series without any price) returns null and the caller skips the prefill for
that axis.
Parameters
- $dates : array<int, DateTime>
- $now : DateTime
Return values
DateTime|nullsaveShipperTariffForm()
private
saveShipperTariffForm(ArrayHash<string|int, mixed> $values, Form|null $form) : bool
Parameters
- $values : ArrayHash<string|int, mixed>
- $form : Form|null
Return values
boolsetShipperTariffFormDefaults()
private
setShipperTariffFormDefaults(Form $form) : void
Parameters
- $form : Form
shipperTariffBandContainers()
private
shipperTariffBandContainers(Container $generation) : array<int, Container>
Parameters
- $generation : Container
Return values
array<int, Container>shipperTariffControlValue()
Returns a container control's value without type juggling over `IComponent` (which has no `getValue()`).
private
shipperTariffControlValue(Container $container, string $name) : mixed
Parameters
- $container : Container
- $name : string
shipperTariffPaymentMethodRef()
Builds a thin payment method reference (the hydrator assembles the entity from the id).
private
shipperTariffPaymentMethodRef(int $methodId) : PaymentMethod
Parameters
- $methodId : int
Return values
PaymentMethodshipperTariffValuesToArray()
Converts a form container (`ArrayHash` from the multiplier) to a plain array so that typed offsets can be used. Anything other than an array or `ArrayHash` is an empty row.
private
shipperTariffValuesToArray(mixed $values) : array<string, mixed>
Parameters
- $values : mixed
Return values
array<string, mixed>translateShipperTariff()
private
translateShipperTariff(string $key[, array<string, string> $params = [] ]) : string
Parameters
- $key : string
- $params : array<string, string> = []
Return values
stringvalidateShipperTariffBandCoverage()
Validates band invariants within one generation: at most one open band, the open band must be the topmost, no overlaps (error) and ideally no gaps (warning only, a carrier may legitimately not ship every weight).
private
validateShipperTariffBandCoverage(array<int, array{weightFrom: string, weightTo: ?string, row: array}> $bands, string $dateKey) : void
Parameters
-
$bands
: array<int, array{weightFrom: string, weightTo: ?string, row: array
}> - $dateKey : string