تمدید خودکار اشتراک

← بازگشت به راهنما

تمدید خودکار اشتراک



| فیلد | مقدار |
|------|--------|
| **نسخه** | 1.9 |
| **آخرین بروزرسانی** | 2026-09-23 |
| **مخاطب** | ادمین |

عملکرد



دستور `billing:process-subscription-renewals` (کرون روزانه ۰۶:۰۰):

  • اشتراک‌های **اصلی** (`parent_subscription_id` خالی) با وضعیت **فعال** و `auto_renew=true` که موعد صدور فاکتور رسیده را پیدا می‌کند

  • - موعد = `next_billing_at` منهای **روزهای قبل از سررسید** روی دسته (`renewal_invoice_days_before`)
    - افزونه‌های فرزند جداگانه فاکتور نمی‌شوند (داخل فاکتور والد می‌آیند)
  • اگر فاکتور تمدید باز (پرداخت‌نشده) از قبل باشد، دوباره صادر نمی‌کند

  • **صورتحساب تمدید** صادر می‌کند — مبلغ از **کاتالوگ لحظه‌ای**:

  • - خط اصلی = قیمت محصول + گزینه‌های قابل تنظیم روی محصول
    - خطوط جدا برای هر افزونهٔ دوره‌ای فعال (با گزینه‌های خودش)
    - مجموع = محصول + گزینه + افزونه (همان منطق `RenewalPricingService::breakdownForOffering`)
    - پس از صدور، `unit_price` والد = محصول+گزینه؛ `unit_price` هر افزونه هم به‌روز می‌شود (نمایش پورتال دوباره‌حساب نمی‌کند)
  • اگر در **تنظیمات اصلی** تیک «پرداخت خودکار از کیف پول» روشن باشد و موجودی کافی باشد → پرداخت از کیف پول → کار `renew` در صف Provision برای اعمال دوره

  • اگر تیک خاموش باشد یا موجودی کم باشد → فقط فاکتور می‌ماند؛ بعد از پرداخت مشتری همان صف `renew` دوره را جلو می‌برد

  • اعلان صدور فاکتور تمدید


  • تمدید دستی (پورتال / ریسلر)



    همان جمع:

    | جزء | منبع |
    |-----|------|
    | محصول | `ProductCyclePricingService` (با تبدیل IRR برای USD) |
    | گزینه‌های محصول | `priceForSelections` (IRR) |
    | افزونه‌های فعال | `AddonOrderBuilder::buildRenewalAddonItems` — خطوط جدا در سفارش |

    بعد از پرداخت، `unit_price` والد فقط محصول+گزینهٔ والد ذخیره می‌شود؛ قیمت افزونه‌ها روی اشتراک فرزند می‌ماند.

    تنظیمات اصلی (tenant)



    **تنظیمات → تنظیمات اصلی → تمدید خودکار اشتراک**

    | فیلد | کلید | پیش‌فرض |
    |------|------|---------|
    | پرداخت خودکار فاکتور تمدید از کیف پول مشتری | `renewal_auto_pay_from_wallet` | خاموش |

    همگام‌سازی نرخ دلار با قیمت اشتراک‌های دلاری: تب **تنظیمات مالی** — [tax-settings.md](./tax-settings.md). با آپدیت نرخ، نسبت روی `unit_price` (که شامل گزینه‌های ذخیره‌شده است) اعمال می‌شود؛ افزونه‌ها اشتراک جدا دارند و جدا مقیاس می‌شوند.

    دسته محصول



    در **اطلاعات دسته → سیاست تغییر پلن و تمدید** (وقتی نحوه تمدید = خودکار):

    | فیلد | پیش‌فرض | اثر |
    |------|---------|-----|
    | صدور فاکتور تمدید خودکار — چند روز قبل از سررسید | ۰ | ۰ = همان روز `next_billing_at` |

    صف اعمال (`provisioning_queue` / action=`renew`)



    بعد از پرداخت فاکتور تمدید کرون:

  • اگر ماژول Provision محصول `supportsRemoteRenew()` داشته باشد → API تمدید مقصد

  • سپس `ends_at` / `next_billing_at` یک دوره جلو می‌رود و افزونه‌های فرزند همگام می‌شوند

  • شکست ریموت یا اعمال → در منوی **صف ساخت سرویس** (Retry)


  • پیش‌فرض ماژول‌ها: بدون API تمدید. نمونه با API: NetBill.

    UI ادمین



    سرویس از **سفارش‌ها → مشاهده** دیده می‌شود. تمدید خودکار روی مدل `subscriptions.auto_renew` است (دسته با `renewal_mode=automatic` روی اشتراک جدید `auto_renew=true` می‌گذارد).

    پنل مشتری / ریسلر (تمدید دستی)



  • جزئیات سرویس → **تمدید سرویس** / **ارتقا / کاهش**

  • تمدید دستی همان پلن یا تغییر میان‌دوره طبق قوانین دسته


  • Cron



    ```bash
    0 6 * * * cd /home/bsshostkhaneh/bss && /usr/local/bin/ea-php83 artisan billing:process-subscription-renewals
    * * * * * cd /home/bsshostkhaneh/bss && /usr/local/bin/ea-php83 artisan schedule:run
    ```

    (`schedule:run` صف `provisioning:process-queue` را هم هر دقیقه اجرا می‌کند.)

    تست



    ```bash
    php artisan billing:process-subscription-renewals
    php artisan provisioning:process-queue
    ```