CoolCMS API

OrderPresenter extends BasePresenter
in package
uses OrderListTrait, OrderDetailTrait, OrderFormTrait, OrderStatusChangeFormTrait, OrderCreditNoteFormTrait, OrderItemPickerTrait, OrderGiftPickerTrait, OrderCustomerPickerTrait, OrderCustomerLookupPickerTrait, VoucherPickerTrait, SellerPickerTrait, PaymentPickerTrait, PickerHostTrait, AdminFormHelpersTrait, AdminEditFormComponentsTrait

FinalYes

Order administration: grid, detail (action `status`, links to the Invoicer invoice and Store reservations/issues), edit form (`OrderFormTrait`, AJAX recalculation through `api/eshop/order/build`) and the status form (`OrderStatusChangeFormTrait`).

IMPORTANT: status changes go only through api/eshop/order/transition → OrderTransitionManager::apply(); any other path skips the transition rules.

The dictionaries (OrderStatus/Voucher/Gift) have their own presenters; this one only consumes them and adds no CRUD logic for them.

Table of Contents

Constants

LOGIN_BACKLINK  : string = 'backlink'
Login page parameter with the key of the stored request to return to ({@see loginReturnArgs()}).
DEFAULT_ITEMS_PER_PAGE  : mixed = 20
Items per page of admin lists when the DB setting is missing.
FORM_BACK_SUBSECTION  : mixed = 'formBack'
Session subsection mapping a key to the previous page URL of edit forms.
SESSION_NAMESPACE  : mixed = 'admin'
BLOCKED_EXTENSIONS  : mixed = ['php', 'php3', 'php4', 'php5', 'php7', 'php8',...
Extensions that must not be uploaded into the web-served folder; otherwise an editor upload would mean running foreign code on the server. It is no content whitelist (the editor uploads what is needed), only a safeguard against executable files.
EDITOR_PAGE_LIMIT  : mixed = 500
Listing cap; the dialog is a suggester, not a paged list.
EDITOR_PAGE_TARGETS  : mixed = ['front:system:page:show']
Routes the editor may link to: text pages only.
EDITOR_UPLOAD_FOLDER  : mixed = 'editorUploads'
Editor root (relative to the `uploads/` root). Changing it to `''` would open the whole `uploads/` tree to the manager; the editor user could then reach (and delete) files of other modules such as products and avatars.
IMAGE_EXTENSIONS  : mixed = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'avif', '...
Extensions the file manager shows as a preview instead of a document icon.
LOCALE_MAP  : mixed = ['cs' => 'cs_CZ', 'en' => 'en_US', 'sk' => 'sk_...
Maps the short language code to the full locale of the registered NEON sources.

Properties

$accessTokenValidator  : AccessTokenValidator
Signature and expiry alone are not enough: a revoked token (`jti` on the deny-list) that has not expired yet would keep the session logged in although the Api guard rejects the same token. Same contract as {@see \App\Core\Traits\Api\Presenters\JwtAuthTrait::checkJwtAuth()}, one implementation.
$adminFormActionsFactory  : FormActionsFactory
$adminLangNavFactory  : LangNavFactory
$adminLanguageManager  : LanguageManager
$adminPageManager  : AdminPageManager
$authManager  : AuthManager
$authStorageManager  : AuthStorageManager
$authUserManager  : UserManager
Admin `UserManager` for {@see UserManager::login()}. A module must not read through another module, so admin has its own `login()` that calls the same Api endpoint (`api/system/auth/login`).
$columnSchema  : ColumnSchema
Limits of the real database columns for {@see guardColumns()}.
$container  : Container
$deviceDetector  : DeviceDetector
$editorAutosaveScope  : EditorAutosaveScope
Scope of the editor autosave drafts, see {@see \App\Core\Security\EditorAutosaveScope}.
$editorLinkPageManager  : PageManager
NOTE: own property name. `$pageManager` already exists on presenters (`PagePickerTrait`), and two `#[Inject]` properties of the same name would collide in the trait composition.
$editorUploadManager  : FileSystemManager
NOTE: own property name, not `$fileSystemManager`.
$eventDispatcher  : EventDispatcher
$formSubmissionGuard  : FormSubmissionGuard
One-time submission tokens of "add" forms, see {@see guardFormSubmitOnce()}.
$jwtManager  : JwtManager
$languageContext  : LanguageContext
$languageManager  : LanguageManager
$localizationContext  : LocalizationContext
$localizationManager  : LocalizationManager
$loginDeviceCookie  : LoginDeviceCookie
Cookie of a known device for the password login throttle ({@see self::rememberLoginDevice()}).
$modalWindowFactory  : ModalWindowFactory
Injected through Nette presenter inject (after construction), not the constructor.
$orderCustomerLookupManager  : CustomerManager
$orderCustomerUserManager  : UserManager
$paymentManager  : PaymentManager
$picker  : string
Picker mode of a list; when not empty, the presenter renders its `show` grid as a selection modal (no add/edit/delete/checkboxes, each row has a select button) in the minimal `@picker.latte` layout.
$pickerExclude  : int
Id of the record that cannot be selected in picker mode (its select button is hidden).
$pickerExcludeSubtreeLft  : int
`lft`/`rgt` bounds of a whole subtree whose nodes cannot be selected in picker mode.
$pickerExcludeSubtreeRgt  : int
$presenterContext  : PresenterContext
$privilegeManager  : PrivilegeManager
$queryCacheContext  : QueryCacheContext
Query cache policy for the whole admin request; `startup()` disables it.
$routerDispatcher  : RouterDispatcher
$sellerManager  : SellerManager
$settingContext  : SettingContext
$settingManager  : SettingManager
$themeContext  : ThemeContext
$themeManager  : ThemeManager
$themeResolver  : DefaultThemeResolver
$translator  : ITranslator
$translatorSessionResolver  : Session
$userManager  : UserManager
$adminPageEntity  : AdminPage|null
$debugMode  : bool
$productionMode  : bool
$savedEntityId  : int|null
Id of the record just saved; set by the `$processData` callback in `createForm()` after a successful save.
$translatorDomain  : string
$apiBridge  : ApiBridge
$carrierRegistry  : CarrierRegistry
$creditNoteComplaintId  : int|null
Complaint the form was prefilled from (kept for the redirect after submit).
$creditNotePreview  : array<string, mixed>|null
Basis of the partial credit note form (`api/eshop/order/credit-note-preview`); `null` when the order has no source invoice, so there is nothing to credit.
$currencyManager  : CurrencyManager
$dataGridFactory  : DataGridFactory
$editedOrder  : Order|null
Edited or displayed order (null when adding).
$giftManager  : GiftManager
$invoiceManager  : InvoiceManager
$invoiceTypeManager  : InvoiceTypeManager
$isLoggingIn  : bool
$orderCurrencyEntities  : array<int, Currency>
Currency id => entity (same source as `orderCurrencyOptions`, so `priceFormat` needs no extra DB query).
$orderCurrencyOptions  : array<int, NotTranslate>
$orderInitialStatusOptions  : array<int, NotTranslate>
$orderItemPrefillWarnings  : array<int, string>
Items whose price the item prefill could not fetch from the catalog after the picker choice (the Api `item-prefill` failed, typically a set without a valid price for the chosen currency). Without this list the prefill would fail silently and the admin would learn about the missing price only from a recalculation error. Row labels (name, code, #id), rendered by `{snippet items}` as an alert; filled by {@see Traits\Forms\OrderFormTrait::prefillOrderItemRows()}.
$orderLanguageOptions  : array<int, NotTranslate>
$orderLocalizationOptions  : array<int, NotTranslate>
$orderManager  : OrderManager
$orderPaymentMethodOptions  : array<int, NotTranslate>
$orderPaymentRegionOptions  : array<int, NotTranslate>
$orderPreview  : array<string, mixed>|null
Preview of the last AJAX recalculation ({@see OrderFormTrait::recalculateOrderForm()}).
$orderPreviewCurrency  : Currency|null
Currency of the last preview (build response `currencyId` resolved through {@see $orderCurrencyEntities}; on the edit GET baseline taken from `$editedOrder->getCurrency()`). `null` = unknown currency, so the template and the `priceFormat` filter leave numbers raw.
$orderPreviewError  : string|null
$orderPreviewWarnings  : array<int, string>
Non-blocking warnings for the last preview or save (currently only the code `paymentMethodUnavailable`, see {@see \App\UI\Api\Eshop\Presenters\OrderPresenter::internalActionBuild()}): codes from the Api response, translated in the template or flash via `form.warnings.<code>`.
$orderSellerUseVat  : bool|null
Per-request cache of the eshop seller's VAT-payer status ({@see Traits\Forms\OrderFormTrait::resolveOrderSellerUseVat()}; `null` = not yet resolved).
$orderStatusManager  : OrderStatusManager
$orderTariffOptions  : array<int, NotTranslate>
$orderTariffPickup  : array<int, array{externalPickup: bool, scriptName: ?string, widget: ?array}>
Tariff id => pickup point context for the order edit form. `externalPickup` says whether the "Pickup point" block is rendered at all; `widget` is the driver configuration (`data-pickup-*` attributes of the "Select on map" button), `null` when the carrier has no `script_name`, no driver in the registry or no API key, so only manual entry remains (message `form.pickup.noDriver`).
$orderUserTypeOptions  : array<int, NotTranslate>
$paymentMethodManager  : PaymentMethodManager
$paymentRegionManager  : PaymentRegionManager
$pickerFactory  : PickerFactory
$productSetManager  : ProductSetManager
$shipperManager  : ShipperManager
$shipperTariffManager  : ShipperTariffManager
$stockDocumentManager  : StockDocumentManager
$stockReservationManager  : StockReservationManager
$theme  : Theme|null
$userPrivileges  : array<int, string>
$userTypeManager  : UserTypeManager
$voucherManager  : VoucherManager

Methods

__construct()  : mixed
actionAdd()  : void
actionCreditNote()  : void
Partial credit note. The order is loaded only for the header (number, customer); the table rows come from the source invoice, not from the order, because the credit note applies to the document, which can differ from the order (fees have their own row, a rounding row was added, the order may have been edited since).
actionEdit()  : void
actionStatus()  : void
beforeRender()  : void
Exposes the AJAX recalculation preview to Latte (`{snippet orderPreview}`).
createComponent()  : IComponent|null
flashFormOwnErrors()  : void
Flashes form-level errors (`$form->getOwnErrors()`) as `danger` messages.
flashRejectedUploads()  : void
Flashes one `warning` listing the files the Api rejected (type, dimensions, unreadable) after a successful save of a form with a dropzone ({@see UploadRejection}).
formatLayoutTemplateFiles()  : array<string|int, mixed>
Admin version of {@see \App\Core\Traits\Front\Presenters\ThemeInitTrait::formatLayoutTemplateFiles()}.
getAdminPageEntity()  : AdminPage|null
getContainer()  : Container
getFormBackUrl()  : string
Returns the stored previous page URL for the key, used by the `cancel` link in the template.
getModalWindow()  : ModalWindow
getRouterDispatcher()  : RouterDispatcher
getTranslator()  : ITranslator
guardFormSubmitOnce()  : void
Protects a form against a double submit: one rendered form saves at most once.
handleChangeLocale()  : void
handleEditorCreateFolder()  : void
Creates a subfolder in `folder` (path relative to the editor root).
handleEditorDelete()  : void
Deletes a file or (recursively) a folder. An empty path would point to the editor root, which cannot be deleted.
handleEditorFiles()  : void
Sends the folder listing for the editor file manager. The `folder` parameter is a path relative to the editor root (empty means the root).
handleEditorPages()  : void
Sends the page list for the link dialog as JSON `{"pages": [{id, label, url}, ...]}` sorted by label.
handleEditorRename()  : void
Renames a file or folder (`path` relative to the editor root).
handleEditorUpload()  : void
Accepts a file from the editor (field `file`, multipart POST; optional `folder` = subfolder of the editor root) and sends JSON `{"location": "/www/uploads/editorUploads/..."}`, the format TinyMCE expects from `images_upload_handler`.
handleLogout()  : void
handleSignOut()  : void
hasServiceByType()  : bool
Returns whether the container has a service of the given type.
hasVatControls()  : bool
Returns whether the form may contain VAT controls at all (`withVat` checkbox, row `vat`/ `priceWithVat`/`totalPriceWithVat`, `shippingVat`, `paymentVat`).
initializeTranslator()  : void
isAddAction()  : bool
Tells whether the current action creates a record: `add` and the `add<Something>` actions (`addMenu`, `addKey`). Derived from the server context only, like {@see formSubmitPrivilege()}.
isAllowed()  : bool
Returns whether the logged-in user has the given privilege.
isSubmitOnceForm()  : bool
Tells whether the form was protected by {@see guardFormSubmitOnce()}.
loginWithCredentials()  : void
Logs in with username and password; called only by the login form (after validation and CSRF).
orderPickupInfo()  : array{externalPickup: bool, scriptName: ?string, widget: ?array}|null
Returns the pickup point context of the selected tariff for `edit.latte` (`{snippet shippingFields}`). `null` = no tariff selected, unknown tariff or no `external_pickup`, so the "Pickup point" block is not rendered at all.
pickupCarrierLabel()  : string|null
Returns a readable carrier name from the `OrderShipper::$pickupCarrier` snapshot (`script_name`).
publishFieldErrors()  : void
Publishes element errors of a failed submit to the client.
redirectToFormBack()  : void
Redirects to the stored previous page and discards the key.
renderAdd()  : void
renderCreditNote()  : void
renderEdit()  : void
renderShow()  : void
renderStatus()  : void
resolveFormBackKey()  : string
Returns the previous-page key: from the URL if present (survives the update redirect), otherwise on a plain GET render of the edit page stores `Referer` in the session under a new random key.
runSubmitOnce()  : bool|null
Runs a saving step of a form under its one-time token (a form without the token just runs it).
setConfigParameters()  : void
setTranslator()  : $this
shouldShowVatFields()  : bool
Returns the initial visibility of the VAT fields (not of the checkbox, see {@see hasVatControls()}).
startup()  : void
typedComponent()  : T
Returns a subcomponent with a verified type.
authorize()  : void
Authorization hook; by default requires the `:Admin` privilege.
authorizeFormSubmit()  : void
Gate for writing presenter forms built by `createForm()`.
authorizeListing()  : void
Gate for reading lists.
checkAdminAccess()  : void
Entry gate to the admin: a guest is sent to login; a logged-in user without `:Admin` is sent to login with an error.
checkAuthentication()  : void
checkCurrentPrivilege()  : void
Builds the key from the current request (`:Admin:<Module>:<Presenter>:<action>`) and checks it. `getName()` already contains the `Admin:...` prefix, so only one leading colon is added.
checkPrivilege()  : void
Checks a specific privilege; throws 403 when denied.
createComponentAdminFormActions()  : FormActions
createComponentAdminLangNav()  : LangNav
createComponentCreditNoteForm()  : Form
createComponentEditForm()  : Form
createComponentGrid()  : DataGrid
createComponentModalWindow()  : ModalWindow
createComponentPicker()  : Multiplier<string|int, Picker>
createComponentStatusForm()  : Form
createForm()  : Form
Creates an edit form with the standard actions and a return to the previous page.
currentLangId()  : int|null
Returns the current language id (for picker labels etc.), null when unknown.
domainTranslator()  : PrefixedTranslator|null
Returns a translator prefixed with the presenter domain, or `null` (empty domain or a translator other than Contributte).
formSubmitPrivilege()  : string
Returns the privilege key required to save a form built by `createForm()`.
getAdminItemsPerPage()  : int
Returns the default items per page of admin lists from the DB setting `admin.itemsPerPage` (module System = 1), falling back to {@see DEFAULT_ITEMS_PER_PAGE}.
getAdminLayout()  : string
Returns the layout name; in picker mode ({@see $picker}) the `show` grid uses the minimal `@picker.latte` (no sidebar/header) so the opener fetch returns only the table.
getFormBackFallback()  : string
Returns the return URL when the previous page is unknown; override in a presenter without a `show` action.
getFormLanguages()  : array<int, Language>
Returns the languages for multilingual form fields (admin `LanguageManager`).
getSessionKey()  : string
Returns a session key string, e.g. 'front.auth.step1'.
getSessionSection()  : SessionSection
Returns a Nette\SessionSection instance using a dynamically built session key.
guardColumns()  : void
Gates every text and number field of the form by the real column it writes to ({@see \App\Core\Forms\ColumnGate::guard()}): an oversized value is an error at the field, never a database error that closes the entity manager (admin walkthrough A1, A14).
initializePresenterContext()  : void
intOrNull()  : int|null
Converts mixed to int or null (an empty or zero value becomes null).
isSameSiteRequest()  : bool
Tells whether the request comes from the own site (Nette SameSite cookie); protects GET actions with a side effect.
loadUserPrivileges()  : void
Loads all privileges of the logged-in user with one database query. Call it right after `checkAdminAccess()` in `startup()` (the user is guaranteed to be logged in by then).
logout()  : void
orderCustomerLookupPicker()  : PickerConfig
orderCustomerPicker()  : PickerConfig
orderGiftPicker()  : PickerConfig
orderInvoices()  : array<int, Invoice>
orderItemProductSetPicker()  : PickerConfig
orderStockDocuments()  : array<int, object>
orderStockReservations()  : array<int, object>
orderTargetStatusFlagsJson()  : string
JSON map `statusId => flags` for `order-status-form.js` (section toggles).
orderVoucherPicker()  : PickerConfig
parseDateTime()  : DateTime|null
Converts a `datetime-local` input or text value to `DateTime`, or null when empty or unparsable.
paymentPicker()  : PickerConfig
pickers()  : array<string, PickerConfig>
Returns the presenter pickers: `userId`/`items`/`gifts` from the Eshop traits and `paymentId` (status form) from the shared System `PaymentPickerTrait`.
sellerPicker()  : PickerConfig
setTranslatorDomain()  : void
setupTemplateTranslator()  : void
Sets a translator prefixed with the presenter domain into the template (as Front components do, see {@see \App\Core\Base\BaseComponent::setup()}).
str()  : string
Safely converts a mixed form value to string.
strOrNull()  : string|null
Converts mixed to string or null (an empty string is stored as null).
addOrderBasicFields()  : void
addOrderCustomerContactRefreshButton()  : void
Adds the force-submit button `order-item-calc.js` clicks after the `customerContactId` select changes (`data-refresh-target`, same generic mechanism as `tariffId` -> `shippingRefresh`).
addOrderCustomerFields()  : void
addOrderCustomerRefreshButton()  : void
Adds the force-submit button picker.js clicks after a customer is picked.
addOrderGiftsMultiplier()  : void
Adds the gifts multiplier: row = gift picker + quantity.
addOrderItemsMultiplier()  : void
Adds the items multiplier: row = product set picker + editable price breakdown.
addOrderItemsPrefillButton()  : void
Adds the shared hidden button picker.js clicks after a product set is picked in any row (`OrderItemPickerTrait::orderItemProductSetPicker()` with `submitButton: 'itemsPrefill'`).
addOrderPaymentRefreshButton()  : void
Force-submit after `paymentMethodId` changes (JS clears paymentPrice/Vat before the click).
addOrderPickupPointFields()  : void
Adds the carrier pickup point controls for order edit.
addOrderPickupRefreshButton()  : void
Adds the force-submit button used after a point is picked in the carrier widget.
addOrderRecalculateButton()  : void
Adds the "Recalculate" button.
addOrderSellerFields()  : void
Adds the seller (shop operator) snapshot fields stored on the order.
addOrderSellerRefreshButton()  : void
Adds the hidden force-submit button that picker.js clicks after a seller is picked.
addOrderShippingFields()  : void
Adds shipping/payment with an editable price (without VAT) and rate.
addOrderShippingRefreshButton()  : void
Force-submit after `tariffId` changes (JS clears shippingPrice/Vat before the click).
addOrderStockCheckFields()  : void
Adds the stock check fieldset below "Shipping and payment" (separate so the override of the strict stock gate is visually apart from shipping/payment, which it does not relate to).
addOrderVouchersMultiplier()  : void
Limit from the raw HTTP data (`onAnchor`) plus `$maxCopies` as a second defense.
allowPartialAdminPromptKey()  : string
Returns the effective `4/order.partial.adminAllowed`; missing in DB means "require full stock" (same semantics as the `$value === '1'` fallback in {@see \App\UI\Api\Eshop\Models\Managers\Traits\OrderBuildTrait::resolveAllowPartial()}, where a missing or other value is false).
applyOrderCustomerUserLink()  : void
Syncs the order's user picker (`userId`, {@see \App\UI\Admin\Eshop\Presenters\Traits\Pickers\OrderCustomerPickerTrait}) and `userTypeId` from the customer record's linked user account (`Customer.userId`).
buildOrderPayload()  : array<string, mixed>
Builds the raw payload for `api/eshop/order/build`: no catalog logic here, only a transcription of form values (as in {@see \App\UI\Api\Eshop\Presenters\OrderPresenter::internalActionBuild()}). `lines` carries trusted price/vat/name/code/unit; shipping/payment go as nested `shipping`/`payment` (tariffId + price + vat).
callOrderBuild()  : array<string, mixed>
computeOrderTargetStatuses()  : NotTranslate>, 1: array}
Mirrors `OrderTransitionManager::checkGating()` (2 rules); the server is the final judge, this only filters the select so the admin does not see obviously rejected targets.
controlValue()  : mixed
Safely reads a field value from the container (form or multiplier row).
createIdentity()  : SimpleIdentity|null
createMultiplierComponent()  : Multiplier<string|int, IComponent>
Creates a multiplier for the component.
createNewComponentInstance()  : IComponent|null
Creates a new component instance without adding it to the presenter; used by the multiplier.
createStandardComponent()  : IComponent|null
Creates a standard component (not a multiplier).
decorateInvoices()  : void
Decorates the grid page with invoices in one `WHERE order_id IN (...)` query. An invoice is linked to the order only by a flat scalar (no cross-module FK), so `setIncludes()` cannot load it.
editorBreadcrumb()  : array<int, array{label: string, path: string}>
Builds the breadcrumb navigation: cumulative segment paths.
editorLinkLangId()  : int
Returns the language used to pick labels and URLs (default 1, Czech).
editorPageLabel()  : string
Returns the page label: title, otherwise name, otherwise `#id`.
editorPageRoute()  : Route|null
Returns the first page route the editor may link to. A page may have several (many-to-many); the whitelisted one is taken, not the first in order, so a page with both `Page:show` and `Page:form` ends up on the right one.
editorPageUrl()  : string|null
Returns the front end address of a page. The router builds it from the page route, so `/o-nas` and any prefix come out on their own.
editorParentFolder()  : string|null
Returns the parent folder (null in the editor root).
editorPath()  : string|null
Converts a client path (relative to the editor root) to an Api path (relative to the `uploads/` root).
editorUploadName()  : string|null
Builds a safe and unique file name. Sanitization copies the Api layer rules (webalize of the base and of the extension), so the name returned in the URL is exactly the name the file is stored under. The random suffix prevents collisions: `writeFile()` overwrites the same name without asking, so two different `obrazek.jpg` files would overwrite each other.
editorUploadUrl()  : string
Returns the public URL of a file. `$path` is relative to the `uploads/` root (so it includes `editorUploads/`), the same shape as other uploads in the system.
ensureEditorRoot()  : void
Creates the editor root folder; when it already exists the Api returns false and nothing happens.
expireIdleLogin()  : bool
Returns whether the login expired from inactivity. If so, revokes the tokens (like a logout), clears the `auth` section, logs out the Nette identity and returns true; otherwise moves the activity stamp forward.
extractOrderWarnings()  : array<int, string>
Returns the `warnings` of the `api/eshop/order/build` response (currently only the code `paymentMethodUnavailable`, see the API `OrderPresenter::internalActionBuild()` docblock) with a runtime guard to `list<string>`, like {@see orderStringKeyedArray()}.
fillOrderCustomerDeliveryFromContact()  : void
Copies the contact's delivery address (`CustomerContact.useDelivery`/`dlv*`) into the order's `useDelivery`/`customerDlv*` fields.
fillOrderCustomerFieldsFromContact()  : void
Overwrites the form's `customer*` fields from the given contact using the same `fieldMap` as the client picker ({@see \App\UI\Admin\Eshop\Presenters\Traits\Pickers\OrderCustomerLookupPickerTrait::orderCustomerLookupFieldMap()}), so the data-key to form-field mapping has a single source of truth.
formComponent()  : IComponent|null
Calls `getComponent()` through the `Container` type, bypassing the faulty vendor annotation `@method BaseControl getComponent(string $name)` on Contributte `BootstrapContainerTrait` (the real component-model signature has 2 arguments and a nullable return; the annotation on a BootstrapForm-typed variable makes phpstan fail).
getClientIp()  : string
initializeMetaTags()  : void
Fills the template with the title, meta tags and HTML text of the page from the translation (`PageText`) of the current language, for the layout (like the Front {@see \App\Core\Traits\Front\Presenters\PageInitTrait}).
initializePage()  : void
invoiceTypeNameOptions()  : array<int, string>
Returns the invoice type map `id => name` for the column; without it the list would show only numbers and an invoice could not be told from a credit note.
isDevelopment()  : bool
loadLocalization()  : Localization|null
loadOrderCustomerAccountUser()  : User|null
Loads the user account by id, or null when not found.
loadOrderCustomerWithContacts()  : Customer|null
Loads the customer with contacts for the address select (`customerContactId`) and the server refresh handlers. `id <= 0` safely returns null, like {@see \App\UI\Admin\Invoicer\Presenters\Traits\Pickers\SellerPickerTrait::loadSeller()}.
loadOrderSelectData()  : void
Loads the form axes once per request: currencies, languages, user types, payment regions, statuses, tariffs and payments. Names are ready DB data, hence `NotTranslate`; otherwise the form domain translator looks them up as a key (`eshop.presenters.order.Euro`) and Tracy reports a missing translation.
loadSeller()  : Seller|null
Loads the seller with contacts, accounts and tax status history for the server-side prefill of the invoice snapshot.
localizationCurrencyKey()  : string|null
Admin ignores the localization currency (it takes the language only).
loginReturnArgs()  : array<string, string>
Remembers the request of a logged-out user so the login can return to it ({@see storeRequest()}, `backlink` of the login page, restored by `AuthStorageTrait::redirectAfterLoginAction()`).
logoutNetteUser()  : void
onlyPricedLines()  : array<int, array<string, mixed>>
Drops rows without a price from the payload; used only by the shipping/payment refresh, which must not fail on `linePriceRequired` while some items are still unpriced (weight/cartTotal then count only trusted rows). Final save and "Recalculate" send all rows unchanged: a missing price must fail visibly there, not vanish silently.
orderBuildFailureMessage()  : string
Returns the preview error text from a failed `order/build` response. A technical failure (DB/ORM/transport) has an empty `message` (the detail is only in the server log) and a generic translated error is shown instead of an empty line. A domain validation message passes unchanged.
orderControlValues()  : ArrayHash<string|int, mixed>
Returns the form values for the AJAX button handlers.
orderCurrencyById()  : Currency|null
Returns the currency entity for an id from the build response (`serializeOrder()['currencyId']`), from the same list `loadOrderSelectData()` built for the `currencyId` select (no extra query). `null` = unknown or missing currency (the build has not run yet or the response omits it); the caller then passes `null` to the `priceFormat` filter, which leaves numbers raw.
orderCustomerContactLabel()  : string
orderCustomerContactOptions()  : array<int, NotTranslate>
Builds the `customerContactId` select items: contact id mapped to a meaningful summary (name or company, street, city). A legacy contact without the structured triple (see the class docblock) falls back to `CustomerContact::getName()`, never to an empty label.
orderCustomerContactPrefillData()  : array<string, string>
Builds the same dictionary as {@see orderCustomerLookupPrefillData()}, but for any contact (not just the first); used after a specific address is chosen in the `customerContactId` select (`OrderFormTrait::refreshOrderCustomerContact()`). The shared data source guarantees that the client `fieldMap` (first contact) and the server refresh (first or chosen contact) never produce different values for the same contact.
orderCustomerFieldMap()  : array<string, string>
orderCustomerLabel()  : string
orderCustomerLookupFieldMap()  : array<string, string>
orderCustomerLookupLabel()  : string
orderCustomerLookupPrefillData()  : array<string, string>
orderCustomerPrefillData()  : array<string, string>
orderExpeditionShipperOptions()  : array<int, NotTranslate>
The carrier name is already translated data from the DB, not a key: `NotTranslate`, otherwise the form's domain translator looks it up as a key and Tracy reports a missing translation.
orderGiftName()  : string
orderItemProductSetName()  : string
Returns the set name in the current language (falls back to the first non-empty one).
orderPayloadGifts()  : array<int, array{giftId: int|string, amount?: int}>
orderPayloadId()  : int|string|null
Returns an id for the build payload: canonical becomes int, empty or `0` becomes `null`. Any other value goes on unchanged, so the API (the single authority, {@see \App\UI\Api\Eshop\Models\Helpers\OrderPayloadHelper::findInvalidIdPath()}) rejects it; `intOrNull()` would turn a tampered hidden `'1.9'` into item #1 here.
orderPayloadLines()  : array<int, array{setId: int|string, quantity: int, orderItemId?: int|string, price?: string, vat?: string, name?: string, code?: string, unit?: string, discountPercents?: string}>
Builds the trusted rows: `price`/`vat` are required on the way to the API (missing: hard fail `linePriceRequired` there, no silent catalog fallback here). The form always carries them from prefill/snapshot, so they are just transcribed.
orderPayloadPickupManual()  : array{code: ?string, name: ?string, street: ?string, city: ?string, zip: ?string, country: ?string}|null
Returns the manually entered pickup point from the six text fields. `null` when both `code` and `name` are empty (both are required for a valid point); the API then ignores the manual path and decides only from the raw widget payload.
orderPayloadPickupPoint()  : array<string, mixed>|null
Decodes the hidden `pickupPoint`, which carries the raw JSON object of the widget (in the edit defaults `OrderShipper::$pickupPointData`), so the API gets the same field as the front checkout. Anything that is not a JSON object becomes `null`: the driver would not recognize an array/scalar and the fail-closed guard would turn it into `pickupPointRequired`.
orderPayloadVoucherCodes()  : array<int, string>
orderPickupWidgetContext()  : array{lang?: string, currency?: string, country?: string, weight?: float}
Returns the context for `CarrierInterface::getWidgetConfig()` in the admin. Language, currency and country come from the edited order (there is none on add, and the widget only appears after a tariff is chosen, when the form already has values). Weight is deliberately not passed: the admin reprices rows by hand and the widget uses weight only to filter offered points.
orderPreviewFromOrder()  : array<string, mixed>
Builds a deterministic preview snapshot straight from the saved order, without calling `api/eshop/order/build` (GET only, `OrderPresenter::actionEdit()`).
orderSellerDefaultsFromSettings()  : array<string, scalar|null>
Returns the default seller from settings for an order that has no own snapshot (add, or a record from before snapshots). The snapshot is built from the live directory because no other source exists: right for a new order, the best available estimate for an old one, which the admin sees and can overwrite before saving.
orderSellerDefaultsWithNotice()  : array<string, scalar|null>
Returns {@see orderSellerDefaultsFromSettings()} and reports the state to the admin. The flash is part of the contract: the seller is required, so without it the admin would learn of the problem only from a save error, and with empty settings would not know where to look (the shop seller setting).
orderSettingSellerId()  : int|null
Resolves the seller id from settings: `4/invoicer.sellerId`, falling back to `7/invoice.default.sellerId` (invoice defaults `invoice.default.*`), the same chain the invoice issue uses ({@see \App\UI\Api\Eshop\Models\Generators\OrderInvoiceGenerator::settingIntOrNull()}). An empty string in DB means "does not exist" (`is_numeric('')` is false).
orderStringKeyedArray()  : array<string, mixed>|null
Runtime guard to `array<string, mixed>`; the `ApiBridge` response is typed `mixed`.
parsePickerName()  : array{0: string, 1: list}
Splits a picker instance name into the config key plus row indexes (multiplier and nested multiplier). `parentId` -> `['parentId', []]`; `address_2` -> `['address', ['2']]`; `parameter_1_0` -> `['parameter', ['1','0']]` (nested).
prefillOrderItemRows()  : void
Picker prefill: for every row with a selected `productSetId` that has no price yet, fetches code/productSetName/unit/vat/price from the catalog (`api/eshop/order/item-prefill`, {@see \App\UI\Api\Eshop\Models\Services\OrderSnapshotBuilder::resolveItemPrefill()}).
processCreditNote()  : bool
Issues the credit note through the Api; redirects on success, returns false (with a flash) otherwise.
processFailedLogin()  : void
processInvalidToken()  : void
processLogin()  : void
processLoginException()  : void
processMissingToken()  : void
processOrderStatusChange()  : void
processSuccessfulLogin()  : void
processValidToken()  : void
readLoginDeviceToken()  : string|null
Returns the raw known-device cookie for the Api login (the Api verifies its signature).
recalculateOrderForm()  : void
Calls `build` (persist=false) with the current form data, including untouched fields.
redirectAfterLoginAction()  : void
After a login attempt: a successful login returns to the request remembered before the login (`backlink`, {@see PrivilegeCheckTrait::loginReturnArgs()}), otherwise to the dashboard; a failed one stays on the login page and keeps the way back.
refreshNetteIdentity()  : bool
Refreshes the token of the same logged-in user: identity data (token, name, email) are overwritten in the stored object without `login()`, so neither the session id nor the form CSRF tokens change. The identity is stored in the session section as an object; the change is written at the end of the request.
refreshOrderCustomer()  : void
Loads the customer with all contacts, fills the address select and prefills the fields from the first contact (same semantics as `refreshOrderSeller()`).
refreshOrderCustomerContact()  : void
Ownership guard: looks the contact up only among the chosen customer's contacts (`Customer::getContact()`). A foreign or nonexistent `customerContactId` (e.g. the select was filled by AJAX from elsewhere, a race) is silently ignored, no failure.
refreshOrderPayment()  : void
Same logic as {@see refreshOrderShipping()}, for the payment method.
refreshOrderPickupPoint()  : void
Handles the pickup widget selection (`pickupRefresh`): calls `build` (persist=false) with the raw widget object in the `pickupPoint` payload and prefills the six text fields from the snapshot in the response (`order.shipper.pickup*`). Same logic as {@see refreshOrderShipping()}, different field set.
refreshOrderSeller()  : void
Loads the seller snapshot from the Invoicer directory into the form.
refreshOrderShipping()  : void
Calls `build` (persist=false) after the tariff changes, with the same payload as `recalculateOrderForm` but without incomplete rows (no price).
rememberLoginDevice()  : void
After a successful login (password or OAuth) issues or renews the known-device cookie ({@see LoginDeviceCookie}): a signed proof that this browser has already logged in to the account. The next login sends it to the Api ({@see self::processLogin()}), and above the account limit the password from this browser is still verified, so foreign attempts do not lock out the owner. HttpOnly, SameSite=Lax, Secure on HTTPS; lifetime from `ratelimit.loginDevice.cookieLifetime`.
resolveLoginErrorMessage()  : string
Resolves the flash message of a failed login.
resolveOrderCustomerIdForContactSelect()  : int|null
Returns the `customerId` used to build the items of the `customerContactId` select.
resolveOrderCustomerLabel()  : string|null
resolveOrderCustomerLookupLabel()  : string|null
resolveOrderGiftLabel()  : string|null
resolveOrderItemProductSetLabel()  : string|null
resolveOrderPreviewCurrency()  : Currency|null
Returns the preview currency from `currencyId` in the serialized `order` of the build response, mapped to the entity from `$orderCurrencyEntities` (built in `loadOrderSelectData()`, no extra query).
resolveOrderSellerUseVat()  : bool
Returns whether the shop operator is a VAT payer, read live from the Invoicer seller.
resolveOrderVoucherLabel()  : string|null
resolvePaymentLabel()  : string|null
resolveSellerLabel()  : string|null
revokeTokensOnLogout()  : void
Calls the Api logout (revokes the refresh family and deny-lists the access `jti`) for the tokens of the current session. Fail-open on purpose: any failure is only logged, because the local logout must not stay unfinished.
rowValue()  : mixed
saveOrderForm()  : bool
sellerLabel()  : string
sellerPrefillData()  : array<string, string>
setControlValue()  : void
Force-sets a field value in the container (form or multiplier row) if it exists.
setNetteUser()  : void
setOrderFormDefaults()  : void
storeEditorUpload()  : bool
Stores a file; the target folder may not exist (first upload into the root), so after a failure the root is created once and the write is retried. Deeper subfolders are created by the editor user through `editorCreateFolder`.
suggestOrderCustomerLookups()  : array<int, array{id: int, label: string, data: array}>
suggestOrderCustomers()  : array<int, array{id: int, label: string, data: array}>
suggestOrderGifts()  : array<int, array{id: int, label: string}>
suggestOrderItemProductSets()  : array<int, array{id: int, label: string}>
suggestOrderVouchers()  : array<int, array{id: int, label: string}>
suggestPayments()  : array<int, array{id: int, label: string}>
Suggestions: searches by variable symbol and payment code (OR).
suggestSellers()  : array<int, array{id: int, label: string, data: array}>
syncPickupControls()  : void
Fills the seven pickup point controls from the shipper snapshot in the `build` response: six text fields, hidden `pickupPoint` with the raw widget object (so saving unchanged keeps exactly what the widget issued) and hidden `pickupPointTariffId` with the tariff the selection belongs to.
tryRefresh()  : bool
Tries an auto-refresh for an expired access token. If the session holds a refresh token and the Api accepts it, stores the new pair in the session and returns true; otherwise returns false and the caller cancels the session.
wireOrderMultiplierButtons()  : void
Multiplier add/remove buttons, as in {@see GiftFormTrait::addGiftOfferSetFields()}.

Constants

Login page parameter with the key of the stored request to return to ({@see loginReturnArgs()}).

public string LOGIN_BACKLINK = 'backlink'

DEFAULT_ITEMS_PER_PAGE

Items per page of admin lists when the DB setting is missing.

protected mixed DEFAULT_ITEMS_PER_PAGE = 20

FORM_BACK_SUBSECTION

Session subsection mapping a key to the previous page URL of edit forms.

protected mixed FORM_BACK_SUBSECTION = 'formBack'

SESSION_NAMESPACE

protected mixed SESSION_NAMESPACE = 'admin'

BLOCKED_EXTENSIONS

Extensions that must not be uploaded into the web-served folder; otherwise an editor upload would mean running foreign code on the server. It is no content whitelist (the editor uploads what is needed), only a safeguard against executable files.

private mixed BLOCKED_EXTENSIONS = ['php', 'php3', 'php4', 'php5', 'php7', 'php8', 'phps', 'phtml', 'phar', 'cgi', 'pl', 'py', 'sh', 'bash', 'htaccess', 'htpasswd']

EDITOR_PAGE_LIMIT

Listing cap; the dialog is a suggester, not a paged list.

private mixed EDITOR_PAGE_LIMIT = 500

EDITOR_PAGE_TARGETS

Routes the editor may link to: text pages only.

private mixed EDITOR_PAGE_TARGETS = ['front:system:page:show']

Other page routes need parameters the editor cannot know (Front:System:User:profile wants id and username, Front:System:Registration:registration wants email and activationKey, advert details want id/name). A link to them could not be built or would lead to a broken address, so they stay out of the offer.

Another target (e.g. Front:System:Page:homepage or Front:System:Page:form) is one more line here, provided its route needs only slug.

EDITOR_UPLOAD_FOLDER

Editor root (relative to the `uploads/` root). Changing it to `''` would open the whole `uploads/` tree to the manager; the editor user could then reach (and delete) files of other modules such as products and avatars.

private mixed EDITOR_UPLOAD_FOLDER = 'editorUploads'

IMAGE_EXTENSIONS

Extensions the file manager shows as a preview instead of a document icon.

private mixed IMAGE_EXTENSIONS = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'avif', 'svg', 'bmp']

LOCALE_MAP

Maps the short language code to the full locale of the registered NEON sources.

private mixed LOCALE_MAP = ['cs' => 'cs_CZ', 'en' => 'en_US', 'sk' => 'sk_SK']

The short code (cs, en, sk) comes from LanguageContext, derived from the URL parameter loc/lang; the full locales are cs_CZ, en_US, sk_SK. translator.neon configures one shared fallback chain [cs_CZ, cs, en_US, en, sk_SK, sk] for all languages, so a short code would always map to cs_CZ first, whatever language is active. A direct match on the full locale bypasses that.

The Contributte LocaleResolvers\Router (the only configured resolver) looks for the route parameter locale, but this application routes under loc, so it always returns null and the translator falls back to default: cs. An explicit setLocale() from here bypasses the resolver, which Translator::getLocale() asks only while no locale has been set explicitly.

Properties

$accessTokenValidator

Signature and expiry alone are not enough: a revoked token (`jti` on the deny-list) that has not expired yet would keep the session logged in although the Api guard rejects the same token. Same contract as {@see \App\Core\Traits\Api\Presenters\JwtAuthTrait::checkJwtAuth()}, one implementation.

public AccessTokenValidator $accessTokenValidator
Attributes
#[Inject]

$authUserManager

Admin `UserManager` for {@see UserManager::login()}. A module must not read through another module, so admin has its own `login()` that calls the same Api endpoint (`api/system/auth/login`).

public UserManager $authUserManager

The own property name avoids a collision with the generic $userManager from UserTrait (typed to the admin CRUD manager).

Attributes
#[Inject]

$columnSchema

Limits of the real database columns for {@see guardColumns()}.

public ColumnSchema $columnSchema
Attributes
#[Inject]

$editorAutosaveScope

Scope of the editor autosave drafts, see {@see \App\Core\Security\EditorAutosaveScope}.

public EditorAutosaveScope $editorAutosaveScope
Attributes
#[Inject]

$editorLinkPageManager

NOTE: own property name. `$pageManager` already exists on presenters (`PagePickerTrait`), and two `#[Inject]` properties of the same name would collide in the trait composition.

public PageManager $editorLinkPageManager
Attributes
#[Inject]

$editorUploadManager

NOTE: own property name, not `$fileSystemManager`.

public FileSystemManager $editorUploadManager

FileSystemPresenter takes the same manager as private readonly in its constructor, and PHP cannot redeclare a property of the same name between public and private.

Attributes
#[Inject]

$formSubmissionGuard

One-time submission tokens of "add" forms, see {@see guardFormSubmitOnce()}.

public FormSubmissionGuard $formSubmissionGuard
Attributes
#[Inject]

$loginDeviceCookie

Cookie of a known device for the password login throttle ({@see self::rememberLoginDevice()}).

public LoginDeviceCookie $loginDeviceCookie
Attributes
#[Inject]

$modalWindowFactory

Injected through Nette presenter inject (after construction), not the constructor.

public ModalWindowFactory $modalWindowFactory
Attributes
#[Inject]

$picker

Picker mode of a list; when not empty, the presenter renders its `show` grid as a selection modal (no add/edit/delete/checkboxes, each row has a select button) in the minimal `@picker.latte` layout.

public string $picker = ''

Opened by Picker; the value is the name of the opener's target field that receives the selection. Persistent, so it stays in grid links (filter/sort/paging) inside the modal. The presenter activates it in createComponent…Grid(): if ($this->picker !== '') { $grid->setPickerMode($this->picker); }.

Attributes
#[Persistent]

$pickerExclude

Id of the record that cannot be selected in picker mode (its select button is hidden).

public int $pickerExclude = 0

Serves self-referencing pickers (a parent page cannot be itself). Passed by Picker in the modal link via PickerConfig::targetParams; 0 means no exclusion.

Attributes
#[Persistent]

$pickerExcludeSubtreeLft

`lft`/`rgt` bounds of a whole subtree whose nodes cannot be selected in picker mode.

public int $pickerExcludeSubtreeLft = 0

Excludes the root and all descendants, so a node cannot be moved under its own descendant. 0 means no subtree exclusion.

Attributes
#[Persistent]

$pickerExcludeSubtreeRgt

public int $pickerExcludeSubtreeRgt = 0
Attributes
#[Persistent]

$queryCacheContext

Query cache policy for the whole admin request; `startup()` disables it.

public QueryCacheContext $queryCacheContext

Injected as a public property like the other admin base services; it cannot live in a trait because startup() touches it first.

Attributes
#[Inject]

$savedEntityId

Id of the record just saved; set by the `$processData` callback in `createForm()` after a successful save.

protected int|null $savedEntityId = null

The apply button (update) uses it: on the add action (new record, no id in the URL) it redirects to editing the new record (edit?id=...). Redirecting to this would lead back to an empty add form and the next apply would create a duplicate. When the callback leaves it null (e.g. a settings form without an edit action), the redirect goes to this.

$translatorDomain

protected string $translatorDomain = 'admin.eshop.presenters.order'

$creditNoteComplaintId

Complaint the form was prefilled from (kept for the redirect after submit).

private int|null $creditNoteComplaintId = null

$creditNotePreview

Basis of the partial credit note form (`api/eshop/order/credit-note-preview`); `null` when the order has no source invoice, so there is nothing to credit.

private array<string, mixed>|null $creditNotePreview = null

$editedOrder

Edited or displayed order (null when adding).

private Order|null $editedOrder = null

$orderCurrencyEntities

Currency id => entity (same source as `orderCurrencyOptions`, so `priceFormat` needs no extra DB query).

private array<int, Currency> $orderCurrencyEntities = []

$orderCurrencyOptions

private array<int, NotTranslate> $orderCurrencyOptions = []

$orderInitialStatusOptions

private array<int, NotTranslate> $orderInitialStatusOptions = []

only statuses with createOrder=1: the initial status of a new order

$orderItemPrefillWarnings

Items whose price the item prefill could not fetch from the catalog after the picker choice (the Api `item-prefill` failed, typically a set without a valid price for the chosen currency). Without this list the prefill would fail silently and the admin would learn about the missing price only from a recalculation error. Row labels (name, code, #id), rendered by `{snippet items}` as an alert; filled by {@see Traits\Forms\OrderFormTrait::prefillOrderItemRows()}.

private array<int, string> $orderItemPrefillWarnings = []

$orderLanguageOptions

private array<int, NotTranslate> $orderLanguageOptions = []

$orderLocalizationOptions

private array<int, NotTranslate> $orderLocalizationOptions = []

localization = amount format on the document

$orderPaymentMethodOptions

private array<int, NotTranslate> $orderPaymentMethodOptions = []

$orderPaymentRegionOptions

private array<int, NotTranslate> $orderPaymentRegionOptions = []

$orderPreview

Preview of the last AJAX recalculation ({@see OrderFormTrait::recalculateOrderForm()}).

private array<string, mixed>|null $orderPreview = null

$orderPreviewCurrency

Currency of the last preview (build response `currencyId` resolved through {@see $orderCurrencyEntities}; on the edit GET baseline taken from `$editedOrder->getCurrency()`). `null` = unknown currency, so the template and the `priceFormat` filter leave numbers raw.

private Currency|null $orderPreviewCurrency = null

$orderPreviewError

private string|null $orderPreviewError = null

$orderPreviewWarnings

Non-blocking warnings for the last preview or save (currently only the code `paymentMethodUnavailable`, see {@see \App\UI\Api\Eshop\Presenters\OrderPresenter::internalActionBuild()}): codes from the Api response, translated in the template or flash via `form.warnings.<code>`.

private array<int, string> $orderPreviewWarnings = []

$orderSellerUseVat

Per-request cache of the eshop seller's VAT-payer status ({@see Traits\Forms\OrderFormTrait::resolveOrderSellerUseVat()}; `null` = not yet resolved).

private bool|null $orderSellerUseVat = null

The VAT gate of the controls asks while building every form section, but the seller cannot change within one request.

$orderTariffOptions

private array<int, NotTranslate> $orderTariffOptions = []

tariffId => "Carrier — Tariff"

$orderTariffPickup

Tariff id => pickup point context for the order edit form. `externalPickup` says whether the "Pickup point" block is rendered at all; `widget` is the driver configuration (`data-pickup-*` attributes of the "Select on map" button), `null` when the carrier has no `script_name`, no driver in the registry or no API key, so only manual entry remains (message `form.pickup.noDriver`).

private array<int, array{externalPickup: bool, scriptName: ?string, widget: ?array}> $orderTariffPickup = []

$orderUserTypeOptions

private array<int, NotTranslate> $orderUserTypeOptions = []

$userPrivileges

private array<int, string> $userPrivileges = []

privileges of the current user loaded in startup()

Methods

__construct()

public __construct(DataGridFactory $dataGridFactory, PickerFactory $pickerFactory, ApiBridge $apiBridge, OrderManager $orderManager, OrderStatusManager $orderStatusManager, GiftManager $giftManager, VoucherManager $voucherManager, ProductSetManager $productSetManager, ShipperManager $shipperManager, ShipperTariffManager $shipperTariffManager, PaymentMethodManager $paymentMethodManager, CurrencyManager $currencyManager, UserTypeManager $userTypeManager, PaymentRegionManager $paymentRegionManager, InvoiceManager $invoiceManager, InvoiceTypeManager $invoiceTypeManager, StockReservationManager $stockReservationManager, StockDocumentManager $stockDocumentManager, CarrierRegistry $carrierRegistry) : mixed
Parameters
$dataGridFactory : DataGridFactory
$pickerFactory : PickerFactory
$apiBridge : ApiBridge
$orderManager : OrderManager
$orderStatusManager : OrderStatusManager
$giftManager : GiftManager
$voucherManager : VoucherManager
$productSetManager : ProductSetManager
$shipperManager : ShipperManager
$shipperTariffManager : ShipperTariffManager
$paymentMethodManager : PaymentMethodManager
$currencyManager : CurrencyManager
$userTypeManager : UserTypeManager
$paymentRegionManager : PaymentRegionManager
$invoiceManager : InvoiceManager
$invoiceTypeManager : InvoiceTypeManager
$stockReservationManager : StockReservationManager
$stockDocumentManager : StockDocumentManager
$carrierRegistry : CarrierRegistry

actionCreditNote()

Partial credit note. The order is loaded only for the header (number, customer); the table rows come from the source invoice, not from the order, because the credit note applies to the document, which can differ from the order (fees have their own row, a rounding row was added, the order may have been edited since).

public actionCreditNote(int $id[, int|null $complaintId = null ]) : void
Parameters
$id : int
$complaintId : int|null = null

actionEdit()

public actionEdit(int $id) : void
Parameters
$id : int

actionStatus()

public actionStatus(int $id) : void
Parameters
$id : int

beforeRender()

Exposes the AJAX recalculation preview to Latte (`{snippet orderPreview}`).

public beforeRender() : void

createComponent()

public createComponent(string $name) : IComponent|null
Parameters
$name : string
Return values
IComponent|null

flashFormOwnErrors()

Flashes form-level errors (`$form->getOwnErrors()`) as `danger` messages.

public flashFormOwnErrors(Form $form) : void

Called from onError of createForm(); public for component forms (AdminComponentFormTrait). Element errors are not flashed; {inputError} renders them at the field.

Parameters
$form : Form

flashRejectedUploads()

Flashes one `warning` listing the files the Api rejected (type, dimensions, unreadable) after a successful save of a form with a dropzone ({@see UploadRejection}).

public flashRejectedUploads(Result $result) : void

The save itself passed and accepted files are stored. The message is already translated (a list of names), so translate = false (see flashFormOwnErrors()). Call it before the redirect, because a flash sent through redirectUrl is lost; public for component forms.

Parameters
$result : Result

formatLayoutTemplateFiles()

Admin version of {@see \App\Core\Traits\Front\Presenters\ThemeInitTrait::formatLayoutTemplateFiles()}.

public formatLayoutTemplateFiles() : array<string|int, mixed>

It starts from AdminPage ($adminPageEntity, column layout), not from the Front $pageEntity, which an admin presenter does not have; admin also has no loggedLayout. The database value wins; getAdminLayout() is the fallback that LoginPresenter overrides with @login.latte.

Return values
array<string|int, mixed>

getContainer()

public getContainer() : Container
Return values
Container

getFormBackUrl()

Returns the stored previous page URL for the key, used by the `cancel` link in the template.

public getFormBackUrl(string|null $key) : string
Parameters
$key : string|null
Return values
string

guardFormSubmitOnce()

Protects a form against a double submit: one rendered form saves at most once.

public guardFormSubmitOnce(Form $form) : void

createForm() applies it to every form of an "add" action (isAddAction()), the component skeleton AdminComponentFormTrait likewise, and forms built outside both call it themselves (product import upload, credit notes, stocktake). A repeated submit of an edit form only saves the same values again, so edits are not guarded.

Adds the hidden token (FormSubmissionGuard::FIELD), issued on every GET render (on POST it comes back from the browser), and data-submit-once for submit-once.js, which blocks a second click in the browser. The server side (runSubmitOnce()) is the authority, because a request can come from outside the browser or the client script may not run. Idempotent.

Parameters
$form : Form

handleChangeLocale()

public handleChangeLocale(string $locale) : void
Parameters
$locale : string

handleEditorCreateFolder()

Creates a subfolder in `folder` (path relative to the editor root).

public handleEditorCreateFolder([string $folder = '' ][, string $name = '' ]) : void
Parameters
$folder : string = ''
$name : string = ''
Attributes
#[Requires]
$methods: 'POST'

handleEditorDelete()

Deletes a file or (recursively) a folder. An empty path would point to the editor root, which cannot be deleted.

public handleEditorDelete([string $path = '' ]) : void
Parameters
$path : string = ''
Attributes
#[Requires]
$methods: 'POST'

handleEditorFiles()

Sends the folder listing for the editor file manager. The `folder` parameter is a path relative to the editor root (empty means the root).

public handleEditorFiles([string $folder = '' ]) : void

Sends JSON {folder, parent, breadcrumb[], folders[], files[]}; paths in the response are again relative to the editor root, and a public URL is given for files only. The server path never leaves the server.

A non-existent folder gives an empty listing, not an error (until something is uploaded the root does not exist physically and the manager just shows the empty state).

Parameters
$folder : string = ''

handleEditorPages()

Sends the page list for the link dialog as JSON `{"pages": [{id, label, url}, ...]}` sorted by label.

public handleEditorPages() : void

Only text pages (EDITOR_PAGE_TARGETS); pages without a filled URL (href) are skipped too, because no link can be built for them.

handleEditorRename()

Renames a file or folder (`path` relative to the editor root).

public handleEditorRename([string $path = '' ][, string $name = '' ]) : void
Parameters
$path : string = ''
$name : string = ''
Attributes
#[Requires]
$methods: 'POST'

handleEditorUpload()

Accepts a file from the editor (field `file`, multipart POST; optional `folder` = subfolder of the editor root) and sends JSON `{"location": "/www/uploads/editorUploads/..."}`, the format TinyMCE expects from `images_upload_handler`.

public handleEditorUpload() : void
Attributes
#[Requires]
$methods: 'POST'

handleLogout()

public handleLogout() : void
Attributes
#[Requires]
$methods: 'POST'

handleSignOut()

public handleSignOut() : void
Attributes
#[Requires]
$methods: 'POST'

hasServiceByType()

Returns whether the container has a service of the given type.

public hasServiceByType(string $className) : bool

The name is composed dynamically (module plus component), so class_exists() runs first, and a true result guarantees a valid type.

Parameters
$className : string
Tags
phpstan-assert-if-true

class-string $className

Return values
bool

hasVatControls()

Returns whether the form may contain VAT controls at all (`withVat` checkbox, row `vat`/ `priceWithVat`/`totalPriceWithVat`, `shippingVat`, `paymentVat`).

public hasVatControls() : bool

On add it depends on the shop seller being a VAT payer (resolveOrderSellerUseVat()); a non-payer gets no controls, since a live toggle would have nothing to switch. On edit always true: the admin must be able to turn VAT on for an order that lacks it, and off for one that has it.

Return values
bool

initializeTranslator()

public initializeTranslator(string|null $alias) : void
Parameters
$alias : string|null

isAddAction()

Tells whether the current action creates a record: `add` and the `add<Something>` actions (`addMenu`, `addKey`). Derived from the server context only, like {@see formSubmitPrivilege()}.

public isAddAction() : bool
Return values
bool

isAllowed()

Returns whether the logged-in user has the given privilege.

public isAllowed(string $key) : bool

Reads the array loaded in startup(), with no database query. Fail-closed: returns false when loadUserPrivileges() was not called or failed.

Public so templates can call it ($presenter->isAllowed(...)) for conditional display of actions outside DataGrid (e.g. static menu management links).

Parameters
$key : string
Return values
bool

isSubmitOnceForm()

Tells whether the form was protected by {@see guardFormSubmitOnce()}.

public isSubmitOnceForm(Form $form) : bool
Parameters
$form : Form
Return values
bool

loginWithCredentials()

Logs in with username and password; called only by the login form (after validation and CSRF).

public loginWithCredentials(string $username, string $password[, bool $remember = false ]) : void

IMPORTANT: this must not be named handleLogin(). A handle* method is a public signal of every presenter (?do=login&username=...&password=...): the password could end up in the URL and the server log, and the form token would be bypassed. Nette finds signals by the handle prefix only.

Parameters
$username : string
$password : string
$remember : bool = false

orderPickupInfo()

Returns the pickup point context of the selected tariff for `edit.latte` (`{snippet shippingFields}`). `null` = no tariff selected, unknown tariff or no `external_pickup`, so the "Pickup point" block is not rendered at all.

public orderPickupInfo(int|null $tariffId) : array{externalPickup: bool, scriptName: ?string, widget: ?array}|null
Parameters
$tariffId : int|null
Return values
array{externalPickup: bool, scriptName: ?string, widget: ?array}|null

pickupCarrierLabel()

Returns a readable carrier name from the `OrderShipper::$pickupCarrier` snapshot (`script_name`).

public pickupCarrierLabel(string|null $scriptName) : string|null

The snapshot is used instead of the live Shipper relation, which may change or be deleted after the order. An unknown or old script_name (driver since removed) falls back to the raw value so the admin still sees something. manual is not the script_name of any driver: it marks a pickup point typed in by hand for a carrier without a driver, so it is translated instead of looked up in the registry (otherwise the raw "manual" would show in the detail).

Parameters
$scriptName : string|null
Return values
string|null

publishFieldErrors()

Publishes element errors of a failed submit to the client.

public publishFieldErrors(Form $form) : void

IMPORTANT: field errors were visible only where the template has {inputError}; server rules on fields without it stopped the form but showed the user no message.

An AJAX submit sends payload.fieldErrors; a full render sets data-server-field-errors on <body> (see @layout.latte), which the script reads on load. The script avoids duplicating {inputError}.

Parameters
$form : Form

redirectToFormBack()

Redirects to the stored previous page and discards the key.

public redirectToFormBack(string|null $key) : void

Public for component forms (AdminComponentFormTrait), whose save submit calls it through $this->getPresenter().

Parameters
$key : string|null

resolveFormBackKey()

Returns the previous-page key: from the URL if present (survives the update redirect), otherwise on a plain GET render of the edit page stores `Referer` in the session under a new random key.

public resolveFormBackKey() : string

Public for component forms (AdminComponentFormTrait); a component reaches it through $this->getPresenter().

Return values
string

runSubmitOnce()

Runs a saving step of a form under its one-time token (a form without the token just runs it).

public runSubmitOnce(Form $form, string $backKey, callable(): bool $save) : bool|null
  • the first submit claims the token and saves; a failed save (false or an exception) releases it, so the corrected form can be sent again; a successful one keeps it with $savedEntityId. A redirect thrown from inside the step counts as a successful save, so the step should set $savedEntityId before redirecting;
  • a submit of an already used token does not run the step, flashes a notice, sets $savedEntityId to the record of the first submit and returns null; the caller leads where the first submit led;
  • a submit arriving while the first one still saves waits for it a few seconds, then behaves as above, or ends on the previous page with a warning (redirect);
  • a missing or malformed token does not run the step; the form gets a fresh token and a message and false is returned (the browser case is a form opened before the protection was deployed).

Public for component forms and form traits outside createForm().

Parameters
$form : Form
$backKey : string
$save : callable(): bool
Return values
bool|null —

true = saved now, false = not saved, null = saved by an earlier submit of the same form

setConfigParameters()

public setConfigParameters([bool $debugMode = false ][, bool $productionMode = false ]) : void
Parameters
$debugMode : bool = false
$productionMode : bool = false

setTranslator()

public setTranslator(ITranslator $translator) : $this
Parameters
$translator : ITranslator
Return values
$this

shouldShowVatFields()

Returns the initial visibility of the VAT fields (not of the checkbox, see {@see hasVatControls()}).

public shouldShowVatFields() : bool

On add it follows the seller's VAT-payer status (same condition as hasVatControls()); on edit only the saved order.withVat, so an order created with VAT keeps showing VAT fields even if the operator has since turned VAT off, and a withVat=false order never shows them. Called from edit.latte ($presenter->shouldShowVatFields()); order-item-calc.js toggles it live, this is only the server-side initial state.

Return values
bool

typedComponent()

Returns a subcomponent with a verified type.

public typedComponent(string $name, T> $type) : T

Use it instead of an inline @var above $this['x'] (which does not narrow the type) and instead of the generic IComponent that $this['x'] returns. See Form::typedComponent().

Parameters
$name : string
$type : T>
Tags
template
Return values
T

authorize()

Authorization hook; by default requires the `:Admin` privilege.

protected authorize() : void

LoginPresenter overrides it so the login page stays reachable for a guest.

authorizeFormSubmit()

Gate for writing presenter forms built by `createForm()`.

protected authorizeFormSubmit(Form $form) : void

IMPORTANT: a form submit is a signal (?do=editForm-submit) that Nette handles on any action, after action*(). A gate in actionAdd()/actionEdit() therefore covers only submits sent to add/edit; a submit sent to a list (show) passes authorizeListing() only, and a save callback without its own gate would write with view-only rights.

Called by createForm() before $processData (only for the update/save buttons) and by custom saving submits outside that gate.

Parameters
$form : Form

authorizeListing()

Gate for reading lists.

protected authorizeListing() : void

IMPORTANT: without this gate anyone inside the admin could open any list without the privilege. The gate lives here once, not in every presenter. The key is derived as in PrivilegeCheckTrait::checkCurrentPrivilege(): :Admin:<Module>:<Presenter>:show.

IMPORTANT: guards only the show action. Other actions have their own gates (add/edit/signals), and a blanket key would not fit them: dashboard, login, downloadPdf, statistics and similar have no ...:<action> key, so the fail-closed check would lock out even the administrator.

NOTE: every show screen needs its key in the privilege table and enabled for the admin role.

checkAdminAccess()

Entry gate to the admin: a guest is sent to login; a logged-in user without `:Admin` is sent to login with an error.

protected checkAdminAccess() : void

checkCurrentPrivilege()

Builds the key from the current request (`:Admin:<Module>:<Presenter>:<action>`) and checks it. `getName()` already contains the `Admin:...` prefix, so only one leading colon is added.

protected checkCurrentPrivilege() : void

Use it where the key matches the action; use explicit checkPrivilege() where it differs (another presenter, add versus edit).

checkPrivilege()

Checks a specific privilege; throws 403 when denied.

protected checkPrivilege(string $key) : void

IMPORTANT: a hidden button is no protection. A hand-built ?...&do=<signal> URL runs the action, so every non-standard action and every mutating signal needs the gate as its first statement; otherwise anyone who types the URL can run it.

IMPORTANT: form actions need two gates, one in the signal and one in process*() (the submit), because a submit arrives as its own request. With only the signal gate the submit stays open. See the WorkList traits.

Parameters
$key : string

createComponentPicker()

protected createComponentPicker() : Multiplier<string|int, Picker>
Return values
Multiplier<string|int, Picker>

createForm()

Creates an edit form with the standard actions and a return to the previous page.

protected createForm(callable(ArrayHash<string|int, mixed>, Form): bool $processData) : Form

Buttons (the template renders them on the right as cancel, update, save):

  • save saves and returns to the previous page,
  • update saves and stays on the edit page (redirect to this),
  • cancel is only a link back, rendered by the template via getFormBackUrl().

On the first load of the edit page (plain GET render, not POST/signal) the previous page is taken from Referer, stored in the session under a random key, and the key goes into the hidden backKey field. It is per form so concurrent tabs do not overwrite each other, and it travels through the update redirect as a URL parameter.

The concrete presenter adds fields and defaults; this method provides the skeleton, buttons and redirects.

Parameters
$processData : callable(ArrayHash<string|int, mixed>, Form): bool

Saves the data; returns success (handles its own flash).

Return values
Form

currentLangId()

Returns the current language id (for picker labels etc.), null when unknown.

protected currentLangId() : int|null
Return values
int|null

domainTranslator()

Returns a translator prefixed with the presenter domain, or `null` (empty domain or a translator other than Contributte).

protected domainTranslator() : PrefixedTranslator|null

beforeRender() sets it only on $this->template. Templates created separately through createTemplate() (e.g. modal content built in the handle phase) do not have it, and their relative {_'...'} keys would print raw. Such places obtain it here.

Return values
PrefixedTranslator|null

formSubmitPrivilege()

Returns the privilege key required to save a form built by `createForm()`.

protected formSubmitPrivilege(Form $form) : string

Derived only from server context (presenter and action), never from a form field, so a changed hidden id cannot select a different right:

  • action add gives ...:add, action edit gives ...:edit;
  • any other action of a presenter with records (it has an add/edit action) gives ...:edit; a record form does not belong there, and whoever sends it needs at least the edit right;
  • a presenter without add/edit actions (single-page settings) gives the key of the current action, i.e. ...:show. Those screens have no other key in RBAC; an unknown action ends on a nonexistent key, which is a 403 (fail-closed).

A form bound to a custom action (sendEmail, inventory, addMenu...) overrides the method in its presenter and returns that action's key, always matched by form name so the exception does not let another form of the same presenter through.

Parameters
$form : Form
Return values
string

getAdminItemsPerPage()

Returns the default items per page of admin lists from the DB setting `admin.itemsPerPage` (module System = 1), falling back to {@see DEFAULT_ITEMS_PER_PAGE}.

protected getAdminItemsPerPage() : int
Return values
int

getAdminLayout()

Returns the layout name; in picker mode ({@see $picker}) the `show` grid uses the minimal `@picker.latte` (no sidebar/header) so the opener fetch returns only the table.

protected getAdminLayout() : string

LoginPresenter overrides it with @login.latte.

Return values
string

getFormBackFallback()

Returns the return URL when the previous page is unknown; override in a presenter without a `show` action.

protected getFormBackFallback() : string
Return values
string

getFormLanguages()

Returns the languages for multilingual form fields (admin `LanguageManager`).

protected getFormLanguages() : array<int, Language>
Return values
array<int, Language>

getSessionKey()

Returns a session key string, e.g. 'front.auth.step1'.

protected getSessionKey([string|null $namespace = null ][, string|null $subsection = null ], string ...$extra) : string
Parameters
$namespace : string|null = null

Base namespace (module prefix). Uses SESSION_NAMESPACE if null.

$subsection : string|null = null

Subsection under the namespace. Uses SESSION_SUBSECTION constant if null.

$extra : string

Additional parts to append (e.g. 'step1', 'wizard', etc.).

Return values
string

getSessionSection()

Returns a Nette\SessionSection instance using a dynamically built session key.

protected getSessionSection([string|null $namespace = null ][, string|null $subsection = null ], string ...$extra) : SessionSection
Parameters
$namespace : string|null = null
$subsection : string|null = null
$extra : string
Tags
see
getSessionKey()
Return values
SessionSection

guardColumns()

Gates every text and number field of the form by the real column it writes to ({@see \App\Core\Forms\ColumnGate::guard()}): an oversized value is an error at the field, never a database error that closes the entity manager (admin walkthrough A1, A14).

protected guardColumns(Form $form, array<string, array<int, class-string>> $containers[, array<int, string> $except = [] ]) : void
Parameters
$form : Form
$containers : array<string, array<int, class-string>>

container path ('' = the form, a multiplier name = its rows) => entities

$except : array<int, string> = []

control names never gated (a value transformed before storage)

intOrNull()

Converts mixed to int or null (an empty or zero value becomes null).

protected intOrNull(mixed $value) : int|null
Parameters
$value : mixed
Return values
int|null

isSameSiteRequest()

Tells whether the request comes from the own site (Nette SameSite cookie); protects GET actions with a side effect.

protected isSameSiteRequest() : bool

getHttpRequest() returns the IRequest interface, while isSameSite() exists only on Nette\Http\Request.

Return values
bool

loadUserPrivileges()

Loads all privileges of the logged-in user with one database query. Call it right after `checkAdminAccess()` in `startup()` (the user is guaranteed to be logged in by then).

protected loadUserPrivileges() : void

orderCustomerLookupPicker()

protected orderCustomerLookupPicker([string $formName = 'editForm' ][, string $targetField = 'customerId' ]) : PickerConfig
Parameters
$formName : string = 'editForm'
$targetField : string = 'customerId'
Return values
PickerConfig

orderCustomerPicker()

protected orderCustomerPicker([string $formName = 'editForm' ][, string $targetField = 'userId' ]) : PickerConfig
Parameters
$formName : string = 'editForm'
$targetField : string = 'userId'
Return values
PickerConfig

orderGiftPicker()

protected orderGiftPicker([string $container = 'gifts' ][, string $targetField = 'giftId' ][, string $displayField = 'giftName' ][, string $formName = 'editForm' ]) : PickerConfig
Parameters
$container : string = 'gifts'
$targetField : string = 'giftId'
$displayField : string = 'giftName'
$formName : string = 'editForm'
Return values
PickerConfig

orderItemProductSetPicker()

protected orderItemProductSetPicker([string $container = 'items' ][, string $targetField = 'productSetId' ][, string $displayField = 'productSetName' ][, string $formName = 'editForm' ]) : PickerConfig
Parameters
$container : string = 'items'
$targetField : string = 'productSetId'
$displayField : string = 'productSetName'
$formName : string = 'editForm'
Return values
PickerConfig

orderStockDocuments()

protected orderStockDocuments(Order $order) : array<int, object>
Parameters
$order : Order
Return values
array<int, object> —

Store issue and receipt documents (StockDocument) of the order.

orderStockReservations()

protected orderStockReservations(Order $order) : array<int, object>
Parameters
$order : Order
Return values
array<int, object> —

Store reservations (StockReservation) of the order.

orderTargetStatusFlagsJson()

JSON map `statusId => flags` for `order-status-form.js` (section toggles).

protected orderTargetStatusFlagsJson() : string
Return values
string

orderVoucherPicker()

protected orderVoucherPicker([string $container = 'vouchers' ][, string $targetField = 'voucherId' ][, string $displayField = 'code' ][, string $formName = 'editForm' ]) : PickerConfig
Parameters
$container : string = 'vouchers'
$targetField : string = 'voucherId'
$displayField : string = 'code'
$formName : string = 'editForm'
Return values
PickerConfig

parseDateTime()

Converts a `datetime-local` input or text value to `DateTime`, or null when empty or unparsable.

protected parseDateTime(mixed $value) : DateTime|null
Parameters
$value : mixed
Return values
DateTime|null

paymentPicker()

protected paymentPicker([string $formName = 'editForm' ][, string $targetField = 'paymentId' ]) : PickerConfig
Parameters
$formName : string = 'editForm'
$targetField : string = 'paymentId'
Return values
PickerConfig

pickers()

Returns the presenter pickers: `userId`/`items`/`gifts` from the Eshop traits and `paymentId` (status form) from the shared System `PaymentPickerTrait`.

protected pickers() : array<string, PickerConfig>

Must be side-effect free: it is also called during the AJAX signal suggest!.

Return values
array<string, PickerConfig>

sellerPicker()

protected sellerPicker(string $formName, string $targetField[, string|null $submitButton = null ]) : PickerConfig
Parameters
$formName : string

name of the form with the hidden field

$targetField : string

name of the hidden control (sellerId)

$submitButton : string|null = null
Return values
PickerConfig

setupTemplateTranslator()

Sets a translator prefixed with the presenter domain into the template (as Front components do, see {@see \App\Core\Base\BaseComponent::setup()}).

protected setupTemplateTranslator() : void

Templates then use short keys {_'key'} resolved as <translatorDomain>.key without {translator}. Shared keys in the layout are written absolutely with the // prefix, which bypasses the domain. The domain comes from the $translatorDomain property of the concrete presenter (admin.system.presenters.<presenter>).

str()

Safely converts a mixed form value to string.

protected str(mixed $value) : string
Parameters
$value : mixed
Return values
string

strOrNull()

Converts mixed to string or null (an empty string is stored as null).

protected strOrNull(mixed $value) : string|null
Parameters
$value : mixed
Return values
string|null

addOrderCustomerContactRefreshButton()

Adds the force-submit button `order-item-calc.js` clicks after the `customerContactId` select changes (`data-refresh-target`, same generic mechanism as `tariffId` -> `shippingRefresh`).

private addOrderCustomerContactRefreshButton(Form $form) : void

Prefills the fields from the chosen (not necessarily first) address.

Parameters
$form : Form

addOrderCustomerRefreshButton()

Adds the force-submit button picker.js clicks after a customer is picked.

private addOrderCustomerRefreshButton(Form $form) : void

The server fills the address select and prefills the customer fields from the first contact authoritatively; the client fieldMap on the picker only gives an instant response from the same data.

Parameters
$form : Form

addOrderGiftsMultiplier()

Adds the gifts multiplier: row = gift picker + quantity.

private addOrderGiftsMultiplier(Form $form) : void

Limit from the raw HTTP data (onAnchor) plus $maxCopies as a second defense.

Parameters
$form : Form

addOrderItemsMultiplier()

Adds the items multiplier: row = product set picker + editable price breakdown.

private addOrderItemsMultiplier(Form $form) : void

Modeled on InvoiceFormTrait::addLineControls(): code/quantity/unit/price/vat/ discountPercents are trusted (the admin edits them) plus three read-only client-side computed fields (order-item-calc.js). IMPORTANT: a plain Container inside the Multiplier does not decorate form-control itself, so the class is added by hand on every field.

Parameters
$form : Form

addOrderItemsPrefillButton()

Adds the shared hidden button picker.js clicks after a product set is picked in any row (`OrderItemPickerTrait::orderItemProductSetPicker()` with `submitButton: 'itemsPrefill'`).

private addOrderItemsPrefillButton(Form $form) : void

validationScope([]) keeps the force-submit from blocking on required fields; createForm() lets save through only via update/save, so this never saves.

Parameters
$form : Form

addOrderPaymentRefreshButton()

Force-submit after `paymentMethodId` changes (JS clears paymentPrice/Vat before the click).

private addOrderPaymentRefreshButton(Form $form) : void
Parameters
$form : Form

addOrderPickupPointFields()

Adds the carrier pickup point controls for order edit.

private addOrderPickupPointFields(Form $form) : void

The admin either picks the point in the carrier widget ("pick on map": JS writes the raw object into hidden pickupPoint and clicks pickupRefresh) or types it into six text fields (payload pickupPointManual). Only the server-side driver normalizes either path; JS maps nothing.

IMPORTANT: the controls are always added, regardless of the selected tariff; the template decides whether to render the block ($presenter->orderPickupInfo()), and hidden pickupPoint must be in the HTML even outside that condition, otherwise a skipped hidden widget loses its value.

Parameters
$form : Form

addOrderPickupRefreshButton()

Adds the force-submit button used after a point is picked in the carrier widget.

private addOrderPickupRefreshButton(Form $form) : void

JS writes the raw widget object into hidden pickupPoint and clicks this button. The server sends the payload to order/build (persist=false), the driver normalizes it and the six text fields are prefilled from the response; the driver is the only source of normalization (as with shippingRefresh).

Parameters
$form : Form

addOrderRecalculateButton()

Adds the "Recalculate" button.

private addOrderRecalculateButton(Form $form) : void

validationScope([]) so it does not block on required fields while the admin is still composing the order; it does not save (outside the update/save gate in createForm()), only calls build with persist=false and redraws the preview panel. It never overwrites the form's row prices: the preview is read-only totals.

Parameters
$form : Form

addOrderSellerFields()

Adds the seller (shop operator) snapshot fields stored on the order.

private addOrderSellerFields(Form $form) : void

The sellerId picker only prefills; the texts stay editable because for an old order that is the only way to issue a document with the details valid at the time (the directory already holds newer ones). sellerId is required (mirrors the API guard sellerRequired); setOrderFormDefaults() prefills it from settings on add and on orders without a snapshot. sellerContactId/sellerBankAccountId only record which directory contact/account was the source; the server fills them in refreshOrderSeller(), admins never edit them.

Parameters
$form : Form

addOrderSellerRefreshButton()

Adds the hidden force-submit button that picker.js clicks after a seller is picked.

private addOrderSellerRefreshButton(Form $form) : void

The client fills the text fields from fieldMap, but the server overwrites them authoritatively and also fills sellerContactId/sellerBankAccountId, which the client cannot see. validationScope([]) skips validation (required seller/items do not block the prefill); createForm() lets save through only via update/save, so this never saves.

Parameters
$form : Form

addOrderShippingFields()

Adds shipping/payment with an editable price (without VAT) and rate.

private addOrderShippingFields(Form $form) : void

Edit defaults come from the snapshot (setOrderFormDefaults); changing the tariff/payment method select force-submits shippingRefresh/paymentRefresh (JS data-refresh-target) and the server recomputes the price from the resolver, including free_from, only on prefill, not on save.

Parameters
$form : Form

addOrderShippingRefreshButton()

Force-submit after `tariffId` changes (JS clears shippingPrice/Vat before the click).

private addOrderShippingRefreshButton(Form $form) : void
Parameters
$form : Form

addOrderStockCheckFields()

Adds the stock check fieldset below "Shipping and payment" (separate so the override of the strict stock gate is visually apart from shipping/payment, which it does not relate to).

private addOrderStockCheckFields(Form $form) : void

Overrides the strict stock gate for this save only. IMPORTANT: it is not a checkbox. The API applies the override only when allowPartial is explicitly bool, so a checkbox would always override 4/order.partial.adminAllowed and "leave it to the setting" would be impossible. A tri-state select with an empty prompt sends null, meaning the key is absent from the payload and the setting applies. Keys are words, not '1'/'0': PHP casts numeric string keys to int and 0 is falsy, so "require full stock" would merge with "not chosen".

The prompt is dynamic: it reads 4/order.partial.adminAllowed from the settings context (getSettingContext()->getSettings()) and picks one of two ready NEON texts (no value interpolated into the translation, only a key choice), so the admin sees what the setting currently means.

Parameters
$form : Form

addOrderVouchersMultiplier()

Limit from the raw HTTP data (`onAnchor`) plus `$maxCopies` as a second defense.

private addOrderVouchersMultiplier(Form $form) : void
Parameters
$form : Form

allowPartialAdminPromptKey()

Returns the effective `4/order.partial.adminAllowed`; missing in DB means "require full stock" (same semantics as the `$value === '1'` fallback in {@see \App\UI\Api\Eshop\Models\Managers\Traits\OrderBuildTrait::resolveAllowPartial()}, where a missing or other value is false).

private allowPartialAdminPromptKey() : string
Return values
string

Syncs the order's user picker (`userId`, {@see \App\UI\Admin\Eshop\Presenters\Traits\Pickers\OrderCustomerPickerTrait}) and `userTypeId` from the customer record's linked user account (`Customer.userId`).

private applyOrderCustomerUserLink(Form $form, Customer $customer) : void

userTypeId feeds the API-derived buyerType (OrderBuildTrait::resolveBuyerType()), so it is written directly after a customer switch, not via setControlValue(), which skips null and would leave it stale. When userId is null (customer without an account) the field is left alone, so a manual or anonymous admin choice survives picking a customer record without a link.

The picker label is resolved at render from the current userId value (Picker::render()); {control picker-userId} only has to sit inside the snippet the handler redraws (customerFields, see edit.latte).

Parameters
$form : Form
$customer : Customer

buildOrderPayload()

Builds the raw payload for `api/eshop/order/build`: no catalog logic here, only a transcription of form values (as in {@see \App\UI\Api\Eshop\Presenters\OrderPresenter::internalActionBuild()}). `lines` carries trusted price/vat/name/code/unit; shipping/payment go as nested `shipping`/`payment` (tariffId + price + vat).

private buildOrderPayload(ArrayHash<string|int, mixed> $values, bool $persist) : array<string, mixed>
Parameters
$values : ArrayHash<string|int, mixed>
$persist : bool
Return values
array<string, mixed>

callOrderBuild()

private callOrderBuild(array<string, mixed> $payload) : array<string, mixed>
Parameters
$payload : array<string, mixed>
Return values
array<string, mixed>

computeOrderTargetStatuses()

Mirrors `OrderTransitionManager::checkGating()` (2 rules); the server is the final judge, this only filters the select so the admin does not see obviously rejected targets.

private computeOrderTargetStatuses(Order $order) : NotTranslate>, 1: array}
Parameters
$order : Order
Return values
NotTranslate>, 1: array}

