Files
orion/docs/guides/letzshop-order-integration.md
Samir Boulahtit 448f01f82b feat: add Letzshop bidirectional order integration
Add complete Letzshop marketplace integration with:
- GraphQL client for order import and fulfillment operations
- Encrypted credential storage per vendor (Fernet encryption)
- Admin and vendor API endpoints for credentials management
- Order import, confirmation, rejection, and tracking
- Fulfillment queue and sync logging
- Comprehensive documentation and test coverage

New files:
- app/services/letzshop/ - GraphQL client and services
- app/utils/encryption.py - Fernet encryption utility
- models/database/letzshop.py - Database models
- models/schema/letzshop.py - Pydantic schemas
- app/api/v1/admin/letzshop.py - Admin API endpoints
- app/api/v1/vendor/letzshop.py - Vendor API endpoints
- docs/guides/letzshop-order-integration.md - Documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 12:19:54 +01:00

17 KiB

Letzshop Order Integration Guide

Complete guide for bidirectional order management with Letzshop marketplace via GraphQL API.

Table of Contents


Overview

The Letzshop Order Integration provides bidirectional synchronization with Letzshop marketplace:

  • Order Import: Fetch unconfirmed orders from Letzshop via GraphQL
  • Order Confirmation: Confirm or reject inventory units
  • Tracking Updates: Set shipment tracking information
  • Audit Trail: Complete logging of all sync operations

Key Features

  • Encrypted Credentials: API keys stored with Fernet encryption
  • Per-Vendor Configuration: Each vendor manages their own Letzshop connection
  • Admin Oversight: Platform admins can manage any vendor's integration
  • Queue-Based Fulfillment: Retry logic for failed operations
  • Multi-Channel Support: Orders tracked with channel attribution

Architecture

