کارتابل فروش و مدیریت فضای رک دیتاسنتر

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

کارتابل فروش و مدیریت فضای رک دیتاسنتر



> version: 2.1 | last_updated: 2026-09-20 | audience: admin

هدف



این سند چهار مسیر کارتابل برای محصول **اجاره فضا دیتاسنتر** (دستهٔ زنده `fday-rk` / فضای رک؛ اسلاگ قدیمی `agarh-fda` اگر soft-delete شده باشد نادیده گرفته می‌شود) را پوشش می‌دهد:

  • **فروش** (sales) — خرید اولیه

  • **ارتقا** (upgrade) — افزایش فضا

  • **کاهش** (downgrade) — کاهش فضا

  • **جمع‌آوری** (collection) — پایان سرویس


  • مسیرهای موجود



    | مسیر | 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` |

    **نکات:**
  • استرداد نسبی برای باقیمانده دوره جاری (اگر کاهش میان‌دوره باشد)

  • مبلغ استرداد در `order.metadata['prorated_refund_amount']` محاسبه و ذخیره می‌شود

  • یونیت‌های اضافی آزاد شده قابل اختصاص به مشتریان دیگر هستند

  • حداقل یک یونیت باید باقی بماند (سرویس کاملاً حذف نمی‌شود)


  • ۴. مسیر جمع‌آوری (Collection / Termination)



    مسیر پایان سرویس و آزادسازی کامل فضا:

    | # | دپارتمان | اکشن |
    |---|----------|------|
    | 1 | **بستن شاهکار** | `http.shahkar_close` (بستن سرویس در شاهکار) |
    | 2 | **آزادسازی فضا** | `inventory.dc_space_release` (آزادسازی تمام یونیت‌ها → Free) |
    | 3 | **پایان اشتراک** | `subscription.terminate` → `order.complete` |

    **نکات:**
  • تمام یونیت‌های مرتبط با سرویس آزاد می‌شوند

  • اگر تجهیز مشتری روی یونیت‌ها نصب شده باشد، ابتدا باید جدا شود

  • وضعیت نهایی subscription: `Terminated`

  • بازگشت وجه (refund) در این مسیر پیش‌بینی نشده؛ در صورت نیاز از credit note دستی استفاده کنید


  • بررسی عدم انجام (مشترک در همه مسیرها)



    در صورت شکست هر مرحله، کار به **بررسی عدم انجام** می‌رود:

    | وضعیت بررسی | معنی |
    |-------------|------|
    | منتظر بررسی | اپراتور تصمیم می‌گیرد |
    | رفع شد — بازگشت به مرحله | `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`

    نصب تجهیز مشتری بعد از تخصیص فضا



    چرخه:

  • مشتری اجاره فضا می‌خرد → Uها **رزرو** می‌شوند

  • کارتابل / activate → Uها **Occupied** + متعلق به اشتراک

  • مشتری سرور می‌آورد → از **جزئیات سرویس** (ادمین یا ریسلر) یا **انبار → تجهیزات** دکمه **«نصب تجهیز روی فضای اجاره»** تجهیز را به همان سرویس وصل کنید

  • حذف/جدا کردن تجهیز → تجهیز `available`؛ Uها همچنان مال همان سرویس اجاره فضا هستند


  • جستجو در فرم تجهیز: نام/کد ملی/موبایل مشتری، شماره سرویس، برچسب فضا.

    تنظیم محصول



    ۱) محصول اصلی



    | فیلد | مقدار |
    |------|--------|
    | دسته | `اجاره فضا` (`agarh-fda`) |
    | `shahkar_service_type` | `26` |
    | اتصال به انبار دیتاسنتر | **فضای رک** |
    | سایت / رک | چند سایت در `datacenter_site_ids`؛ اگر بیش از یکی باشد مشتری/ریسلر انتخاب می‌کند |
    | **المان‌های فروش دیتاسنتر** | روشن کنید چه چیزی می‌فروشید |

    المان‌ها (روی محصول اصلی، بعد از اتصال انبار) — فقط چیزهایی که به انبار مربوط‌اند:

    | المان | معنی |
    |--------|------|
    | گزینه تعداد یونیت (U) | تعداد از گزینه با نقش «تعداد یونیت رک»؛ اگر خاموش → فیلد «تعداد یونیت ثابت» |
    | IP ثابت (انبار BSS) | گزینه با انبار IP ثابت (جدا از DCIM) |

    فایروال / RAM / IP اضافه Virtualizor و مشابه را در بخش عادی **گزینه‌های قابل‌تنظیم** با «نوع منبع VPS» بسازید؛ جزو المان‌های انبار دیتاسنتر نیستند.

    ۲) گزینه قابل‌تنظیم (افزونه configurable)



    روی گروه گزینه:

    | فیلد | مقدار |
    |------|--------|
    | نقش المان دیتاسنتر | مثلاً **تعداد یونیت رک (U)** |
    | اتصال به انبار | خالی بگذارید (برای U) |
    | روی هر سطح | فیلد **تعداد یونیت (U)** — عنوان آزاد است |

    اولویت تعداد U در خرید:

  • اگر المان rack_units روی محصول روشن باشد → `provisioning_delta.dc_space_units` روی choice با نقش یونیت

  • وگرنه → تعداد ثابت روی محصول


  • نصب و 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
    ```

    مرتبط



  • [dedicated-sales-cartable.md](./dedicated-sales-cartable.md)

  • [dcim-datacenter-manager.md](./dcim-datacenter-manager.md)

  • [workflow-actions.md](./workflow-actions.md)

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