controlValue()

Safely reads a field value from the container (form or multiplier row).

private controlValue(Container $container, string $field) : mixed
Parameters
$container : Container
$field : string

createIdentity()

private createIdentity(array<string, mixed> $payload, string $token) : SimpleIdentity|null
Parameters
$payload : array<string, mixed>
$token : string
Return values
SimpleIdentity|null

createMultiplierComponent()

Creates a multiplier for the component.

private createMultiplierComponent(string $name) : Multiplier<string|int, IComponent>
Parameters
$name : string
Return values
Multiplier<string|int, IComponent>

createNewComponentInstance()

Creates a new component instance without adding it to the presenter; used by the multiplier.

private createNewComponentInstance(string $baseName[, int|string|null $uniqueKey = null ]) : IComponent|null
Parameters
$baseName : string
$uniqueKey : int|string|null = null
Return values
IComponent|null

createStandardComponent()

Creates a standard component (not a multiplier).

private createStandardComponent(string $name) : IComponent|null
Parameters
$name : string
Return values
IComponent|null

decorateInvoices()

Decorates the grid page with invoices in one `WHERE order_id IN (...)` query. An invoice is linked to the order only by a flat scalar (no cross-module FK), so `setIncludes()` cannot load it.

private decorateInvoices(array<int, object> $items) : void
Parameters
$items : array<int, object>

