Appearance
Public Marketplace (Mirakl) Integration
Flow ID: IN-04 | Module(s): eshop, job, Public, Transporters | Complexity: High Last Updated: 2026-04-04
Business Overview
Public is a Greek retail marketplace powered by the Mirakl platform. This integration provides polling-based order synchronization using the Mirakl Shop SDK, with five scheduled background jobs covering the full order lifecycle: fetching awaiting orders, syncing status updates, sending tracking information, marking orders as shipped, and backfilling shipping/customer data. Orders are accepted or rejected at the line-item level (unlike Shopflix which operates at the order level). The integration includes transporter selection during acceptance and automatic carrier mapping via the Mirakl carrier registry.
API Reference
The integration uses the Mirakl PHP Shop SDK (Mirakl\MMP\Shop\Client\ShopApiClient) rather than direct HTTP calls.
| SDK Method | Purpose |
|---|---|
getOrders(GetOrdersRequest) | Fetch orders by state and date range |
acceptOrder(AcceptOrderRequest) | Accept/reject individual order lines |
shipOrder(ShipOrderRequest) | Mark order as shipped |
updateOrderTrackingInfo(UpdateOrderTrackingInfoRequest) | Send tracking number and carrier details |
getOrderDocuments(GetOrderDocumentsRequest) | Check for delivery bills |
downloadOrdersDocuments(DownloadOrdersDocumentsRequest) | Download delivery bill PDF |
getShippingCarriers() | List available carrier codes for tracking |
API endpoint: https://publicgr-prod.mirakl.net/api
Authentication: API Key + Store ID passed to ShopApiClient constructor.
Timezone handling: All Mirakl dates are in UTC and converted to Europe/Athens via convertTime().
Code Flow
1. Fetch Awaiting Orders (Job)
Entry point: AdvGetPublicMarketplaceAwaitingOrders::executeCommand()
AdvGetPublicMarketplaceAwaitingOrders
|-- Check PUBLIC_MARKETPLACE.ENABLED + API_KEY
|-- PublicOrders::getPendingOrders(date - 1 week)
| |-- GetOrdersRequest with state=WAITING_ACCEPTANCE, TAX_INCLUDED
| |-- transformOrderData() maps Mirakl objects to arrays
|-- Get existing order IDs from DB to avoid duplicates
|-- For each new order:
|-- mapOrderData() -> insert into public_orders
|-- insertOrderBasket() -> batch insert into public_line_items2. Update Order Status (Job)
Entry point: AdvUpdatePublicOrdersStatus::executeCommand()
AdvUpdatePublicOrdersStatus
|-- PublicOrders::getOrders(date - 1 week) -- all states
|-- For each order that exists locally:
|-- Map Mirakl status to internal state
|-- Update public_orders.state3. Send Tracking Information (Job)
Entry point: AdvSetTrackingPublicMarketplace::executeCommand()
AdvSetTrackingPublicMarketplace
|-- Get orders needing tracking from order_model::getOrdersForTrackingPublicMarketplace()
|-- For each order:
|-- Build tracking details (carrier_code, tracking_number, carrier_url)
|-- PublicOrders::setTrackingDetails() with carrier lookup from Mirakl
|-- On success: set is_tracking_sent = true4. Mark Orders Shipped (Job)
Entry point: AdvSetPublicOrdersSent::executeCommand()
AdvSetPublicOrdersSent
|-- Get SENT orders via order_model::getOrdersPublicMarketplaceForSetSent()
|-- For each: PublicOrders::setOrderShipped()
|-- Batch update is_sent = 1 for successful orders5. Backfill Shipping Data (Job)
Entry point: AdvGetPublicMarketplaceShippingData::executeCommand()
AdvGetPublicMarketplaceShippingData
|-- Get accepted orders missing customer data (got_customer_data = 0)
|-- For each: fetch full order from Mirakl API
|-- Extract billing + shipping addresses
|-- Update shop_order with address fields
|-- Update shop_customer with address fields
|-- Set got_customer_data = 16. Admin Accept Flow
Entry point: Adv_public_orders_admin::accept($orderId)
accept($orderId)
|-- Validate order exists + acceptance_until_date not expired + no existing shop_order_id
|-- Load available transporters via public_order_transporters()
|-- Match line items to shop products via EAN/product_code
|-- Stock validation (bypassable via DISABLE_PRODUCT_STOCK_CHECK)
|-- On POST accept_order:
|-- Get order line IDs for line-item acceptance
|-- PublicOrders::acceptOrder($orderId, $orderLineIds)
|-- Re-fetch order from API for latest customer data
|-- Build fake cart from line items
|-- Create guest customer (with randomized email to avoid collisions)
|-- Create internal order with selected transporter, status=PAID
|-- Provider = PUBLIC_MARKETPLACE_PROVIDER constant
|-- Fire ERP hook7. Admin Reject Flow
Entry point: Adv_public_orders_admin::reject($orderId)
reject($orderId)
|-- Get order line IDs
|-- PublicOrders::rejectOrder($orderId, $orderLineIds) -- marks all lines as rejected
|-- Update public_orders.state = 'rejected'8. Status Mapping
Mirakl API statuses mapped to internal states:
| Mirakl Status | Internal State |
|---|---|
| STAGING | open |
| WAITING_ACCEPTANCE | open |
| WAITING_DEBIT | accepted |
| WAITING_DEBIT_PAYMENT | accepted |
| SHIPPING | accepted |
| SHIPPED | dispatched |
| TO_COLLECT | dispatched |
| RECEIVED | delivered |
| CLOSED | expired |
| REFUSED | rejected |
| CANCELED | cancelled |
Architecture
ecommercen/job/libraries/
AdvGetPublicMarketplaceAwaitingOrders.php -- Fetch new orders (JobCommand)
AdvUpdatePublicOrdersStatus.php -- Sync status changes (JobCommand)
AdvSetTrackingPublicMarketplace.php -- Send tracking info (JobCommand)
AdvSetPublicOrdersSent.php -- Mark shipped (JobCommand)
AdvGetPublicMarketplaceShippingData.php -- Backfill addresses (JobCommand)
src/Public/PublicOrders.php -- Mirakl SDK client wrapper
ecommercen/core/AdvFactories.php -- Factory method: Factories::publicMarketplace()
ecommercen/eshop/controllers/Adv_public_orders_admin.php -- Admin controller
ecommercen/eshop/models/Adv_public_orders_model.php -- Legacy model
src/Domains/Marketplace/Public/Order/ -- Modern domain layer (read-only)
Repository/{Entity,Repository,RepositoryConfigurator}.php
Service.php, ListRequest.php
src/Domains/Marketplace/Public/LineItem/ -- Modern domain layer (read-only)
Repository/{Entity,Repository,RepositoryConfigurator}.php
Service.php, ListRequest.php
src/Rest/Marketplace/Controllers/PublicOrder.php -- REST API controller
src/Rest/Marketplace/Controllers/PublicLineItem.php -- REST API controller
src/Rest/Marketplace/Resources/PublicOrder/ -- Resource + Collection
src/Rest/Marketplace/Resources/PublicLineItem/ -- Resource + Collection
application/views/admin/public_orders/{list,accept,reject}.php -- Admin viewsFactory pattern: All jobs use Factories::publicMarketplace() to instantiate PublicOrders with registry config, ensuring consistent configuration.
Delivery bill support: The PublicOrders client includes checkIfDeliveryBillExists($orderCode) and getOrderDeliveryBill($orderCode) methods for retrieving SYSTEM_DELIVERY_BILL documents. These are called from the general orders admin controller (Adv_orders_admin) rather than the Public-specific admin controller.
Data Model
public_orders
| Column | Type | Description |
|---|---|---|
order_id | varchar(255) PK | Mirakl order ID (string) |
state | enum | open, accepted, rejected, cancelled, expired, dispatched, delivered, partially_returned, returned |
invoice | tinyint(1) | Invoice requested flag |
is_tracking_sent | tinyint(1) | Tracking info sent to Mirakl |
is_sent | tinyint(1) | Ship notification sent to Mirakl |
can_cancel | tinyint(1) | Whether order can be cancelled |
order_date | datetime | Order creation date |
has_invoice | tinyint(1) | Has invoice attached |
created_at | datetime | Local record creation |
updated_at | datetime | Last local update |
shipping_deadline | datetime | Must-ship-by date |
acceptance_until_date | datetime | Accept/reject deadline |
shipping_price | decimal(10,2) | Shipping cost |
total_price | decimal(10,2) | Order total |
commission_price | decimal(10,2) | Mirakl commission amount |
order_type | varchar(255) | Billing type (receipt/invoice) |
customer_id | varchar(255) | Mirakl customer ID |
first_name, last_name | varchar(255) | Customer name |
email | varchar(255) | Customer email |
region | varchar(255) | Shipping zone label |
comments | text | Customer comments |
got_customer_data | tinyint(1) | Whether customer address data has been backfilled from Mirakl |
shop_order_id | int(11) | Linked internal order ID |
public_line_items
| Column | Type | Description |
|---|---|---|
id | int(11) PK AI | Auto-increment ID |
public_order_id | varchar(255) | Parent order ID |
order_line_id | varchar(255) | Mirakl order line ID (used for line-item accept/reject) |
product_name | varchar(255) | Product title |
quantity | int(11) | Ordered quantity |
unit_price | decimal(11,2) | Price per unit |
total_price | decimal(11,2) | Line total |
ean | varchar(255) | SKU/EAN for product matching |
public_transporters_mapping
| Column | Type | Description |
|---|---|---|
transporter_id | int(11) PK | Internal transporter ID |
code | varchar(255) PK | Mirakl carrier code |
Configuration
Registry Keys (PUBLIC_MARKETPLACE group)
| Key | Type | Purpose |
|---|---|---|
ENABLED | bool | Master toggle for the integration |
API_KEY | string | Mirakl Shop API key |
STORE_ID | string | Mirakl store identifier |
DISABLE_PRODUCT_STOCK_CHECK | bool | Bypass stock validation during accept (optional) |
Registry Keys (XML_FEEDS group)
| Key | Purpose |
|---|---|
IS_ENABLED_PUBLIC_MARKETPLACE | Enable product feed for Public |
IS_PROTECTED_PUBLIC_MARKETPLACE | Token-protect the feed URL |
PUBLIC_MARKETPLACE_TOKEN | Feed authentication token |
CUSTOM_PRICE_PUBLIC_MARKETPLACE | Enable custom price modifier |
CUSTOM_PRICE_PUBLIC_MARKETPLACE_MODIFIER | Price modifier percentage |
Job Configuration (application/config/jobs.php)
php
'public_marketplace' => [
'enabled' => false, // Enable per client
'commands' => [
['command' => 'GetPublicMarketplaceAwaitingOrders', 'schedule' => '*/30 * * * *'],
['command' => 'SetTrackingPublicMarketplace', 'schedule' => '0 */1 * * *'],
['command' => 'SetPublicOrdersSent', 'schedule' => '0 */1 * * *'],
['command' => 'UpdatePublicOrdersStatus', 'schedule' => '0 */1 * * *'],
['command' => 'GetPublicMarketplaceShippingData', 'schedule' => '*/5 * * * *'],
]
]REST API Routes
| Method | Path | Action |
|---|---|---|
| GET | /rest/marketplace/public/order | Collection (filterable, sortable) |
| GET | /rest/marketplace/public/order/item | Single by filters |
| GET | /rest/marketplace/public/order/{id} | Single by ID (string PK) |
| GET | /rest/marketplace/public/line-item | Line item collection |
| GET | /rest/marketplace/public/line-item/item | Single line item by filters |
| GET | /rest/marketplace/public/line-item/{id} | Single line item by ID |
Client Extension Points
- Job overrides: Create corresponding files in
application/modules/job/libraries/ - Admin controller override:
application/modules/eshop/controllers/Public_orders_admin.php - Model override:
application/modules/eshop/models/Public_orders_model.php - Transporter mapping: Admin UI for mapping internal transporters to Mirakl carrier codes (
public_transporters_mappingtable) - Product feed: Separate
AdvPublicMarketplaceXmlfeed controller for Public product catalog - Stock check bypass: Per-client via
PUBLIC_MARKETPLACE.DISABLE_PRODUCT_STOCK_CHECK
Business Rules
| Rule | Description |
|---|---|
| Line-item acceptance | Each order line is individually accepted/rejected (unlike Shopflix full-order) |
| Acceptance deadline | Orders can only be accepted before acceptance_until_date expires |
| One-time acceptance | Orders with existing shop_order_id cannot be re-accepted |
| Transporter selection | Admin selects a transporter during acceptance; carrier mapped to Mirakl code |
| Guest email randomization | Guest customer emails use uniqid() prefix to avoid collisions |
| Shipping data backfill | Customer address data not available at order creation; backfilled by separate job |
| Tracking carrier lookup | Carrier codes resolved from Mirakl's carrier registry, not hardcoded |
| UTC to Athens conversion | All Mirakl timestamps converted from UTC to Europe/Athens |
| Commission tracking | Mirakl commission stored per order for financial reconciliation |
| Invoice from additional fields | Billing type, tax code, tax office extracted from Mirakl additional_fields |
| Accepted orders = PAID | Internal order status set to PAID with PUBLIC_MARKETPLACE_PROVIDER |
Related Flows
- AD-11 Marketplace Orders -- shared marketplace admin patterns
- AD-03 Order Management -- internal order processing after acceptance
- AD-06 Transporter Admin -- transporter-to-carrier mapping
- IN-01 Feed Generation -- Public marketplace product feed
- IN-09 Transporter Integrations -- carrier integration patterns
- SY-01 Cron Framework -- job scheduling infrastructure