Appearance
Marketplace Order Management
Flow ID: AD-11 Module(s): eshop, webhooks Complexity: High Last Updated: 2026-04-04
Business Context
Three marketplace integrations receive external orders and convert them into internal shop orders: Skroutz SmartCart (webhook-based, real-time), Shopflix (polling-based), and Public Marketplace/Mirakl (polling-based). Each has its own order lifecycle, stock validation, and fulfillment flow. All create "fake carts" and guest customers to generate internal orders.
Entry Points
| Type | Path / Trigger | Controller | Method |
|---|---|---|---|
| Webhook | Skroutz new_order / order_updated | ecommercen/webhooks/AdvSmartCart.php | handle() |
| Cron | Shopflix polling | AdvHandleShopflixOrders job | executeCommand() |
| Cron | Public marketplace polling | AdvGetPublicMarketplaceAwaitingOrders job | executeCommand() |
| Admin | Skroutz orders | ecommercen/eshop/controllers/Adv_skroutz_orders_admin.php | index(), accept(), reject() |
| Admin | Shopflix orders | Adv_shopflix_orders_admin.php | index(), accept(), reject() |
| Admin | Public orders | Adv_public_orders_admin.php | index(), accept(), reject() |
Architecture Comparison
| Aspect | Skroutz | Shopflix | Public (Mirakl) |
|---|---|---|---|
| Sync | Webhook push (real-time) | Polling pull (job) | Polling pull (job) |
| Product lookup | shop_product.skroutz_id + size/color attributes | product_codes.product_code exact match | EAN/product code |
| Rejection | Line-item level with reason codes | Full order only | Line-item level |
| Express orders | Auto-accept if express=true | N/A | N/A |
| Invoice | Separate skroutz_invoice_details table | Fields in main order | additional_fields JSON |
| Vouchers | Via standard transporter flow | JSON array in shopflix_vouchers column | Mirakl handles |
| Auto-cancel | Via webhook state change | If status becomes I (Cancelled) or D (Rejected) | Manual only |
| Provider tag | skroutz_smart_cart | shopflix_marketplace | PUBLIC_MARKETPLACE_PROVIDER |
Common Flow Pattern
All three follow the same pattern for order acceptance:
- Receive order (webhook or poll) → store in marketplace-specific table
- Admin reviews in marketplace order listing
- Stock validation —
getLiveProductsParsed()checksproductAvailabilityStocks >= quantity. Bypassable viaDISABLE_PRODUCT_STOCK_CHECKregistry. - Accept via API — calls marketplace API to confirm acceptance
- Create internal order — builds fake cart, creates guest customer, calls
order_model->create_order_admin()with status=PAID - Fire ERP hook —
internalApiOrderForErpHook()
Business Rules
| Rule | Description |
|---|---|
| All accepted orders = status PAID | Marketplace orders are pre-paid externally |
| Stock check bypassable | DISABLE_PRODUCT_STOCK_CHECK registry flag |
| Skroutz auto-cleanup | Orders 5+ days old without shop_order_id are auto-deleted |
| Shopflix auto-cancel | If polling detects status I or D, internal order is auto-canceled |
| Guest customers created per order | Each marketplace order creates a new guest customer |
| Skroutz express auto-accept | Express orders skip manual acceptance |
Data Model
| Table | Marketplace | Purpose |
|---|---|---|
skroutz_orders | Skroutz | Order header (code, state, courier, expires_at) |
skroutz_line_items | Skroutz | Order items (shop_uid, quantity, price) |
skroutz_invoice_details | Skroutz | Invoice data (company, VAT, DOY) |
shopflix_orders | Shopflix | Order header (order_id, status, shipment_ids) |
shopflix_line_items | Shopflix | Order items (product data, quantity, price) |
public_orders | Public | Order header (order_id, state, total_price) |
public_line_items | Public | Order items (order_line_id, ean, quantity) |
Marketplace Activity Status (Live Production Data)
Based on live production data across deployed clients:
| Marketplace | Table | Approximate Rows | Status | Notes |
|---|---|---|---|---|
| Skroutz SmartCart | skroutz_orders | ~46,000+ | Active | Primary marketplace. Webhook-driven, real-time. Multiple clients active. |
| Shopflix | shopflix_orders | 0 | Inactive | Code exists, no production usage. Shopflix marketplace was discontinued. |
| Public/Mirakl | public_orders | 0 | Inactive | Code exists, no production usage. Requires Mirakl API credentials. |
| IRIS | iris_orders | 0 | Inactive | Payment-linked orders (IRIS payment gateway), not a traditional marketplace. |
| JCC | jcc_order_ids | 0 | Inactive | Payment-linked orders (JCC payment gateway, Cyprus), not a traditional marketplace. |
Key finding: Skroutz SmartCart is the only actively used marketplace integration. All other marketplace integrations exist in code but have zero production usage. IRIS and JCC are not true marketplaces -- they are payment gateway order ID linking tables.
REST API Endpoints (Marketplace Module)
The modern REST layer exposes read-only endpoints for all marketplace entities at src/Rest/Marketplace/. All endpoints require JWT authentication.
Skroutz Endpoints
| Method | Path | Controller | Status |
|---|---|---|---|
| GET | /rest/marketplace/skroutz/order | SkroutzOrder::index() | 200 (active data) |
| GET | /rest/marketplace/skroutz/order/item | SkroutzOrder::item() | 200 |
| GET | /rest/marketplace/skroutz/order/{code} | SkroutzOrder::show() | 200 |
| GET | /rest/marketplace/skroutz/line-item | SkroutzLineItem::index() | 200 |
| GET | /rest/marketplace/skroutz/line-item/item | SkroutzLineItem::item() | 200 |
| GET | /rest/marketplace/skroutz/line-item/{id} | SkroutzLineItem::show() | 200 |
| GET | /rest/marketplace/skroutz/invoice-detail | SkroutzInvoiceDetail::index() | 200 |
| GET | /rest/marketplace/skroutz/invoice-detail/item | SkroutzInvoiceDetail::item() | 200 |
| GET | /rest/marketplace/skroutz/invoice-detail/{id} | SkroutzInvoiceDetail::show() | 200 |
Shopflix Endpoints
| Method | Path | Controller | Status |
|---|---|---|---|
| GET | /rest/marketplace/shopflix/order | ShopflixOrder::index() | 200 (empty result set) |
| GET | /rest/marketplace/shopflix/order/item | ShopflixOrder::item() | 200 |
| GET | /rest/marketplace/shopflix/order/{id} | ShopflixOrder::show() | 200 |
| GET | /rest/marketplace/shopflix/line-item | ShopflixLineItem::index() | 200 (empty result set) |
| GET | /rest/marketplace/shopflix/line-item/item | ShopflixLineItem::item() | 200 |
| GET | /rest/marketplace/shopflix/line-item/{id} | ShopflixLineItem::show() | 200 |
Public/Mirakl Endpoints
| Method | Path | Controller | Status |
|---|---|---|---|
| GET | /rest/marketplace/public/order | PublicOrder::index() | 200 (empty result set) |
| GET | /rest/marketplace/public/order/item | PublicOrder::item() | 200 |
| GET | /rest/marketplace/public/order/{id} | PublicOrder::show() | 200 |
| GET | /rest/marketplace/public/line-item | PublicLineItem::index() | 200 (empty result set) |
| GET | /rest/marketplace/public/line-item/item | PublicLineItem::item() | 200 |
| GET | /rest/marketplace/public/line-item/{id} | PublicLineItem::show() | 200 |
IRIS Endpoints
| Method | Path | Controller | Status |
|---|---|---|---|
| GET | /rest/marketplace/iris/order | IrisOrder::index() | 200 (empty result set) |
| GET | /rest/marketplace/iris/order/item | IrisOrder::item() | 200 |
| GET | /rest/marketplace/iris/order/{id} | IrisOrder::show() | 200 |
JCC Endpoints
| Method | Path | Controller | Status |
|---|---|---|---|
| GET | /rest/marketplace/jcc/order | JccOrder::index() | 200 (empty result set) |
| GET | /rest/marketplace/jcc/order/item | JccOrder::item() | 200 |
| GET | /rest/marketplace/jcc/order/{id} | JccOrder::show() | 200 |
Note: All write endpoints (POST, PUT, DELETE) are commented out in
rest_routes.phpfor all marketplace entities. Only GET (read) operations are exposed.
IRIS and JCC Detail
IRIS and JCC are not traditional marketplace integrations. They are payment gateway order ID linking tables:
iris_orders: Links IRIS payment gateway order IDs (irisOrderId,messageId,initiatingPartyRefId) toshop_order_id. Can also link togift_card_orders_idfor gift card payments.jcc_order_ids: Links JCC (Cyprus) payment gateway order IDs (jcc_order_id) toshop_order_id.
These exist in the REST Marketplace module for API consistency but are functionally payment record linkage, not marketplace order management.
Data Model (Detailed Column Reference)
skroutz_orders Table
| Column | Type | Description |
|---|---|---|
code | VARCHAR(255) PK | Skroutz order code (natural key, not auto-increment) |
state | ENUM | open, accepted, rejected, cancelled, expired, dispatched, delivered, partially_returned, returned |
invoice | TINYINT(1) | Invoice requested flag |
comments | VARCHAR(255) | Customer order comments |
courier | VARCHAR(255) | Assigned courier name |
courier_voucher | VARCHAR(255) | Courier voucher number |
courier_tracking_codes | VARCHAR(255) | Serialized tracking codes array |
created_at | DATETIME | Order creation on Skroutz |
expires_at | DATETIME | Acceptance deadline |
dispatch_until | DATETIME | Dispatch deadline |
number_of_parcels | VARCHAR(500) | Comma-separated parcel count options |
pickup_location | TEXT | JSON pickup location options |
pickup_window | TEXT | JSON pickup time window options |
reject_options | TEXT | JSON rejection reason options |
customer_id | VARCHAR(50) | Skroutz customer ID |
first_name | VARCHAR(50) | Customer first name |
last_name | VARCHAR(50) | Customer last name |
street_name | VARCHAR(255) | Delivery street (null if collection point) |
street_number | VARCHAR(10) | Delivery street number |
zip | VARCHAR(10) | Postal code |
city | VARCHAR(100) | City |
region | VARCHAR(100) | Region |
pickup_from_collection_point | TINYINT(1) | Collection point delivery flag |
collection_point_address | VARCHAR(500) | Collection point address |
number_of_parcels_selected | INT(11) | Admin-selected parcel count |
pickup_window_selected | VARCHAR(250) | Admin-selected pickup window |
pickup_location_selected | VARCHAR(250) | Admin-selected pickup location |
shop_order_id | INT(11) NULL | FK to shop_order.id (set after acceptance) |
express | TINYINT(1) | Express delivery flag (auto-accept trigger) |
skroutz_line_items Table
| Column | Type | Description |
|---|---|---|
id | INT(11) PK AI | Line item ID |
skroutz_id | VARCHAR(255) | Skroutz product ID |
shop_uid | VARCHAR(255) | Shop product UID for matching |
product_name | VARCHAR(255) | Product display name |
quantity | INT(11) | Ordered quantity |
size_label / size_value / size_shop_value | VARCHAR(50) | Size attribute data |
unit_price | DECIMAL(11,2) | Per-unit price |
total_price | DECIMAL(11,2) | Line total |
price_includes_vat | TINYINT(1) | VAT inclusion flag |
ean | VARCHAR(255) | Product EAN barcode |
extra_info | VARCHAR(255) | Additional product info |
skroutz_order_code | VARCHAR(255) | FK to skroutz_orders.code |
skroutz_invoice_details Table
| Column | Type | Description |
|---|---|---|
id | INT(11) PK AI | Record ID |
company | VARCHAR(100) | Company name |
profession | VARCHAR(100) | Profession |
vat_number | VARCHAR(9) | Tax ID (AFM) |
doy | VARCHAR(100) | Tax office |
street_name / street_number / zip / city / region | VARCHAR | Invoice address |
vat_exclusion_requested | TINYINT(1) | VAT exemption requested |
vat_exl_rep_* | VARCHAR | VAT exclusion representative ID data |
skroutz_order_code | VARCHAR(255) | FK to skroutz_orders.code |
shopflix_orders Table
| Column | Type | Description |
|---|---|---|
order_id | INT(11) PK | Shopflix order ID (natural key) |
order_reference | VARCHAR(255) | Shopflix order reference |
status | VARCHAR(50) | Shopflix status code |
payment_method | VARCHAR(50) | Payment method |
gift_wrapper | TINYINT(1) | Gift wrap flag |
b_firstname / b_lastname / b_address / b_city / b_state / b_zipcode / b_country / b_phone | VARCHAR | Billing address |
timestamp / last_order_change | VARCHAR(30) | Order timestamps |
voucher_creation_datetime | DATETIME | Voucher creation time |
email / phone | VARCHAR | Contact details |
total / subtotal / discount / subtotal_discount / display_subtotal | DECIMAL(10,2) | Price breakdown |
shipping | VARCHAR(255) | Shipping method |
shipment_ids | VARCHAR(255) | Shipment tracking IDs |
shopflix_vouchers | VARCHAR(255) | JSON voucher data |
shipping_cost / display_shipping_cost | DECIMAL(10,2) | Shipping costs |
shop_order_id | VARCHAR(255) | FK to shop_order.id (set after acceptance) |
shopflix_line_items Table
| Column | Type | Description |
|---|---|---|
id | INT(11) PK AI | Line item ID |
shop_uid | INT(11) | Shop product UID |
shopflix_order_id | VARCHAR(255) | FK to shopflix_orders.order_id |
product_id / product_code / product | VARCHAR(255) | Product identifiers and name |
amount | INT(11) | Quantity |
base_price / original_price / total_price | DECIMAL(10,2) | Price data |
ean | VARCHAR(255) | Product EAN |
master_product_code | VARCHAR(255) | Parent product code |
product_status / status_a39 | VARCHAR(50) | Status fields |
item_id | INT(11) | Shopflix item ID |
delivery_date / pickup_date | DATE | Logistics dates |
product_url | VARCHAR(255) | Product URL |
public_orders Table
| Column | Type | Description |
|---|---|---|
order_id | VARCHAR(255) PK | Public/Mirakl order ID (natural key) |
state | ENUM | Same states as Skroutz |
invoice | TINYINT(1) | Invoice flag |
is_tracking_sent | TINYINT(1) | Tracking sent to marketplace |
is_sent | TINYINT(1) | Order dispatched flag |
can_cancel | TINYINT(1) | Cancellable flag |
order_date | DATETIME | Original order date |
has_invoice | TINYINT(1) | Invoice exists flag |
shipping_deadline / acceptance_until_date | DATETIME | Deadline timestamps |
shipping_price / total_price / commission_price | DECIMAL(10,2) | Price data |
order_type | VARCHAR(255) | Order type classification |
customer_id / first_name / last_name / email / region / comments | VARCHAR | Customer data |
shop_order_id | INT(11) | FK to shop_order.id (set after acceptance) |
public_line_items Table
| Column | Type | Description |
|---|---|---|
id | INT(11) PK AI | Line item ID |
public_order_id | VARCHAR(255) | FK to public_orders.order_id |
order_line_id | VARCHAR(255) | Mirakl line ID |
product_name | VARCHAR(255) | Product name |
quantity | INT(11) | Quantity |
unit_price / total_price | DECIMAL(11,2) | Prices |
ean | VARCHAR(255) | Product EAN |
public_transporters_mapping Table
| Column | Type | Description |
|---|---|---|
transporter_id | INT(11) PK | Internal transporter FK |
code | VARCHAR(255) PK | Public marketplace courier code |
Maps Public/Mirakl courier codes to internal transporter IDs for voucher creation.
iris_orders Table
| Column | Type | Description |
|---|---|---|
id | INT(11) PK AI | Record ID |
messageId | VARCHAR(35) | IRIS message ID |
initiatingPartyRefId | VARCHAR(35) | Initiating party reference |
irisOrderId | VARCHAR(64) | IRIS payment order ID |
shop_order_id | INT(11) NULL | FK to shop_order.id |
gift_card_orders_id | INT(11) NULL | FK to gift card orders table |
jcc_order_ids Table
| Column | Type | Description |
|---|---|---|
id | INT(11) PK AI | Record ID |
jcc_order_id | VARCHAR(255) | JCC payment order ID |
shop_order_id | INT(11) | FK to shop_order.id |
Admin Controller Details
Adv_skroutz_orders_admin.php
The Skroutz admin controller handles order listing, acceptance, and rejection only. It has 4 methods:
| Method | Description |
|---|---|
index() | Paginated listing with filters (state, courier, pickup location) |
resetIndex() | Clear session filters |
accept($code) | Accept order: validate stock, call Skroutz API, create internal order |
reject($code) | Reject order: per-line-item rejection with reason codes via Skroutz API |
Note: Voucher operations for Skroutz orders (create, cancel, print vouchers; manifests) are handled via the main
Adv_orders_admincontroller, not the Skroutz-specific controller.
Skroutz-specific batch actions (via overridden doBatchActionsSystem()):
accept_orders-- Batch accept multiple Skroutz ordersreject_orders-- Batch reject multiple Skroutz ordersmass_create_vouchers-- Batch voucher generationmass_cancel_vouchers-- Batch voucher cancellationmass_print_vouchers-- Batch voucher printingget_manifest-- Get pickup manifest
Skroutz-specific features:
- Pickup location selection from accepted orders (
getAllSkroutzPickupLocationsFromOrders()) - Courier filtering from order data (
getAllSkroutzCouriersFromOrders()) - Express order auto-acceptance when
express=true - Auto-cleanup of orders 5+ days old without
shop_order_id
Adv_shopflix_orders_admin.php
| Method | Description |
|---|---|
index() | Paginated listing |
resetIndex() | Clear filters |
accept($code) | Accept order via Shopflix API + create internal order |
reject($code) | Reject order via Shopflix API |
createOrderVouchers($code) | Generate vouchers |
canceOrderlVouchers($code) | Cancel vouchers |
printVoucher($voucher) | Print voucher |
massPrintVouchers($orders) | Batch print |
massCreateVouchers($orders) | Batch create vouchers |
massCancelVouchers($orders) | Batch cancel vouchers |
getManifest($orders) | Get manifest |
getManifestByDate() | Get manifest by date |
Adv_public_orders_admin.php
| Method | Description |
|---|---|
index() | Paginated listing with state filter |
processFilters() | Filter processing for state/date |
resetIndex() | Clear filters |
accept($orderId) | Accept: validate stock, create internal order, call Public API |
reject($orderId) | Reject via Public/Mirakl API |
transformTransportersData() | Map internal transporters to Public marketplace codes |
Public-specific validation: isValidOrder(), extractProductIds(), getLiveProductsParsed(), checkProductStock() -- validates each line item against live inventory before acceptance.
Related Flows
- AD-03 Order Management -- internal order processing after acceptance
- AD-06 Transporter Management -- marketplace transporter code mapping via
public_transporters_mapping - AD-13 Settings --
SMARTCART,SHOPFLIX,PUBLIC_MARKETPLACEregistry groups for marketplace configuration - IN-02 Skroutz Marketplace -- Skroutz feed + order integration
- IN-09 Transporter Integrations -- voucher creation for marketplace orders