editorBreadcrumb()

Builds the breadcrumb navigation: cumulative segment paths.

private editorBreadcrumb(string $relative) : array<int, array{label: string, path: string}>
Parameters
$relative : string
Return values
array<int, array{label: string, path: string}>

editorLinkLangId()

Returns the language used to pick labels and URLs (default 1, Czech).

private editorLinkLangId() : int
Return values
int

editorPageLabel()

Returns the page label: title, otherwise name, otherwise `#id`.

private editorPageLabel(Page $page, int $langId) : string
Parameters
$page : Page
$langId : int
Return values
string

editorPageRoute()

Returns the first page route the editor may link to. A page may have several (many-to-many); the whitelisted one is taken, not the first in order, so a page with both `Page:show` and `Page:form` ends up on the right one.

private editorPageRoute(Page $page) : Route|null
Parameters
$page : Page
Return values
Route|null

editorPageUrl()

Returns the front end address of a page. The router builds it from the page route, so `/o-nas` and any prefix come out on their own.

private editorPageUrl(Page $page, int $langId) : string|null
Parameters
$page : Page
$langId : int
Return values
string|null —

null when the page is not a text page (see EDITOR_PAGE_TARGETS), has no filled URL, or its route cannot build a link

editorParentFolder()

Returns the parent folder (null in the editor root).

