2025-09-25 15:11:28 +09:00
|
|
|
import { Injectable, Inject, BadRequestException } from "@nestjs/common";
|
|
|
|
|
import { Logger } from "nestjs-pino";
|
2025-09-25 16:38:21 +09:00
|
|
|
import { FreebitOrchestratorService } from "@bff/integrations/freebit/services/freebit-orchestrator.service";
|
2025-09-25 15:11:28 +09:00
|
|
|
import { SimValidationService } from "./sim-validation.service";
|
|
|
|
|
import { SimNotificationService } from "./sim-notification.service";
|
|
|
|
|
import { getErrorMessage } from "@bff/core/utils/error.util";
|
|
|
|
|
import type { SimCancelRequest } from "../types/sim-requests.types";
|
|
|
|
|
|
|
|
|
|
@Injectable()
|
|
|
|
|
export class SimCancellationService {
|
|
|
|
|
constructor(
|
2025-09-25 16:38:21 +09:00
|
|
|
private readonly freebitService: FreebitOrchestratorService,
|
2025-09-25 15:11:28 +09:00
|
|
|
private readonly simValidation: SimValidationService,
|
|
|
|
|
private readonly simNotification: SimNotificationService,
|
|
|
|
|
@Inject(Logger) private readonly logger: Logger
|
|
|
|
|
) {}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Cancel SIM service
|
|
|
|
|
*/
|
|
|
|
|
async cancelSim(
|
|
|
|
|
userId: string,
|
|
|
|
|
subscriptionId: number,
|
|
|
|
|
request: SimCancelRequest = {}
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
const { account } = await this.simValidation.validateSimSubscription(userId, subscriptionId);
|
|
|
|
|
|
|
|
|
|
// Determine run date (PA02-04 requires runDate); default to 1st of next month
|
|
|
|
|
let runDate = request.scheduledAt;
|
|
|
|
|
if (runDate && !/^\d{8}$/.test(runDate)) {
|
|
|
|
|
throw new BadRequestException("Scheduled date must be in YYYYMMDD format");
|
|
|
|
|
}
|
|
|
|
|
if (!runDate) {
|
|
|
|
|
const nextMonth = new Date();
|
|
|
|
|
nextMonth.setMonth(nextMonth.getMonth() + 1);
|
|
|
|
|
nextMonth.setDate(1);
|
|
|
|
|
const y = nextMonth.getFullYear();
|
|
|
|
|
const m = String(nextMonth.getMonth() + 1).padStart(2, "0");
|
|
|
|
|
const d = String(nextMonth.getDate()).padStart(2, "0");
|
|
|
|
|
runDate = `${y}${m}${d}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await this.freebitService.cancelSim(account, runDate);
|
|
|
|
|
|
|
|
|
|
this.logger.log(`Successfully cancelled SIM for subscription ${subscriptionId}`, {
|
|
|
|
|
userId,
|
|
|
|
|
subscriptionId,
|
|
|
|
|
account,
|
|
|
|
|
runDate,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await this.simNotification.notifySimAction("Cancel SIM", "SUCCESS", {
|
|
|
|
|
userId,
|
|
|
|
|
subscriptionId,
|
|
|
|
|
account,
|
|
|
|
|
runDate,
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const sanitizedError = getErrorMessage(error);
|
|
|
|
|
this.logger.error(`Failed to cancel SIM for subscription ${subscriptionId}`, {
|
|
|
|
|
error: sanitizedError,
|
|
|
|
|
userId,
|
|
|
|
|
subscriptionId,
|
|
|
|
|
});
|
|
|
|
|
await this.simNotification.notifySimAction("Cancel SIM", "ERROR", {
|
|
|
|
|
userId,
|
|
|
|
|
subscriptionId,
|
|
|
|
|
error: sanitizedError,
|
|
|
|
|
});
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|