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
+39
View File
@@ -112,6 +112,45 @@ export class BillingController {
);
}
// ─── Payment Gateway ─────────────────────────────────────────────
@Post('gateway/initiate')
@ApiOperation({ summary: 'Initiate a payment gateway transaction' })
async initiateGateway(
@Request() req: any,
@Body() body: { amount: number; description?: string; callbackUrl: string },
) {
// In production, integrate with Zarinpal/IDPay/etc.
// For now, simulate a gateway redirect URL.
const trackingCode = `PAY-${Date.now()}-${Math.random().toString(36).substring(2, 8).toUpperCase()}`;
return {
success: true,
trackingCode,
gatewayUrl: `${body.callbackUrl}?trackingCode=${trackingCode}&amount=${body.amount}&status=success`,
message: 'Redirect user to gatewayUrl to complete payment',
};
}
@Post('gateway/verify')
@ApiOperation({ summary: 'Verify a payment gateway transaction and charge wallet' })
async verifyGateway(
@Request() req: any,
@Body() body: { trackingCode: string; amount: number },
) {
// In production, verify with the gateway provider.
// For now, auto-approve and charge the wallet.
await this.billingService.chargeWallet(
req.user.id,
body.amount,
`Payment gateway: ${body.trackingCode}`,
);
return {
success: true,
message: 'Payment verified and wallet charged',
trackingCode: body.trackingCode,
};
}
// ─── Wallet Admin ─────────────────────────────────────────────────
@Get('admin/wallets')