Developer API
The Szamlazz plugin exposes services, an invoice provider, an order-edit UI component, MCP tools, and console commands for integration with yStore's invoicing system and external/automation clients.
Services
Access services via the plugin instance:
use Yui\Szamlazz\Plugin;
$szamlazz = Plugin::getInstance();
$api = $szamlazz->getApi();
$invoices = $szamlazz->getInvoices();
$dashboard = $szamlazz->getDashboard();
$license = $szamlazz->getLicense();
ApiService
Builds the authenticated connection to the Szamlazz.hu Agent API.
setOrder(?Order $order)-- associates an order with the service before building a connection; the order is passed through toEVENT_BEFORE_API_CONNECTIONlisteners.getConnection(): ?SzamlaAgent-- creates aSzamlaAgentAPIconnection using the settings' API Key, appliesLog::LOG_LEVEL_ERRORwhen Sandbox Mode is on, and sets the Log E-mail if configured. Returnsnullif the underlyingSzamlaAgentExceptionis thrown (for example on a malformed API key).
EVENT_BEFORE_API_CONNECTION
Triggered on ApiService immediately before the Szamlazz.hu connection is created, letting a listener
inspect or override the settings array that will be used to build it (for example to swap the API key for a
different site/brand at connection time).
use yii\base\Event;
use Yui\Szamlazz\services\ApiService;
use Yui\Szamlazz\events\BeforeApiConnectionEvent;
Event::on(
ApiService::class,
ApiService::EVENT_BEFORE_API_CONNECTION,
function (BeforeApiConnectionEvent $event) {
// $event->order -- the yui\craft\records\Order currently being processed, if any
// $event->settings -- the plugin settings array about to be used; mutate and it takes effect
$event->settings['apiKey'] = resolveApiKeyForOrder($event->order);
}
);
InvoiceService
Creates, deletes, regenerates, downloads, and lists Szamlazz.hu invoices from order data.
dispatchInvoiceGeneration(int $orderId, ?string $orderStatus, bool $manualCreate = false, bool $force = false, string $commentAction = 'generated')-- entry point used by the manual "Create" action and the MCPszamlazz_create_invoicetool. When Use queue for invoice generation is on and$manualCreateisfalse, pushes aGenerateInvoiceJobonto Craft's queue instead of running inline; falls back to a synchronous call if queueing fails.isQueueEnabled(): bool-- whether queue-based generation is enabled and a queue component is available.createInvoice(int $orderId, ?string $orderStatus, bool $manualCreate = false, bool $force = false, string $commentAction = 'generated'): bool|array-- loads the order, builds its invoice data via yStore's sharedbuildInvoiceData(), and delegates tocreateInvoiceFromData(). Returnsfalseif the order can't be loaded, or if$manualCreateisfalseand$orderStatusisn't in Generate invoice when.createInvoiceFromData(array $invoiceData, bool $manualCreate = false, bool $force = false, string $commentAction = 'generated'): bool|array-- the invoice-provider entry point (called bySzamlazzInvoiceProvider::createInvoice()); builds and sends the invoice to Szamlazz.hu from a normalized$invoiceDataarray (order/customer/items/totals undermeta/customer/items/totals). Returnstrueon success,falseon an unexpected failure, or an array of human-readable error messages (e.g. "the invoice already exists", or a zero-total order with Zero Total Orders disabled). Downloads and stores the resulting PDF as a Craft asset and adds an order comment recording the action.getInvoicePreviewData(int $orderId): array-- builds the same invoice data (settings, details, client, items, totals) that would be sent to Szamlazz.hu, without calling the API; backs the order-edit Preview action and theszamlazz_preview_invoiceMCP tool.getInvoicesByOrderId(int $orderId): array-- returns every invoice record for an order (with file path, URL, status, and download/regenerate URLs when applicable); used by the order-edit menu, theSzamlazzInvoiceProvider::getAttachments()callback, and theszamlazz_get_invoicesMCP tool.deleteInvoice(int $orderId, bool $isRegeneration = false): bool|array-- generates a storno (reverse) invoice against Szamlazz.hu for each active invoice record, then archives (soft delete) or hard-deletes the local record and asset depending on Soft delete invoices.regenerateInvoice(int $orderId): bool|array-- deletes the existing invoice (storno) and immediately creates a new one, forcing creation even if one already existed.sendInvoice(int $orderId, ?string $orderStatus): bool-- emails the invoice PDF to the customer when Send Invoice to customer in email is on and the order status matches Send invoice when. Called automatically on the order-status-change event when queue-based generation is off, and by theszamlazz_send_invoiceMCP tool.downloadInvoice(int $orderId): bool|Asset/downloadInvoices(int $orderId): array-- returns the latest (or all) stored PDF asset(s) for an order; used by both the CP download action and the consoledownloadcommand.resyncInvoiceAssets(): array{processed:int,updated:int,missingOrders:int,missingAssets:int,createdAssets:int}-- for invoice records missing anasset_id, attempts to find or import the matching PDF from the store's asset filesystem by filename (pdf-{incrementId}.pdf); backs the Resync invoices settings action andResyncInvoiceAssetsJob.
Every invoice/client/item detail sent to Szamlazz.hu is assembled from the normalized invoice data (billing/ shipping address, company/tax IDs, line items and configurable sub-items, discounts, shipping, payment) and the plugin's settings (tax payer status, tax class, invoice language, and whether shipping/payment are added as line items).
DashboardService
Extends the shared yui\craftcore\services\CoreDashboardService to build the Szamlazz.hu → Dashboard
modules: Total invoices, In this period, and Archived KPI tiles, a Status breakdown list, and
a Recent invoices table (date, order, type, status).
LicenseService
Extends the shared yui\craftcore\services\CoreLicenseService to back the Szamlazz.hu → License CP
page (shared yui/craft-core license activation/status UI), persisting entitlement/validation state on the
plugin's own settings model.
Invoice provider
Yui\Szamlazz\providers\SzamlazzInvoiceProvider registers itself with handle szamlazz (label
"Számlázz.hu") on yui\craft\services\sales\InvoiceService::EVENT_REGISTER_INVOICE_PROVIDERS, so it appears
alongside any other invoice provider yStore has registered.
public function isEnabled(): bool
{
return Plugin::getInstance()?->getSettings()?->enabled ?? false;
}
The provider is enabled purely based on the Enabled settings toggle. createInvoice(array $invoiceData)
delegates to InvoiceService::createInvoiceFromData(), and getAttachments(array $invoiceData) returns the
invoices already recorded for the order (via $invoiceData['meta']['order_id']) using
InvoiceService::getInvoicesByOrderId(). Automatic invoice creation on order-status change is driven by
yStore's shared invoicing system calling this provider, not by a Szamlazz-specific status listener; the
Szamlazz-specific EVENT_AFTER_ORDER_STATUS_CHANGE handler only handles Delete invoice when the order
status is and, when queueing is off, sending the invoice email.
Order-edit component
When Show Szamlazz Button is on, the plugin hooks into the order-edit-extra-actions template hook and
renders a menu (szamlazz/components/order/edit/manage-invoice.twig) on the order edit page. The available
actions are computed per order from the existing invoice record and the order's status:
- Create Invoice -- shown when the order has no active invoice yet.
- Preview, Download Invoice, Regenerate Invoice, Delete Invoice -- shown when an active invoice exists.
- The whole menu is hidden when the order's status is in Hide Szamlazz controls when an order has one of these statuses.
These map to InvoiceController::actionCreate(), actionPreview(), actionDownload(),
actionRegenerate(), and actionDelete(). InvoiceController and InvoiceService::getInvoicesByOrderId()
independently enforce the same Hide Szamlazz controls restriction against the order's current status, so
manual actions stay blocked even if a request reaches the controller directly. This restriction is separate
from automatic invoice creation/deletion, which run purely off Generate invoice when and Delete
invoice when the order status is regardless of this setting.
Notifications
Yui\Szamlazz\plugin\Events registers three notification types on
yui\craftcore\services\NotificationService::EVENT_REGISTER_NOTIFICATION_TYPES, so they appear with a
human-readable label and description in the shared CP notification preferences UI:
| Type | Severity | Label |
|---|---|---|
invoice.created | info | Invoice created |
invoice.failed | warning | Invoice creation failed |
invoice.error | critical | Invoice system unavailable |
InvoiceService emits these (source szamlazz) at the same points it records an order comment or logs an
error inside createInvoiceFromData():
invoice.created-- after an invoice is successfully created and its PDF stored.invoice.failed-- when creation is skipped because the invoice already exists, or because the order's grand total is zero and Zero Total Orders is disabled.invoice.error-- whencreateInvoiceFromData()catches an exception (for example an unreachable Szamlazz.hu API), with the exception message as the notification body.
Each notification is created via yui\craftcore\Plugin::getInstance()->getNotifications()->createNotification();
if yui/craft-core's plugin instance isn't available, the call is silently skipped so a notification failure
never blocks invoice creation itself.
MCP Tools
When the yui/craft-mcp plugin is installed, Szamlazz registers six MCP tools on
yui\mcp\Plugin::EVENT_REGISTER_TOOLS, all extending the shared AbstractSzamlazzTool base, which accepts
an order identifier (order_id and/or increment_id).
| Tool name | Purpose | Permission |
|---|---|---|
szamlazz_get_invoices | List invoices (including storno/archived) for an order. | read |
szamlazz_preview_invoice | Preview invoice customer/items/totals without creating or sending anything. | read |
szamlazz_create_invoice | Manually create an invoice, bypassing the status trigger and forcing creation. | WRITE |
szamlazz_send_invoice | Email the invoice PDF to the customer, subject to Send Invoice settings. | WRITE |
szamlazz_regenerate_invoice | Delete the existing invoice and generate a fresh one. | WRITE |
szamlazz_delete_invoice | Storno (reverse) and archive the invoice for an order. | DESTRUCTIVE |
Each tool returns a success/found flag plus order_id and either the requested data or an errors/
error field describing why the operation failed (for example a disabled sendInvoiceViaEmail setting).
Console commands
Yui\Szamlazz\console\controllers\InvoicesController exposes the same regenerate/download operations as
Craft console commands, for scripting and ops tooling:
php craft szamlazz/invoices/regenerate <orderId>
php craft szamlazz/invoices/download <orderId> [--destination=<path>] [--all]
regenerate <orderId>-- deletes and re-creates the invoice for the order; exits non-zero and prints each error message tostderron failure.download <orderId> [-d|--destination=<path>] [-a|--all]-- prints the on-disk path of the order's latest invoice PDF (or every invoice PDF for the order, with--all), and additionally copies each file into--destinationif provided (auto-renaming to avoid overwriting an existing file with the same name).
Both commands resolve the invoice service through Plugin::getInstance(), so they run against whichever
site/environment the CLI request is scoped to. GenerateInvoiceJob swaps in a QueueRequest shim when it
runs under a console request that doesn't expose getUserIP(), so queued invoice generation behaves
correctly whether it's processed by a web-triggered listener queue runner or php craft queue/run.
CP Routes
| Route | Purpose |
|---|---|
szamlazz, szamlazz/dashboard | Dashboard |
szamlazz/invoices, /invoices/table-data, /invoices/delete | Invoice list, AJAX table data, bulk delete |
szamlazz/invoice/create/<orderId> | Manual invoice creation from the order edit page |
szamlazz/invoice/preview/<orderId> | Invoice preview (no API call) |
szamlazz/invoice/update/<orderId> | Manual invoice update |
szamlazz/invoice/download/<orderId> | Invoice PDF download |
szamlazz/invoice/delete/<orderId> | Invoice deletion (storno) |
szamlazz/invoice/regenerate/<orderId> | Delete + re-create the invoice |
szamlazz/settings, /settings/save-settings, /settings/resync-invoices | Settings page, save, PDF resync |
szamlazz/license, /license/redeem, /revoke, /activate, /delete, /copy-token | License activation/status |
Data model
Yui\Szamlazz\records\InvoiceRecord (table {{%yui_szamlazz_invoices}}, see Yui\Szamlazz\db\Table) stores
one row per invoice/storno document: order_id, invoice_id, invoice_type (invoice or storno),
reference_number, status (issued, notification_failed, storno, archived, …), last_status_change,
invoice_data (JSON metadata -- invoice number, customer portal URL, net/gross amounts, raw API response
headers), asset_id (linked PDF asset), archived/archived_at (soft-delete state), and the standard
dateCreated/dateUpdated columns.
Settings model
Yui\Szamlazz\models\Settings (extends yui\craftcore\models\BasePluginSettingsModel) holds every field
documented in Settings, plus license/dashboard-layout persistence fields used internally by
LicenseService and DashboardService. Validation: API Key is required only when the plugin is enabled
(Settings::rules()). siteOverridableAttributes() returns sandboxMode, apiKey, logEmail,
company_id, invoiceLanguage, and szamlazzMarketCountry, so a multi-site store can invoice against
different Szamlazz.hu accounts/markets per site.
Compatibility
- Craft CMS 5+ (
craftcms/cms^5.2.0) yui/craft-core^1, declared inrequire--Settingsextendsyui\craftcore\models\BasePluginSettingsModelat runtime. (yui/craft-plugin^2 also appears incomposer.json, but only inrequire-dev-- it is not a runtime dependency.)benjaminhu/szamlazz-php-api2.10.* (unofficial Szamlazz.hu Agent API client)- Optional:
yui/craft-mcp, for the MCP tools described above