FutureForgeFutureForge

خدمات FutureForge

  • طراحی و ساخت محصولاز شناخت نیاز تا انتشار محصول، یک مسیر روشن پیش رو دارید.
  • توسعه فول‌استکوب‌اپلیکیشن، API و داده را هماهنگ و یکپارچه توسعه دهید.
  • ممیزی مهندسیپیش از هزینه‌ی بیشتر، از وضعیت واقعی محصول‌تان باخبر شوید.
  • مشاوره معماریپیش از یک تصمیم فنی پرهزینه، گزینه‌ها را درست بسنجید.
  • زیرساخت و استقرارمحصول را با خیال راحت منتشر کنید و پایدار نگه دارید.
  • هوش مصنوعی در محصولهوش مصنوعی را فقط جایی به کار می‌گیریم که مسئله‌ای را حل کند.
نمونه‌کارهایادداشت‌هاقیمت‌گذاریدرباره ما
شروع گفتگو
  1. خانه
  2. /یادداشت‌ها
  3. /یادداشت‌ها
FutureForge

استودیوی مهندسی محصول — طراحی، ساخت و استقرار نرم‌افزار.

خدمات

طراحی سایت با وردپرستوسعه اختصاصیمهندسی محصولزیرساخت و استقرارمشاوره معماریهوش مصنوعی در محصول

راهنمای انتخاب

یادداشت‌هاقیمت‌گذاریتخمین هزینه پروژهمقایسه روش‌هانمونه‌کارهادرباره ماتماس

ارتباط

hello@futureforge.ir

ایده‌ای برای ساخت دارید؟

نیازتان را مطرح کنید تا درباره مسیر توسعه و قدم بعدی صحبت کنیم.

شروع گفتگو

© 2026 FutureForge. همه حقوق محفوظ است.

حریم خصوصیشرایط استفاده
خانهنمونه‌کارشروعتماس
معماری نرم‌افزار

مدیریت سفارش فروشگاه اینترنتی: ماشین حالت پرداخت، لغو و بازپرداخت

سا
سهیل ابراهیم‌پور
·۲ آبان ۱۴۰۵·7 دقیقه مطالعه
مدیریت سفارشstate machineبازپرداختwebhookidempotency
معمار نرم‌افزار کنار نمودار وضعیت‌های سفارش و پرداخت

سفارش را با دو ماشین حالت، جدول گذار صریح، رفتار امن در برابر تکرار webhook و آشتی با درگاه طراحی کنید؛ الگوها از مستند Stripe.

سفارش یک فروشگاه اینترنتی «یک رکورد با فیلد وضعیت» به نظر می‌رسد، تا روزی که مشتری پرداخت می‌کند اما درگاه دیر جواب می‌دهد، یا سفارش را لغو می‌کند در حالی که بسته در انبار آماده شده است. در آن لحظه است که پراکندگی وضعیت‌ها (paid، PAID، done، ok) و شرط‌های تودرتو گران تمام می‌شود. این مقاله یک الگوی مشخص برای چرخهٔ سفارش را پیشنهاد می‌دهد: ماشین حالت صریح، جداسازی وضعیت سفارش از وضعیت پرداخت، و رفتار امن در برابر تکرار و تأخیر.

مرز مقاله روشن است. الگوهای وضعیت پرداخت، لغو، بازپرداخت و webhook را از مستندات رسمی Stripe می‌گیریم، چون مستند عمومی و کامل دارد؛ این به معنای پیشنهاد Stripe برای ایران نیست و درگاه‌های ایرانی ممکن است نام‌ها و رفتار دیگری داشته باشند. الزامات مالی، مالیاتی و حقوقی (مثل صدور صورت‌حساب، قوانین حق انصراف یا مهلت بازپرداخت) در این مقاله بررسی نشده‌اند و باید از منبع رسمی روز و مشاور حقوقی گرفته شوند. هر جا از «توصیهٔ نویسنده» می‌گوییم، منبع مستقلی ندارد و تجربهٔ مهندسی عمومی است.

دو ماشین حالت، نه یکی

