Data Sync Integration Guide
Hướng dẫn tích hợp push dữ liệu từ OMS, WMS, Helpdesk, và Accounting vào hệ thống SOS để tính điểm Seller. Tất cả sync endpoints sử dụng upsert (INSERT...ON CONFLICT UPDATE), đảm bảo idempotent — gọi nhiều lần vẫn an toàn.
Integration Sequence
┌────────┐ ┌──────────┐ ┌──────────────┐ ┌────────────┐
│ OMS │ │ WMS │ │ Helpdesk │ │ Accounting │
│ │ │ │ │ (Frappe) │ │ │
└───┬────┘ └────┬─────┘ └──────┬───────┘ └─────┬──────┘
│ │ │ │
│ /sync/orders │ /sync/inventory │ /sync/tickets │ /sync/payments
│ /sync/forecasts │ │ /sync/revenue
│ /sync/campaign-actuals │ │
│ │ │ │
▼ ▼ ▼ ▼
┌───────────────────────────────────────────────────────────────────┐
│ Boxme SOS API (/api/sync/*) │
│ │
│ sos_order_operation_raw sos_inventory_health_raw │
│ seller_forecast_submission sos_ticket_sla_raw │
│ campaign_actual_result sos_payment_raw │
│ am_portfolio_period_score │
└─────────────────────────────────┬─────────────────────────────────┘
│
POST /api/sos/monthly/calculate
│
▼
Scoring Engine (P/O/T/F/I)
1. OMS → Orders (O-Score)
Endpoint: POST /api/sync/orders
Push dữ liệu thời gian push đơn hàng. Hệ thống nhận pre-aggregated data theo period.
{
"seller_code": "SEL001",
"period": "2026-02",
"total_orders": 150,
"orders_within_30min": 140,
"orders_late": 10,
"avg_push_time_minutes": 18.5
}
| Field | Required | Description |
|---|---|---|
seller_code | ✅ | Mã seller |
period | ✅ | Format: YYYY-MM |
total_orders | ✅ | Tổng số đơn trong kỳ |
orders_within_30min | ❌ | Số đơn push trong 30 phút |
orders_late | ❌ | Số đơn push trễ |
avg_push_time_minutes | ❌ | Thời gian push trung bình |
Upsert: ON CONFLICT(seller_id, period) DO UPDATE
Tần suất khuyến nghị: Daily hoặc cuối tháng trước ngày tính điểm.
2. OMS → Forecasts (P-Score)
Endpoint: POST /api/sync/forecasts
Push forecast submission cho campaign cụ thể.
{
"seller_code": "SEL001",
"campaign_code": "CAMP-2026-02",
"submitted_at": "2026-01-28T10:00:00Z",
"forecasted_order_volume": 5000,
"forecasted_sku_breakdown": { "SKU001": 2000, "SKU002": 3000 },
"notes": "Valentine sale forecast"
}
| Field | Required | Description |
|---|---|---|
seller_code | ✅ | Mã seller |
campaign_code | ✅ | Mã campaign (phải tồn tại) |
forecasted_order_volume | ✅ | Sản lượng dự báo |
submitted_at | ❌ | Thời điểm submit (default: now) |
Versioning: Hệ thống tự track submission_version. Submit lần 1 → is_first_submission = true.
3. WMS/OMS → Campaign Actuals (P-Score)
Endpoint: POST /api/sync/campaign-actuals
Push kết quả thực tế sau campaign để so sánh với forecast.
{
"seller_code": "SEL001",
"campaign_code": "CAMP-2026-02",
"actual_order_volume": 4800,
"actual_sku_breakdown": { "SKU001": 1900, "SKU002": 2900 }
}
Upsert: ON CONFLICT(seller_id, campaign_id) DO UPDATE
4. Helpdesk → Tickets (T-Score)
Endpoint: POST /api/sync/tickets
Push ticket SLA metrics từ Frappe Helpdesk.
{
"seller_code": "SEL001",
"period": "2026-02",
"total_tickets": 25,
"avg_response_time_hours": 3.5,
"breakdown": {
"under_4h": 18,
"4h_8h": 4,
"8h_16h": 2,
"over_16h": 1
}
}
| Field | Required | Description |
|---|---|---|
seller_code | ✅ | Mã seller |
period | ✅ | Format: YYYY-MM |
total_tickets | ❌ | Tổng số ticket |
avg_response_time_hours | ❌ | Thời gian phản hồi trung bình |
breakdown | ❌ | Phân bổ theo khung giờ |
Upsert: ON CONFLICT(seller_id, period) DO UPDATE
5. Accounting → Payments (F-Score)
Endpoint: POST /api/sync/payments
Push dữ liệu thanh toán. Hỗ trợ 2 format: pre-aggregated hoặc raw invoices.
Format A: Pre-aggregated
{
"seller_code": "SEL001",
"period": "2026-02",
"total_invoices": 10,
"invoices_on_time": 7,
"invoices_late_1_7": 2,
"invoices_late_7_15": 1,
"invoices_late_15_20": 0,
"invoices_late_over_20": 0,
"worst_days_late": 12,
"total_outstanding_amount": 15000000,
"currency": "VND"
}
Format B: Raw invoices
{
"seller_code": "SEL001",
"period": "2026-02",
"invoices": [
{ "invoice_id": "INV001", "days_late": 0, "amount": 5000000 },
{ "invoice_id": "INV002", "days_late": 5, "amount": 3000000 },
{ "invoice_id": "INV003", "days_late": 12, "amount": 7000000 }
],
"currency": "VND"
}
Hệ thống tự aggregate từ mảng invoices: tính worst_days_late, total_outstanding_amount, phân nhóm trễ.
6. WMS → Inventory (I-Score)
Endpoint: POST /api/sync/inventory
Push snapshot tồn kho.
{
"seller_code": "SEL001",
"snapshot_date": "2026-02-28",
"total_cbm": 150.5,
"total_sku_qty": 12000,
"aging_over_90d_cbm": 22.3,
"aging_over_90d_sku_qty": 1800,
"aging_over_180d_cbm": 5.1,
"aging_over_180d_pct": 3.4
}
Tính toán tự động:
aging_pct_by_cbm = aging_over_90d_cbm / total_cbm × 100aging_pct_by_qty = aging_over_90d_sku_qty / total_sku_qty × 100aging_pct_used = MAX(aging_pct_by_cbm, aging_pct_by_qty)— giá trị này dùng để tính I-Score
Upsert: ON CONFLICT(seller_id, period) DO UPDATE
7. Accounting → AM Revenue
Endpoint: POST /api/sync/revenue
Push dữ liệu doanh thu AM để tính AM KPI.
{
"am_id": 1,
"period": "2026-02",
"revenue_target": 500000000,
"revenue_actual": 450000000
}
Tính toán tự động: revenue_achievement_pct = actual / target × 100
Implementation Checklist
| Step | Hệ thống | Endpoint | Tần suất | Priority |
|---|---|---|---|---|
| 1 | OMS | /sync/orders | Daily | 🔴 High |
| 2 | OMS | /sync/forecasts | Per campaign | 🟡 Medium |
| 3 | WMS/OMS | /sync/campaign-actuals | Post-campaign | 🟡 Medium |
| 4 | Helpdesk | /sync/tickets | Daily | 🔴 High |
| 5 | Accounting | /sync/payments | Weekly | 🔴 High |
| 6 | WMS | /sync/inventory | Monthly | 🟡 Medium |
| 7 | Accounting | /sync/revenue | Monthly | 🟢 Low |
Error Handling
Tất cả sync endpoints trả về:
// Success
{ "success": true }
// Seller not found
{ "error": "Seller SEL001 not found" } // 404
// Missing required fields
{ "error": "seller_code and period required" } // 400
Recommendation: Triển khai retry logic (3 retries, exponential backoff) ở phía caller cho trường hợp network error hoặc 500.