Appearance
Shopflix Marketplace Integration
Flow ID: IN-03 | Module(s): eshop, job, Shopflix | Complexity: High Last Updated: 2026-04-04
Business Overview
Shopflix is a Greek marketplace platform. This integration provides polling-based order synchronization where a scheduled job fetches new and updated orders from the Shopflix REST API, stores them locally, and presents them to admin users for acceptance or rejection. Upon acceptance, a corresponding internal shop order is created with status PAID. The integration also handles courier voucher management (create, print, cancel, mass operations) and shipping manifest generation through the Shopflix Courier API.
API Reference
| Endpoint | Method | Purpose |
|---|---|---|
/api/orders{?params} | GET | List orders with pagination and date filtering |
/api/orders/{orderId} | GET | Get single order details |
/api/orders/{orderId} | PUT | Update order status (accept: G, reject: D) |
/api/courier/{shipmentId} | GET | Create voucher for shipment |
/api/courier?print={voucher}&labelFormat=pdf | GET | Print single voucher as PDF |
/api/courier?printmass={vouchers}&labelFormat=pdf | GET | Print multiple vouchers as combined PDF |
/api/courier?cancel={voucher} | GET | Cancel a voucher |
/api/courier?custom_manifest=1&shipments={ids} | GET | Generate shipping manifest PDF |
Authentication: Basic Auth with base64(API_EMAIL:API_KEY) in the Authorization header.
Environments:
- Testing:
https://4bg28dqy1b.execute-api.eu-central-1.amazonaws.com/api - Production:
https://merchant.api.shopflix.gr/api
Code Flow
1. Order Polling (Background Job)
Entry point: AdvHandleShopflixOrders::executeCommand()
AdvHandleShopflixOrders
|-- checks SHOPFLIX.IS_ENABLED registry
|-- getOrdersFromShopflix()
| |-- getOrderListFromShopflix()
| | |-- ShopflixOrders::getOrdersList() with date_from = last known timestamp
| | |-- Paginates through all pages (100 items/page)
| |-- For each order with status != 'C' (Completed):
| | |-- ShopflixOrders::getOrderData(order_id)
| | |-- shopflix_orders_model::handleOrderCreation()
| | |-- Skip if order already exists
| | |-- Insert order header into shopflix_orders
| | |-- Insert line items into shopflix_line_items
|-- getShopflixOrderUpdates()
|-- Fetch all incomplete orders from DB
|-- For each, re-fetch from API
|-- If last_order_change is newer, call handleOrderUpdate()
|-- Update order fields + line items
|-- If status is I (Cancelled) or D (Rejected), auto-cancel internal shop order2. Admin Accept Flow
Entry point: Adv_shopflix_orders_admin::accept($code)
accept($code)
|-- Load order data + line items
|-- Match line items to shop products via product_codes.product_code
|-- Stock validation: getLiveProductsParsed() checks per-SKU availability
| (bypassable via SHOPFLIX.DISABLE_PRODUCT_STOCK_CHECK)
|-- On POST accept_order:
|-- ShopflixOrders::acceptOrder($code) -- PUT status='G' to API
|-- Build fake cart from line items (createShopflixFakeCart)
|-- Create guest customer via customer_model::add_customer_front()
|-- Create internal order via order_model::create_order_admin()
|-- Set order status = PAID, provider = 'shopflix_marketplace'
|-- Update shopflix_orders: shop_order_id, status='Processing'
|-- Fire ERP hook: internalApiOrderForErpHook()3. Admin Reject Flow
Entry point: Adv_shopflix_orders_admin::reject($code)
reject($code)
|-- ShopflixOrders::rejectOrder($code) -- PUT status='D' to API
|-- Update shopflix_orders status = 'Rejected'4. Voucher Management
| Action | Method | Behavior |
|---|---|---|
| Create single | createOrderVouchers($code) | Iterates shipment_ids, calls ShopflixOrders::createVoucher() per shipment |
| Create mass | massCreateVouchers($orders) | Batch voucher creation across multiple orders |
| Print single | printVoucher($voucher) | Returns base64-decoded PDF via ShopflixOrders::printVoucher() |
| Print mass | massPrintVouchers($orders) | Combines multiple voucher PDFs using FPDI library |
| Cancel single | canceOrderlVouchers($code) | Cancels all vouchers on an order, clears DB fields |
| Cancel mass | massCancelVouchers($orders) | Batch cancel across orders |
| Manifest | getManifest($orders) | Generates shipping manifest PDF from shipment IDs |
| Manifest by date | getManifestByDate() | Today's orders manifest |
5. Status Mapping
The Shopflix API uses single-character status codes mapped to human-readable values via resolveShopflixStatuses():
| Code | Status | Terminal? |
|---|---|---|
| O | Placed | No |
| G | Processing | No |
| H | To be Shipped | No |
| J | Shipped | No |
| S | On Transit | No |
| E | Partial Delivery | No |
| L | Failed to Deliver | No |
| K | Delivered | No |
| D | Rejected | Yes (triggers auto-cancel) |
| I | Cancelled | Yes (triggers auto-cancel) |
| C | Completed | Yes |
| U | Return requested | No |
| A | On the way to the store | No |
| T | Delivered to the store | No |
| V | Return completed | Yes |
| W | Processing return | No |
| X | Return declined | No |
Architecture
ecommercen/job/libraries/AdvHandleShopflixOrders.php -- Polling job (JobCommand)
src/Shopflix/ShopflixOrders.php -- API client (Guzzle HTTP)
ecommercen/eshop/controllers/Adv_shopflix_orders_admin.php -- Admin controller
ecommercen/eshop/models/Adv_shopflix_orders_model.php -- Legacy model (Adv_base_model)
ecommercen/helpers/shopflix_helper.php -- Status mapping helper
src/Domains/Marketplace/Shopflix/Order/ -- Modern domain layer (read-only)
Repository/{Entity,Repository,RepositoryConfigurator}.php
Service.php, ListRequest.php
src/Domains/Marketplace/Shopflix/LineItem/ -- Modern domain layer (read-only)
Repository/{Entity,Repository,RepositoryConfigurator}.php
Service.php, ListRequest.php
src/Rest/Marketplace/Controllers/ShopflixOrder.php -- REST API controller
src/Rest/Marketplace/Controllers/ShopflixLineItem.php -- REST API controller
src/Rest/Marketplace/Resources/ShopflixOrder/ -- Resource + Collection
src/Rest/Marketplace/Resources/ShopflixLineItem/ -- Resource + Collection
application/views/admin/shopflix_orders/{list,accept,reject}.php -- Admin viewsDual-layer pattern: The legacy model handles all write operations (order creation, updates, voucher tracking). The modern domain layer provides read-only REST API access for external integrations.
Data Model
shopflix_orders
| Column | Type | Description |
|---|---|---|
order_id | int(11) PK | Shopflix order ID |
order_reference | varchar(255) | Shopflix reference code |
status | varchar(50) | Resolved status string |
payment_method | varchar(50) | Payment method name |
invoice_id | int(11) | Invoice request flag |
afm | varchar(30) | Tax ID (for invoices) |
doy | varchar(100) | Tax office (for invoices) |
profession | varchar(255) | Customer profession |
company | varchar(255) | Company name |
company_address | varchar(255) | Company address |
b_firstname ... b_phone | varchar | Billing address fields |
email | varchar(255) | Customer email |
phone | varchar(50) | Customer phone |
timestamp | varchar(30) | Order creation timestamp |
last_order_change | varchar(30) | Last modification timestamp |
total, subtotal, discount | decimal(10,2) | Pricing fields |
shipping | varchar(255) | Courier name |
shipment_ids | varchar(255) | JSON array of shipment IDs |
shopflix_vouchers | varchar(255) | JSON array of voucher numbers |
voucher_creation_datetime | datetime | When vouchers were created |
shop_order_id | varchar(255) | Linked internal order ID |
shopflix_line_items
| Column | Type | Description |
|---|---|---|
id | int(11) PK AI | Auto-increment ID |
shopflix_order_id | varchar(255) FK | Parent order ID |
product_id | varchar(255) | Shopflix product ID |
product_code | varchar(255) | Product SKU (used for matching) |
product | varchar(255) | Product name |
amount | int(11) | Quantity |
base_price, original_price, total_price | decimal(10,2) | Pricing |
ean | varchar(255) | EAN barcode |
delivery_date, pickup_date | date | Logistics dates |
master_product_code | varchar(255) | Parent product code |
item_id | int(11) | Shopflix item ID |
Configuration
Registry Keys (SHOPFLIX group)
| Key | Type | Purpose |
|---|---|---|
IS_ENABLED | int | Master toggle for the integration |
IS_PRODUCTION | int | 0 = testing API, 1 = production API |
API_EMAIL | string | Shopflix API email for Basic Auth |
API_KEY | string | Shopflix API key for Basic Auth |
DISABLE_PRODUCT_STOCK_CHECK | bool | Bypass stock validation on accept |
IS_DEBUG_CALL | int | Log all API requests/responses to logs/shopflixOrders.php |
Job Configuration (application/config/jobs.php)
php
'shopflix_marketplace' => [
'enabled' => false, // Enable per client
'commands' => [
['command' => 'HandleShopflixOrders', 'schedule' => '*/30 * * * *', 'graceTime' => 60, 'retryTimes' => 1]
]
]REST API Routes
| Method | Path | Action |
|---|---|---|
| GET | /rest/marketplace/shopflix/order | Collection (filterable, sortable) |
| GET | /rest/marketplace/shopflix/order/item | Single by filters |
| GET | /rest/marketplace/shopflix/order/{id} | Single by ID |
| GET | /rest/marketplace/shopflix/line-item | Line item collection |
| GET | /rest/marketplace/shopflix/line-item/item | Single line item by filters |
| GET | /rest/marketplace/shopflix/line-item/{id} | Single line item by ID |
Client Extension Points
- Job override: Create
application/modules/job/libraries/HandleShopflixOrders.phpin client repo - Admin controller override:
application/modules/eshop/controllers/Shopflix_orders_admin.php - Model override:
application/modules/eshop/models/Shopflix_orders_model.php - Registry settings: All configuration via admin UI (Settings > Third Party Providers)
- Stock check bypass: Per-client via
SHOPFLIX.DISABLE_PRODUCT_STOCK_CHECK
Business Rules
| Rule | Description |
|---|---|
| Accepted orders = PAID | All marketplace orders are pre-paid; internal status set to PAID |
| Auto-cancel on I/D | Polling detects Cancelled (I) or Rejected (D) and auto-cancels internal order |
| Completed orders skipped | Orders with status C are never fetched or created |
| Guest customer per order | Each accepted order creates a new guest customer |
| Product matching by SKU | Line items matched via product_codes.product_code exact match |
| Cancel guard | Internal order only canceled if not already in SENT/PAID_SENT/INVOICED/CANCELED/RETURN |
| Invoice support | If invoice_id present, invoice fields (AFM, DOY, company) are captured and order type set to invoice |
| Date-based polling | Only fetches orders newer than the most recent timestamp in local DB |
Related Flows
- AD-11 Marketplace Orders -- shared marketplace admin patterns
- AD-03 Order Management -- internal order processing after acceptance
- IN-09 Transporter Integrations -- voucher creation patterns
- SY-01 Cron Framework -- job scheduling infrastructure