# PATCH /character/reservation/refund

# Charter: Process Reservation Refund

این اندپوینت برای پردازش بازپرداخت (Refund) برای یک یا چند رزرو قطعی (`status=1`) طراحی شده است. فرآیند شامل محاسبه جریمه (به صورت درصدی یا مبلغ ثابت)، به‌روزرسانی اطلاعات مالی رزرو، ثبت رکورد بازپرداخت در جدول مجزا، و در نهایت تغییر وضعیت رزرو به "مسترد شده" (`status=3`) است. این عملیات به صورت دسته‌ای (batch) برای لیستی از رزروها قابل اجراست.

<div class="api-docs" id="bkmrk-"></div>## Request Overview

<div class="api-docs" id="bkmrk-url%3A-%2Fv2%2Fcharter%2Fres"><div class="endpoint-info"><div>**URL:** `/v2/charter/reservation/refund`</div><div>**Method:** <span class="method-patch">PATCH</span></div><div>**Controller:** CharterController@storeRefundCharterReservation</div><div>**Middleware Stack:** authWithJwt</div></div></div>## Access Control

<div class="api-docs" id="bkmrk-%D8%AF%D8%B3%D8%AA%D8%B1%D8%B3%DB%8C-%D9%85%D8%B9%D8%AA%D8%A8%D8%B1-jwt">- دسترسی معتبر JWT

</div>## Request Body (JSON)

<div class="api-docs" id="bkmrk-field-type-descripti"><table class="schema-table" dir="rtl"><thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>type</td><td>string</td><td>**(الزامی)** نوع چارتر را مشخص می‌کند تا جداول پایگاه داده مربوطه هدف قرار گیرند. مقادیر مجاز: `"accommodation"` یا `"route"`.</td></tr><tr><td>items</td><td>array\[integer\]</td><td>**(الزامی)** آرایه‌ای از شناسه‌های رزروهایی که باید مسترد شوند.</td></tr><tr><td>financial</td><td>object</td><td>**(الزامی)** آبجکتی شامل جزئیات جریمه کنسلی.</td></tr><tr><td>financial.value\_type</td><td>string</td><td>**(الزامی)** نوع محاسبه جریمه. مقادیر مجاز: `"percent"` (درصدی از مبلغ قابل پرداخت) یا `"currency"` (مبلغ ثابت).</td></tr><tr><td>financial.value</td><td>number</td><td>**(الزامی)** مقدار جریمه. اگر `value_type` برابر `percent` باشد، این عدد بین 0 تا 100 است.</td></tr><tr><td>financial.description</td><td>string</td><td>**(الزامی)** توضیحی برای دلیل استرداد و جریمه.</td></tr></tbody></table>

</div>## Logic Details

منطق این اندپوینت در دو فاز اصلی اجرا می‌شود: فاز اعتبارسنجی و آماده‌سازی، و فاز اجرای تغییرات در پایگاه داده.

### فاز ۱: اعتبارسنجی و محاسبه جریمه (در یک حلقه)

سیستم در یک حلقه، هر شناسه رزرو ارسال شده در آرایه `items` را پردازش می‌کند:

<div class="api-docs" id="bkmrk-%D8%AF%D8%B1%DB%8C%D8%A7%D9%81%D8%AA-%D8%A7%D8%B7%D9%84%D8%A7%D8%B9%D8%A7%D8%AA-%D8%B1%D8%B2%D8%B1%D9%88%3A">1. **دریافت اطلاعات رزرو:** ابتدا رزرو مربوط به `item` فعلی از پایگاه داده خوانده می‌شود. 
    - **اگر رزرو یافت نشود:** عملیات فوراً متوقف شده و خطای `422` با کد `1000` و پیام "آیتم \[ID+10000\] یافت نشد" بازگردانده می‌شود.
2. **بررسی وضعیت رزرو:** وضعیت (`status`) رزرو بررسی می‌شود. 
    - **اگر وضعیت برابر `1` (قطعی) نباشد:** عملیات متوقف شده و خطای `422` با کد `1000` و پیام "آیتم \[ID+10000\] در وضعیت خرید قطعی نمی باشد" بازگردانده می‌شود.
3. **محاسبه جریمه (Penalty):**
    - اطلاعات مالی فعلی رزرو از فیلد `financial` (که به صورت JSON ذخیره شده) استخراج می‌شود.
    - بر اساس `request->financial['value_type']`: 
        - اگر `percent` باشد: `penalty = (original_payable * value) / 100`
        - اگر `currency` باشد: `penalty = value`
4. **آماده‌سازی داده‌های جدید:** یک آبجکت اطلاعاتی جدید برای این رزرو ساخته شده و به صورت موقت در یک آرایه به نام `$queryInsert` نگهداری می‌شود. این آبجکت شامل اطلاعاتی است که باید در جدول `charter_refunds` درج شود، از جمله آبجکت مالی جدید که در آن مبلغ قابل پرداخت (`payable`) به صورت `original_payable - penalty` محاسبه شده است.

</div>**نکته مهم:** اعتبارسنجی به صورت متوالی انجام می‌شود. در صورت بروز خطا برای هر یک از آیتم‌ها، کل فرآیند متوقف شده و هیچ تغییری در پایگاه داده اعمال نمی‌گردد.

### فاز ۲: اجرای تغییرات در پایگاه داده

اگر فاز اول برای تمام آیتم‌ها بدون خطا به پایان برسد و حداقل یک آیتم معتبر برای استرداد وجود داشته باشد، سیستم وارد این فاز می‌شود:

