Skip to content

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

EndpointMethodPurpose
/api/orders{?params}GETList orders with pagination and date filtering
/api/orders/{orderId}GETGet single order details
/api/orders/{orderId}PUTUpdate order status (accept: G, reject: D)
/api/courier/{shipmentId}GETCreate voucher for shipment
/api/courier?print={voucher}&labelFormat=pdfGETPrint single voucher as PDF
/api/courier?printmass={vouchers}&labelFormat=pdfGETPrint multiple vouchers as combined PDF
/api/courier?cancel={voucher}GETCancel a voucher
/api/courier?custom_manifest=1&shipments={ids}GETGenerate 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 order

2. 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

ActionMethodBehavior
Create singlecreateOrderVouchers($code)Iterates shipment_ids, calls ShopflixOrders::createVoucher() per shipment
Create massmassCreateVouchers($orders)Batch voucher creation across multiple orders
Print singleprintVoucher($voucher)Returns base64-decoded PDF via ShopflixOrders::printVoucher()
Print massmassPrintVouchers($orders)Combines multiple voucher PDFs using FPDI library
Cancel singlecanceOrderlVouchers($code)Cancels all vouchers on an order, clears DB fields
Cancel massmassCancelVouchers($orders)Batch cancel across orders
ManifestgetManifest($orders)Generates shipping manifest PDF from shipment IDs
Manifest by dategetManifestByDate()Today's orders manifest

5. Status Mapping

The Shopflix API uses single-character status codes mapped to human-readable values via resolveShopflixStatuses():

CodeStatusTerminal?
OPlacedNo
GProcessingNo
HTo be ShippedNo
JShippedNo
SOn TransitNo
EPartial DeliveryNo
LFailed to DeliverNo
KDeliveredNo
DRejectedYes (triggers auto-cancel)
ICancelledYes (triggers auto-cancel)
CCompletedYes
UReturn requestedNo
AOn the way to the storeNo
TDelivered to the storeNo
VReturn completedYes
WProcessing returnNo
XReturn declinedNo

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 views

Dual-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

ColumnTypeDescription
order_idint(11) PKShopflix order ID
order_referencevarchar(255)Shopflix reference code
statusvarchar(50)Resolved status string
payment_methodvarchar(50)Payment method name
invoice_idint(11)Invoice request flag
afmvarchar(30)Tax ID (for invoices)
doyvarchar(100)Tax office (for invoices)
professionvarchar(255)Customer profession
companyvarchar(255)Company name
company_addressvarchar(255)Company address
b_firstname ... b_phonevarcharBilling address fields
emailvarchar(255)Customer email
phonevarchar(50)Customer phone
timestampvarchar(30)Order creation timestamp
last_order_changevarchar(30)Last modification timestamp
total, subtotal, discountdecimal(10,2)Pricing fields
shippingvarchar(255)Courier name
shipment_idsvarchar(255)JSON array of shipment IDs
shopflix_vouchersvarchar(255)JSON array of voucher numbers
voucher_creation_datetimedatetimeWhen vouchers were created
shop_order_idvarchar(255)Linked internal order ID

shopflix_line_items

ColumnTypeDescription
idint(11) PK AIAuto-increment ID
shopflix_order_idvarchar(255) FKParent order ID
product_idvarchar(255)Shopflix product ID
product_codevarchar(255)Product SKU (used for matching)
productvarchar(255)Product name
amountint(11)Quantity
base_price, original_price, total_pricedecimal(10,2)Pricing
eanvarchar(255)EAN barcode
delivery_date, pickup_datedateLogistics dates
master_product_codevarchar(255)Parent product code
item_idint(11)Shopflix item ID

Configuration

Registry Keys (SHOPFLIX group)

KeyTypePurpose
IS_ENABLEDintMaster toggle for the integration
IS_PRODUCTIONint0 = testing API, 1 = production API
API_EMAILstringShopflix API email for Basic Auth
API_KEYstringShopflix API key for Basic Auth
DISABLE_PRODUCT_STOCK_CHECKboolBypass stock validation on accept
IS_DEBUG_CALLintLog 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

MethodPathAction
GET/rest/marketplace/shopflix/orderCollection (filterable, sortable)
GET/rest/marketplace/shopflix/order/itemSingle by filters
GET/rest/marketplace/shopflix/order/{id}Single by ID
GET/rest/marketplace/shopflix/line-itemLine item collection
GET/rest/marketplace/shopflix/line-item/itemSingle 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.php in 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

RuleDescription
Accepted orders = PAIDAll marketplace orders are pre-paid; internal status set to PAID
Auto-cancel on I/DPolling detects Cancelled (I) or Rejected (D) and auto-cancels internal order
Completed orders skippedOrders with status C are never fetched or created
Guest customer per orderEach accepted order creates a new guest customer
Product matching by SKULine items matched via product_codes.product_code exact match
Cancel guardInternal order only canceled if not already in SENT/PAID_SENT/INVOICED/CANCELED/RETURN
Invoice supportIf invoice_id present, invoice fields (AFM, DOY, company) are captured and order type set to invoice
Date-based pollingOnly fetches orders newer than the most recent timestamp in local DB