import { ActionData, ActivationData } from "#domain/DTOs/objeniousapi.js" import { HttpClient } from "sim-shared/infrastructure/HTTPClient.js" import { AxiosError } from "axios" import { Result } from "sim-shared/domain/Result.js" import { ObjeniousOperation, IOperationsRepository as OperationsRepositoryPort } from "sim-shared/domain/operationsRepository.port.js" import assert from "node:assert" import { OrderRepository } from "sim-shared/infrastructure/OrderRepository.js" // TODO: // - Pasar a un archivo de DTOs // - Mucha repeticion por funcion, deberia hacer una plantilla export class SimUseCases { private readonly httpClient: HttpClient private readonly operationRepository: OperationsRepositoryPort private readonly orderRepository: OrderRepository constructor(args: { httpClient: HttpClient, operationRepository: OperationsRepositoryPort, orderRepository: OrderRepository }) { this.httpClient = args.httpClient this.operationRepository = args.operationRepository this.orderRepository = args.orderRepository } private async logOperation(data: ObjeniousOperation) { await this.operationRepository.createOperation({ ...data }) } /** * Garantiza el flujo de todos los casos de uso de: * - Petición según la acción * - Control de errores * - Siempre devuelve un Result * - Almacena la operacion en la base de datos * - Actualiza el estado del order * * Necesita: * - Mas control según el codigo de error */ private generateUseCase< PAYLOAD, RESPONSETYPE extends { requestId: string } >(args: { correlation_id?: string, url: string, operation: string, operationPayload: PAYLOAD, iccid: string onError?: (_: any) => void // on code response?? }): () => Promise> { return async () => { const req = this.httpClient.client.post(args.url, { ...args.operationPayload }) try { const response = await req; if (response.status == 200) { assert(response.data.requestId != undefined) // Creacion de la operacion inicial, antes de tener los datos const operation: ObjeniousOperation = { operation: args.operation, iccids: String(args.iccid), status: "noMassID", request_id: response.data.requestId } this.logOperation(operation) .then().catch(e => console.error(e)) if (args.correlation_id != undefined) { this.orderRepository.updateOrder({ correlation_id: args.correlation_id!, new_status: "running", // Siempre es runing la primera vez que se consume }) .then(e => console.log("Order actualizado: ", e)) .catch(e => console.error("Error actualizando order", args.correlation_id)) } return >{ error: undefined, data: true } } else { return { error: String(response.status), data: undefined } } } catch (error) { console.error(`[Sim.usecase] Error ${args.operation}`, (error as AxiosError).response?.status) return { error: "Error general de la peticion", data: undefined } } } } public activate(activationData: ActivationData): () => Promise> { const OPERATION_URL = "/actions/activateLine" return async () => { const req = this.httpClient.client.post(OPERATION_URL, { ...activationData }) try { const response = await req if (response.status == 200) { console.log("Activacion con exito", response.data) const operation: ObjeniousOperation = { operation: "activate", iccids: String(activationData.identifier.identifiers), status: "noMassID", request_id: response.data.requestId } this.logOperation(operation).then().catch(e => console.error(e)) return >{ error: undefined, data: true } } else { // muy mejorable el control de errores return { error: String(response.status), data: undefined } } } catch (error) { console.error("[Sim.usecase] Error activando ", (error as AxiosError).response?.status) return { error: "Error general de la peticion", data: undefined } } } } public preActivate(preActivateData: ActionData): () => Promise> { const OPERATION_URL = "/actions/preactivateLine" return async () => { const req = this.httpClient.client.post(OPERATION_URL, { ...preActivateData }) try { const resp = await req if (resp.status == 200) { console.log("Sim preactivada con exito", resp.data) const operation: ObjeniousOperation = { correlation_id: preActivateData.correlation_id, operation: "preActivate", iccids: String(preActivateData.identifier.identifiers), status: "noMassID", request_id: resp.data.requestId } this.logOperation(operation).then().catch(e => console.error(e)) return >{ error: undefined, data: true } } else { return >{ error: String(resp.status), data: undefined } } } catch (error) { console.error("Error preactivacion", preActivateData) return >{ error: "Error preactivando la sim" + preActivateData.identifier, data: undefined } } } } public reActivate(pauseData: ActionData): () => Promise> { const OPERATION_URL = "/actions/reactivateLine" return async () => { const req = this.httpClient.client.post(OPERATION_URL, { ...pauseData }) try { const response = await req if (response.status == 200) { console.log("[o] Sim solicitud de reactivacion ", response.data) return >{ error: undefined, data: true } } else { return { error: String(response.status), data: undefined } } } catch (error) { console.error("[x] Error reactivacion", (error as AxiosError).response?.status) return >{ error: "Error reactivando la sim" + pauseData.identifier, data: undefined } } } } public suspend(suspendData: ActionData): () => Promise> { const OPERATION_URL = "/actions/suspendLine" return this.generateUseCase({ correlation_id: suspendData.correlation_id, operationPayload: suspendData, url: OPERATION_URL, iccid: suspendData.identifier.identifiers[0], // operation: "suspend" }) } public terminate(terminationData: ActionData): () => Promise> { const OPERATION_URL = "/actions/terminateLine" return this.generateUseCase({ correlation_id: terminationData.correlation_id, operationPayload: terminationData, url: OPERATION_URL, iccid: terminationData.identifier.identifiers[0], // operation: "terminate" }) } }