314 lines
11 KiB
TypeScript
314 lines
11 KiB
TypeScript
|
|
// SIM Management Controller Endpoints
|
||
|
|
// These endpoints should be added to your subscriptions controller
|
||
|
|
// Location: apps/bff/src/modules/subscriptions/subscriptions.controller.ts
|
||
|
|
|
||
|
|
import {
|
||
|
|
Controller,
|
||
|
|
Get,
|
||
|
|
Post,
|
||
|
|
Body,
|
||
|
|
Param,
|
||
|
|
Query,
|
||
|
|
Request,
|
||
|
|
ParseIntPipe,
|
||
|
|
BadRequestException,
|
||
|
|
} from "@nestjs/common";
|
||
|
|
import { ApiTags, ApiOperation, ApiParam, ApiQuery, ApiBody, ApiResponse, ApiBearerAuth } from "@nestjs/swagger";
|
||
|
|
import { ZodValidationPipe } from "@bff/core/validation";
|
||
|
|
import type { RequestWithUser } from "@bff/modules/auth/auth.types";
|
||
|
|
import { SimManagementService } from "../sim-management.service";
|
||
|
|
import {
|
||
|
|
simTopupRequestSchema,
|
||
|
|
simChangePlanRequestSchema,
|
||
|
|
simCancelRequestSchema,
|
||
|
|
simFeaturesRequestSchema,
|
||
|
|
type SimTopupRequest,
|
||
|
|
type SimChangePlanRequest,
|
||
|
|
type SimCancelRequest,
|
||
|
|
type SimFeaturesRequest,
|
||
|
|
} from "../sim-management/types/sim-requests.types";
|
||
|
|
|
||
|
|
// ==================== SIM Management Endpoints ====================
|
||
|
|
// Add these methods to your SubscriptionsController class
|
||
|
|
|
||
|
|
@ApiTags("subscriptions")
|
||
|
|
@Controller("subscriptions")
|
||
|
|
@ApiBearerAuth()
|
||
|
|
export class SimEndpointsController {
|
||
|
|
constructor(private readonly simManagementService: SimManagementService) {}
|
||
|
|
|
||
|
|
@Get(":id/sim/debug")
|
||
|
|
@ApiOperation({
|
||
|
|
summary: "Debug SIM subscription data",
|
||
|
|
description: "Retrieves subscription data to help debug SIM management issues",
|
||
|
|
})
|
||
|
|
@ApiParam({ name: "id", type: Number, description: "Subscription ID" })
|
||
|
|
@ApiResponse({ status: 200, description: "Subscription debug data" })
|
||
|
|
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")
|
||
|
|
@ApiOperation({
|
||
|
|
summary: "Get SIM details and usage",
|
||
|
|
description: "Retrieves comprehensive SIM information including details and current usage",
|
||
|
|
})
|
||
|
|
@ApiParam({ name: "id", type: Number, description: "Subscription ID" })
|
||
|
|
@ApiResponse({ status: 200, description: "SIM information" })
|
||
|
|
@ApiResponse({ status: 400, description: "Not a SIM subscription" })
|
||
|
|
@ApiResponse({ status: 404, description: "Subscription not found" })
|
||
|
|
async getSimInfo(
|
||
|
|
@Request() req: RequestWithUser,
|
||
|
|
@Param("id", ParseIntPipe) subscriptionId: number
|
||
|
|
) {
|
||
|
|
return this.simManagementService.getSimInfo(req.user.id, subscriptionId);
|
||
|
|
}
|
||
|
|
|
||
|
|
@Get(":id/sim/info")
|
||
|
|
@ApiOperation({
|
||
|
|
summary: "Get SIM information (alias for /sim)",
|
||
|
|
description: "Retrieves comprehensive SIM information including details and current usage",
|
||
|
|
})
|
||
|
|
@ApiParam({ name: "id", type: Number, description: "Subscription ID" })
|
||
|
|
@ApiResponse({ status: 200, description: "SIM information" })
|
||
|
|
@ApiResponse({ status: 400, description: "Not a SIM subscription" })
|
||
|
|
@ApiResponse({ status: 404, description: "Subscription not found" })
|
||
|
|
async getSimInfoAlias(
|
||
|
|
@Request() req: RequestWithUser,
|
||
|
|
@Param("id", ParseIntPipe) subscriptionId: number
|
||
|
|
) {
|
||
|
|
return this.simManagementService.getSimInfo(req.user.id, subscriptionId);
|
||
|
|
}
|
||
|
|
|
||
|
|
@Get(":id/sim/details")
|
||
|
|
@ApiOperation({
|
||
|
|
summary: "Get SIM details",
|
||
|
|
description: "Retrieves detailed SIM information including ICCID, plan, status, etc.",
|
||
|
|
})
|
||
|
|
@ApiParam({ name: "id", type: Number, description: "Subscription ID" })
|
||
|
|
@ApiResponse({ status: 200, description: "SIM details" })
|
||
|
|
async getSimDetails(
|
||
|
|
@Request() req: RequestWithUser,
|
||
|
|
@Param("id", ParseIntPipe) subscriptionId: number
|
||
|
|
) {
|
||
|
|
return this.simManagementService.getSimDetails(req.user.id, subscriptionId);
|
||
|
|
}
|
||
|
|
|
||
|
|
@Get(":id/sim/usage")
|
||
|
|
@ApiOperation({
|
||
|
|
summary: "Get SIM data usage",
|
||
|
|
description: "Retrieves current data usage and recent usage history",
|
||
|
|
})
|
||
|
|
@ApiParam({ name: "id", type: Number, description: "Subscription ID" })
|
||
|
|
@ApiResponse({ status: 200, description: "SIM usage data" })
|
||
|
|
async getSimUsage(
|
||
|
|
@Request() req: RequestWithUser,
|
||
|
|
@Param("id", ParseIntPipe) subscriptionId: number
|
||
|
|
) {
|
||
|
|
return this.simManagementService.getSimUsage(req.user.id, subscriptionId);
|
||
|
|
}
|
||
|
|
|
||
|
|
@Get(":id/sim/top-up-history")
|
||
|
|
@ApiOperation({
|
||
|
|
summary: "Get SIM top-up history",
|
||
|
|
description: "Retrieves data top-up history for the specified date range",
|
||
|
|
})
|
||
|
|
@ApiParam({ name: "id", type: Number, description: "Subscription ID" })
|
||
|
|
@ApiQuery({ name: "fromDate", description: "Start date (YYYYMMDD)", example: "20240101" })
|
||
|
|
@ApiQuery({ name: "toDate", description: "End date (YYYYMMDD)", example: "20241231" })
|
||
|
|
@ApiResponse({ status: 200, description: "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")
|
||
|
|
@ApiOperation({
|
||
|
|
summary: "Top up SIM data quota",
|
||
|
|
description: "Add data quota to the SIM service",
|
||
|
|
})
|
||
|
|
@ApiParam({ name: "id", type: Number, description: "Subscription ID" })
|
||
|
|
@ApiBody({
|
||
|
|
description: "Top-up request",
|
||
|
|
schema: {
|
||
|
|
type: "object",
|
||
|
|
properties: {
|
||
|
|
quotaMb: { type: "number", description: "Quota in MB", example: 1000 },
|
||
|
|
amount: {
|
||
|
|
type: "number",
|
||
|
|
description: "Amount to charge in JPY (optional, defaults to calculated amount)",
|
||
|
|
example: 500,
|
||
|
|
},
|
||
|
|
currency: {
|
||
|
|
type: "string",
|
||
|
|
description: "ISO currency code (optional, defaults to JPY)",
|
||
|
|
example: "JPY",
|
||
|
|
},
|
||
|
|
},
|
||
|
|
required: ["quotaMb"],
|
||
|
|
},
|
||
|
|
})
|
||
|
|
@ApiResponse({ status: 200, description: "Top-up successful" })
|
||
|
|
async topUpSim(
|
||
|
|
@Request() req: RequestWithUser,
|
||
|
|
@Param("id", ParseIntPipe) subscriptionId: number,
|
||
|
|
@Body(new ZodValidationPipe(simTopupRequestSchema)) body: SimTopupRequest
|
||
|
|
) {
|
||
|
|
await this.simManagementService.topUpSim(req.user.id, subscriptionId, body);
|
||
|
|
return { success: true, message: "SIM top-up completed successfully" };
|
||
|
|
}
|
||
|
|
|
||
|
|
@Post(":id/sim/change-plan")
|
||
|
|
@ApiOperation({
|
||
|
|
summary: "Change SIM plan",
|
||
|
|
description:
|
||
|
|
"Change the SIM service plan. The change will be automatically scheduled for the 1st of the next month. Available plans: 5GB, 10GB, 25GB, 50GB.",
|
||
|
|
})
|
||
|
|
@ApiParam({ name: "id", type: Number, description: "Subscription ID" })
|
||
|
|
@ApiBody({
|
||
|
|
description: "Plan change request",
|
||
|
|
schema: {
|
||
|
|
type: "object",
|
||
|
|
properties: {
|
||
|
|
newPlanCode: {
|
||
|
|
type: "string",
|
||
|
|
description: "New plan code",
|
||
|
|
enum: ["5GB", "10GB", "25GB", "50GB"],
|
||
|
|
example: "25GB"
|
||
|
|
},
|
||
|
|
},
|
||
|
|
required: ["newPlanCode"],
|
||
|
|
},
|
||
|
|
})
|
||
|
|
@ApiResponse({ status: 200, description: "Plan change successful" })
|
||
|
|
async changeSimPlan(
|
||
|
|
@Request() req: RequestWithUser,
|
||
|
|
@Param("id", ParseIntPipe) subscriptionId: number,
|
||
|
|
@Body(new ZodValidationPipe(simChangePlanRequestSchema)) body: SimChangePlanRequest
|
||
|
|
) {
|
||
|
|
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")
|
||
|
|
@ApiOperation({
|
||
|
|
summary: "Cancel SIM service",
|
||
|
|
description: "Cancel the SIM service (immediate or scheduled)",
|
||
|
|
})
|
||
|
|
@ApiParam({ name: "id", type: Number, description: "Subscription ID" })
|
||
|
|
@ApiBody({
|
||
|
|
description: "Cancellation request",
|
||
|
|
schema: {
|
||
|
|
type: "object",
|
||
|
|
properties: {
|
||
|
|
scheduledAt: {
|
||
|
|
type: "string",
|
||
|
|
description: "Schedule cancellation (YYYYMMDD)",
|
||
|
|
example: "20241231",
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
required: false,
|
||
|
|
})
|
||
|
|
@ApiResponse({ status: 200, description: "Cancellation successful" })
|
||
|
|
async cancelSim(
|
||
|
|
@Request() req: RequestWithUser,
|
||
|
|
@Param("id", ParseIntPipe) subscriptionId: number,
|
||
|
|
@Body(new ZodValidationPipe(simCancelRequestSchema)) body: SimCancelRequest
|
||
|
|
) {
|
||
|
|
await this.simManagementService.cancelSim(req.user.id, subscriptionId, body);
|
||
|
|
return { success: true, message: "SIM cancellation completed successfully" };
|
||
|
|
}
|
||
|
|
|
||
|
|
@Post(":id/sim/reissue-esim")
|
||
|
|
@ApiOperation({
|
||
|
|
summary: "Reissue eSIM profile",
|
||
|
|
description:
|
||
|
|
"Reissue a downloadable eSIM profile (eSIM only). Optionally provide a new EID to transfer to.",
|
||
|
|
})
|
||
|
|
@ApiParam({ name: "id", type: Number, description: "Subscription ID" })
|
||
|
|
@ApiBody({
|
||
|
|
description: "Optional new EID to transfer the eSIM to",
|
||
|
|
schema: {
|
||
|
|
type: "object",
|
||
|
|
properties: {
|
||
|
|
newEid: {
|
||
|
|
type: "string",
|
||
|
|
description: "32-digit EID",
|
||
|
|
example: "89049032000001000000043598005455",
|
||
|
|
},
|
||
|
|
},
|
||
|
|
required: [],
|
||
|
|
},
|
||
|
|
})
|
||
|
|
@ApiResponse({ status: 200, description: "eSIM reissue successful" })
|
||
|
|
@ApiResponse({ status: 400, description: "Not an eSIM subscription" })
|
||
|
|
async reissueEsimProfile(
|
||
|
|
@Request() req: RequestWithUser,
|
||
|
|
@Param("id", ParseIntPipe) subscriptionId: number,
|
||
|
|
@Body() body: { newEid?: string } = {}
|
||
|
|
) {
|
||
|
|
await this.simManagementService.reissueEsimProfile(req.user.id, subscriptionId, body.newEid);
|
||
|
|
return { success: true, message: "eSIM profile reissue completed successfully" };
|
||
|
|
}
|
||
|
|
|
||
|
|
@Post(":id/sim/features")
|
||
|
|
@ApiOperation({
|
||
|
|
summary: "Update SIM features",
|
||
|
|
description:
|
||
|
|
"Enable/disable voicemail, call waiting, international roaming, and switch network type (4G/5G)",
|
||
|
|
})
|
||
|
|
@ApiParam({ name: "id", type: Number, description: "Subscription ID" })
|
||
|
|
@ApiBody({
|
||
|
|
description: "Features update request",
|
||
|
|
schema: {
|
||
|
|
type: "object",
|
||
|
|
properties: {
|
||
|
|
voiceMailEnabled: { type: "boolean" },
|
||
|
|
callWaitingEnabled: { type: "boolean" },
|
||
|
|
internationalRoamingEnabled: { type: "boolean" },
|
||
|
|
networkType: { type: "string", enum: ["4G", "5G"] },
|
||
|
|
},
|
||
|
|
},
|
||
|
|
})
|
||
|
|
@ApiResponse({ status: 200, description: "Features update successful" })
|
||
|
|
async updateSimFeatures(
|
||
|
|
@Request() req: RequestWithUser,
|
||
|
|
@Param("id", ParseIntPipe) subscriptionId: number,
|
||
|
|
@Body(new ZodValidationPipe(simFeaturesRequestSchema)) body: SimFeaturesRequest
|
||
|
|
) {
|
||
|
|
await this.simManagementService.updateSimFeatures(req.user.id, subscriptionId, body);
|
||
|
|
return { success: true, message: "SIM features updated successfully" };
|
||
|
|
}
|
||
|
|
|
||
|
|
@Get("debug/sim-details/:account")
|
||
|
|
// @Public() // Uncomment if you have a Public decorator for debug endpoints
|
||
|
|
@ApiOperation({
|
||
|
|
summary: "[DEBUG] Get SIM details from Freebit",
|
||
|
|
description: "Query Freebit API directly to see plan code and details for any account",
|
||
|
|
})
|
||
|
|
@ApiParam({ name: "account", description: "SIM account number (e.g., 02000215161147)" })
|
||
|
|
async debugSimDetails(@Param("account") account: string) {
|
||
|
|
return await this.simManagementService.getSimDetailsDebug(account);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|