System Components

                    ┌─────────────────────────────────────────┐
                    │           Frontend Interfaces            │
                    ├─────────────────────────────────────────┤
                    │  Vendor Portal          Admin Portal     │
                    │  /vendor/letzshop       /admin/letzshop  │
                    └─────────────────────────────────────────┘
                                        │
                    ┌─────────────────────────────────────────┐
                    │              API Layer                   │
                    ├─────────────────────────────────────────┤
                    │  /api/v1/vendor/letzshop/*               │
                    │  /api/v1/admin/letzshop/*                │
                    └─────────────────────────────────────────┘
                                        │
                    ┌─────────────────────────────────────────┐
                    │           Service Layer                  │
                    ├─────────────────────────────────────────┤
                    │  LetzshopClient        CredentialsService│
                    │  (GraphQL)             (Encryption)      │
                    └─────────────────────────────────────────┘
                                        │
                    ┌─────────────────────────────────────────┐
                    │           Data Layer                     │
                    ├─────────────────────────────────────────┤
                    │  VendorLetzshopCredentials               │
                    │  LetzshopOrder                           │
                    │  LetzshopFulfillmentQueue                │
                    │  LetzshopSyncLog                         │
                    └─────────────────────────────────────────┘
                                        │
                    ┌─────────────────────────────────────────┐
                    │         Letzshop GraphQL API             │
                    │         https://letzshop.lu/graphql      │
                    └─────────────────────────────────────────┘

Data Flow

  1. Credentials Setup: Vendor/Admin stores encrypted API key
  2. Order Import: System fetches unconfirmed shipments from Letzshop
  3. Order Processing: Orders stored locally with Letzshop IDs
  4. Fulfillment: Vendor confirms/rejects orders, sets tracking
  5. Sync Back: Operations sent to Letzshop via GraphQL mutations

Setup and Configuration

Prerequisites

  • Letzshop API key (obtained from Letzshop merchant portal)
  • Active vendor account on the platform

Step 1: Configure API Credentials

Via Vendor Portal

  1. Navigate to Settings > Letzshop Integration
  2. Enter your Letzshop API key
  3. Click Test Connection to verify
  4. Enable Auto-Sync if desired (optional)
  5. Click Save

Via Admin Portal

  1. Navigate to Marketplace > Letzshop
  2. Select the vendor from the list
  3. Click Configure Credentials
  4. Enter the API key
  5. Click Save & Test

Step 2: Test Connection

# Test connection via API
curl -X POST /api/v1/vendor/letzshop/test \
  -H "Authorization: Bearer $TOKEN"

Response:

{
  "success": true,
  "message": "Connection successful",
  "response_time_ms": 245.5
}

Configuration Options

Setting Default Description
api_endpoint https://letzshop.lu/graphql GraphQL endpoint URL
auto_sync_enabled false Enable automatic order sync
sync_interval_minutes 15 Auto-sync interval (5-1440 minutes)

Order Import

Manual Import

Import orders on-demand via the vendor portal or API:

# Trigger order import
curl -X POST /api/v1/vendor/letzshop/orders/import \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"operation": "order_import"}'

Response:

{
  "success": true,
  "message": "Import completed: 5 imported, 2 updated",
  "orders_imported": 5,
  "orders_updated": 2,
  "errors": []
}

What Gets Imported

The import fetches unconfirmed shipments from Letzshop containing:

  • Order ID and number
  • Customer email and name
  • Order total and currency
  • Inventory units (products to fulfill)
  • Shipping/billing addresses
  • Current order state

Order States

Letzshop State Description
unconfirmed Awaiting vendor confirmation
confirmed Vendor confirmed, ready to ship
shipped Tracking number set
delivered Delivery confirmed
returned Items returned

Sync Status

Local orders track their sync status:

Status Description
pending Imported, awaiting action
confirmed Confirmed with Letzshop
rejected Rejected with Letzshop
shipped Tracking set with Letzshop

Fulfillment Operations

Confirm Order

Confirm that you can fulfill the order:

# Confirm all inventory units in an order
curl -X POST /api/v1/vendor/letzshop/orders/{order_id}/confirm \
  -H "Authorization: Bearer $TOKEN"

# Or confirm specific units
curl -X POST /api/v1/vendor/letzshop/orders/{order_id}/confirm \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"inventory_unit_ids": ["unit_abc123", "unit_def456"]}'

Reject Order

Reject order if you cannot fulfill:

curl -X POST /api/v1/vendor/letzshop/orders/{order_id}/reject \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Out of stock"}'

Set Tracking

Add tracking information for shipment:

curl -X POST /api/v1/vendor/letzshop/orders/{order_id}/tracking \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tracking_number": "1Z999AA10123456784",
    "tracking_carrier": "ups"
  }'

Supported carriers: dhl, ups, fedex, post_lu, etc.


API Reference

Vendor Endpoints

Base path: /api/v1/vendor/letzshop

Method Endpoint Description
GET /status Get integration status
GET /credentials Get credentials (API key masked)
POST /credentials Create/update credentials
PATCH /credentials Partial update credentials
DELETE /credentials Remove credentials
POST /test Test stored credentials
POST /test-key Test API key without saving
GET /orders List Letzshop orders
GET /orders/{id} Get order details
POST /orders/import Import orders from Letzshop
POST /orders/{id}/confirm Confirm order
POST /orders/{id}/reject Reject order
POST /orders/{id}/tracking Set tracking info
GET /logs List sync logs
GET /queue List fulfillment queue

Admin Endpoints

Base path: /api/v1/admin/letzshop

Method Endpoint Description
GET /vendors List vendors with Letzshop status
GET /vendors/{id}/credentials Get vendor credentials
POST /vendors/{id}/credentials Set vendor credentials
PATCH /vendors/{id}/credentials Update vendor credentials
DELETE /vendors/{id}/credentials Delete vendor credentials
POST /vendors/{id}/test Test vendor connection
POST /test Test any API key
GET /vendors/{id}/orders List vendor's Letzshop orders
POST /vendors/{id}/sync Trigger sync for vendor

Response Schemas

Credentials Response

{
  "id": 1,
  "vendor_id": 5,
  "api_key_masked": "letz****",
  "api_endpoint": "https://letzshop.lu/graphql",
  "auto_sync_enabled": false,
  "sync_interval_minutes": 15,
  "last_sync_at": "2025-01-15T10:30:00Z",
  "last_sync_status": "success",
  "last_sync_error": null,
  "created_at": "2025-01-01T00:00:00Z",
  "updated_at": "2025-01-15T10:30:00Z"
}

Order Response

{
  "id": 123,
  "vendor_id": 5,
  "letzshop_order_id": "gid://letzshop/Order/12345",
  "letzshop_shipment_id": "gid://letzshop/Shipment/67890",
  "letzshop_order_number": "LS-2025-001234",
  "letzshop_state": "unconfirmed",
  "customer_email": "customer@example.com",
  "customer_name": "John Doe",
  "total_amount": "99.99",
  "currency": "EUR",
  "sync_status": "pending",
  "inventory_units": [
    {"id": "gid://letzshop/InventoryUnit/111", "state": "unconfirmed"}
  ],
  "created_at": "2025-01-15T10:00:00Z",
  "updated_at": "2025-01-15T10:00:00Z"
}

Database Models

VendorLetzshopCredentials

Stores encrypted API credentials per vendor.

class VendorLetzshopCredentials(Base):
    __tablename__ = "vendor_letzshop_credentials"

    id: int                      # Primary key
    vendor_id: int               # FK to vendors (unique)
    api_key_encrypted: str       # Fernet encrypted API key
    api_endpoint: str            # GraphQL endpoint URL
    auto_sync_enabled: bool      # Enable auto-sync
    sync_interval_minutes: int   # Sync interval
    last_sync_at: datetime       # Last sync timestamp
    last_sync_status: str        # success, failed, partial
    last_sync_error: str         # Error message if failed

LetzshopOrder

Tracks imported orders from Letzshop.

class LetzshopOrder(Base):
    __tablename__ = "letzshop_orders"

    id: int                      # Primary key
    vendor_id: int               # FK to vendors
    letzshop_order_id: str       # Letzshop order GID
    letzshop_shipment_id: str    # Letzshop shipment GID
    letzshop_order_number: str   # Human-readable order number
    local_order_id: int          # FK to orders (if imported locally)
    letzshop_state: str          # Current Letzshop state
    customer_email: str          # Customer email
    customer_name: str           # Customer name
    total_amount: str            # Order total
    currency: str                # Currency code
    raw_order_data: JSON         # Full order data from Letzshop
    inventory_units: JSON        # List of inventory units
    sync_status: str             # pending, confirmed, rejected, shipped
    tracking_number: str         # Tracking number (if set)
    tracking_carrier: str        # Carrier code

LetzshopFulfillmentQueue

Queue for outbound operations with retry logic.

class LetzshopFulfillmentQueue(Base):
    __tablename__ = "letzshop_fulfillment_queue"

    id: int                      # Primary key
    vendor_id: int               # FK to vendors
    letzshop_order_id: int       # FK to letzshop_orders
    operation: str               # confirm, reject, set_tracking
    payload: JSON                # Operation data
    status: str                  # pending, processing, completed, failed
    attempts: int                # Retry count
    max_attempts: int            # Max retries (default 3)
    error_message: str           # Last error if failed
    response_data: JSON          # Response from Letzshop

LetzshopSyncLog

Audit trail for all sync operations.

class LetzshopSyncLog(Base):
    __tablename__ = "letzshop_sync_logs"

    id: int                      # Primary key
    vendor_id: int               # FK to vendors
    operation_type: str          # order_import, confirm, etc.
    direction: str               # inbound, outbound
    status: str                  # success, failed, partial
    records_processed: int       # Total records
    records_succeeded: int       # Successful records
    records_failed: int          # Failed records
    error_details: JSON          # Detailed error info
    started_at: datetime         # Operation start time
    completed_at: datetime       # Operation end time
    duration_seconds: int        # Total duration
    triggered_by: str            # user_id, scheduler, webhook

Security

API Key Encryption

API keys are encrypted using Fernet symmetric encryption:

from app.utils.encryption import encrypt_value, decrypt_value

# Encrypt before storing
encrypted_key = encrypt_value(api_key)

# Decrypt when needed
api_key = decrypt_value(encrypted_key)

The encryption key is derived from the application's jwt_secret_key using PBKDF2.

Access Control

  • Vendors: Can only manage their own Letzshop integration
  • Admins: Can manage any vendor's integration
  • API Keys: Never returned in plain text (always masked)

Troubleshooting

Connection Failed

Symptoms: "Connection failed" error when testing

Possible Causes:

  • Invalid API key
  • API key expired
  • Network issues
  • Letzshop service unavailable

Solutions:

  1. Verify API key in Letzshop merchant portal
  2. Regenerate API key if expired
  3. Check network connectivity
  4. Check Letzshop status page

Orders Not Importing

Symptoms: Import runs but no orders appear

Possible Causes:

  • No unconfirmed orders in Letzshop
  • API key doesn't have required permissions
  • Orders already imported

Solutions:

  1. Check Letzshop dashboard for unconfirmed orders
  2. Verify API key has order read permissions
  3. Check existing orders with sync_status: pending

Fulfillment Failed

Symptoms: Confirm/reject/tracking operations fail

Possible Causes:

  • Order already processed
  • Invalid inventory unit IDs
  • API permission issues

Solutions:

  1. Check order state in Letzshop
  2. Verify inventory unit IDs are correct
  3. Check fulfillment queue for retry status
  4. Review error message in response

Sync Logs

Check sync logs for detailed operation history:

curl -X GET /api/v1/vendor/letzshop/logs \
  -H "Authorization: Bearer $TOKEN"

Best Practices

For Vendors

  1. Test connection after setting up credentials
  2. Import orders regularly (or enable auto-sync)
  3. Confirm orders promptly to avoid delays
  4. Set tracking as soon as shipment is dispatched
  5. Monitor sync logs for any failures

For Admins

  1. Review vendor status regularly via admin dashboard
  2. Assist vendors with connection issues
  3. Monitor sync logs for platform-wide issues
  4. Set up alerts for failed syncs (optional)


Version History

  • v1.0 (2025-12-13): Initial Letzshop order integration
    • GraphQL client for order import
    • Encrypted credential storage
    • Fulfillment operations (confirm, reject, tracking)
    • Admin and vendor API endpoints
    • Sync logging and queue management