private editorParentFolder(string $relative) : string|null
Parameters
$relative : string
Return values
string|null

editorPath()

Converts a client path (relative to the editor root) to an Api path (relative to the `uploads/` root).

private editorPath(string $relative) : string|null

This is the only place where the prefix is added, so the segment check lives here too. The Api rejects .. as well, but without this check a ../ from the request would not escape uploads/ yet would escape editorUploads/ into neighboring folders of other modules.

Parameters
$relative : string
Return values
string|null —

null when the path contains a forbidden segment

editorUploadName()

Builds a safe and unique file name. Sanitization copies the Api layer rules (webalize of the base and of the extension), so the name returned in the URL is exactly the name the file is stored under. The random suffix prevents collisions: `writeFile()` overwrites the same name without asking, so two different `obrazek.jpg` files would overwrite each other.

private editorUploadName(string $untrustedName) : string|null
Parameters
$untrustedName : string
Return values
string|null —

null for a forbidden extension or an unusable name

editorUploadUrl()

Returns the public URL of a file. `$path` is relative to the `uploads/` root (so it includes `editorUploads/`), the same shape as other uploads in the system.

private editorUploadUrl(string $path) : string
Parameters
$path : string
Return values
string

ensureEditorRoot()

Creates the editor root folder; when it already exists the Api returns false and nothing happens.

