Developer / API
Services
Registered as plugin components in plugin\Services::_registerComponents() and reachable via
Plugin::getInstance()->get('<id>') (or the getOrders() getter for orders):
| Component id | Service | Responsibility |
|---|---|---|
api | ApiService | Builds the HTTP client from the current settings, converts XML between UTF-8 and windows-1250 (POHODA's expected encoding), and posts/parses XML against the mServer. sendXml() is the entry point every other service uses to talk to POHODA. |
orders | OrdersService | Builds order/dataPack XML for export (exportOrders()) and parses listOrdersResponse XML back into arrays (importOrders()). |
items | ItemsService | Builds stock/dataPack XML for export (exportItems()), parses listStockResponse/data-pack XML back into arrays (importItems()), and parses an uploaded XML file directly (parseItemsFromXml()). |
buffer | BufferService | Persists imported stock items into the pohoda_items table (saveItems()), drives the sync/import queue jobs (queueSync(), queueImport()), and imports buffered records into Craft entries (importItems()/importRecord()) using a MapperService-resolved field mapping. |
mapper | MapperService | Resolves the CP mapping UI's source options (built-in fields plus flattened data.* paths from a sample record's raw payload) and extracts a value for a given source from an Item record (extractValue()). |
license | LicenseService | Shared license activation/redemption service, same pattern as other yStore/craft-core plugins. |
ApiService, OrdersService, and ItemsService extend AbstractService, which resolves the
plugin instance and settings model lazily and allows both to be injected (setPlugin(),
setSettings()) — this is what makes the services independently unit-testable outside a full
Craft application (see tests/ApiServiceTest.php, tests/ItemsServiceTest.php,
tests/OrdersServiceTest.php).
Data model
Yui\Pohoda\records\Item (table pohoda_items, created by
m240227_000000_create_items_buffer.php) is the local stock buffer: sku, name, price,
stock, vat, warehouse, data (the full POHODA payload as JSON), syncedAt,
importedEntryId, importedAt. It's a plain craft\db\ActiveRecord, not a Craft element — the
buffer is an internal staging table, not something queried through element APIs.
Invoice provider integration
Yui\Pohoda\providers\PohodaInvoiceProvider extends yui\craft\base\BaseInvoiceProvider and is
registered on yui\craft\services\sales\InvoiceService::EVENT_REGISTER_INVOICE_PROVIDERS in
Plugin::init() — only when that class exists, so Pohoda degrades gracefully without the
yStore checkout/invoicing stack installed. Its getHandle() is pohoda, isEnabled() mirrors the
plugin's Enable setting, and createInvoice(array $invoiceData) maps the generic invoice data
array (order meta, customer, totals, items, shipping/payment as pseudo line items) into the shape
OrdersService::exportOrders() expects, then calls it. To customize how invoice data maps onto a
POHODA order (e.g. different VAT handling, extra line item metadata), extend or replace this
provider rather than patching OrdersService — it's the single seam between the generic invoicing
pipeline and Pohoda's XML format.
CP routes
Registered in plugin\Routes.php, all under the pohoda/ prefix:
settings(index/advanced/test-connection) →SettingsControlleritems(index/import) →ItemsControllerlicense(index/redeem/revoke/activate/delete/copy-token) → shared license flow
ItemsController actions require the accessPlugin-pohoda permission in addition to a CP
request; SettingsController::actionImportXml() additionally requires a POST with an uploaded
xml file field.
Console commands
Items — Yui\Pohoda\console\controllers\ItemsController
# Export a JSON array of items (stdin or --input=<path>) as POHODA stock XML
php craft pohoda/items/export [--input=<path>] [--output=<path>]
# Fetch stock items from POHODA; --format=json (default) or xml
php craft pohoda/items/import [--code=<sku>] [--lastChange=<iso8601>] [--page=<n>] [--limit=<n>]
[--includeStockBalance=1] [--format=json|xml] [--output=<path>]
# Fetch stock items and save them into the local buffer table
php craft pohoda/items/sync-buffer [--code=<sku>] [--lastChange=<iso8601>] [--page=<n>]
[--limit=<n>] [--includeStockBalance=1] [--queue=1]
# Import buffered items into Craft entries using a target entry type + field mapping
php craft pohoda/items/import-buffer --entryTypeId=<id> [--siteId=<id>] [--ids=<id,id,...>]
[--map="target:source,target:source"] [--queue=1]
-i/-o/-f/-m are short aliases for --input/--output/--format/--map. --queue
defaults to true on both buffer commands — pass --queue=0 to run synchronously and get an
immediate count instead of a queue job id. import-buffer requires --entryTypeId; without it
the command throws immediately rather than guessing a target.
Orders — Yui\Pohoda\console\controllers\OrdersController
# Export a JSON array of orders (stdin or --input=<path>) as POHODA order XML
php craft pohoda/orders/export [--input=<path>] [--output=<path>]
# Fetch orders/invoices from POHODA; --format=json (default) or xml
php craft pohoda/orders/import [--number=<n>] [--dateFrom=<Y-m-d>] [--dateTo=<Y-m-d>]
[--orderType=<type>] [--includeUnpaid=1] [--page=<n>] [--limit=<n>] [--format=json|xml]
[--output=<path>]
--orderType defaults to issuedInvoice when omitted. Both import commands auto-paginate through
POHODA's requestSettings page/limit unless the caller restricts pagination through --limit
combined with a single --page.
MCP tools
Registered (only when yui\mcp\Plugin is installed) on
\yui\mcp\Plugin::EVENT_REGISTER_TOOLS in Plugin::init():
| Tool | Permission | Purpose |
|---|---|---|
pohoda_export_order | WRITE | Export a single order (same shape as the orders/export console command's per-item JSON) to POHODA; returns the raw response XML. |
pohoda_import_orders | default | Fetch orders from POHODA with the same filters as orders/import (orderType, number, dateFrom/dateTo, includeUnpaid, limit/page/autoPaginate); returns {count, items}. |
pohoda_lookup_item | default | Look up stock items by code and/or lastChange (at least one required); returns {count, items} with price and stock balance. autoPaginate defaults to false here, unlike the console/service default, since lookups are expected to target a small result set. |
All three delegate straight to OrdersService/ItemsService — there's no separate MCP-only
business logic, so behavior changes made to those services apply to both the console commands and
the MCP tools automatically.
Twig
Pohoda doesn't register a craft.pohoda template variable or any Twig extension — it has no
storefront-facing rendering. All interaction happens through the CP screens, console commands, or
MCP tools described above.