کارتابل فروش و مدیریت فضای رک دیتاسنتر
> version: 2.1 | last_updated: 2026-09-20 | audience: admin
هدف
این سند چهار مسیر کارتابل برای محصول **اجاره فضا دیتاسنتر** (دستهٔ زنده `fday-rk` / فضای رک؛ اسلاگ قدیمی `agarh-fda` اگر soft-delete شده باشد نادیده گرفته میشود) را پوشش میدهد:
مسیرهای موجود
| مسیر | Pipeline Slug | Seeder | کاربرد |
|------|---------------|--------|--------|
| فروش | `datacenter-space-sales` | `DatacenterSpaceSalesWorkflowCaseSeeder` | خرید اولیه فضای رک |
| ارتقا | `rack-space-upgrade` | `UpgradeRackSpaceWorkflowCaseSeeder` | افزایش فضای موجود |
| کاهش | `rack-space-downgrade` | `DowngradeRackSpaceWorkflowCaseSeeder` | کاهش فضای موجود |
| جمعآوری | `rack-space-collection` | `CollectionRackSpaceWorkflowCaseSeeder` | پایان سرویس و آزادسازی فضا |
۱. مسیر فروش (Sales)
مسیر خرید اولیه فضای رک:
| # | دپارتمان | اکشن |
|---|----------|------|
| 1 | **بررسی پرداخت** | `order.check_payment` |
| 2 | **ارسال به شاهکار** | `http.shahkar_put` (`service.type` از محصول؛ پیشفرض **26**) |
| 3 | **اختصاص فضا** | `inventory.dc_space_allocate` (یونیتهای رزروشده → Occupied) |
| 4 | **فعالسازی** | `subscription.activate` → `order.complete` (allocate مجدد اگر لازم؛ idempotent) |
شکست هر مرحله → **بررسی عدم انجام** → بازگشت یا **لغو و برگشت هزینه**.
۲. مسیر ارتقا (Upgrade)
مسیر افزایش فضای رک موجود:
| # | دپارتمان | اکشن |
|---|----------|------|
| 1 | **بررسی پرداخت** | `order.check_payment` (پرداخت مابهالتفاوت) |
| 2 | **بهروزرسانی شاهکار** | `http.shahkar_update` (بهروزرسانی اطلاعات سرویس) |
| 3 | **اختصاص فضای اضافی** | `inventory.dc_space_allocate` (رزرو یونیتهای اضافی → Occupied) |
| 4 | **فعالسازی** | `subscription.activate` → `order.complete` |
**نکات:**
۳. مسیر کاهش (Downgrade)
مسیر کاهش فضای رک موجود:
| # | دپارتمان | اکشن |
|---|----------|------|
| 1 | **استرداد نسبی** | `credit_note.prorated_refund_to_wallet` (استرداد نسبی به کیف پول) |
| 2 | **بهروزرسانی شاهکار** | `http.shahkar_update` (بهروزرسانی اطلاعات سرویس) |
| 3 | **آزادسازی فضا** | `inventory.dc_space_release` (آزادسازی یونیتهای اضافی → Free) |
| 4 | **فعالسازی** | `subscription.activate` → `order.complete` |
**نکات:**
۴. مسیر جمعآوری (Collection / Termination)
مسیر پایان سرویس و آزادسازی کامل فضا:
| # | دپارتمان | اکشن |
|---|----------|------|
| 1 | **بستن شاهکار** | `http.shahkar_close` (بستن سرویس در شاهکار) |
| 2 | **آزادسازی فضا** | `inventory.dc_space_release` (آزادسازی تمام یونیتها → Free) |
| 3 | **پایان اشتراک** | `subscription.terminate` → `order.complete` |
**نکات:**
بررسی عدم انجام (مشترک در همه مسیرها)
در صورت شکست هر مرحله، کار به **بررسی عدم انجام** میرود:
| وضعیت بررسی | معنی |
|-------------|------|
| منتظر بررسی | اپراتور تصمیم میگیرد |
| رفع شد — بازگشت به مرحله | `workflow.resume_failed_stage` → waiting همان مرحلهٔ شکستخورده (مثلاً `dcspace-assign-failed` → `dcspace-waiting-assign`) + اجرای دوبارهٔ on_enter |
| ارسال به لغو / برگشت | دپارتمان لغو (در مسیر فروش و ارتقا → برگشت هزینه؛ در کاهش → لغو درخواست) |
نگاشت از تاریخچهٔ کیس + `on_failure_status_id` + slug.
انبار دیتاسنتر — برداشت خودکار یونیت
| نوع فروش | انبار | برداشت |
|----------|--------|--------|
| **سرور اختصاصی** | `inventory_kind = datacenter_server` روی **محصول اصلی** | رزرو `DcDevice` آزاد → تخصیص |
| **اجاره فضا / کولوكیشن** | `inventory_kind = datacenter_space` روی **محصول اصلی** | رزرو یونیت متوالی → Occupied |
گزینه قابلتنظیم را به انبار DCIM وصل نکنید.
سرویس: `DatacenterSpaceOrderService`
| مرحله | رفتار |
|--------|--------|
| خرید (مشتری / ریسلر) | `assertStockForOffering` — تعداد از فیلد صریح U روی choice با نقش یونیت (یا تعداد ثابت محصول)؛ بدون فضای آزاد خرید متوقف میشود |
| ثبت سفارش | `reserveForOrder` → وضعیت یونیتها `reserved` + metadata سفارش/اشتراک |
یونیتهایی که تجهیز فیزیکی روی آنهاست (مثلاً سرور available در همان U) برای اجاره فضا رزرو نمیشوند؛ ذخیره تجهیز در DCIM یونیت را Occupied همگام میکند.
اگر روی رک **فاصله تخصیص** (`allocation_unit_gap`) تنظیم شده باشد (مثلاً ۱)، بین هر بلوک اشغالشده/رزروشده و تخصیص بعدی همان تعداد U خالی در نظر گرفته میشود و به مشتری بعدی داده نمیشود.
| بعد از submit | `linkSubscriptions` |
| کارتابل / فعالسازی | `allocateForSubscription` → `occupied` |
| لغو سفارش / قطع اشتراک | `releaseForOrder` / `releaseForSubscription` → دوباره `free` |
فیلترها از `provisioning_config`: `datacenter_site_ids` (چندتایی؛ تکی قدیمی `datacenter_site_id` هم خوانده میشود)، اختیاری `dc_rack_id`.
اگر بیش از یک سایت روی محصول باشد، در چکاوت مشتری و سفارش ریسلر فیلد **دیتاسنتر** نشان داده میشود؛ اگر فقط یکی باشد مخفی است و همان استفاده میشود.
اکشنهای workflow: `inventory.dc_space_reserve` · `inventory.dc_space_allocate` · `inventory.dc_space_release`
نصب تجهیز مشتری بعد از تخصیص فضا
چرخه:
جستجو در فرم تجهیز: نام/کد ملی/موبایل مشتری، شماره سرویس، برچسب فضا.
تنظیم محصول
۱) محصول اصلی
| فیلد | مقدار |
|------|--------|
| دسته | `اجاره فضا` (`agarh-fda`) |
| `shahkar_service_type` | `26` |
| اتصال به انبار دیتاسنتر | **فضای رک** |
| سایت / رک | چند سایت در `datacenter_site_ids`؛ اگر بیش از یکی باشد مشتری/ریسلر انتخاب میکند |
| **المانهای فروش دیتاسنتر** | روشن کنید چه چیزی میفروشید |
المانها (روی محصول اصلی، بعد از اتصال انبار) — فقط چیزهایی که به انبار مربوطاند:
| المان | معنی |
|--------|------|
| گزینه تعداد یونیت (U) | تعداد از گزینه با نقش «تعداد یونیت رک»؛ اگر خاموش → فیلد «تعداد یونیت ثابت» |
| IP ثابت (انبار BSS) | گزینه با انبار IP ثابت (جدا از DCIM) |
فایروال / RAM / IP اضافه Virtualizor و مشابه را در بخش عادی **گزینههای قابلتنظیم** با «نوع منبع VPS» بسازید؛ جزو المانهای انبار دیتاسنتر نیستند.
۲) گزینه قابلتنظیم (افزونه configurable)
روی گروه گزینه:
| فیلد | مقدار |
|------|--------|
| نقش المان دیتاسنتر | مثلاً **تعداد یونیت رک (U)** |
| اتصال به انبار | خالی بگذارید (برای U) |
| روی هر سطح | فیلد **تعداد یونیت (U)** — عنوان آزاد است |
اولویت تعداد U در خرید:
نصب و Seed
فروش اولیه
```bash
cd /home/bsshostkhaneh/bss
/opt/cpanel/ea-php83/root/usr/bin/php artisan db:seed \
--class='Modules\Order\Database\Seeders\DatacenterSpaceSalesWorkflowCaseSeeder' --force
```
ارتقا فضا
```bash
/opt/cpanel/ea-php83/root/usr/bin/php artisan db:seed \
--class='Modules\Order\Database\Seeders\UpgradeRackSpaceWorkflowCaseSeeder' --force
```
کاهش فضا
```bash
/opt/cpanel/ea-php83/root/usr/bin/php artisan db:seed \
--class='Modules\Order\Database\Seeders\DowngradeRackSpaceWorkflowCaseSeeder' --force
```
جمعآوری
```bash
/opt/cpanel/ea-php83/root/usr/bin/php artisan db:seed \
--class='Modules\Order\Database\Seeders\CollectionRackSpaceWorkflowCaseSeeder' --force
```
> **نکته (۲۰۲۶-۰۹-۲۰):** seeder جمعآوری قبلاً بهاشتباه `WorkflowPipelinePurpose::Termination` داشت (در enum وجود ندارد) و هیچ pipelineای ساخته نمیشد. الان `Collection` است و بعد از seed، کارتابل روی دستهٔ زنده (`fday-rk`) روشن میشود. همیشه با PHP ۸.۳ اجرا کنید (`/opt/cpanel/ea-php83/...`).
نصب همه
```bash
/opt/cpanel/ea-php83/root/usr/bin/php artisan db:seed \
--class='Modules\Order\Database\Seeders\DatacenterSpaceSalesWorkflowCaseSeeder' --force && \
/opt/cpanel/ea-php83/root/usr/bin/php artisan db:seed \
--class='Modules\Order\Database\Seeders\UpgradeRackSpaceWorkflowCaseSeeder' --force && \
/opt/cpanel/ea-php83/root/usr/bin/php artisan db:seed \
--class='Modules\Order\Database\Seeders\DowngradeRackSpaceWorkflowCaseSeeder' --force && \
/opt/cpanel/ea-php83/root/usr/bin/php artisan db:seed \
--class='Modules\Order\Database\Seeders\CollectionRackSpaceWorkflowCaseSeeder' --force
```