{{-- ── SCHEDULED JOBS ───────────────────────────────────────────────────── --}}
Scheduled jobs (Supervisor · queue worker required)
SyncEbayOrders · every 5 min
ProcessStalePrices · every 5 min
ScrapeAllmakesPsp · every 6 hours
SyncShopifyOrders · ⚠ NOT scheduled — reconciles fulfilled + cancelled on each manual run
{{-- ── LEGEND ────────────────────────────────────────────────────────────── --}}
Theme-aware — switches with Filament dark/light toggle
{{-- ── DIAGRAM 1: eBay Order Chain ──────────────────────────────────────── --}}
TRIGGER
eBay Order Received
SyncEbayOrders · every 5 min
{{-- ── DIAGRAM 2: Shopify Order Chain ──────────────────────────────────── --}}
TRIGGER
Shopify Order Received
Webhook orders/create · SyncShopifyOrders
{{-- ── DIAGRAM 3: Order Processed Chain ──────────────────────────────────── --}}
EVENT
Order Marked as Processed → Stock Deduction → Channel Sync → Fulfillment Dispatch
OrderObserver · shared across all order sources
{{-- ── DIAGRAM 4: Stock / Product Changes ──────────────────────────────── --}}
TRIGGER
Stock or Product Changed
ProductQuantityObserver · ProductObserver
{{-- ── DIAGRAM 5a: Pricing Engine — stale products ─────────────────────── --}}
SCHEDULED
Pricing Engine — Individual stale products
ProcessStalePrices · every 5 min
{{-- ── DIAGRAM 5b: Pricing Engine — fee profile / rule change ───────────── --}}
EVENT
Pricing Engine — Fee profile or rule changed / Force Update All SKUs
ChannelFeeProfileObserver · PricingRuleObserver · supersede-safe fan-in
{{-- ── DIAGRAM 6: AllmakesPSP ───────────────────────────────────────────── --}}
SCHEDULED
Allmakes PSP Connector
ScrapeAllmakesPsp · every 6 hours
{{-- ── SHOPIFY SECTION HEADER ──────────────────────────────────────────── --}}
Shopify listings & pricing — detailed routing
{{-- ── DIAGRAM S1: Listing status lifecycle ────────────────────────────── --}}
STATUS
Listing status lifecycle
channel_listings.status · drives tab counts in ManageListingsV2
{{-- ── DIAGRAM S2: Create new listings ─────────────────────────────────── --}}
CREATE
Create new Shopify listings — ShopifyBatchCreateJob
ManageListingsV2 · Not Listed tab → "Create Listings"
{{-- ── DIAGRAM S3: Batch sync phases ───────────────────────────────────── --}}
SYNC
Update existing listings — sync paths
Bulk: ShopifyBatchSyncJob · Single product: SyncProductToChannels (SEO, description, all listing attrs)
{{-- ── DIAGRAM S4: Price sync routing ──────────────────────────────────── --}}
PRICE
Price sync — automatic paths to Shopify
Manual tick + Sync = full sync (see SYNC diagram above)
{{-- ── SHOPIFY API FIELD TABLE ───────────────────────────────────────────── --}}
API
Shopify API field routing — which mutation handles what
| Field |
Mutation / Endpoint |
Mode |
Job / Phase |
Notes |
@foreach([
['Title', 'productUpdate', 'bulk-jsonl', 'BatchSyncJob · Phase 3', ''],
['Description', 'productUpdate', 'bulk-jsonl', 'BatchSyncJob · Phase 3', ''],
['Vendor / Type / Tags', 'productUpdate', 'bulk-jsonl', 'BatchSyncJob · Phase 3', ''],
['Published status', 'productUpdate', 'bulk-jsonl', 'BatchSyncJob · Phase 3', ''],
['URL handle', 'productUpdate', 'per-product', 'BatchSyncJob · Phase 3.6', 'redirectNewHandle:true — bulk JSONL silently ignores handle'],
['Images', 'REST /products/{id}', 'rest', 'BatchSyncJob · Phase 3.5', 'GraphQL bulk ops do not support src image uploads'],
['Price ⚠', 'productVariantsBulkUpdate', 'bulk-jsonl', 'BulkPriceUpdateJob', 'NOT productUpdate — silently ignored on new product model (2024+)'],
['Cost price', 'productVariantsBulkUpdate', 'bulk-jsonl', 'BulkPriceUpdateJob', 'via inventoryItem.cost'],
['Barcode / EAN', 'productVariantsBulkUpdate', 'per-product', 'BatchSyncJob · Phase 3.6b', ''],
['Weight', 'productVariantsBulkUpdate', 'per-product', 'BatchSyncJob · Phase 3.6b', 'via inventoryItem.measurement.weight'],
['Stock quantity', 'inventorySetQuantities', 'batched', 'BatchSyncJob · Phase 4', '250 items per GQL call · per warehouse → Shopify location mapping'],
['Stock quantity', 'REST inventory', 'rest', 'SyncProductToChannels', 'Observer on ProductQuantity change or order fulfilment'],
['SEO Title (title_tag)', 'REST /products/{id}/metafields.json', 'rest', 'SyncProductToChannels', 'namespace=global · GET then PUT/POST upsert · API 2024-01 removed shorthand from product body'],
['SEO Description (description_tag)', 'REST /products/{id}/metafields.json', 'rest', 'SyncProductToChannels', 'namespace=global · same upsert as title_tag · falls back to meta_description then stripped description'],
] as [$field, $mutation, $mode, $phase, $note])
| {{ $field }} |
{{ $mutation }}
|
@if($mode === 'bulk-jsonl')
Bulk JSONL
@elseif($mode === 'per-product')
Per-product
@elseif($mode === 'batched')
Batched GQL
@else
REST
@endif
|
{{ $phase }} |
{{ $note }} |
@endforeach
{{-- ── GAPS PANEL ────────────────────────────────────────────────────────── --}}
⚠ Known gaps & issues in automation chains
HIGH
SyncShopifyOrders is not scheduled.
Shopify orders only import if the webhook fires or the job is manually triggered. Fix: add SyncShopifyOrders::dispatch() to the scheduler in bootstrap/app.php every 5–10 min.
HIGH
eBay → Shopify: if the webhook fails, the Cydekick order table stays empty.
The eBay sync audit will show "1 imported" but no order appears until SyncShopifyOrders runs. Scheduling it (above) fixes this automatically.
MED
Products in warehouses with no LocationMapping never trigger channel sync on stock change.
ProductQuantityObserver exits silently if no mapping row exists for that warehouse. Check: Channels → Stock Location Mappings — every active picking location should have a row.
MED
Order lines with no active SkuMapping are not synced to any channel after fulfilment.
Stock is deducted internally but qty is never pushed to Shopify or eBay. Lines appear as [UNLINKED] in Channel Orders. Check: Channels → Sync Reference for unlinked products.
MED
Product name / description changes set needs_update but nothing auto-pushes to Shopify or eBay.
ProductObserver flags the listing but no job is dispatched. Listings go stale silently. Use Listings → Needs Update tab to manually push, or add a dispatch call to ProductObserver.
MED
eBay prices are never auto-pushed by the pricing engine.
RecalculateProductChannelPrice explicitly skips eBay channels when dispatching sync ("Only Shopify channels have SKU mappings to sync"). eBay listing prices are only updated when a listing is manually pushed or created.
INFO
SyncProductToChannels is the active per-product sync path — not deprecated for single-product operations.
Handles all single-product listing pushes: Update button (Product → Channel Listings), Push Now (Channels → Listings), Save & Sync (modal), observer-driven stock sync, and price recalculation. Pushes title, description, SEO title/description, vendor, tags, handle, price, barcode, weight, images, stock, and fitment metafields. ShopifyBatchSyncJob handles bulk/scheduled operations only and does not push SEO.
LIVE
Order fulfillment dispatch — Shopify + eBay (2026-08-26).
When an order transitions open → processed, OrderFulfillmentService::dispatch() automatically pushes tracking + carrier to the channel via FulfillableChannelDriver::fulfillOrder(). ShopifyClient and EbayClient both implement the interface. API errors are logged but do not block the order save — use the Resend Dispatch button on ViewOrder to retry. The dispatched_at column on orders records when dispatch succeeded.
{{-- ── MERMAID ───────────────────────────────────────────────────────────────── --}}