تصميم آلة حالات الطلب 2026 — نمذجة دورة حياة الطلبات في السلع الرقمية
آلة حالات الطلب هي قلب أي تنفيذ B2B. التصميم الصحيح يجعل النظام قابلاً للملاحظة والتنقيح والتدقيق. أما التصميم السيئ فيولّد حالات مستحيلة وحالات تسابق قد تطاردها لأشهر. هذه المقالة دليل مفصّل لتصميم آلة حالات (FSM) لطلبات السلع الرقمية، متوائمة مع دورة حياة طلبات FoxReload.
1. ست حالات أساسية
تُرجِع واجهة FoxReload حالات الطلب هذه — active، paid، processing، completed، cancelled، failed. وينبغي أن تعكسها آلة الحالات الداخلية لديك:
enum OrderState {
ACTIVE = 'active', // created, awaiting payment
PAID = 'paid', // payment confirmed, queued for fulfilment
PROCESSING = 'processing', // supplier API called, awaiting result
COMPLETED = 'completed', // success, codes in externalData
CANCELLED = 'cancelled', // cancelled — see cancelReason
FAILED = 'failed', // terminal — fulfilment failed
}
الانتقالات المسموح بها (الرسم البياني):
active → paid | cancelled | failed
paid → processing | cancelled | failed
processing → completed | cancelled | failed
completed → (terminal)
cancelled → (terminal)
failed → (terminal)
أي انتقال آخر (مثلاً completed ← processing) غير صالح ويجب أن يرمي استثناءً.
حقل cancelReason على الطلب الملغى يكون أحد — payment_failure، payment_expiration، user_request، أو null.
2. الثوابت
الثابت خاصية صحيحة دوماً بصرف النظر عن الحالة. بالنسبة للطلب:
total_amount > 0paid_at IS NULL⇔state ∈ {active, cancelled, failed}completed_at IS NULL⇔state ≠ completedcodes IS NULL OR codes = []⇔state ≠ completedcancel_reason IS NOT NULL⇒state = cancelled
تحقّق من الثوابت داخل معالج انتقال آلة الحالات وفي قاعدة البيانات عبر قيود CHECK:
ALTER TABLE orders ADD CONSTRAINT chk_completed_codes
CHECK (state != 'completed' OR codes IS NOT NULL);
ALTER TABLE orders ADD CONSTRAINT chk_cancel_reason
CHECK (cancel_reason IS NULL OR state = 'cancelled');
3. XState أم enum+switch؟
للمشاريع الصغيرة/المتوسطة، يكفي enum + switch:
async function transition(order: Order, event: OrderEvent): Promise<Order> {
const next = nextState(order.state, event.type);
if (!next) throw new Error(`invalid transition ${order.state} + ${event.type}`);
return db.tx(async (tx) => {
const updated = await tx.orders.update(order.id, {
state: next,
version: order.version + 1, // optimistic lock
}, { where: { version: order.version } });
await tx.audit.insert({
event_id: randomUUID(),
order_id: order.id,
from_state: order.state,
to_state: next,
actor: event.actor,
timestamp: new Date(),
});
return updated;
});
}
للتدفقات المعقدة (متعدد الموردين، التسليم الجزئي، احتجاز الاحتيال) يقدّم XState مخططاً بصرياً وحالات هرمية.
4. استطلاع واجهة FoxReload لتحديثات الحالة
FoxReload لا تُرسل webhooks. تتقدّم آلة حالاتك عبر استطلاع GET /api/orders/{order_id} ومزامنة الحالة المُرجَعة إلى حالتك المحلية:
async function syncOrderState(localOrder: Order, apiKey: string): Promise<Order> {
const res = await fetch(
`https://public-api.foxreload.com/api/orders/${localOrder.foxreloadOrderId}`,
{ headers: { 'X-API-Key': apiKey } },
);
const remote = await res.json();
if (remote.status !== localOrder.state) {
return transition(localOrder, { type: remote.status, actor: 'system' });
}
return localOrder;
}
شغّل هذا في حلقة استطلاع مع تراجع أسّي حتى يبلغ الطلب حالة نهائية.
5. مقارنة التطبيقات
| المنهج | أسطر الكود | قابل للتصوّر | آمن من حيث النوع | الأداء |
|---|---|---|---|---|
| أعلام منطقية | 50 | لا | لا | الأفضل |
| Enum + switch | 150 | لا | قوي | الأفضل |
| XState | 200+ | نعم (Inspector) | قوي | جيد |
| Temporal workflow | 500+ | نعم | قوي | جيد (لا تزامني) |
بالنسبة لمعظم تكاملات FoxReload، يكفي enum+switch. انتقالات الحالة بسيطة (للأمام تماماً، دون تفرّع يتجاوز الحالات النهائية)، ونمط الاستطلاع يتطابق بنظافة مع مهمة خلفية واحدة لكل طلب.
CTA
تكشف واجهة FoxReload حالة الطلب الحالية وأكواد externalData لكل عنصر عبر GET /api/orders/{id}. استطلعها لتحريك انتقالات آلة حالاتك. احصل على الوصول.