private ensureEditorRoot() : void

expireIdleLogin()

Returns whether the login expired from inactivity. If so, revokes the tokens (like a logout), clears the `auth` section, logs out the Nette identity and returns true; otherwise moves the activity stamp forward.

private expireIdleLogin(AuthSessionStorage $authStorage) : bool

Admin keeps 30 min, or 8 h with its own "remember me", regardless of the front end "remember me" (the auth section is shared, its 31 days do not count here). An expiry in admin logs out of the front end too (one session).

Parameters
$authStorage : AuthSessionStorage
Return values
bool

extractOrderWarnings()

Returns the `warnings` of the `api/eshop/order/build` response (currently only the code `paymentMethodUnavailable`, see the API `OrderPresenter::internalActionBuild()` docblock) with a runtime guard to `list<string>`, like {@see orderStringKeyedArray()}.

private extractOrderWarnings(array<string, mixed> $response) : array<int, string>
Parameters
$response : array<string, mixed>
Return values
array<int, string>

fillOrderCustomerDeliveryFromContact()

Copies the contact's delivery address (`CustomerContact.useDelivery`/`dlv*`) into the order's `useDelivery`/`customerDlv*` fields.

private fillOrderCustomerDeliveryFromContact(Form $form, CustomerContact $contact) : void

