diff --git a/apps/bff/src/vendors/freebit/freebit.service.ts b/apps/bff/src/vendors/freebit/freebit.service.ts index c85f801b..a69e8fbc 100644 --- a/apps/bff/src/vendors/freebit/freebit.service.ts +++ b/apps/bff/src/vendors/freebit/freebit.service.ts @@ -580,16 +580,67 @@ export class FreebititService { */ async reissueEsimProfile(account: string): Promise { try { - const request: Omit = { account }; + // Use PA05-41 eSIM Account Activation API (addAcct) for reissue + const authKey = await this.getAuthKey(); - await this.makeAuthenticatedRequest( - '/esim/reissueProfile/', - request - ); + // Fetch details to get current EID and plan/network where available + const details = await this.getSimDetails(account); + if (details.simType !== 'esim') { + throw new BadRequestException('This operation is only available for eSIM subscriptions'); + } - this.logger.log(`Successfully reissued eSIM profile for account ${account}`, { account }); + if (!details.eid) { + throw new BadRequestException('eSIM EID not found for this account'); + } + + const payload: import('./interfaces/freebit.types').FreebititEsimAccountActivationRequest = { + authKey, + aladinOperated: '20', + createType: 'reissue', + eid: details.eid, // existing EID used for reissue + account, + simkind: 'esim', + addKind: 'R', + // Optional enrichments omitted to minimize validation mismatches + }; + + const url = `${this.config.baseUrl}/mvno/esim/addAcct/`; + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + body: JSON.stringify(payload), + }); + + if (!response.ok) { + const text = await response.text().catch(() => ''); + this.logger.error('Freebit PA05-41 HTTP error', { url, status: response.status, statusText: response.statusText, body: text?.slice(0, 500) }); + throw new InternalServerErrorException(`HTTP ${response.status}: ${response.statusText}`); + } + + const data = await response.json() as import('./interfaces/freebit.types').FreebititEsimAccountActivationResponse; + const rc = typeof data.resultCode === 'number' ? String(data.resultCode) : (data.resultCode || ''); + if (rc !== '100') { + const message = data.message || 'Unknown error'; + this.logger.error('Freebit PA05-41 API error response', { + endpoint: '/mvno/esim/addAcct/', + resultCode: data.resultCode, + statusCode: data.statusCode, + message, + }); + throw new FreebititErrorImpl( + `API Error: ${message}`, + rc || '0', + data.statusCode || '0', + message + ); + } + + this.logger.log(`Successfully reissued eSIM profile via PA05-41 for account ${account}`, { account }); } catch (error: any) { - this.logger.error(`Failed to reissue eSIM profile for account ${account}`, { + if (error instanceof BadRequestException) throw error; + this.logger.error(`Failed to reissue eSIM profile via PA05-41 for account ${account}`, { error: error.message, account, }); diff --git a/apps/bff/src/vendors/freebit/interfaces/freebit.types.ts b/apps/bff/src/vendors/freebit/interfaces/freebit.types.ts index a06f386a..1dc1052d 100644 --- a/apps/bff/src/vendors/freebit/interfaces/freebit.types.ts +++ b/apps/bff/src/vendors/freebit/interfaces/freebit.types.ts @@ -230,6 +230,45 @@ export interface FreebititEsimAddAccountResponse { }; } +// PA05-41 eSIM Account Activation (addAcct) +export interface FreebititEsimAccountActivationRequest { + authKey: string; + aladinOperated: string; // '10' issue, '20' no-issue + masterAccount?: string; + masterPassword?: string; + createType: 'new' | 'reissue' | 'exchange' | string; + eid?: string; // required for reissue/exchange per business rules + account: string; // MSISDN + simkind: 'esim' | string; + repAccount?: string; + size?: string; + addKind?: 'N' | 'R' | string; // e.g., 'R' for reissue + oldEid?: string; + oldProductNumber?: string; + mnp?: { + reserveNumber: string; + reserveExpireDate: string; // YYYYMMDD + }; + firstnameKanji?: string; + lastnameKanji?: string; + firstnameZenKana?: string; + lastnameZenKana?: string; + gender?: string; // 'M' | 'F' | etc + birthday?: string; // YYYYMMDD + shipDate?: string; // YYYYMMDD + planCode?: string; + deliveryCode?: string; + globalIp?: string; // '10' none, '20' with global IP (env-specific mapping) + contractLine?: string; // '4G' | '5G' +} + +export interface FreebititEsimAccountActivationResponse { + resultCode: number | string; + status?: any; + statusCode?: string; + message?: string; +} + // Portal-specific types for SIM management export interface SimDetails { account: string;