خطای رایج این است که همهٔ چیز در یک فیلد status جمع شود: «در انتظار پرداخت»، «پرداخت‌شده»، «در حال بسته‌بندی»، «ارسال‌شده»، «مرجوعی». این فیلد دو چیز متفاوت را قاطی می‌کند: پول و فیزیک سفارش. توصیهٔ نویسنده این است که حداقل دو وضعیت جدا نگه دارید:

  • وضعیت پرداخت که از درگاه می‌آید و ماشین حالت خودش را دارد.
  • وضعیت تحویل سفارش که به انبار و ارسال مربوط است.

Stripe خودش پرداخت را با یک شیء جدا (PaymentIntent) و ماشین حالت جدا مدل می‌کند. این الگو برای هر درگاهی قابل‌تقلید است، حتی اگر فقط «شروع»، «موفق» و «ناموفق» داشته باشد.

وضعیت‌های پرداخت: درس از مستند Stripe

مستند Stripe شش وضعیت اصلی برای PaymentIntent تعریف می‌کند: requires_payment_method، requires_confirmation، requires_action (مثلاً احراز هویت 3D Secure)، processing، succeeded و canceled. چند نکته در آن برای هر طراح سفارشی مفید است:

  • در succeeded جریان پرداخت کامل است و می‌توان سفارش را با اطمینان انجام داد.
  • اگر تلاش پرداخت (مثلاً به‌دلیل رد کارت) شکست بخورد، وضعیت به requires_payment_method برمی‌گردد تا مشتری دوباره تلاش کند. یعنی «شکست تلاش» لزوماً «شکست سفارش» نیست.
  • روش‌های ناهمگام می‌توانند تا چند روز طول بکشند و در این مدت پرداخت قابل تضمین نیست (processing).

برای فروشگاه شما، معادل ساده‌اش می‌تواند این باشد: pending_payment (سفارش ثبت شده، پول نیامده)، payment_processing (درگاه هنوز تعیین تکلیف نکرده)، paid، payment_failed (قابل تلاش مجدد) و payment_canceled. اینکه درگاه ایرانی شما کدام وضعیت‌ها را برمی‌گرداند باید از مستند همان درگاه بخوانید؛ ما آن را بررسی نکرده‌ایم.

وضعیت سفارش و جدول گذارهای مجاز

برای وضعیت سفارش، یک جدول گذار صریح بنویسید و هر گذار غیرمجاز را در کد رد کنید. نمونه‌ای از پیشنهاد نویسنده (نه استاندارد):

ازبهرویدادنکته
createdawaiting_paymentمشتری به پرداخت رفتموجودی رزرو می‌شود
awaiting_paymentconfirmedپرداخت موفق (تأیید سمت سرور)فقط از وضعیت پرداخت paid
awaiting_paymentcanceledانصراف یا انقضارزرو آزاد می‌شود
confirmedpackedانبار بسته‌بندی کرداز این‌جا لغو ساده نیست
packedshippedتحویل به حمل‌ونقلکد رهگیری ثبت می‌شود
shippeddeliveredتحویل مشتری
confirmed / packedcanceled_after_paymentلغوبازپرداخت لازم می‌شود
deliveredreturn_requestedدرخواست مرجوعیقواعد تجاری شما + الزامات حقوقی روز

کلید این جدول «فقط از وضعیت درست» است: سفارش فقط وقتی confirmed می‌شود که وضعیت پرداخت از سمت سرور paid شده باشد، نه فقط به‌خاطر بازگشت مرورگر مشتری از درگاه.

نمودار وضعیت‌های سفارش و بازپرداخت
نمودار مفهومی.

لغو و بازپرداخت

