Assist_Design/apps/bff/src/modules/subscriptions/subscriptions.controller.ts

210 lines
6.9 KiB
TypeScript
Raw Normal View History

2025-08-22 17:02:49 +09:00
import {
Controller,
Get,
Post,
2025-08-22 17:02:49 +09:00
Param,
Query,
Body,
Request,
ParseIntPipe,
BadRequestException,
UsePipes,
Header,
2025-08-22 17:02:49 +09:00
} from "@nestjs/common";
import { SubscriptionsService } from "./subscriptions.service";
import { SimManagementService } from "./sim-management.service";
2025-08-28 16:57:57 +09:00
import {
Subscription,
SubscriptionList,
SubscriptionStats,
SimActionResponse,
SimPlanChangeResult,
subscriptionQuerySchema,
type SubscriptionQuery,
} from "@customer-portal/domain/subscriptions";
import { InvoiceList } from "@customer-portal/domain/billing";
import { createPaginationSchema } from "@customer-portal/domain/toolkit/validation/helpers";
import type { z } from "zod";
import {
simTopupRequestSchema,
simChangePlanRequestSchema,
simCancelRequestSchema,
simFeaturesRequestSchema,
simReissueRequestSchema,
type SimInfo,
type SimTopupRequest,
type SimChangePlanRequest,
type SimCancelRequest,
type SimFeaturesRequest,
type SimReissueRequest,
} from "@customer-portal/domain/sim";
import { ZodValidationPipe } from "@customer-portal/validation/nestjs";
import type { RequestWithUser } from "@bff/modules/auth/auth.types";
const subscriptionInvoiceQuerySchema = createPaginationSchema({
defaultLimit: 10,
maxLimit: 100,
minLimit: 1,
});
type SubscriptionInvoiceQuery = z.infer<typeof subscriptionInvoiceQuerySchema>;
2025-08-22 17:02:49 +09:00
@Controller("subscriptions")
export class SubscriptionsController {
constructor(
private readonly subscriptionsService: SubscriptionsService,
private readonly simManagementService: SimManagementService
) {}
@Get()
@Header("Cache-Control", "private, max-age=300") // 5 minutes, user-specific
@UsePipes(new ZodValidationPipe(subscriptionQuerySchema))
async getSubscriptions(
@Request() req: RequestWithUser,
@Query() query: SubscriptionQuery
): Promise<SubscriptionList> {
const { status } = query;
return this.subscriptionsService.getSubscriptions(req.user.id, { status });
}
2025-08-22 17:02:49 +09:00
@Get("active")
@Header("Cache-Control", "private, max-age=300") // 5 minutes, user-specific
async getActiveSubscriptions(@Request() req: RequestWithUser): Promise<Subscription[]> {
2025-08-27 10:54:05 +09:00
return this.subscriptionsService.getActiveSubscriptions(req.user.id);
}
2025-08-22 17:02:49 +09:00
@Get("stats")
@Header("Cache-Control", "private, max-age=300") // 5 minutes, user-specific
async getSubscriptionStats(@Request() req: RequestWithUser): Promise<SubscriptionStats> {
2025-08-27 10:54:05 +09:00
return this.subscriptionsService.getSubscriptionStats(req.user.id);
}
2025-08-22 17:02:49 +09:00
@Get(":id")
@Header("Cache-Control", "private, max-age=300") // 5 minutes, user-specific
async getSubscriptionById(
@Request() req: RequestWithUser,
2025-08-22 17:02:49 +09:00
@Param("id", ParseIntPipe) subscriptionId: number
): Promise<Subscription> {
2025-08-27 10:54:05 +09:00
return this.subscriptionsService.getSubscriptionById(req.user.id, subscriptionId);
}
2025-08-22 17:02:49 +09:00
@Get(":id/invoices")
@Header("Cache-Control", "private, max-age=60") // 1 minute, may update with payments
async getSubscriptionInvoices(
@Request() req: RequestWithUser,
2025-08-22 17:02:49 +09:00
@Param("id", ParseIntPipe) subscriptionId: number,
@Query(new ZodValidationPipe(subscriptionInvoiceQuerySchema)) query: SubscriptionInvoiceQuery
): Promise<InvoiceList> {
return this.subscriptionsService.getSubscriptionInvoices(req.user.id, subscriptionId, query);
}
// ==================== SIM Management Endpoints ====================
@Get(":id/sim/debug")
async debugSimSubscription(
@Request() req: RequestWithUser,
@Param("id", ParseIntPipe) subscriptionId: number
): Promise<Record<string, unknown>> {
return this.simManagementService.debugSimSubscription(req.user.id, subscriptionId);
}
@Get(":id/sim")
async getSimInfo(
@Request() req: RequestWithUser,
@Param("id", ParseIntPipe) subscriptionId: number
): Promise<SimInfo> {
return this.simManagementService.getSimInfo(req.user.id, subscriptionId);
}
@Get(":id/sim/details")
async getSimDetails(
@Request() req: RequestWithUser,
@Param("id", ParseIntPipe) subscriptionId: number
) {
return this.simManagementService.getSimDetails(req.user.id, subscriptionId);
}
@Get(":id/sim/usage")
async getSimUsage(
@Request() req: RequestWithUser,
@Param("id", ParseIntPipe) subscriptionId: number
) {
return this.simManagementService.getSimUsage(req.user.id, subscriptionId);
}
@Get(":id/sim/top-up-history")
async getSimTopUpHistory(
@Request() req: RequestWithUser,
@Param("id", ParseIntPipe) subscriptionId: number,
@Query("fromDate") fromDate: string,
@Query("toDate") toDate: string
) {
if (!fromDate || !toDate) {
throw new BadRequestException("fromDate and toDate are required");
}
return this.simManagementService.getSimTopUpHistory(req.user.id, subscriptionId, {
fromDate,
toDate,
});
}
@Post(":id/sim/top-up")
@UsePipes(new ZodValidationPipe(simTopupRequestSchema))
async topUpSim(
@Request() req: RequestWithUser,
@Param("id", ParseIntPipe) subscriptionId: number,
@Body() body: SimTopupRequest
): Promise<SimActionResponse> {
await this.simManagementService.topUpSim(req.user.id, subscriptionId, body);
return { success: true, message: "SIM top-up completed successfully" };
}
@Post(":id/sim/change-plan")
@UsePipes(new ZodValidationPipe(simChangePlanRequestSchema))
async changeSimPlan(
@Request() req: RequestWithUser,
@Param("id", ParseIntPipe) subscriptionId: number,
@Body() body: SimChangePlanRequest
): Promise<SimPlanChangeResult> {
const result = await this.simManagementService.changeSimPlan(req.user.id, subscriptionId, body);
return {
success: true,
message: "SIM plan change completed successfully",
...result,
};
}
@Post(":id/sim/cancel")
@UsePipes(new ZodValidationPipe(simCancelRequestSchema))
async cancelSim(
@Request() req: RequestWithUser,
@Param("id", ParseIntPipe) subscriptionId: number,
@Body() body: SimCancelRequest
): Promise<SimActionResponse> {
await this.simManagementService.cancelSim(req.user.id, subscriptionId, body);
return { success: true, message: "SIM cancellation completed successfully" };
}
@Post(":id/sim/reissue-esim")
@UsePipes(new ZodValidationPipe(simReissueRequestSchema))
async reissueEsimProfile(
@Request() req: RequestWithUser,
@Param("id", ParseIntPipe) subscriptionId: number,
@Body() body: SimReissueRequest
): Promise<SimActionResponse> {
await this.simManagementService.reissueEsimProfile(req.user.id, subscriptionId, body);
return { success: true, message: "eSIM profile reissue completed successfully" };
}
@Post(":id/sim/features")
@UsePipes(new ZodValidationPipe(simFeaturesRequestSchema))
async updateSimFeatures(
@Request() req: RequestWithUser,
@Param("id", ParseIntPipe) subscriptionId: number,
@Body() body: SimFeaturesRequest
): Promise<SimActionResponse> {
await this.simManagementService.updateSimFeatures(req.user.id, subscriptionId, body);
return { success: true, message: "SIM features updated successfully" };
}
}