۵.۱ چرا این بخش حیاتی است؟
این بخش دقیقاً مشخص میکند POS شما بعد از دریافت سفارش چه کارهایی باید انجام دهد و با چه ترتیب و زمانبندیای. بخش «پردازش سفارش» مستقیم روی تجربه مشتری، نرخ NFC و تماسهای مرکز تماس اثر میگذارد.
- Webhook و MQTT فقط کانال دریافت «داده سفارش» هستند.
- اعمال وضعیتها (Ack / Pick / Accept / Reject) از طریق Order API انجام میشود.
- هر مرحله «برگشتپذیر» نیست (مگر در سناریوی ویرایش سفارش).
۵.۲ مرور چرخه عمر سفارش (State Machine)
سفارش بعد از ثبت/ویرایش با وضعیتهای مشخص به فروشگاه ارسال میشود و تا زمانی که فروشگاه پاسخ ندهد ممکن است مجدداً ارسال شود. سپس با انجام اکشنهای فروشگاه، وضعیت سفارش در پلتفرم تغییر میکند:
56 / 714 (New / Re-send) → ACK (204) → 61
↓
PICK (204) → 713
↓
تصمیم نهایی: ACCEPT یا REJECT(Need Call)
۵.۳ SLA و پنجرههای زمانی (برای جلوگیری از Call Center)
بعد از دریافت سفارش، دو کار باید خیلی سریع انجام شود:
- Ack: به محض دریافت سفارش (برای اعلام «دریافت شد»)
- تصمیمگیری بعد از Ack: سفارش باید سریعاً به «تأیید» یا «نیاز به تماس» برسد
۵.۴ آدرس پایه Order API
تمام اندپوینتهای پردازش سفارش زیر این Base قرار دارند:
https://api-proxy.snapp.express/va/v1/order
۵.۵ ACK – تأیید دریافت سفارش
بلافاصله بعد از دریافت سفارش (Webhook یا MQTT)، POS باید Ack ارسال کند. Ack یعنی «سفارش به دست من رسید و در سیستم ثبت شد».
Endpoint
POST https://api-proxy.snapp.express/va/v1/order/{orderCode}/ack
Authorization: Bearer <access_token>
نمونه
curl --location --request POST \
'https://api-proxy.snapp.express/va/v1/order/8549yn4g/ack' \
--header 'Authorization: Bearer some_token_string'
204 No Content و بدنه خالی.
1023 یعنی orderCode پیدا نشد (معمولاً orderCode اشتباه یا سفارش منقضی/لغو شده).
الزام پیادهسازی در POS
- قبل از Ack: سفارش را در DB داخلی ثبت کنید (با کلید یکتا =
orderCode) - Ack باید Idempotent باشد: اگر دوباره آمد، دوباره Ack بزنید (یا موفق تلقی کنید)
- بعد از Ack: تایمر ۵ دقیقهای تصمیمگیری را فعال کنید (قبول / نیاز به تماس)
۵.۶ PICK – «باز کردن سفارش توسط اپراتور»
Pick به معنی این است که اپراتور فروشگاه سفارش را باز کرده و وارد فاز آمادهسازی شده است. این مرحله معمولاً بعد از Ack و قبل از تصمیم نهایی انجام میشود.
Endpoint
POST https://api-proxy.snapp.express/va/v1/order/{orderCode}/pick
Authorization: Bearer <access_token>
نمونه
curl --location --request POST \
'https://api-proxy.snapp.express/va/v1/order/8549yn4g/pick' \
--header 'Authorization: Bearer some_token_string'
204 No Content.
1023سفارش یافت نشد1068قبلاً Pick شده1059قبلاً تایید شده1060قبلاً Need Call / Reject شده
۵.۷ ACCEPT – تأیید سفارش
وقتی فروشگاه مطمئن است سفارش قابل انجام است، باید Accept ارسال کند. این مرحله سفارش را «تأیید» میکند.
Endpoint
POST https://api-proxy.snapp.express/va/v1/order/{orderCode}/accept
Authorization: Bearer <access_token>
Content-Type: application/json
Body (طبق داک)
{
"packingPrice": 0,
"delta": 0,
"deliveryTime": 0,
"riderPickupTime": 0
}
packingPriceهمیشه ۰ است.deltaمیزان اختلاف قیمت (به تومان) بین POS و سفارش است.deliveryTimeفقط در حالت Own Delivery، «زمان تحویل به مشتری» است؛ در غیر این صورت ۰.riderPickupTimeزمان جمعآوری و بستهبندی در فروشگاه است (مبنای زمان رسیدن پیک).
2110زمان دلیوری غیرمجاز503خطای دسترسی (موقت)1059قبلاً تایید شده1060قبلاً Need Call شده
الزامهای پیادهسازی (برای کاهش NFC/Call)
- اگر کالاها OK هستند، Accept را داخل پنجره ۵ دقیقهای بعد از Ack ارسال کنید.
- اگر «ابهام» دارید (کالا نیست/جایگزین دارد/نیاز به هماهنگی)، بجای معطل کردن، Need Call کنید (Reject با reasonId).
- Accept هم باید Idempotent باشد: اگر دوباره ارسال شد و خطای «قبلاً تایید شده» آمد، موفق تلقی کنید.
۵.۸ Need Call (Reject) – ارسال به مرکز تماس با دلیل + توضیح + جایگزین
در این داک، Reject یعنی بردن سفارش به وضعیت «نیاز به تماس». هدف این است که با ارسال اطلاعات دقیق در همان درخواست، تعداد تماسهای مرکز تماس با فروشگاه کم شود و تصمیم نهایی سریعتر گرفته شود.
قدم ۱: دریافت لیست دلیلها (Decline Reasons)
GET https://api-proxy.snapp.express/va/v1/order/decline-reason/
Authorization: Bearer <access_token>
قدم ۲: ارسال Need Call (Reject)
POST https://api-proxy.snapp.express/va/v1/order/{orderCode}/reject
Authorization: Bearer <access_token>
Content-Type: application/json
Body استاندارد (پیشنهادی و Vendor-friendly)
{
"reasonId": 177,
"comment": "شیر این برند موجود نیست. امکان ارسال برند X یا Y هست.",
"nonExistentProducts": [
{
"barcode": "34144555",
"suggestedProductBarcodes": ["53535222", "4568745451"]
}
]
}
1059 دریافت کنید.
- حتماً
commentرا دقیق و عملیاتی بنویسید. - اگر فقط چند قلم مشکل دارند، برای همانها
nonExistentProductsو جایگزین پیشنهاد دهید. - اگر مشکل «قیمت/دلتا» است، مقدار
deltaرا در Accept درست کنید یا Need Call را با توضیح شفاف بفرستید.
۵.۹ جدول وضعیتها (StatusCode) برای پیادهسازی درست در POS
در دیتای دریافتی (Webhook/MQTT) فیلد statusCode میآید.
پیشنهاد میشود POS بر اساس آن رفتار کند:
| statusCode | معنی | اقدام پیشنهادی POS |
|---|---|---|
| 56 | سفارش ثبت یا ویرایش شده | ثبت/آپدیت در DB → Ack |
| 714 | ارسال مجدد سفارش | Idempotent upsert → اگر Ack نشده: Ack |
| 61 | Ack شده | ورود به فاز عملیاتی → Pick/Decision |
| 713 | Pick شده | اپراتور در جریان است → Decision سریع |
| 42 | تایید شده / ویرایش تایید شده | ثبت در DB و ادامه عملیات |
| 51 | Need Call / رد شده و در صف مرکز تماس | ثبت، جلوگیری از عملیات تکراری |
| 54 | لغو شده | بستن سفارش در POS |
| 71 | نیازمند پرداخت اضافه | نمایش به اپراتور (بدون تغییر خودسرانه) |
۵.۱۰ سناریوهای اجرایی (برای جلوگیری از NFC / False-Flow)
سناریو A: سفارش جدید (Happy Path)
- Webhook رسید (56/714) → سفارش را Idempotent در DB ذخیره کن
- فوراً Ack بزن
- اپراتور سفارش را باز کرد → Pick
- همه اقلام OK → Accept (داخل پنجره ۵ دقیقه بعد از Ack)
سناریو B: چند قلم موجود نیست ولی جایگزین دارید
- Ack سریع
- Pick
- Reject(Need Call) با
reasonId+commentدقیق +suggestedProductBarcodes - همزمان در POS، موجودی SKUهای مشکلدار را اصلاح کنید و در فلو سینک بهروز کنید (برای کاهش تکرار NFC)
سناریو C: سفارش تکراری/ارسال مجدد (714)
- اگر سفارش قبلاً در DB هست، دوباره ایجاد نکنید؛ فقط Upsert کنید
- اگر Ack زده شده، Ack مجدد هم قابل قبول است (Idempotent)
۵.۱۱ Error Handling و Retry (اصولی و امن)
- برای خطاهای شبکه/Timeout/5xx: Retry با backoff (۱s، ۲s، ۴s، ۸s) و حداکثر ۳–۵ بار
- برای خطاهای «منطقی» مثل
1023،1059،1060،1068: Retry نکنید؛ فقط Log + کنترل جریان - برای جلوگیری از عملیات تکراری، درخواستها را Idempotent طراحی کنید (کلید داخلی: orderCode + action)
(orderCode, statusCode_in, action, sent_at, http_status, error_code, latency_ms)
۵.۱۲ ادامه مسیر
در بخش بعدی، ساختار خطاها، پیامهای استاندارد و سیاست Retry را دقیقتر و با مثالهای بیشتر بررسی میکنیم.
رفتن به بخش ۶: ارور هندلینگ