در مستند Stripe، لغو PaymentIntent پیش از رسیدن به processing یا succeeded ممکن است؛ لغو آن را برای تلاش‌های بعدی نامعتبر می‌کند، وجوه نگه‌داشته‌شده را آزاد می‌کند و قابل‌برگشت نیست. پس از موفقیت پرداخت، راه برگرداندن پول API بازپرداخت است. از این دو الگو برای طراحی خودتان می‌توان یاد گرفت:

  1. لغو پیش از پرداخت با بازپرداخت پس از پرداخت دو عمل متفاوت‌اند و هرکدام گذار و رویداد جدا دارند.
  2. لغو را غیرقابل‌برگشت بگیرید. اگر مشتری دوباره خرید کرد، سفارش یا تلاش پرداخت جدید بسازید.
  3. بازپرداخت را یک رکورد جدا (با مبلغ، دلیل، وضعیت خودش) ثبت کنید، نه فقط عوض‌کردن وضعیت سفارش. بازپرداخت جزئی هم ممکن است پیش بیاید.

اینکه بازپرداخت در درگاه شما چگونه و در چه مهلتی انجام می‌شود، باید از قرارداد و مستند همان درگاه گرفته شود. در این مقاله بررسی نشده است.

وقتی درگاه خبر می‌دهد: تکرار، ترتیب و سرعت

درگاه‌هایی که رویداد (webhook یا callback) می‌فرستند، همان مشکلات را دارند. مستند Stripe چند قاعدهٔ دقیق می‌گوید که مستقل از درگاه مفیدند:

  • تکرار: ممکن است یک رویداد چند بار تحویل شود. شناسهٔ رویدادهای پردازش‌شده را ثبت کنید و دوباره پردازش نکنید.
  • ترتیب: ترتیب تحویل تضمین‌شده نیست و فیلد زمان ثانیه‌ای برای تعیین ترتیب مناسب نیست. اگر رویداد «فاکتور پرداخت شد» پیش از «فاکتور ساخته شد» رسید، شیء را از API بخوانید.
  • امضا: امضا را با بدنهٔ خام درخواست و secret تأیید کنید؛ بدون این کار هر کس می‌تواند رویداد جعلی بفرستد و مثلاً سفارش را «پرداخت‌شده» کند.
  • سرعت: پیش از هر منطق سنگین سریع پاسخ 2xx بدهید و پردازش را به صف ناهمگام بسپارید.

اگر درگاه شما امضا ندارد (بعضی روش‌ها فقط پارامتر بازگشت مرورگر می‌دهند)، قاعدهٔ طلایی این است که هرگز فقط به آن پارامتر اعتماد نکنید و وضعیت را با یک فراخوانی سمت سرور به درگاه تأیید (verify) کنید. این توصیهٔ نویسنده است؛ مستند درگاه شما باید روش دقیق را بگوید.

idempotency در ثبت سفارش و پرداخت

Stripe توضیح می‌دهد که کلید idempotency اجازه می‌دهد درخواست پس از خطای اتصال بی‌خطر تکرار شود. سرور پاسخ اولین درخواست با آن کلید را نگه می‌دارد و اگر پارامترها فرق کنند خطا می‌دهد. در فروشگاه خودتان:

  • هنگام کلیک «پرداخت»، یک شناسهٔ یکتا برای تلاش بسازید تا دو کلیک سریع دو پرداخت نسازد.
  • در confirmed‌کردن سفارش، با شرط «فقط اگر الان awaiting_payment است» عمل کنید تا دو callback هم‌زمان دوباره موجودی را کم نکنند.
  • در تماس با انبار و حمل‌ونقل هم هر درخواست شناسهٔ یکتا داشته باشد.

برای همگام‌سازی موجودی با انبار می‌توانید جزئیات بیشتر را در مقالهٔ اتصال موجودی بخوانید؛ در این مقاله فقط به ماشین حالت پرداخته‌ایم.

آشتی با دفتر پرداخت

حتی با webhook و idempotency، ممکن است رویدادی گم شود. توصیهٔ نویسنده: یک کار دوره‌ای بنویسید که سفارش‌های awaiting_payment و payment_processing قدیمی‌تر از یک آستانه (که خودتان تعیین می‌کنید) را از درگاه استعلام کند و تعارض‌ها را گزارش دهد. هر سفارشی که درگاه «موفق» می‌گوید و شما «در انتظار» دارید، باید به‌صورت خودکار یا دستی تعیین تکلیف شود. این کار با پایش و هشدار کامل می‌شود؛ برای مبانی پایش Monitoring چیست؟ را ببینید.