Used by both selection paths (picker and address select) via fillOrderCustomerFieldsFromContact(). useDelivery=false on the contact means no separate delivery address, so customerDlv* are always cleared, not just hidden; otherwise the previous contact's address would linger in the form. ?? '' instead of a plain (string): with useDelivery=true but an empty (null) dlv* field, setControlValue() and its is_scalar guard would skip it silently and keep the old value.

Parameters
$form : Form
$contact : CustomerContact

fillOrderCustomerFieldsFromContact()

Overwrites the form's `customer*` fields from the given contact using the same `fieldMap` as the client picker ({@see \App\UI\Admin\Eshop\Presenters\Traits\Pickers\OrderCustomerLookupPickerTrait::orderCustomerLookupFieldMap()}), so the data-key to form-field mapping has a single source of truth.

private fillOrderCustomerFieldsFromContact(Form $form, CustomerContact $contact) : void
Parameters
$form : Form
$contact : CustomerContact

formComponent()

Calls `getComponent()` through the `Container` type, bypassing the faulty vendor annotation `@method BaseControl getComponent(string $name)` on Contributte `BootstrapContainerTrait` (the real component-model signature has 2 arguments and a nullable return; the annotation on a BootstrapForm-typed variable makes phpstan fail).

private formComponent(Container $container, string $name) : IComponent|null
Parameters
$container : Container
$name : string
Return values
IComponent|null