<div class="api-docs" id="bkmrk-%D8%B3%DB%8C%D8%B3%D8%AA%D9%85-%D8%B1%D9%88%DB%8C-%D8%A2%D8%B1%D8%A7%DB%8C%D9%87-%24que">1. سیستم روی آرایه `$queryInsert` (که در فاز اول آماده شده) حلقه می‌زند.
2. **درج رکورد استرداد:** برای هر آیتم، یک رکورد جدید در جدول `charter_refunds` با اطلاعات محاسبه شده درج می‌شود و شناسه (ID) رکورد جدید دریافت می‌گردد (`$refundId`).
3. **به‌روزرسانی رزرو اصلی:** رزرو اصلی در جدول `charter_reservations` به‌روزرسانی می‌شود: 
    - فیلد `status` به `3` (مسترد شده) تغییر می‌کند.
    - فیلد `refund_id` با شناسه رکورد استرداد (`$refundId`) پر می‌شود.
4. **عملیات ویژه برای اقامتگاه:** اگر نوع چارتر `accommodation` باشد، یک عملیات اضافی انجام می‌شود: 
    - رکورد(های) مرتبط با این رزرو در جدول `charter_reservation_accommodation_rooms` نیز حذف نرم (soft delete) می‌شوند (`status` به `2` تغییر کرده و `deleted_at` تنظیم می‌شود). این کار باعث آزاد شدن اتاق‌های اختصاص داده شده به این رزرو می‌شود.

</div>## Response Structure

### پاسخ موفق

در صورتی که تمام عملیات با موفقیت انجام شود (حتی اگر هیچ آیتم معتبری برای استرداد وجود نداشته باشد)، سرور یک پاسخ خالی با کد وضعیت `204 No Content` باز می‌گرداند.

### پاسخ‌های خطا

<div class="api-docs" id="bkmrk-%DA%A9%D8%AF-422-unprocessable">- **کد `422 Unprocessable Entity`:** این خطا در یکی از دو حالت زیر در فاز اعتبارسنجی رخ می‌دهد:   
    \- `code`: 1000, `message`: "آیتم \[ID\] یافت نشد." (زمانی که شناسه رزرو نامعتبر است)   
    \- `code`: 1000, `message`: "آیتم \[ID\] در وضعیت خرید قطعی نمی باشد." (زمانی که رزرو قبلاً کنسل، حذف یا مسترد شده است)
- **پاسخ استثنا (Exception):** در صورت بروز هرگونه خطای پیش‌بینی نشده در حین اجرای منطق (مانند خطای پایگاه داده)، یک پاسخ با ساختار سفارشی بازگردانده می‌شود که برای اشکال‌زدایی مفید است. (معمولاً با کد وضعیت 500 یا 400) ```
    {
        "status": false,
        "time": 1670154000,
        "message": "Error message details...",
        "trace": [...]
    }
    ```

</div>## Flowchart

<div class="api-docs" id="bkmrk-start-%28patch-%2Freserv"><div class="flowchart"><div class="flow-item">Start (PATCH /reservation/refund)</div><div class="flow-arrow">↓</div><div class="flow-item">Receive Request Body:  
<small>`type`, `items`, `financial`</small></div><div class="flow-arrow">↓</div><div class="flow-item-process" style="background-color: #e3f2fd;">**Start Loop:** For each `id` in `items`</div><div class="flow-arrow">↓</div><div class="flow-decision" style="background-color: #fff9c4;">Reservation with `id` exists?</div><div class="flow-split"><div class="flow-path"><div class="flow-arrow">↓ Yes</div><div class="flow-decision" style="background-color: #fff9c4;">Reservation `status` == 1?</div><div class="flow-split"><div class="flow-path"><div class="flow-arrow">↓ Yes</div><div class="flow-item-process" style="background-color: #e8f5e9;">1. Calculate penalty  
2. Prepare new financial data  
3. Add to temporary `$queryInsert` array</div></div><div class="flow-path"><div class="flow-arrow">↓ No</div><div class="flow-item-error">Return 422: Invalid Status</div></div></div></div><div class="flow-path"><div class="flow-arrow">↓ No</div><div class="flow-item-error">Return 422: Not Found</div></div></div><div class="flow-arrow" style="clear: both;">↓</div><div class="flow-item-process" style="background-color: #e3f2fd;">**End Loop**</div><div class="flow-arrow">↓</div><div class="flow-decision" style="background-color: #fff9c4;">Is `$queryInsert` array not empty?</div><div class="flow-split"><div class="flow-path"><div class="flow-arrow">↓ Yes</div><div class="flow-item-process" style="background-color: #e3f2fd;">**Start DB Update Loop:**  
For each item in `$queryInsert`</div><div class="flow-arrow">↓</div><div class="flow-item-process" style="background-color: #e8f5e9;">1. Insert into `charter_refunds` table  
2. Update `charter_reservations`: `status=3`, `refund_id=new_id`</div><div class="flow-arrow">↓</div><div class="flow-decision" style="background-color: #fff9c4;">Is `type` == 'accommodation'?</div><div class="flow-split"><div class="flow-path"><div class="flow-arrow">↓ Yes</div><div class="flow-item-process" style="background-color: #e8f5e9;">Soft-delete from `..._rooms` table</div></div><div class="flow-path"><div class="flow-arrow">↓ No</div></div></div><div class="flow-arrow" style="clear: both;">↓</div><div class="flow-item-process" style="background-color: #e3f2fd;">**End DB Update Loop**</div></div><div class="flow-path"><div class="flow-arrow">↓ No</div></div></div><div class="flow-arrow" style="clear: both;">↓</div><div class="flow-item-success">Return 204 No Content</div></div></div>