Assist_Design/apps/bff/src/orders/services/sim-fulfillment.service.ts

210 lines
6.4 KiB
TypeScript
Raw Normal View History

import { Injectable, Inject } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import { FreebititService } from "../../vendors/freebit/freebit.service";
import { OrderDetailsDto } from "../types/order-details.dto";
import { getSalesforceFieldMap } from "../../common/config/field-map";
export interface SimFulfillmentRequest {
orderDetails: OrderDetailsDto;
configurations: Record<string, unknown>;
}
@Injectable()
export class SimFulfillmentService {
constructor(
private readonly freebit: FreebititService,
@Inject(Logger) private readonly logger: Logger
) {}
/**
* Handle SIM-specific fulfillment after WHMCs provisioning
*/
async fulfillSimOrder(request: SimFulfillmentRequest): Promise<void> {
const { orderDetails, configurations } = request;
this.logger.log("Starting SIM fulfillment", {
orderId: orderDetails.id,
orderType: orderDetails.orderType,
});
// Extract SIM-specific configurations
const simType = configurations.simType as "eSIM" | "Physical SIM" | undefined;
const eid = configurations.eid as string | undefined;
const activationType = configurations.activationType as "Immediate" | "Scheduled" | undefined;
const scheduledAt = configurations.scheduledAt as string | undefined;
const phoneNumber = configurations.mnpPhone as string | undefined;
const mnp = this.extractMnpConfig(configurations);
const addons = this.extractAddonConfig(configurations);
// Find the main SIM plan from order items
const simPlanItem = orderDetails.items.find(item =>
item.product.itemClass === "Plan" || item.product.sku?.toLowerCase().includes("sim")
);
if (!simPlanItem) {
throw new Error("No SIM plan found in order items");
}
const planSku = simPlanItem.product.sku;
if (!planSku) {
throw new Error("SIM plan SKU not found");
}
// Validate required fields
if (simType === "eSIM" && (!eid || eid.length < 15)) {
throw new Error("EID is required for eSIM and must be valid");
}
if (!phoneNumber) {
throw new Error("Phone number is required for SIM activation");
}
// Perform Freebit activation
await this.activateSim({
account: phoneNumber,
eid,
planSku,
simType: simType || "eSIM",
activationType: activationType || "Immediate",
scheduledAt,
mnp,
addons,
});
this.logger.log("SIM fulfillment completed successfully", {
orderId: orderDetails.id,
account: phoneNumber,
planSku,
});
}
/**
* Activate SIM via Freebit API
*/
private async activateSim(params: {
account: string;
eid?: string;
planSku: string;
simType: "eSIM" | "Physical SIM";
activationType: "Immediate" | "Scheduled";
scheduledAt?: string;
mnp?: {
reserveNumber?: string;
reserveExpireDate?: string;
account?: string;
firstnameKanji?: string;
lastnameKanji?: string;
firstnameZenKana?: string;
lastnameZenKana?: string;
gender?: string;
birthday?: string;
};
addons?: {
voiceMail?: boolean;
callWaiting?: boolean;
};
}): Promise<void> {
const {
account,
eid,
planSku,
simType,
activationType,
scheduledAt,
mnp,
addons,
} = params;
try {
// Activate eSIM if applicable
if (simType === "eSIM") {
await this.freebit.activateEsimAccountNew({
account,
eid: eid!,
planCode: planSku,
contractLine: "5G",
shipDate: activationType === "Scheduled" ? scheduledAt : undefined,
mnp:
mnp && mnp.reserveNumber && mnp.reserveExpireDate
? {
reserveNumber: mnp.reserveNumber,
reserveExpireDate: mnp.reserveExpireDate,
}
: undefined,
identity: mnp ? {
firstnameKanji: mnp.firstnameKanji,
lastnameKanji: mnp.lastnameKanji,
firstnameZenKana: mnp.firstnameZenKana,
lastnameZenKana: mnp.lastnameZenKana,
gender: mnp.gender,
birthday: mnp.birthday,
} : undefined,
});
this.logger.log("eSIM activated successfully", {
account,
planSku,
scheduled: activationType === "Scheduled",
});
} else {
this.logger.warn("Physical SIM activation path is not implemented; skipping Freebit call", {
account,
});
}
// Apply add-ons (voice options) if selected
if (addons && (addons.voiceMail || addons.callWaiting)) {
await this.freebit.updateSimFeatures(account, {
voiceMailEnabled: !!addons.voiceMail,
callWaitingEnabled: !!addons.callWaiting,
});
this.logger.log("SIM add-ons applied", {
account,
voiceMail: addons.voiceMail,
callWaiting: addons.callWaiting,
});
}
} catch (error) {
this.logger.error("SIM activation failed", {
account,
planSku,
error: error instanceof Error ? error.message : String(error),
});
throw error;
}
}
/**
* Extract MNP configuration from order configurations
*/
private extractMnpConfig(configurations: Record<string, unknown>) {
const isMnp = configurations.isMnp;
if (!isMnp || isMnp !== "true") {
return undefined;
}
return {
reserveNumber: configurations.mnpNumber as string | undefined,
reserveExpireDate: configurations.mnpExpiry as string | undefined,
account: configurations.mvnoAccountNumber as string | undefined,
firstnameKanji: configurations.portingFirstName as string | undefined,
lastnameKanji: configurations.portingLastName as string | undefined,
firstnameZenKana: configurations.portingFirstNameKatakana as string | undefined,
lastnameZenKana: configurations.portingLastNameKatakana as string | undefined,
gender: configurations.portingGender as string | undefined,
birthday: configurations.portingDateOfBirth as string | undefined,
};
}
/**
* Extract addon configuration from order configurations
*/
private extractAddonConfig(configurations: Record<string, unknown>) {
// Check if voice addons are present in the configurations
// This would need to be determined based on the order items or configurations
// For now, return undefined - this can be enhanced based on actual addon detection logic
return undefined;
}
}