initializeMetaTags()

Fills the template with the title, meta tags and HTML text of the page from the translation (`PageText`) of the current language, for the layout (like the Front {@see \App\Core\Traits\Front\Presenters\PageInitTrait}).

private initializeMetaTags(AdminPage|null $adminPageEntity) : void

When the page or translation is missing, the values are empty strings and the layout uses its fallbacks.

Parameters
$adminPageEntity : AdminPage|null

invoiceTypeNameOptions()

Returns the invoice type map `id => name` for the column; without it the list would show only numbers and an invoice could not be told from a credit note.

private invoiceTypeNameOptions() : array<int, string>
Return values
array<int, string>

loadOrderCustomerAccountUser()

Loads the user account by id, or null when not found.

private loadOrderCustomerAccountUser(int $id) : User|null

Admin Manager::find() returns a SingleQuery, not an entity, hence findAll()->first() (as in SellerPickerTrait::loadSeller()). $this->orderCustomerUserManager is injected by OrderCustomerPickerTrait (same presenter, properties shared across traits).

Parameters
$id : int
Return values
User|null

loadOrderCustomerWithContacts()

Loads the customer with contacts for the address select (`customerContactId`) and the server refresh handlers. `id <= 0` safely returns null, like {@see \App\UI\Admin\Invoicer\Presenters\Traits\Pickers\SellerPickerTrait::loadSeller()}.

private loadOrderCustomerWithContacts(int $id) : Customer|null
Parameters
$id : int
Return values
Customer|null

loadOrderSelectData()

Loads the form axes once per request: currencies, languages, user types, payment regions, statuses, tariffs and payments. Names are ready DB data, hence `NotTranslate`; otherwise the form domain translator looks them up as a key (`eshop.presenters.order.Euro`) and Tracy reports a missing translation.

private loadOrderSelectData() : void

loadSeller()

Loads the seller with contacts, accounts and tax status history for the server-side prefill of the invoice snapshot.

private loadSeller(int $id) : Seller|null
Parameters
$id : int
Return values
Seller|null

localizationCurrencyKey()

Admin ignores the localization currency (it takes the language only).

private localizationCurrencyKey(object $localization) : string|null
Parameters
$localization : object
Return values
string|null

loginReturnArgs()

Remembers the request of a logged-out user so the login can return to it ({@see storeRequest()}, `backlink` of the login page, restored by `AuthStorageTrait::redirectAfterLoginAction()`).

private loginReturnArgs() : array<string, string>

Without it a save sent after a logout in another tab (or after the idle timeout) ended on the login page with no explanation, the login led to the dashboard and the filled-in form was lost. A restored POST renders the form again with the submitted values, but Nette does not process it (Request::RESTORED, no blind replay): the admin checks the values and saves once more. An AJAX request is not stored (naja would replay it as a page). The user id stored with the request is the previous identity, so a different account logging in is not sent there.

Return values
array<string, string>

onlyPricedLines()

Drops rows without a price from the payload; used only by the shipping/payment refresh, which must not fail on `linePriceRequired` while some items are still unpriced (weight/cartTotal then count only trusted rows). Final save and "Recalculate" send all rows unchanged: a missing price must fail visibly there, not vanish silently.

private onlyPricedLines(mixed $lines) : array<int, array<string, mixed>>

Takes mixed (read back from the payload typed array<string, mixed>) and narrows the rows itself, so callers need no casts.

Parameters
$lines : mixed
Return values
array<int, array<string, mixed>>

orderBuildFailureMessage()

Returns the preview error text from a failed `order/build` response. A technical failure (DB/ORM/transport) has an empty `message` (the detail is only in the server log) and a generic translated error is shown instead of an empty line. A domain validation message passes unchanged.

private orderBuildFailureMessage(array<string, mixed> $response) : string
Parameters
$response : array<string, mixed>
Return values
string

orderControlValues()

Returns the form values for the AJAX button handlers.

private orderControlValues(Form $form) : ArrayHash<string|int, mixed>

IMPORTANT: every AJAX button handler of this form must read values from the controls, never via $form->getValues(). The helper buttons have setValidationScope([]), so Nette marks controls outside the scope as omitted and Container::getValues() skips them: getValues()->items returns [}], the lines payload is empty and the API reports missing items (recalculate and shipping/payment prefill would always fail with "the order must have at least one item"). Native "Save" validates the whole form, so nothing is omitted there. getContainers() also forces createCopies() (multiplier rows from httpData).

Parameters
$form : Form
Return values
ArrayHash<string|int, mixed> —

same shape getValues() would return (for buildOrderPayload(), unchanged)

orderCurrencyById()

Returns the currency entity for an id from the build response (`serializeOrder()['currencyId']`), from the same list `loadOrderSelectData()` built for the `currencyId` select (no extra query). `null` = unknown or missing currency (the build has not run yet or the response omits it); the caller then passes `null` to the `priceFormat` filter, which leaves numbers raw.

private orderCurrencyById(int|null $id) : Currency|null
Parameters
$id : int|null
Return values
Currency|null

orderCustomerContactOptions()

Builds the `customerContactId` select items: contact id mapped to a meaningful summary (name or company, street, city). A legacy contact without the structured triple (see the class docblock) falls back to `CustomerContact::getName()`, never to an empty label.

private orderCustomerContactOptions(Customer $customer) : array<int, NotTranslate>

The summary is ready text from the card index, not a translation key, hence NotTranslate; otherwise the form's domain translator looks it up as a key and Tracy reports a missing translation.

Parameters
$customer : Customer
Return values
array<int, NotTranslate>

orderCustomerContactPrefillData()

Builds the same dictionary as {@see orderCustomerLookupPrefillData()}, but for any contact (not just the first); used after a specific address is chosen in the `customerContactId` select (`OrderFormTrait::refreshOrderCustomerContact()`). The shared data source guarantees that the client `fieldMap` (first contact) and the server refresh (first or chosen contact) never produce different values for the same contact.

private orderCustomerContactPrefillData(CustomerContact $contact) : array<string, string>
Parameters
$contact : CustomerContact
Return values
array<string, string>

orderCustomerFieldMap()

private orderCustomerFieldMap() : array<string, string>
Return values
array<string, string> —

data key (see orderCustomerPrefillData()) mapped to the form field

orderCustomerLookupFieldMap()

private orderCustomerLookupFieldMap() : array<string, string>
Return values
array<string, string> —

data key mapped to the order form field

orderCustomerLookupPrefillData()

private orderCustomerLookupPrefillData(Customer $customer) : array<string, string>
Parameters
$customer : Customer
Return values
array<string, string> —

data key (fieldMap) mapped to the value from the first contact

orderCustomerPrefillData()

private orderCustomerPrefillData(User $user) : array<string, string>
Parameters
$user : User
Return values
array<string, string>

orderExpeditionShipperOptions()

The carrier name is already translated data from the DB, not a key: `NotTranslate`, otherwise the form's domain translator looks it up as a key and Tracy reports a missing translation.

private orderExpeditionShipperOptions() : array<int, NotTranslate>
Return values
array<int, NotTranslate>

orderItemProductSetName()

Returns the set name in the current language (falls back to the first non-empty one).

private orderItemProductSetName(ProductSet $set) : string
Parameters
$set : ProductSet
Return values
string

orderPayloadGifts()

private orderPayloadGifts(mixed $rows) : array<int, array{giftId: int|string, amount?: int}>
Parameters
$rows : mixed
Return values
array<int, array{giftId: int|string, amount?: int}>

orderPayloadId()

Returns an id for the build payload: canonical becomes int, empty or `0` becomes `null`. Any other value goes on unchanged, so the API (the single authority, {@see \App\UI\Api\Eshop\Models\Helpers\OrderPayloadHelper::findInvalidIdPath()}) rejects it; `intOrNull()` would turn a tampered hidden `'1.9'` into item #1 here.

private orderPayloadId(mixed $value) : int|string|null
Parameters
$value : mixed
Return values
int|string|null

orderPayloadLines()

Builds the trusted rows: `price`/`vat` are required on the way to the API (missing: hard fail `linePriceRequired` there, no silent catalog fallback here). The form always carries them from prefill/snapshot, so they are just transcribed.

private orderPayloadLines(mixed $rows) : array<int, array{setId: int|string, quantity: int, orderItemId?: int|string, price?: string, vat?: string, name?: string, code?: string, unit?: string, discountPercents?: string}>
Parameters
$rows : mixed
Return values
array<int, array{setId: int|string, quantity: int, orderItemId?: int|string, price?: string, vat?: string, name?: string, code?: string, unit?: string, discountPercents?: string}>

orderPayloadPickupManual()

Returns the manually entered pickup point from the six text fields. `null` when both `code` and `name` are empty (both are required for a valid point); the API then ignores the manual path and decides only from the raw widget payload.

private orderPayloadPickupManual(ArrayHash<string|int, mixed> $values) : array{code: ?string, name: ?string, street: ?string, city: ?string, zip: ?string, country: ?string}|null
Parameters
$values : ArrayHash<string|int, mixed>
Return values
array{code: ?string, name: ?string, street: ?string, city: ?string, zip: ?string, country: ?string}|null

orderPayloadPickupPoint()

Decodes the hidden `pickupPoint`, which carries the raw JSON object of the widget (in the edit defaults `OrderShipper::$pickupPointData`), so the API gets the same field as the front checkout. Anything that is not a JSON object becomes `null`: the driver would not recognize an array/scalar and the fail-closed guard would turn it into `pickupPointRequired`.

private orderPayloadPickupPoint(mixed $value) : array<string, mixed>|null
Parameters
$value : mixed
Return values
array<string, mixed>|null

orderPayloadVoucherCodes()

private orderPayloadVoucherCodes(mixed $rows) : array<int, string>
Parameters
$rows : mixed
Return values
array<int, string>

orderPickupWidgetContext()

Returns the context for `CarrierInterface::getWidgetConfig()` in the admin. Language, currency and country come from the edited order (there is none on add, and the widget only appears after a tariff is chosen, when the form already has values). Weight is deliberately not passed: the admin reprices rows by hand and the widget uses weight only to filter offered points.

private orderPickupWidgetContext() : array{lang?: string, currency?: string, country?: string, weight?: float}
Return values
array{lang?: string, currency?: string, country?: string, weight?: float}

orderPreviewFromOrder()

Builds a deterministic preview snapshot straight from the saved order, without calling `api/eshop/order/build` (GET only, `OrderPresenter::actionEdit()`).

private orderPreviewFromOrder(Order $order) : array<string, mixed>

The shape must be identical to OrderPayloadHelper::serializeOrder(): {snippet orderPreview} reads the same keys whether the preview came from a build (recalculate/ shippingRefresh/paymentRefresh) or from here. No repricing, only reading saved entity snapshots (items/shipper/paymentMethod/vouchers/gifts/totals), exactly as setOrderFormDefaults() sees them.

Parameters
$order : Order
Return values
array<string, mixed>

orderSellerDefaultsFromSettings()

Returns the default seller from settings for an order that has no own snapshot (add, or a record from before snapshots). The snapshot is built from the live directory because no other source exists: right for a new order, the best available estimate for an old one, which the admin sees and can overwrite before saving.

private orderSellerDefaultsFromSettings() : array<string, scalar|null>
Return values
array<string, scalar|null> —

empty = settings have no seller (or none exists for the configured id), so the form stays empty and the required field asks the admin for one

orderSellerDefaultsWithNotice()

Returns {@see orderSellerDefaultsFromSettings()} and reports the state to the admin. The flash is part of the contract: the seller is required, so without it the admin would learn of the problem only from a save error, and with empty settings would not know where to look (the shop seller setting).

private orderSellerDefaultsWithNotice(bool $legacyOrder) : array<string, scalar|null>
Parameters
$legacyOrder : bool

true = edit of an order without its own snapshot; false = add, where prefill is expected and nothing is reported

Return values
array<string, scalar|null>

orderSettingSellerId()

