Skip to content

۰۶ — چرخه سفارش (Order Lifecycle)


۱. فلو اصلی (پیاده‌سازی شده)

┌─────────────────┐
│ Browse & reserve│  مشتری باکس سرپرایز را انتخاب می‌کند
└────────┬────────┘

┌─────────────────┐
│      Pay        │  درگاه آنلاین یا «پرداخت در محل»
└────────┬────────┘

┌─────────────────────────┐
│ awaiting_vendor          │  وندور باید تأیید کند قبل از اطلاع‌رسانی مشتری
│ SMS → وندور              │
└────────┬────────────────┘

┌─────────────────┐
│  confirmed      │  کد pickup فعال، SMS → مشتری
└────────┬────────┘

┌─────────────────┐
│ Pickup window   │  مشتری مراجعه می‌کند، کد نشان می‌دهد
└────────┬────────┘

┌─────────────────┐
│ picked_up       │  وندور کد را تأیید کرد — موفق
└─────────────────┘

۲. State machine — order_status (پیاده‌سازی واقعی)

                    ┌──────────┐
                    │ pending  │  سفارش ایجاد شد، منتظر پرداخت
                    └────┬─────┘
                         │ payment OK (gateway callback) OR pay_at_pickup

                    ┌─────────────────┐
                    │ awaiting_vendor  │  پرداخت دریافت شد
                    │ SMS → وندور     │  وندور باید تأیید کند
                    └────────┬────────┘
                             │ POST /api/vendor/orders/[id]/confirm

                    ┌──────────┐
                    │confirmed │  SMS → مشتری؛ کد pickup فعال
                    └────┬─────┘
                         │ vendor confirm-pickup

                    ┌──────────┐
                    │picked_up │  SUCCESS — terminal
                    └──────────┘

لغو (cancel):
  pending          → cancelled  (مشتری یا سیستم)
  awaiting_vendor  → cancelled  (مشتری یا وندور — **تنها قبل از تأیید وندور**)
  confirmed        → ❌ نمی‌توان لغو کرد

no_show (cron):
  confirmed → no_show  (بعد از pickup_end بدون تأیید)

تعاریف

Statusمعنی
pendingسفارش ثبت؛ منتظر پرداخت یا تایید pay-at-pickup
awaiting_vendorپرداخت OK. وندور SMS دریافت کرده. باید تأیید کند قبل از اطلاع‌رسانی مشتری
confirmedوندور تأیید کرد. مشتری SMS دریافت کرده. Pickup code فعال
picked_upوندور کد را verify کرد — terminal success
cancelledلغو شده — فقط وقتی هنوز awaiting_vendor یا pending است
no_showمشتری نیامد — cron بعد از pickup_end set می‌کند

۳. State machine — payment_status

Statusمعنی
pendingpay-at-pickup یا منتظر callback درگاه
paidپول دریافت/تایید شد
failedدرگاه fail
refundedبرگشت وجه

ترکیب‌های مجاز MVP

payment_methodflow
gatewaypending → (Zarinpal callback) paid → order awaiting_vendor
pay_at_pickuppayment pending + order awaiting_vendor → vendor confirms → confirmed → vendor marks paid at pickup

۴. State machine — SurpriseBox.status

Statusمعنی
draftوندور ساخته، publish نکرده
activeقابل رزرو
sold_outquantity_remaining = 0
expiredبعد از pickup_end
cancelledوندور/ادمین لغو کرد

۵. سیاست لغو (Cancel Policy)

مشتری می‌تواند لغو کند وقتی:

  • order_status = pending یا awaiting_vendor

مشتری نمی‌تواند لغو کند وقتی:

  • order_status = confirmed, picked_up, no_show, cancelled

وندور می‌تواند لغو کند:

  • POST /api/vendor/orders/[id]/cancel — در هر مرحله‌ای قبل از picked_up

UI: دکمه لغو فقط اگر polling نشان دهد status هنوز pending یا awaiting_vendor است نمایش داده می‌شود.


۶. Inventory rules

  1. Decrement فقط وقتی order → awaiting_vendor (بعد از پرداخت)
  2. Race condition: transaction/lock روی quantity_remaining
  3. اگر دو کاربر همزمان — یکی success، یکی «آخرین باکس رزرو شد»
  4. Cancel → increment (اگر قبل از picked_up)

۷. Pickup code

موردپیشنهاد MVP
Format۶ رقم numeric
Uniquenessper order
Displayفقط وقتی order_status = confirmed
Expiryمعتبر تا pickup_end
Abuserate-limit verify attempts

۸. Timeline events (برای SMS/log)

EventTriggerSMS
order.createdPOST /orders
payment.completedgateway callbackوندور: «سفارش جدید»
order.awaiting_vendorpayment OKوندور SMS
order.confirmedvendor confirmsمشتری: «آماده تحویل»
pickup.remindercron: 30 min before pickup_endمشتری
pickup.completedvendor confirm-pickup
order.no_showcron after pickup_end
order.cancelledcancel APIمشتری
payment.refundedadmin/refund jobمشتری

→ قالب SMS: 10-sms-notifications.md


۹. Vendor confirm flow (پیاده‌سازی شده)

  1. Gateway callback → awaiting_vendor → SMS به وندور
  2. وندور پنل را باز می‌کند (polling 5 ثانیه)
  3. وندور «تأیید سفارش» می‌زند → POST /api/vendor/orders/[id]/confirm
  4. API: order.status = confirmed، SMS به مشتری
  5. مشتری در صفحه order/[id] (polling 5 ثانیه) می‌بیند که کد تحویل ظاهر شده

۱۰. Vendor pickup flow

  1. مشتری کد ۶ رقمی را نشان می‌دهد
  2. وندور کد را در confirm-pickup وارد می‌کند
  3. API: POST /api/vendor/orders/confirm-pickup با { pickupCode }
  4. اگر pay_at_pickup → همزمان payment_status = paid
  5. order → picked_up

۱۱. No-show policy

قانونپیشنهاد MVP
Triggernow > pickup_end AND status = confirmed
Actionstatus → no_show (cron job)
Payment gatewayno refund
Payment pay_at_pickupno charge
Inventoryباکس «سوخت» — دیگر برنمی‌گردد

→ تصمیم نهایی: 11-open-decisions.md


۱۲. Mermaid

mermaid
stateDiagram-v2
    [*] --> pending: reserve
    pending --> awaiting_vendor: payment OK
    pending --> cancelled: timeout/fail
    awaiting_vendor --> confirmed: vendor confirms
    awaiting_vendor --> cancelled: cancel (before confirm)
    confirmed --> picked_up: vendor confirm-pickup
    confirmed --> no_show: past pickup_end
    picked_up --> [*]
    no_show --> [*]
    cancelled --> [*]