موارد مرزی که باید تست شوند

  • مشتری بعد از پرداخت موفق مرورگر را می‌بندد (سفارش باید بر اساس webhook یا استعلام تأیید شود).
  • دو callback هم‌زمان برای یک سفارش.
  • پرداخت موفق بعد از انقضای رزرو (موجودی ممکن است دیگر نباشد؛ تصمیم تجاری لازم است: بازپرداخت یا تأمین).
  • لغو سفارش هم‌زمان با بسته‌بندی در انبار.
  • بازپرداخت جزئی و بازپرداخت مجدد.
  • رویداد با ترتیب معکوس رسیده است.

چک‌لیست پیاده‌سازی

  1. وضعیت پرداخت و وضعیت تحویل جدا ثبت می‌شوند.
  2. جدول گذارهای مجاز در کد اعمال می‌شود و گذار غیرمجاز خطا می‌دهد.
  3. سفارش فقط با تأیید سمت سرور پرداخت تأیید می‌شود.
  4. شناسهٔ رویدادهای پردازش‌شده ثبت می‌شود و پردازش تکراری بی‌اثر است.
  5. امضا یا استعلام سمت سرور برای هر callback وجود دارد.
  6. لغو و بازپرداخت رکورد و رویداد جدا دارند.
  7. کار آشتی دوره‌ای و هشدار وجود دارد.
  8. مرزهای حقوقی/مالی (مرجوعی، فاکتور) از منبع رسمی روز بررسی شده‌اند، نه از این مقاله.

برای تصمیم‌های معماری بزرگ‌تر، مقالهٔ انتخاب معماری اپلیکیشن وب را ببینید.

منابع و مراجع

  • How Payment Intents and Setup Intents work — Stripe.
  • Receive Stripe events in your webhook endpoint — Stripe.
  • Idempotent requests (Stripe API) — Stripe.

نویسنده

سا

سهیل ابراهیم‌پور بنیان‌گذار FutureForge است. روی طراحی محصول، معماری و استقرار نرم‌افزار سفارشی کار می‌کند.

یادداشت‌های مرتبط

یادداشت‌های مرتبط

دسته‌بندی‌ها

خدمات مرتبط

از یادداشت تا پروژه

اگر با مسئله‌ای شبیه این روبه‌رو هستید، درباره‌ی شرایط پروژه‌تان با هم صحبت کنیم.

برای انتخاب مسیر فنی پروژه‌تان کمک می‌خواهید؟

از مسئله و محدودیت‌هایتان بگویید؛ اگر بتوانیم همراهی‌تان کنیم، برای گفت‌وگو هماهنگ می‌کنیم.

سهیل ابراهیم‌پور
یادداشت‌ها
هزینه استفاده از API هوش مصنوعی
دیتاست ارزیابی LLM
Monolith در برابر Microservices: کدام را انتخاب کنیم؟
چگونه Database مناسب را انتخاب کنیم؟
انتخاب زبان: Node.js، Python، PHP یا Go؟

معماری نرم‌افزار

هزینه استفاده از API هوش مصنوعی

۲۷ مهر ۱۴۰۵

معماری نرم‌افزار

دیتاست ارزیابی LLM

۲۷ مهر ۱۴۰۵

معماری نرم‌افزار

Monolith در برابر Microservices: کدام را انتخاب کنیم؟

۲۹ شهریور ۱۴۰۵

معماری نرم‌افزار

چگونه Database مناسب را انتخاب کنیم؟

۲۹ شهریور ۱۴۰۵

معماری نرم‌افزار

انتخاب زبان: Node.js، Python، PHP یا Go؟

۲۹ شهریور ۱۴۰۵
همه یادداشت‌ها256
معماری نرم‌افزار16
واژه‌نامه37
عملیات و استقرار87
مهندسی محصول103
راهنمای وب13
طراحی و ساخت محصول
توسعه فول‌استک
ممیزی مهندسی
مشاوره معماری
زیرساخت و استقرار
شروع گفتگو
ابزارهای رایگان
شروع گفتگو