feat: implement tax calculations for subscription and SMS wallet payments
- Updated SubscriptionPeriod interface to include tax-related fields: tax_percent, tax_rials, and payable_rials. - Modified payment API documentation to reflect changes in tax handling for subscriptions and SMS wallet charges. - Adjusted PaymentController to calculate payment amounts based on subscription period details instead of client input. - Enhanced PaymentManager to handle net amounts for SMS wallet charges, ensuring tax is not credited to the wallet. - Created PaymentTaxCalculator and SubscriptionTaxCalculator services to manage tax calculations consistently across payment types. - Added tests for tax calculations in both subscription and SMS wallet contexts, ensuring correct behavior with and without tax enabled. - Updated frontend components to display tax information appropriately during payment processes.
This commit is contained in:
@@ -12,6 +12,25 @@
|
||||
|
||||
> `max_resources` سقف منابع محیط است. مقدار `-1` یعنی نامحدود. مقادیر شیپشده: `free` = ۱، `basic` = ۳، `professional` = `-1`. اجرای این سقف در `POST /api/v1/resource` است — [resource.md](resource.md).
|
||||
|
||||
### مالیات دورهها
|
||||
|
||||
`price_rials` هر دوره **خالص** است و مالیات رویش **اضافه** میشود. این برعکسِ نوبت است؛ آنجا
|
||||
مبلغ شامل مالیات است و `CommissionService` مالیات را از دلش استخراج میکند.
|
||||
|
||||
نرخ از همان کلیدهای سراسری `tax_enabled` و `tax_percent` در SiteConfig میآید — کلید جداگانهای
|
||||
برای اشتراک وجود ندارد. محاسبه در `App\Subscription\Service\SubscriptionTaxCalculator`.
|
||||
|
||||
هر دوره سه فیلد محاسبهشدهٔ اضافه دارد. `price_rials` دستنخورده میماند تا کلاینت قدیمی نشکند:
|
||||
|
||||
| فیلد | معنی |
|
||||
|------|------|
|
||||
| `price_rials` | قیمت خالص، بدون مالیات — همان چیزی که ادمین وارد میکند |
|
||||
| `tax_percent` | درصد مؤثر؛ با `tax_enabled=0` برابر `0` |
|
||||
| `tax_rials` | `round(price_rials × tax_percent / 100)` |
|
||||
| `payable_rials` | `price_rials + tax_rials` — مبلغی که واقعاً پرداخت میشود |
|
||||
|
||||
دورهٔ رایگان یا تریال (`price_rials = 0`) مالیات نمیگیرد.
|
||||
|
||||
**Response 200:**
|
||||
```json
|
||||
{
|
||||
@@ -42,6 +61,9 @@
|
||||
"label": "یک ماهه",
|
||||
"duration_months": 1,
|
||||
"price_rials": 290000,
|
||||
"tax_percent": 10,
|
||||
"tax_rials": 29000,
|
||||
"payable_rials": 319000,
|
||||
"is_trial": false,
|
||||
"active": true,
|
||||
"sort_order": 1
|
||||
@@ -141,7 +163,6 @@
|
||||
```json
|
||||
{
|
||||
"gateway": "mellat",
|
||||
"amount_rials": 290000,
|
||||
"period_uuid": "uuid-of-subscription-period",
|
||||
"frontend_address": "https://example.com/payment-result"
|
||||
}
|
||||
@@ -150,18 +171,25 @@
|
||||
| فیلد | نوع | الزامی |
|
||||
|------|-----|--------|
|
||||
| gateway | string (mellat\|sep) | ✅ |
|
||||
| amount_rials | integer | ✅ |
|
||||
| period_uuid | string (UUID) | ✅ |
|
||||
| frontend_address | string (URL) | ❌ |
|
||||
|
||||
> **`amount_rials` دیگر پذیرفته نمیشود.** مبلغ سمت سرور از دورهٔ اشتراک محاسبه میشود:
|
||||
> `price_rials + tax_rials`. اگر کلاینت آن را بفرستد نادیده گرفته میشود. دلیلش بستنِ راهِ
|
||||
> دستکاری قیمت است. دورهٔ ناموجود یا غیرفعال → `422 ERR_VALIDATION_001` روی فیلد `period_uuid`.
|
||||
|
||||
**Response 200:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"payment_uuid": "...",
|
||||
"redirect_url": "https://gateway.shaparak.ir/...",
|
||||
"order_id": "ORD-XXXXXXXXXXXXXXXX"
|
||||
"pay_url": "https://clinic-pro.ir/api/v1/payment/pay/ORD-XXXXXXXXXXXXXXXX",
|
||||
"order_id": "ORD-XXXXXXXXXXXXXXXX",
|
||||
"price_rials": 290000,
|
||||
"tax_percent": 10,
|
||||
"tax_rials": 29000,
|
||||
"payable_rials": 319000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user