BSS HostKhaneh

قیمت‌گذاری چنددوره‌ای محصول اصلی

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

قیمت‌گذاری چنددوره‌ای محصول اصلی



> version: 1.7 | last_updated: 2026-09-27 | audience: admin

هدف



یک محصول recurring می‌تواند هم‌زمان قیمت **ساعتی / ماهانه / سه‌ماهه / شش‌ماهه / سالانه** و در صورت نیاز **دوره‌های سفارشی بر اساس روز** (مثلاً ۲۵ روزه) داشته باشد؛ بدون ساخت چند SKU جدا.

دورهٔ **ساعتی** درگاه بانکی ندارد. قیمت همان ردیف، مبلغ هر ساعت است. خرید فقط وقتی انجام می‌شود که کیف پول حداقل یک ساعتِ همهٔ سرویس‌های ساعتی فعال (با مالیات) را بپوشاند. برای هر مشتری یک ردیف در `hourly_customer_coverages` ساخته می‌شود: نرخ سوختن ساعتی، تعداد ساعت قابل‌پوشش، مبلغ رزروشده و `next_check_at`. کران `billing:process-hourly` هر دقیقه فقط ردیف‌هایی را می‌خواند که زمان پوشش‌شان رسیده باشد. خرید، جمع‌آوری، شارژ و خرج کیف پول همان ردیف را دوباره حساب می‌کند. اگر موجودی به یک ساعت مشترک نرسد، سرویس‌های ساعتی با `hourly_wallet_hold` معلق می‌شوند و با شارژ کافی دوباره روشن می‌شوند. توقف توسط مشتری همان **درخواست جمع‌آوری** است. افزونه بدون قیمت ساعتی در این ساعت مبلغی ندارد.

تنظیم در ادمین



تب **قیمت** محصول اصلی با مدل **دوره‌ای**:

| فیلد | نقش |
|------|-----|
| دوره پیش‌فرض | فقط مقادیر استاندارد enum (`monthly` …) — نمایش کاتالوگ + fallback ستون |
| قیمت ماهانه / سه‌ماهه / … | ماتریس `cycle_pricing` — **قیمت صفر = دوره در فروشگاه نیست** |
| دوره‌های سفارشی (Repeater) | روز + برچسب + قیمت + نصب → کلید `custom_{days}` داخل همان JSON |
| فیلدهای تک‌قیمت قدیمی | برای مدل یک‌بار / پیش‌پرداخت |

پس از ذخیره، `price` و `setup_fee` از ردیف دورهٔ پیش‌فرض استاندارد (یا اولین دوره با قیمت > 0) همگام می‌شوند. ستون `billing_cycle` محصول **هرگز** مقدار `custom_*` نمی‌گیرد.

نمونه `cycle_pricing`



```json
{
"monthly": { "price": 1000000, "setup": 0 },
"yearly": { "price": 10000000, "setup": 0 },
"custom_25": { "days": 25, "label": "۲۵ روزه", "price": 850000, "setup": 0 }
}
```

خرید



  • پورتال و ریسلر: انتخاب دوره (استاندارد یا سفارشی) → مبلغ و `billing_cycle` روی آیتم سفارش و اشتراک (مثلاً `custom_25`)

  • **گزینه‌های قابل تنظیم** و افزونه‌ها از همان دورهٔ انتخاب‌شدهٔ محصول پیروی می‌کنند:

  • - دوره استاندارد → ردیف همان دوره روی choice / افزونه
    - دوره سفارشی → اگر روی choice قیمت `custom_*` تعریف شده همان؛ وگرنه ماهانه × (روز / ۳۰)
    - در فرم ادمین choice: Repeater «دوره‌های سفارشی» کنار ماتریس ماهانه/…
  • با تغییر رادیو دوره در checkout/ریسلر، برچسب و مبلغ گزینه‌ها در UI هم به‌روز می‌شود

  • تمدید و زمان‌بندی صورتحساب: `BillingPeriod::addInterval` / `daysFromKey` با همان کلید اشتراک

  • پروریشن افزونه میان‌دوره: `AddonProrationService::resolveCycleDays` از دورهٔ اشتراک والد


  • داده



  • ستون: `product_offerings.cycle_pricing` JSON

  • سرویس: `ProductCyclePricingService` + `BillingPeriod` + `ConfigurableOptionService::choicePricingForKey`

  • سازگاری: محصولات قبلی با migration از `price`/`billing_cycle` پر شده‌اند


  • مرتبط



  • [create-product.md](./create-product.md)

  • [product-addons.md](./product-addons.md)

  • [ADR-034](../DECISIONS.md) — پس‌پرداخت تقویمی **فقط جلالی** (میلادی نداریم)

  • فاز ۲: [jalali-postpaid-billing.md](./jalali-postpaid-billing.md) — هم‌ترازی تقویم/سالگرد جلالی