Resolves the seller id from settings: `4/invoicer.sellerId`, falling back to `7/invoice.default.sellerId` (invoice defaults `invoice.default.*`), the same chain the invoice issue uses ({@see \App\UI\Api\Eshop\Models\Generators\OrderInvoiceGenerator::settingIntOrNull()}). An empty string in DB means "does not exist" (`is_numeric('')` is false).

private orderSettingSellerId() : int|null
Return values
int|null

orderStringKeyedArray()

Runtime guard to `array<string, mixed>`; the `ApiBridge` response is typed `mixed`.

private orderStringKeyedArray(mixed $value) : array<string, mixed>|null
Parameters
$value : mixed
Return values
array<string, mixed>|null

parsePickerName()

Splits a picker instance name into the config key plus row indexes (multiplier and nested multiplier). `parentId` -> `['parentId', []]`; `address_2` -> `['address', ['2']]`; `parameter_1_0` -> `['parameter', ['1','0']]` (nested).

private parsePickerName(string $name) : array{0: string, 1: list}

The separator is an underscore, not a dash: - is the component path separator in Nette ({control picker-address_0} = Multiplier picker -> child address_0). A config key must not end with _<number> (keys: parentId, address, parameter).

Parameters
$name : string
Return values
array{0: string, 1: list}

prefillOrderItemRows()

Picker prefill: for every row with a selected `productSetId` that has no price yet, fetches code/productSetName/unit/vat/price from the catalog (`api/eshop/order/item-prefill`, {@see \App\UI\Api\Eshop\Models\Services\OrderSnapshotBuilder::resolveItemPrefill()}).

private prefillOrderItemRows(Form $form) : void

Rows where the admin already entered a price are skipped. Resolver query only: no order context, no saving. Quantity is left unchanged (it only feeds the price tier).

Parameters
$form : Form

processCreditNote()

Issues the credit note through the Api; redirects on success, returns false (with a flash) otherwise.

private processCreditNote(ArrayHash<string|int, mixed> $values) : bool
Parameters
$values : ArrayHash<string|int, mixed>
Return values
bool

processLogin()

private processLogin(string $username, string $password[, bool $remember = false ]) : void
Parameters
$username : string
$password : string
$remember : bool = false

processLoginException()

private processLoginException(Exception $e) : void
Parameters
$e : Exception

readLoginDeviceToken()

Returns the raw known-device cookie for the Api login (the Api verifies its signature).

private readLoginDeviceToken() : string|null
Return values
string|null

recalculateOrderForm()

Calls `build` (persist=false) with the current form data, including untouched fields.

private recalculateOrderForm(Form $form) : void
Parameters
$form : Form

redirectAfterLoginAction()

After a login attempt: a successful login returns to the request remembered before the login (`backlink`, {@see PrivilegeCheckTrait::loginReturnArgs()}), otherwise to the dashboard; a failed one stays on the login page and keeps the way back.

private redirectAfterLoginAction() : void

refreshNetteIdentity()

Refreshes the token of the same logged-in user: identity data (token, name, email) are overwritten in the stored object without `login()`, so neither the session id nor the form CSRF tokens change. The identity is stored in the session section as an object; the change is written at the end of the request.

private refreshNetteIdentity(array<string, mixed> $payload, string $token) : bool
Parameters
$payload : array<string, mixed>
$token : string
Return values
bool —

false when impossible (nobody logged in or another user); the caller uses login

refreshOrderCustomer()

Loads the customer with all contacts, fills the address select and prefills the fields from the first contact (same semantics as `refreshOrderSeller()`).

private refreshOrderCustomer(Form $form) : void

A deleted or unselected customer empties the select (prompt only).

Parameters
$form : Form

refreshOrderCustomerContact()

Ownership guard: looks the contact up only among the chosen customer's contacts (`Customer::getContact()`). A foreign or nonexistent `customerContactId` (e.g. the select was filled by AJAX from elsewhere, a race) is silently ignored, no failure.

private refreshOrderCustomerContact(Form $form) : void
Parameters
$form : Form

refreshOrderPayment()

Same logic as {@see refreshOrderShipping()}, for the payment method.

private refreshOrderPayment(Form $form) : void
Parameters
$form : Form

refreshOrderPickupPoint()

Handles the pickup widget selection (`pickupRefresh`): calls `build` (persist=false) with the raw widget object in the `pickupPoint` payload and prefills the six text fields from the snapshot in the response (`order.shipper.pickup*`). Same logic as {@see refreshOrderShipping()}, different field set.

private refreshOrderPickupPoint(Form $form) : void

IMPORTANT: the preview (persist=false) returns no error for a missing or unusable point (contract), so a nonsense widget answer shows only as fields not being prefilled; hence no already filled values are cleared here.

Parameters
$form : Form

refreshOrderSeller()

Loads the seller snapshot from the Invoicer directory into the form.

private refreshOrderSeller(Form $form) : void

Uses the first contact and first bank account (same semantics as SellerPickerTrait::sellerPrefillData()). Values are always overwritten: the admin picked the seller again, so the current details are wanted.

Parameters
$form : Form

refreshOrderShipping()

Calls `build` (persist=false) after the tariff changes, with the same payload as `recalculateOrderForm` but without incomplete rows (no price).

private refreshOrderShipping(Form $form) : void

JS clears shippingPrice/shippingVat beforehand. Without dropping those rows the strict linePriceRequired would block even the shipping prefill. Empty shippingPrice/Vat in the payload makes buildShipperFromRow() compute fresh through ShippingPriceResolver (including free_from), only here, not on final save.

Parameters
$form : Form

rememberLoginDevice()

After a successful login (password or OAuth) issues or renews the known-device cookie ({@see LoginDeviceCookie}): a signed proof that this browser has already logged in to the account. The next login sends it to the Api ({@see self::processLogin()}), and above the account limit the password from this browser is still verified, so foreign attempts do not lock out the owner. HttpOnly, SameSite=Lax, Secure on HTTPS; lifetime from `ratelimit.loginDevice.cookieLifetime`.

private rememberLoginDevice(mixed $payload) : void
Parameters
$payload : mixed

resolveLoginErrorMessage()

Resolves the flash message of a failed login.

private resolveLoginErrorMessage(Result $result) : string

IMPORTANT: a brute-force throttle must not be shown as "wrong password"; the limit would then look like an inexplicably failing form.

results.rateLimitExceeded (the generic text of ResultCode) carries no seconds and does not belong to login. The login flow therefore has its own key in the same family as admin.general.login.error.message: login.rateLimit.message, with the seconds passed as %count% (Contributte: numeric 2nd argument).

The Api sends retryAfter in data (AuthPresenter::rateLimitedResult()); the internal bridge call does not see the Retry-After header.

Parameters
$result : Result
Return values
string

resolveOrderCustomerIdForContactSelect()

Returns the `customerId` used to build the items of the `customerContactId` select.

private resolveOrderCustomerIdForContactSelect() : int|null

Evaluated at form construction, not in onValidate:

  • POST/AJAX (save or any force-submit): takes the submitted value from httpData (Nette\Http\Request::getPost()), not from the control, which has not read httpData yet at this point. Otherwise SelectBox drops the submitted address because items were built from an empty customerId (classic dynamic-select trap, see DependentSelectTrait).
  • GET edit: the saved order's customerId (items must contain the saved customerContactId that setOrderFormDefaults() sets).
  • GET add: no customer yet, null, the select stays empty with a prompt.
Return values
int|null

resolveOrderCustomerLabel()

private resolveOrderCustomerLabel(int $id) : string|null
Parameters
$id : int
Return values
string|null

resolveOrderCustomerLookupLabel()

private resolveOrderCustomerLookupLabel(int $id) : string|null
Parameters
$id : int
Return values
string|null

resolveOrderGiftLabel()

private resolveOrderGiftLabel(int $id) : string|null
Parameters
$id : int
Return values
string|null

resolveOrderItemProductSetLabel()

private resolveOrderItemProductSetLabel(int $id) : string|null
Parameters
$id : int
Return values
string|null

resolveOrderPreviewCurrency()

Returns the preview currency from `currencyId` in the serialized `order` of the build response, mapped to the entity from `$orderCurrencyEntities` (built in `loadOrderSelectData()`, no extra query).

private resolveOrderPreviewCurrency(array<string, mixed>|null $orderData) : Currency|null

null (missing or unknown id) makes the priceFormat filter leave numbers raw, see OrderPresenter::orderCurrencyById().

Parameters
$orderData : array<string, mixed>|null
Return values
Currency|null

resolveOrderSellerUseVat()

Returns whether the shop operator is a VAT payer, read live from the Invoicer seller.

private resolveOrderSellerUseVat() : bool

IMPORTANT: do not read the settings copy 4/useVat; nothing synchronizes it with the seller, so after the company is edited in Invoicer (VAT registered or canceled) the form would offer VAT controls that contradict how the document will be issued. The seller is the authority.

The seller is resolved by the same chain as the invoice generator (OrderInvoiceGenerator::buildFromOrder()): the order snapshot order.sellerId, then 4/invoicer.sellerId, then 7/invoice.default.sellerId; orderSettingSellerId() handles the settings half (including skipping non-numeric or <= 0 values). The seller's tax status as of today is taken from its history (Seller::resolveUseVatOn()): a payer gets VAT controls, an identified person or non-payer does not. The per-document mode at the tax point stays with the composer/generator.

A missing or unconfigured seller yields false (no VAT controls) and is logged; without the log VAT would vanish from the whole screen with no trace of why.

NOTE: not the seller's display flag show_prices_with_vat, which only controls how prices are shown on the front end (the price list is always net).

Return values
bool

resolveOrderVoucherLabel()

private resolveOrderVoucherLabel(int $id) : string|null
Parameters
$id : int
Return values
string|null

resolvePaymentLabel()

private resolvePaymentLabel(int $id) : string|null
Parameters
$id : int
Return values
string|null

resolveSellerLabel()

private resolveSellerLabel(int $id) : string|null
Parameters
$id : int
Return values
string|null

revokeTokensOnLogout()

Calls the Api logout (revokes the refresh family and deny-lists the access `jti`) for the tokens of the current session. Fail-open on purpose: any failure is only logged, because the local logout must not stay unfinished.

private revokeTokensOnLogout(AuthSessionStorage $authStorage, mixed $userId) : void
Parameters
$authStorage : AuthSessionStorage
$userId : mixed

rowValue()

private rowValue(mixed $row, string $key) : mixed
Parameters
$row : mixed
$key : string

saveOrderForm()

private saveOrderForm(ArrayHash<string|int, mixed> $values) : bool
Parameters
$values : ArrayHash<string|int, mixed>
Return values
bool

sellerPrefillData()

private sellerPrefillData(Seller $seller) : array<string, string>
Parameters
$seller : Seller
Return values
array<string, string>

setControlValue()

Force-sets a field value in the container (form or multiplier row) if it exists.

private setControlValue(Container $container, string $field, mixed $value) : void
Parameters
$container : Container
$field : string
$value : mixed

setNetteUser()

private setNetteUser(array<string, mixed>|null $payload, string $token) : void
Parameters
$payload : array<string, mixed>|null
$token : string

storeEditorUpload()

Stores a file; the target folder may not exist (first upload into the root), so after a failure the root is created once and the write is retried. Deeper subfolders are created by the editor user through `editorCreateFolder`.

private storeEditorUpload(string $folder, string $name, string $base64) : bool
Parameters
$folder : string
$name : string
$base64 : string
Return values
bool

suggestOrderCustomerLookups()

private suggestOrderCustomerLookups(string $query) : array<int, array{id: int, label: string, data: array}>
Parameters
$query : string
Return values
array<int, array{id: int, label: string, data: array}>

suggestOrderCustomers()

private suggestOrderCustomers(string $query) : array<int, array{id: int, label: string, data: array}>
Parameters
$query : string
Return values
array<int, array{id: int, label: string, data: array}>

suggestOrderGifts()

private suggestOrderGifts(string $query) : array<int, array{id: int, label: string}>
Parameters
$query : string
Return values
array<int, array{id: int, label: string}>

suggestOrderItemProductSets()

private suggestOrderItemProductSets(string $query) : array<int, array{id: int, label: string}>
Parameters
$query : string
Return values
array<int, array{id: int, label: string}>

suggestOrderVouchers()

private suggestOrderVouchers(string $query) : array<int, array{id: int, label: string}>
Parameters
$query : string
Return values
array<int, array{id: int, label: string}>

suggestPayments()

Suggestions: searches by variable symbol and payment code (OR).

private suggestPayments(string $query) : array<int, array{id: int, label: string}>

NOTE: a code is filled in only for a minority of payments, so a code-only filter would leave most of them unfindable. The label is built by PaymentPickerLabel, the same function as in the modal over the grid.

Parameters
$query : string
Return values
array<int, array{id: int, label: string}>

suggestSellers()

private suggestSellers(string $query) : array<int, array{id: int, label: string, data: array}>
Parameters
$query : string
Return values
array<int, array{id: int, label: string, data: array}>

syncPickupControls()

Fills the seven pickup point controls from the shipper snapshot in the `build` response: six text fields, hidden `pickupPoint` with the raw widget object (so saving unchanged keeps exactly what the widget issued) and hidden `pickupPointTariffId` with the tariff the selection belongs to.

private syncPickupControls(Form $form, array<string, mixed>|null $shipper, int|null $tariffId) : void

IMPORTANT: without a pickup code in the snapshot (the tariff needs none, or build cleared it after a tariff change) all seven are emptied; otherwise the previous carrier's point would stay in the fields and the next submit would send it back.

Parameters
$form : Form
$shipper : array<string, mixed>|null

shipping snapshot from order.shipper of the response

$tariffId : int|null

tariff just submitted by the form (not in the build response)

tryRefresh()

Tries an auto-refresh for an expired access token. If the session holds a refresh token and the Api accepts it, stores the new pair in the session and returns true; otherwise returns false and the caller cancels the session.

private tryRefresh(AuthSessionStorage $authStorage) : bool
Parameters
$authStorage : AuthSessionStorage
Return values
bool

wireOrderMultiplierButtons()

Multiplier add/remove buttons, as in {@see GiftFormTrait::addGiftOfferSetFields()}.

private wireOrderMultiplierButtons(Multiplier $multiplier, string $snippet) : void
Parameters
$multiplier : Multiplier
$snippet : string
On this page

Search results