منصة B2B للسلع الرقمية

تصميم آلة حالات الطلب 2026 — نمذجة دورة حياة الطلبات

تصميم إنتاجي لآلة حالات طلب B2B — 6 حالات أساسية، ثوابت الانتقال، سجل تدقيقي، وتطبيق TypeScript متوائم مع دورة حياة طلبات FoxReload.

تصميم آلة حالات الطلب 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. الثوابت

الثابت خاصية صحيحة دوماً بصرف النظر عن الحالة. بالنسبة للطلب:

  1. total_amount > 0
  2. paid_at IS NULLstate ∈ {active, cancelled, failed}
  3. completed_at IS NULLstate ≠ completed
  4. codes IS NULL OR codes = []state ≠ completed
  5. cancel_reason IS NOT NULLstate = 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}. استطلعها لتحريك انتقالات آلة حالاتك. احصل على الوصول.

الأسئلة الشائعة

كم حالة يجب أن تملك آلة حالات الطلب؟
على الأقل 5–6 للسلع الرقمية — active ثم paid ثم processing ثم completed، مع cancelled وfailed كحالتين نهائيتين ماصّتين. أما الحالات المرنة مثل partial_fulfillment فلا تُضاف إلا إذا فرضها منطق العمل — كل حالة إضافية تضيف نحو 5% من العلل.
هل يمكنني استخدام أعلام منطقية بدل آلة الحالات؟
لا. الأعلام مثل is_paid وis_processing وis_completed تخلق حالات مستحيلة (مثلاً is_completed=true بينما is_paid=false). آلة الحالات القائمة على enum تضمن أن كل طلب في حالة صالحة واحدة بالضبط. هذا يزيل أكثر من 30% من علل الحالة.
كيف أتراجع عن طلب عند الخطأ؟
آلة الحالات لا تتراجع. من processing، عند خطأ المورّد، انتقل إلى cancelled أو failed (نهائية). لا حواف عكسية — فهي تكسر المسار التدقيقي. إذا فشل طلب FoxReload، تحقّق من حقل cancelReason للسياق.
ماذا يُسجَّل في السجل التدقيقي لكل انتقال؟
event_id (UUIDv4)، order_id، from_state، to_state، الطابع الزمني، الفاعل (user_id أو 'system')، السبب، source_ip، البيانات الوصفية (مثلاً cancelReason عند الإلغاء). إلحاقي فقط — لا تحديثات على الصفوف الموجودة.
احصل على وصول واجهة FoxReload

مقالات ذات صلة