feat: billing v2 — runtime-based plans, English UI, payment flow

- ServicePlan now has 'runtime' field (nodejs/laravel/wordpress)
- Admin billing page: Application Type dropdown, English UI, Toman prices
- calculateCost filters active plans by matching runtime
- Wallet page: English UI, payment gateway integration (Pay Now button)
- Deploy page Review step: billing cycle selector (hourly/monthly/yearly),
  payment method choice (wallet or payment gateway), Pay & Deploy button
- Payment gateway endpoints: POST /billing/gateway/initiate + /verify
  (simulated — ready for Zarinpal/IDPay integration)
- Deploy requires payment: wallet deduction or gateway charge before deploy
This commit is contained in:
keyhan
2026-04-07 02:05:58 +03:30
parent 4974f88e8c
commit c2c6a32ae8
9 changed files with 441 additions and 138 deletions
+12 -3
View File
@@ -1,7 +1,7 @@
import { IsString, IsEnum, IsOptional, IsBoolean, IsNumber, IsArray, ValidateNested, Min } from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import { BillingCycle, PricingResourceType } from '../../common/enums';
import { BillingCycle, PricingResourceType, AppRuntime } from '../../common/enums';
export class CreatePricingRuleDto {
@ApiProperty({ enum: PricingResourceType })
@@ -20,11 +20,15 @@ export class CreatePricingRuleDto {
}
export class CreateServicePlanDto {
@ApiProperty({ example: 'Node.js Basic' })
@ApiProperty({ example: 'Node.js Standard' })
@IsString()
name: string;
@ApiPropertyOptional({ example: 'Basic plan for Node.js applications' })
@ApiProperty({ enum: AppRuntime, example: 'nodejs' })
@IsEnum(AppRuntime)
runtime: AppRuntime;
@ApiPropertyOptional({ example: 'Standard plan for Node.js applications' })
@IsOptional()
@IsString()
description?: string;
@@ -46,6 +50,11 @@ export class UpdateServicePlanDto {
@IsString()
name?: string;
@ApiPropertyOptional({ enum: AppRuntime })
@IsOptional()
@IsEnum(AppRuntime)
runtime?: AppRuntime;
@ApiPropertyOptional()
@IsOptional()
@IsString()