diff --git a/.env b/.env index c654b08..f7b9e8a 100644 --- a/.env +++ b/.env @@ -14,8 +14,9 @@ RABBITMQ_VHOST=sim-vhost # Hay cosas que unificar de varios servicios POSTGRES_DB=postgres -POSTGRES_DATABASE=postres -POSTGRES_HOST=postgresql-sim-1 +POSTGRES_DATABASE=postgres +#POSTGRES_HOST=postgresql-sim +POSTGRES_HOST=localhost POSTGRES_PORT=5432 DEV_POSTGRES_PORT=5432 POSTGRES_USER=postgres diff --git a/deployment/database/00-init.sql b/deployment/database/00-init.sql index 8334ea0..203546d 100644 --- a/deployment/database/00-init.sql +++ b/deployment/database/00-init.sql @@ -7,7 +7,7 @@ drop domain if exists imsi_type cascade; CREATE DOMAIN imsi_type as varchar(15); -CREATE table if not exists sim_car ( +CREATE table if not exists sim_cards ( id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, imei imei_type, iccid iccid_type, @@ -91,8 +91,8 @@ CREATE TABLE if not exists sim_subscription_operations ( ), CONSTRAINT fk_subscription_id - FOREIGN KEY(subscription_id) - REFERENCES sim_subscriptions(id) + FOREIGN KEY(sim_id) + REFERENCES sim_subscription(id) ); -- Se supone que indica un cambio diff --git a/deployment/database/01-objenious.sql b/deployment/database/01-objenious.sql index 49f7d76..06fc472 100644 --- a/deployment/database/01-objenious.sql +++ b/deployment/database/01-objenious.sql @@ -17,13 +17,13 @@ CREATE TABLE if not exists objenious_operation ( last_change_date TIMESTAMP NOT NULL DEFAULT now(), end_date TIMESTAMP, error TEXT, - status status_enum, -- Por definir los status que va a usar -) + status status_enum +); -- operaciones pendientes para revisar -CREATE INDEX pending_operations +CREATE INDEX IF NOT EXISTS pending_operations ON objenious_operation(start_date) - WHERE end_date IS NULL + WHERE end_date IS NULL; CREATE TABLE if not exists objenious_operation_change ( id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, @@ -35,8 +35,7 @@ CREATE TABLE if not exists objenious_operation_change ( new_mass_action_id TEXT, CONSTRAINT fk_operation_id FOREIGN KEY(operation_id) REFERENCES objenious_operation(id) -) - -CREATE INDEX fk_operation_change - ON objenious_operation_change(operation_id) +); +CREATE INDEX operation_change + ON objenious_operation_change(operation_id); diff --git a/deployment/database/init.sql b/deployment/database/init.sql new file mode 100644 index 0000000..d8ce9df --- /dev/null +++ b/deployment/database/init.sql @@ -0,0 +1,145 @@ +-- eliminar los drop para prod +drop domain if exists imei_type cascade; +CREATE DOMAIN imei_type as varchar(15); +drop domain if exists iccid_type cascade; +CREATE DOMAIN iccid_type as varchar(22); +drop domain if exists imsi_type cascade; +CREATE DOMAIN imsi_type as varchar(15); + + +CREATE table if not exists sim_cards ( + id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + imei imei_type, + iccid iccid_type, + imsi imsi_type, + user_id BIGINT, + subscription_id BIGINT, + created_at TIMESTAMP, + last_update TIMESTAMP, + deleted_at TIMESTAMP +); + + +CREATE TABLE if not exists sim_envio ( + id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + codigo_origen TEXT, + codigo_distrito TEXT, + pedido_id BIGINT, + sim_id BIGINT, + + fecha_envio TIMESTAMP, + fecha_email TIMESTAMP, + is_preactivado BOOLEAN, + fecha_devolucion TIMESTAMP, + created_at TIMESTAMP, + + CONSTRAINT fk_sim_id + FOREIGN KEY(sim_id) REFERENCES sim_cards(id) +); + +-- Mock, No es parte de SIMs +CREATE TABLE if not exists sf_subscription ( + id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY +); + +-- No habria que meterle las propiedades del tipo de subscripcion +CREATE TABLE if not exists sim_subscription_types ( + id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + subscription TEXT NOT NULL, + created_at TIMESTAMP, + updated_at TIMESTAMP, + deleted_at TIMESTAMP +); + +CREATE TABLE if not exists sim_company ( + id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + name TEXT, + created_at TIMESTAMP, + updated_at TIMESTAMP, + deleted_at TIMESTAMP +); + +CREATE TABLE sim_subscription ( + id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + company_id INT, + subscription_type_id INT, + sim_id BIGINT, + order_id BIGINT, + + created_at TIMESTAMP, + updated_at TIMESTAMP, + deleted_at TIMESTAMP, + + CONSTRAINT fk_sim_id + FOREIGN KEY(sim_id) REFERENCES sim_cards(id), + + CONSTRAINT fk_company_id + FOREIGN KEY(company_id) REFERENCES sim_company(id), + + CONSTRAINT fk_subscription_type_id + FOREIGN KEY(subscription_type_id) REFERENCES sim_subscription_types(id) +); + +CREATE TABLE if not exists sim_subscription_operations ( + id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + sim_id BIGINT, + operation_type TEXT NOT NULL, + happened_at TIMESTAMP, + + CONSTRAINT valid_operations CHECK ( + operation_type in ('free','preactivate','activate','pause','cancel') + ), + + CONSTRAINT fk_subscription_id + FOREIGN KEY(sim_id) + REFERENCES sim_subscription(id) +); + +-- Se supone que indica un cambio +CREATE TABLE sim_subscription_historic ( + id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + subscription_id BIGINT, + iccid iccid_type, + company_id INT +); + +CREATE TYPE status_enum AS ENUM ('noRequestID','noMassID','running','finished','error','other'); + +-- Tabla para gestionar las peticiones de cambio de objenious. +-- Para una o mas lineas se pueden lanzar operacione que no sabemos +-- con certeza cuando van a terminar. +CREATE TABLE if not exists objenious_operation ( + id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + retry_count INT DEFAULT 0, + max_retry INT DEFAULT 5, + max_date_retry TIMESTAMP DEFAULT NULL, + iccids TEXT, + request_id TEXT, + mass_action_id TEXT, + operation TEXT NOT NULL, + start_date TIMESTAMP NOT NULL DEFAULT now(), + last_change_date TIMESTAMP NOT NULL DEFAULT now(), + end_date TIMESTAMP, + error TEXT, + status status_enum +); + +-- operaciones pendientes para revisar +CREATE INDEX IF NOT EXISTS pending_operations + ON objenious_operation(start_date) + WHERE end_date IS NULL; + +CREATE TABLE if not exists objenious_operation_change ( + id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + operation_id BIGINT, + creation_date TIMESTAMP NOT NULL DEFAULT now(), + error TEXT, + new_status status_enum, + new_request_id TEXT, + new_mass_action_id TEXT, + CONSTRAINT fk_operation_id + FOREIGN KEY(operation_id) REFERENCES objenious_operation(id) +); + +CREATE INDEX operation_change + ON objenious_operation_change(operation_id); diff --git a/docs/sim-api/Activate.bru b/docs/sim-api/Activate.bru index 3a76bda..9664fb7 100644 --- a/docs/sim-api/Activate.bru +++ b/docs/sim-api/Activate.bru @@ -11,8 +11,8 @@ post { } body:form-urlencoded { - iccid: 8933201124059176320 - offer: SAVEFAMILY1 + iccid: 8933201125065160422 + offer: SAVEFAMILY2 } settings { diff --git a/docs/sim-api/Pause.bru b/docs/sim-api/Pause.bru index a1d2aac..cef1ed7 100644 --- a/docs/sim-api/Pause.bru +++ b/docs/sim-api/Pause.bru @@ -11,11 +11,11 @@ post { } params:query { - : + ~iccid: } body:form-urlencoded { - iccid: 8933201124059176320 + iccid: 8933201125065160414 } settings { diff --git a/packages/shared/infrastructure/PgClient.ts b/packages/shared/infrastructure/PgClient.ts index 77285c8..07a6100 100644 --- a/packages/shared/infrastructure/PgClient.ts +++ b/packages/shared/infrastructure/PgClient.ts @@ -26,4 +26,16 @@ export class PgClient { return await this.pgPool.query(text, params); }; + + /** + * Función para validar la conexión al inicio. + */ + public async checkDatabaseConnection(): Promise { + const client = await this.pgPool.connect(); + const res = await client.query('SELECT NOW()'); + console.log(`[o] Database connected successfully at: ${res.rows[0].now}`); + client.release(); // Liberamos el cliente de vuelta al pool + return; + // Si algo falla se tiene que propagar + }; } diff --git a/packages/sim-consumidor-objenious/aplication/Sim.controller.ts b/packages/sim-consumidor-objenious/aplication/Sim.controller.ts index 157ffc2..e6a1d73 100644 --- a/packages/sim-consumidor-objenious/aplication/Sim.controller.ts +++ b/packages/sim-consumidor-objenious/aplication/Sim.controller.ts @@ -84,6 +84,7 @@ export class SimController { this.tryUseCase(msg, this.useCases.activate({ dueDate: this.genDueDate(2 * 60).toISOString(), + customerAccountCode: "9.49411.10", // TODO: Al .env identifier: { identifierType: "ICCID", identifiers: [iccid] diff --git a/packages/sim-consumidor-objenious/aplication/Sim.usecases.ts b/packages/sim-consumidor-objenious/aplication/Sim.usecases.ts index 3908e13..74223bc 100644 --- a/packages/sim-consumidor-objenious/aplication/Sim.usecases.ts +++ b/packages/sim-consumidor-objenious/aplication/Sim.usecases.ts @@ -2,6 +2,7 @@ import { ActionData, ActivationData } from "#domain/DTOs/objeniousapi.js" import { HttpClient } from "#shared/infrastructure/HTTPClient.js" import { AxiosError } from "axios" import { Result } from "#shared/domain/Result" +import { ObjeniousOperation, IOperationsRepository as OperationsRepositoryPort } from "#domain/operationsRepository.port" // TODO: // - Pasar a un archivo de DTOs @@ -9,38 +10,54 @@ import { Result } from "#shared/domain/Result" export class SimUseCases { - private httpClient: HttpClient - + private readonly httpClient: HttpClient + private readonly operationRepository: OperationsRepositoryPort constructor(args: { - - httpClient: HttpClient + httpClient: HttpClient, + operationRepository: OperationsRepositoryPort }) { this.httpClient = args.httpClient + this.operationRepository = args.operationRepository } - + private async logOperation(data: ObjeniousOperation) { + await this.operationRepository.createOperation({ + ...data + }) + } public activate(activationData: ActivationData): () => Promise> { const OPERATION_URL = "/actions/activateLine" return async () => { - // TODO: validacion de campos - const req = this.httpClient.client.post(OPERATION_URL, { ...activationData }) - try { const response = await req console.log("[!] El status de la respuesta es", response.status) if (response.status == 200) { console.log("Activacion con exito", response.data.response) + + const operation: ObjeniousOperation = { + operation: "activate", + iccids: activationData.identifier.identifiers, + status: "noMassID" + } + + this.logOperation(operation).then(e => { + console.log("Logueada operacion", operation) + }).catch(e => console.error(e)) + return >{ error: undefined, data: true } + + } else { + // muy mejorable el control de errores return { error: String(response.status), data: undefined diff --git a/packages/sim-consumidor-objenious/domain/DTOs/objeniousapi.ts b/packages/sim-consumidor-objenious/domain/DTOs/objeniousapi.ts index 2b90167..e52e187 100644 --- a/packages/sim-consumidor-objenious/domain/DTOs/objeniousapi.ts +++ b/packages/sim-consumidor-objenious/domain/DTOs/objeniousapi.ts @@ -9,6 +9,7 @@ export type ActionData = { } export type ActivationData = ActionData & { + customerAccountCode: "9.49411.10" | string, offer: { code: string | "SAVEFAMILY1" | "SAVEFAMILY2", services: any[] diff --git a/packages/sim-consumidor-objenious/domain/operationsRepository.port.ts b/packages/sim-consumidor-objenious/domain/operationsRepository.port.ts index 40292a0..f992f27 100644 --- a/packages/sim-consumidor-objenious/domain/operationsRepository.port.ts +++ b/packages/sim-consumidor-objenious/domain/operationsRepository.port.ts @@ -5,7 +5,7 @@ export type StatusEnum = 'noRequestID' | 'noMassID' | 'running' | 'finished' | ' export interface IOperationsRepository { createOperation(data: ObjeniousOperation): Promise> updateOperation(data: ObjeniousOperationChange): Promise> - getPendingOerations(): Promise> + getPendingOperations(): Promise> } export type ObjeniousOperation = { diff --git a/packages/sim-consumidor-objenious/index.ts b/packages/sim-consumidor-objenious/index.ts index dc2d585..dd51e76 100644 --- a/packages/sim-consumidor-objenious/index.ts +++ b/packages/sim-consumidor-objenious/index.ts @@ -1,6 +1,9 @@ +import { OperationsRepository } from "#adapters/OperationRepository.js" import { startRMQClient } from "#config/eventBus.config" import { httpInstance } from "#config/httpClient.config" +import { pgPool } from "#config/postgreConfig.js" +import { PgClient } from "#shared/infrastructure/PgClient.js" import { SimController } from "./aplication/Sim.controller.js" import { SimRouter } from "./aplication/Sim.router.js" import { SimUseCases } from "./aplication/Sim.usecases.js" @@ -8,10 +11,18 @@ import { SimUseCases } from "./aplication/Sim.usecases.js" async function startWorker() { const rmqClient = await startRMQClient() const httpClient = httpInstance + + const pgClient = new PgClient({ pool: pgPool }) + + await pgClient.checkDatabaseConnection() + + const operationRepository = new OperationsRepository(pgClient) + const simActivationController = new SimController( rmqClient, new SimUseCases({ - httpClient: httpClient + httpClient: httpClient, + operationRepository: operationRepository }) ) const simRouter = new SimRouter(simActivationController, rmqClient) diff --git a/packages/sim-consumidor-objenious/infrastructure/OperationRepository.ts b/packages/sim-consumidor-objenious/infrastructure/OperationRepository.ts index 9102377..821d394 100644 --- a/packages/sim-consumidor-objenious/infrastructure/OperationRepository.ts +++ b/packages/sim-consumidor-objenious/infrastructure/OperationRepository.ts @@ -13,11 +13,11 @@ export class OperationsRepository implements IOperationsRepository { async createOperation(data: ObjeniousOperation): Promise> { const query = ` - INSERT INTO objenious_operation (operacion, iccids, status, max_rety) - VALUES ($1, $2, $3, $4) + INSERT INTO objenious_operation (operation, iccids, status, max_retry, request_id) + VALUES ($1, $2, $3, $4, $5) RETURNING *`; const iccids = data.iccids.join(",") - const values = [data.operation, data.iccids, data.status, data.max_retry]; + const values = [data.operation, data.iccids, data.status, data.max_retry, data.request_id]; const { rows } = await this.pgClient.query(query, values); return >{ data: rows[0] diff --git a/run.local.sh b/run.local.sh index 2cd97eb..193944f 100755 --- a/run.local.sh +++ b/run.local.sh @@ -1,2 +1,4 @@ #/bin/bash +rm deployment/database/init.sql +cat deployment/database/*.sql >deployment/database/init.sql docker compose -f deployment/local/docker/docker-compose.yaml --project-directory ./ up --watch