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; } @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 { 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 { 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 ? { 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) { 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) { // 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; } }