feat: billing system — service plans, wallet, cost calculation

- Backend: billing module with ServicePlan, PricingRule, Wallet, WalletTransaction entities
- Admin can CRUD service plans with hourly/monthly/yearly billing cycles
- Each plan has flexible pricing rules (base_fee, cpu, memory, storage, db addon)
- Wallet system: auto-created per user, charge, deduct, refund, transaction history
- Cost calculation endpoint: cross-cycle conversion (hourly*720=monthly, monthly*12=yearly)
- Frontend: admin billing management page (/dashboard/admin/billing)
- Frontend: user wallet page with balance, quick-charge, transaction history
- Deploy page: cost breakdown shown in Review step (hourly/monthly/yearly)
- Navigation: Wallet link for users, Billing Plans link for admins
This commit is contained in:
keyhan
2026-04-07 01:45:45 +03:30
parent ac489c88d8
commit 4974f88e8c
16 changed files with 1302 additions and 3 deletions
@@ -0,0 +1,41 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToOne,
JoinColumn,
CreateDateColumn,
} from 'typeorm';
import { TransactionType } from '../../common/enums';
import { Wallet } from './wallet.entity';
@Entity('wallet_transactions')
export class WalletTransaction {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ type: 'enum', enum: TransactionType })
type: TransactionType;
@Column({ type: 'decimal', precision: 14, scale: 2 })
amount: number; // Amount in Toman (positive)
@Column({ type: 'decimal', precision: 14, scale: 2 })
balanceAfter: number; // Balance after this transaction
@Column({ nullable: true })
description: string; // e.g. "Charge via admin", "Payment for app: my-app (monthly)"
@Column({ nullable: true })
applicationId: string; // Linked application (for deductions)
@ManyToOne(() => Wallet, (wallet: Wallet) => wallet.transactions, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'walletId' })
wallet: Wallet;
@Column()
walletId: string;
@CreateDateColumn()
createdAt: Date;
}