.
This commit is contained in:
parent
bbd79cc869
commit
c05585775d
@ -1,4 +1,4 @@
|
|||||||
import { ValueObject } from "@/core/common/domain";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
interface IAccountStatusProps {
|
interface IAccountStatusProps {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ValueObject } from "@/core/common/domain";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ValueObject } from "@/core/common/domain";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import bcrypt from "bcrypt";
|
import bcrypt from "bcrypt";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ValueObject } from "@/core/common/domain";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ValueObject } from "@/core/common/domain";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ValueObject } from "@/core/common/domain";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ValueObject } from "@/core/common/domain";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
interface IInvoiceStatusProps {
|
interface IInvoiceStatusProps {
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
"main": "index.ts",
|
"main": "index.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc && tsup",
|
"build": "tsc && tsup",
|
||||||
|
"dev": "node --import=tsx --watch src/index.ts",
|
||||||
"start:dev": "node --import=tsx --watch src/index.ts",
|
"start:dev": "node --import=tsx --watch src/index.ts",
|
||||||
"start:prod": "node dist/index.js",
|
"start:prod": "node dist/index.js",
|
||||||
"clean": "rm -rf dist node_modules",
|
"clean": "rm -rf dist node_modules",
|
||||||
@ -41,6 +42,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@erp/auth": "workspace:*",
|
"@erp/auth": "workspace:*",
|
||||||
"@erp/core": "workspace:*",
|
"@erp/core": "workspace:*",
|
||||||
|
"@erp/invoices": "workspace:*",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"cls-rtracer": "^2.6.3",
|
"cls-rtracer": "^2.6.3",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
@ -49,9 +51,7 @@
|
|||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"helmet": "^8.0.0",
|
"helmet": "^8.0.0",
|
||||||
"http": "0.0.1-security",
|
"http": "0.0.1-security",
|
||||||
"http-status": "^2.1.0",
|
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"libphonenumber-js": "^1.11.20",
|
|
||||||
"luxon": "^3.5.0",
|
"luxon": "^3.5.0",
|
||||||
"module-alias": "^2.2.3",
|
"module-alias": "^2.2.3",
|
||||||
"mysql2": "^3.12.0",
|
"mysql2": "^3.12.0",
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
|
import { globalErrorHandler } from "@erp/core";
|
||||||
//import { initPackages } from "@/core/package-loader";
|
//import { initPackages } from "@/core/package-loader";
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
import express, { Application } from "express";
|
import express, { Application } from "express";
|
||||||
import helmet from "helmet";
|
import helmet from "helmet";
|
||||||
import responseTime from "response-time";
|
import responseTime from "response-time";
|
||||||
import { globalErrorHandler } from "./core/common/presentation";
|
import { logger } from "./lib/logger";
|
||||||
import { logger } from "./core/logger";
|
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { logger } from "@/core/logger";
|
import { logger } from "@/lib/logger";
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
import { Sequelize } from "sequelize";
|
import { Sequelize } from "sequelize";
|
||||||
import { registerModels } from "./register-models";
|
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
@ -50,20 +49,19 @@ export async function tryConnectToDatabase() {
|
|||||||
|
|
||||||
if (!database) {
|
if (!database) {
|
||||||
const error = new Error("❌ Database not found.");
|
const error = new Error("❌ Database not found.");
|
||||||
logger.error({
|
logger.error(error.message, {
|
||||||
message: error.message,
|
|
||||||
label: "tryConnectToDatabase",
|
label: "tryConnectToDatabase",
|
||||||
});
|
});
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
logger.info({ message: `🔸 Connecting to database...`, label: "tryConnectToDatabase" });
|
logger.info("🔸 Connecting to database...", {
|
||||||
|
label: "tryConnectToDatabase",
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await database.authenticate();
|
await database.authenticate();
|
||||||
await registerModels(database);
|
|
||||||
|
|
||||||
logger.info({
|
logger.info(`✔️${" "}Database connection established successfully.`, {
|
||||||
message: `✔️${" "}Database connection established successfully.`,
|
|
||||||
label: "tryConnectToDatabase",
|
label: "tryConnectToDatabase",
|
||||||
meta: {
|
meta: {
|
||||||
host: process.env.DB_HOST,
|
host: process.env.DB_HOST,
|
||||||
@ -74,8 +72,7 @@ export async function tryConnectToDatabase() {
|
|||||||
});
|
});
|
||||||
return database;
|
return database;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error({
|
logger.error(`❌ Unable to connect to the database: ${(error as Error).message}`, {
|
||||||
message: `❌ Unable to connect to the database: ${(error as Error).message}`,
|
|
||||||
error,
|
error,
|
||||||
label: "tryConnectToDatabase",
|
label: "tryConnectToDatabase",
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,78 +0,0 @@
|
|||||||
import * as path from "path";
|
|
||||||
import { logger } from "@/core/logger";
|
|
||||||
import * as glob from "glob";
|
|
||||||
import { DataTypes, Sequelize } from "sequelize";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 🔹 Registra todos los modelos en Sequelize
|
|
||||||
*/
|
|
||||||
export const registerModels = async (database: Sequelize) => {
|
|
||||||
if (!database) {
|
|
||||||
const error = new Error("❌ Database not found.");
|
|
||||||
logger.error({
|
|
||||||
message: error.message,
|
|
||||||
label: "initModels",
|
|
||||||
});
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cwd = path.resolve(`${__dirname}/../`);
|
|
||||||
const models: { [key: string]: any } = {};
|
|
||||||
|
|
||||||
// Opciones para buscar los modelos
|
|
||||||
const globOptions = {
|
|
||||||
cwd,
|
|
||||||
nocase: true,
|
|
||||||
nodir: true,
|
|
||||||
absolute: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
logger.info(`🔎 Searching models in: ${cwd}`);
|
|
||||||
|
|
||||||
// Buscamos los ficheros que terminen en .model.js o .model.ts
|
|
||||||
for (const file of glob.sync("**/*.model.{js,ts}", globOptions)) {
|
|
||||||
logger.info({ message: `📄 File >> ${file}...`, label: "registerModels" });
|
|
||||||
const modelFile = require(path.resolve(cwd, file));
|
|
||||||
const modelDef = modelFile.default;
|
|
||||||
const model = typeof modelDef === "function" ? modelDef(database, DataTypes) : false;
|
|
||||||
|
|
||||||
if (model) {
|
|
||||||
models[model.name] = model;
|
|
||||||
logger.info({
|
|
||||||
message: `🔸 Model "${model.name}" registered (sequelize)`,
|
|
||||||
label: "registerModels",
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
logger.info({ message: "🚫 No model", label: "registerModels" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
logger.error("❌ Error registering models:", error);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configurar asociaciones
|
|
||||||
for (const model of Object.values(models)) {
|
|
||||||
if (typeof model.associate === "function") {
|
|
||||||
model.associate(database);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Sincronizamos DB en modo desarrollo
|
|
||||||
if (process.env.NODE_ENV !== "production") {
|
|
||||||
await database.sync({ force: false, alter: true });
|
|
||||||
logger.info({ message: `✔️${" "}Database synchronized successfully.`, label: "initModels" });
|
|
||||||
} else {
|
|
||||||
logger.warning({
|
|
||||||
message: "⚠️ Running in production mode - Skipping database sync.",
|
|
||||||
label: "initModels",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
const error = err as Error;
|
|
||||||
logger.error({ message: "❌ Error synchronizing database:", error, label: "initModels" });
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
import { IModuleServer, ModuleParams } from "@/core";
|
|
||||||
import { logger } from "@/core/logger";
|
|
||||||
import { invoicesRouter, models } from "../../../../../modules/invoices/src/api/intrastructure";
|
|
||||||
|
|
||||||
export const invoicesModule: IModuleServer = {
|
|
||||||
metadata: {
|
|
||||||
name: "invoices",
|
|
||||||
version: "1.0.0",
|
|
||||||
dependencies: [],
|
|
||||||
},
|
|
||||||
init(params: ModuleParams) {
|
|
||||||
// const contacts = getService<ContactsService>("contacts");
|
|
||||||
invoicesRouter(params);
|
|
||||||
logger.info({ message: "🚀 Invoices module initialized", label: "invoices" });
|
|
||||||
},
|
|
||||||
registerDependencies(params) {
|
|
||||||
const { database } = params;
|
|
||||||
logger.info({ message: "🚀 Invoices module dependencies registered", label: "invoices" });
|
|
||||||
return {
|
|
||||||
models,
|
|
||||||
services: {
|
|
||||||
getInvoice: () => {},
|
|
||||||
/*...*/
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
export * from "./infrastructure";
|
|
||||||
export * from "./presentation";
|
|
||||||
@ -1,4 +1,2 @@
|
|||||||
export * from "./sequelize";
|
|
||||||
export * from "./database";
|
|
||||||
//export * from "./passport";
|
//export * from "./passport";
|
||||||
export * from "./sequelize";
|
//export * from "./sequelize";
|
||||||
|
|||||||
@ -1,20 +0,0 @@
|
|||||||
export interface IErrorDTO {
|
|
||||||
detail?: string;
|
|
||||||
instance?: string;
|
|
||||||
status: number;
|
|
||||||
title: string;
|
|
||||||
type?: string;
|
|
||||||
context: IErrorContextDTO;
|
|
||||||
extra: IErrorExtraDTO;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IErrorContextDTO {
|
|
||||||
user?: unknown;
|
|
||||||
params?: Record<string, any>;
|
|
||||||
query?: Record<string, any>;
|
|
||||||
body?: Record<string, any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IErrorExtraDTO {
|
|
||||||
errors: Record<string, any>[];
|
|
||||||
}
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
export * from "./error.dto";
|
|
||||||
export * from "./types.dto";
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
export interface IMoneyDTO {
|
|
||||||
amount: number | null;
|
|
||||||
scale: number;
|
|
||||||
currency_code: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPercentageDTO {
|
|
||||||
amount: number | null;
|
|
||||||
scale: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IQuantityDTO {
|
|
||||||
amount: number | null;
|
|
||||||
scale: number;
|
|
||||||
}
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
export * from "./dto";
|
|
||||||
export * from "./express";
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export * from "./common";
|
|
||||||
@ -1 +1 @@
|
|||||||
export * from "./httpServer";
|
export * from "../../../lib/httpServer";
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
|
import { logger } from "@/lib/logger";
|
||||||
|
import { DateTime } from "luxon";
|
||||||
import http from "node:http";
|
import http from "node:http";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import { logger } from "@/core/logger";
|
|
||||||
import { DateTime } from "luxon";
|
|
||||||
import { createApp } from "./app";
|
import { createApp } from "./app";
|
||||||
import { ENV } from "./config";
|
import { ENV } from "./config";
|
||||||
import { tryConnectToDatabase } from "./config/database";
|
import { tryConnectToDatabase } from "./config/database";
|
||||||
import { initModules } from "./core/helpers";
|
import { initModules } from "./lib/modules";
|
||||||
import { registerModules } from "./register-modules";
|
import { registerModules } from "./register-modules";
|
||||||
|
|
||||||
// Guardamos información del estado del servidor
|
// Guardamos información del estado del servidor
|
||||||
@ -91,7 +91,7 @@ const server = http
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
.on("close", () =>
|
.on("close", () =>
|
||||||
logger.info(`Shut down at: ${DateTime.now().toLocaleString(DateTime.DATETIME_FULL)}`)
|
logger.info(`Shutdown at: ${DateTime.now().toLocaleString(DateTime.DATETIME_FULL)}`)
|
||||||
)
|
)
|
||||||
.on("connection", serverConnection)
|
.on("connection", serverConnection)
|
||||||
.on("error", serverError);
|
.on("error", serverError);
|
||||||
@ -149,7 +149,7 @@ process.on("uncaughtException", (error: Error) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const address in addresses) {
|
for (const address of addresses) {
|
||||||
logger.info(`⚡️ Server accessible at: http://${address}:${currentState.port}`);
|
logger.info(`⚡️ Server accessible at: http://${address}:${currentState.port}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
apps/server/src/lib/index.ts
Normal file
2
apps/server/src/lib/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./logger";
|
||||||
|
export * from "./modules";
|
||||||
@ -12,4 +12,8 @@ export class ConsoleLogger implements ILogger {
|
|||||||
error(message: string, error?: Error | any) {
|
error(message: string, error?: Error | any) {
|
||||||
console.error(`[ERROR] ${message}`, error?.stack || error);
|
console.error(`[ERROR] ${message}`, error?.stack || error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug(message: string, meta?: any) {
|
||||||
|
console.debug(`[DEBUG] ${message}`, meta ?? "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -19,4 +19,9 @@ export class SentryLogger implements ILogger {
|
|||||||
console.error(`[ERROR] ${message}`, error);
|
console.error(`[ERROR] ${message}`, error);
|
||||||
//Sentry.captureException(error);
|
//Sentry.captureException(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug(message: string, meta?: any) {
|
||||||
|
console.debug(`[DEBUG] ${message}`, meta);
|
||||||
|
//Sentry.captureMessage(message, "debug");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,7 +1,8 @@
|
|||||||
import { authAPIModule } from "@erp/auth";
|
//import { authAPIModule } from "@erp/auth";
|
||||||
import { registerModule } from "./core/helpers";
|
import { invoicesAPIModule } from "@erp/invoices";
|
||||||
|
import { registerModule } from "./lib/modules";
|
||||||
|
|
||||||
export const registerModules = () => {
|
export const registerModules = () => {
|
||||||
//registerPackage(ContactsPackage);
|
//registerModule(authAPIModule);
|
||||||
registerModule(authAPIModule);
|
registerModule(invoicesAPIModule);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -9,12 +9,6 @@
|
|||||||
"outDir": "dist"
|
"outDir": "dist"
|
||||||
},
|
},
|
||||||
//"files": ["src/index.ts"], // Esta opción compila sólo los archivos listados (y sus dependencias importadas).
|
//"files": ["src/index.ts"], // Esta opción compila sólo los archivos listados (y sus dependencias importadas).
|
||||||
"include": [
|
"include": ["src"],
|
||||||
"src/**/*.ts",
|
|
||||||
"../../packages/rdx-ddd/src/aggregate-root.ts",
|
|
||||||
"../../packages/rdx-ddd/src/domain-entity.ts",
|
|
||||||
"../../packages/rdx-ddd/src/index.ts",
|
|
||||||
"../../packages/rdx-ddd/src/aggregate-root-repository.interface.ts"
|
|
||||||
],
|
|
||||||
"exclude": ["src/**/__tests__/*", "src/**/*.mock.*", "src/**/*.test.*", "node_modules", "dist"]
|
"exclude": ["src/**/__tests__/*", "src/**/*.mock.*", "src/**/*.test.*", "node_modules", "dist"]
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
1
false/metadata-v1.3/registry.npmjs.org/express.json
Normal file
1
false/metadata-v1.3/registry.npmjs.org/express.json
Normal file
File diff suppressed because one or more lines are too long
1
false/metadata-v1.3/registry.npmjs.org/http-status.json
Normal file
1
false/metadata-v1.3/registry.npmjs.org/http-status.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -10,11 +10,11 @@ export const authAPIModule: IModuleServer = {
|
|||||||
// const contacts = getService<ContactsService>("contacts");
|
// const contacts = getService<ContactsService>("contacts");
|
||||||
const { logger } = params;
|
const { logger } = params;
|
||||||
//invoicesRouter(params);
|
//invoicesRouter(params);
|
||||||
logger.info({ message: "🚀 Auth module initialized", label: "invoices" });
|
logger.info("🚀 Auth module initialized", { label: "auth" });
|
||||||
},
|
},
|
||||||
registerDependencies(params: ModuleParams) {
|
registerDependencies(params: ModuleParams) {
|
||||||
const { database, logger } = params;
|
const { database, logger } = params;
|
||||||
logger.info({ message: "🚀 Auth module dependencies registered", label: "invoices" });
|
logger.info("🚀 Auth module dependencies registered", { label: "auth" });
|
||||||
return {
|
return {
|
||||||
//models,
|
//models,
|
||||||
services: {
|
services: {
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
"./components/*": "./src/web/components/*.tsx"
|
"./components/*": "./src/web/components/*.tsx"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
"express": "^4.18.2",
|
||||||
"joi": "^17.13.3",
|
"joi": "^17.13.3",
|
||||||
"react": "^18 || ^19",
|
"react": "^18 || ^19",
|
||||||
"react-dom": "^18 || ^19",
|
"react-dom": "^18 || ^19",
|
||||||
@ -20,17 +21,22 @@
|
|||||||
"@biomejs/biome": "1.9.4",
|
"@biomejs/biome": "1.9.4",
|
||||||
"@testing-library/react-hooks": "^8.0.1",
|
"@testing-library/react-hooks": "^8.0.1",
|
||||||
"@types/axios": "^0.14.4",
|
"@types/axios": "^0.14.4",
|
||||||
|
"@types/express": "^4.17.21",
|
||||||
"@types/jest": "29.5.14",
|
"@types/jest": "29.5.14",
|
||||||
"@types/react": "^19.1.2",
|
"@types/react": "^19.1.2",
|
||||||
"@types/react-dom": "^19.1.3",
|
"@types/react-dom": "^19.1.3",
|
||||||
"typescript": "^5.8.3"
|
"typescript": "^5.8.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@repo/rdx-ddd": "workspace:*",
|
||||||
"@repo/rdx-utils": "workspace:*",
|
"@repo/rdx-utils": "workspace:*",
|
||||||
"@repo/rdx-criteria": "workspace:*",
|
"@repo/rdx-criteria": "workspace:*",
|
||||||
"@tanstack/react-query": "^5.75.4",
|
"@tanstack/react-query": "^5.75.4",
|
||||||
"axios": "^1.9.0",
|
"axios": "^1.9.0",
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"http-status": "^2.1.0",
|
||||||
"joi": "^17.13.3",
|
"joi": "^17.13.3",
|
||||||
|
"libphonenumber-js": "^1.11.20",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-router-dom": "^6.26.0",
|
"react-router-dom": "^6.26.0",
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
export * from "./dto";
|
||||||
|
export * from "./infrastructure";
|
||||||
export * from "./logger";
|
export * from "./logger";
|
||||||
export * from "./modules";
|
export * from "./modules";
|
||||||
export * from "./dto";
|
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { logger } from "@/core/logger";
|
|
||||||
import { NextFunction, Request, Response } from "express";
|
import { NextFunction, Request, Response } from "express";
|
||||||
import httpStatus from "http-status";
|
import httpStatus from "http-status";
|
||||||
import { ApiError } from "./api-error";
|
import { ApiError } from "./api-error";
|
||||||
@ -9,7 +8,6 @@ export abstract class ExpressController {
|
|||||||
protected next!: NextFunction;
|
protected next!: NextFunction;
|
||||||
|
|
||||||
static errorResponse(apiError: ApiError, res: Response) {
|
static errorResponse(apiError: ApiError, res: Response) {
|
||||||
logger.error(`[${apiError.status}] ${apiError.title}: ${apiError.detail}`);
|
|
||||||
return res.status(apiError.status).json(apiError);
|
return res.status(apiError.status).json(apiError);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +157,6 @@ export abstract class ExpressController {
|
|||||||
this.executeImpl();
|
this.executeImpl();
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const _error = error as Error;
|
const _error = error as Error;
|
||||||
logger.error(`Unhandled error in controller: ${_error.message}`);
|
|
||||||
this.internalServerError(_error.message);
|
this.internalServerError(_error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { logger } from "@/core/logger";
|
import { logger } from "@/lib/logger";
|
||||||
import { NextFunction, Request, Response } from "express";
|
import { NextFunction, Request, Response } from "express";
|
||||||
import { ApiError } from "../api-error";
|
import { ApiError } from "../api-error";
|
||||||
|
|
||||||
2
modules/core/src/infrastructure/index.ts
Normal file
2
modules/core/src/infrastructure/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./express";
|
||||||
|
export * from "./sequelize";
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { DomainEntity } from "@/core/common/domain";
|
import { DomainEntity } from "@repo/rdx-ddd";
|
||||||
import { Collection, Result } from "@repo/rdx-utils";
|
import { Collection, Result } from "@repo/rdx-utils";
|
||||||
import { Model } from "sequelize";
|
import { Model } from "sequelize";
|
||||||
|
|
||||||
@ -50,6 +50,10 @@ export abstract class SequelizeMapper<
|
|||||||
params?: MapperParamsType
|
params?: MapperParamsType
|
||||||
): Result<Collection<TEntity>, Error> {
|
): Result<Collection<TEntity>, Error> {
|
||||||
try {
|
try {
|
||||||
|
if (source.length === 0) {
|
||||||
|
return Result.ok(new Collection([], totalCount));
|
||||||
|
}
|
||||||
|
|
||||||
const items = source.map(
|
const items = source.map(
|
||||||
(value, index) => this.mapToDomain(value, { index, ...params }).data
|
(value, index) => this.mapToDomain(value, { index, ...params }).data
|
||||||
);
|
);
|
||||||
@ -1,7 +1,6 @@
|
|||||||
import { IAggregateRootRepository, UniqueID } from "@/core/common/domain";
|
import { IAggregateRootRepository, UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { ModelDefined, Sequelize, Transaction } from "sequelize";
|
import { ModelDefined, Sequelize, Transaction } from "sequelize";
|
||||||
import { logger } from "../logger";
|
|
||||||
|
|
||||||
export abstract class SequelizeRepository<T> implements IAggregateRootRepository<T> {
|
export abstract class SequelizeRepository<T> implements IAggregateRootRepository<T> {
|
||||||
protected readonly _database!: Sequelize;
|
protected readonly _database!: Sequelize;
|
||||||
@ -141,7 +140,7 @@ export abstract class SequelizeRepository<T> implements IAggregateRootRepository
|
|||||||
): Result<never, Error> {
|
): Result<never, Error> {
|
||||||
const _error = error as Error;
|
const _error = error as Error;
|
||||||
|
|
||||||
logger.error({ message: `Database error: ${_error.message}`, label: "SequelizeRepository" });
|
//logger.error({ message: `Database error: ${_error.message}`, label: "SequelizeRepository" });
|
||||||
|
|
||||||
// Si la clase hija proporciona un mapeo personalizado, lo usa
|
// Si la clase hija proporciona un mapeo personalizado, lo usa
|
||||||
if (errorMapper) {
|
if (errorMapper) {
|
||||||
@ -2,4 +2,5 @@ export interface ILogger {
|
|||||||
info(message: string, meta?: any): void;
|
info(message: string, meta?: any): void;
|
||||||
warn(message: string, meta?: any): void;
|
warn(message: string, meta?: any): void;
|
||||||
error(message: string, error?: Error | any): void;
|
error(message: string, error?: Error | any): void;
|
||||||
|
debug(message: string, meta?: any): void;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,25 +16,33 @@
|
|||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"ag-grid-community": "^33.3.0",
|
"ag-grid-community": "^33.3.0",
|
||||||
"ag-grid-react": "^33.3.0",
|
"ag-grid-react": "^33.3.0",
|
||||||
|
"express": "^4.18.2",
|
||||||
"i18next": "^25.1.1",
|
"i18next": "^25.1.1",
|
||||||
"lucide-react": "^0.503.0",
|
"lucide-react": "^0.503.0",
|
||||||
"react": "^18 || ^19",
|
"react": "^18 || ^19",
|
||||||
"react-dom": "^18 || ^19",
|
"react-dom": "^18 || ^19",
|
||||||
"react-i18next": "^15.5.1",
|
"react-i18next": "^15.5.1",
|
||||||
"react-router-dom": "^6.26.0"
|
"react-router-dom": "^6.26.0",
|
||||||
|
"sequelize": "^6.37.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "1.9.4",
|
"@biomejs/biome": "1.9.4",
|
||||||
|
"@types/express": "^4.17.21",
|
||||||
"@types/react": "^19.1.2",
|
"@types/react": "^19.1.2",
|
||||||
"@types/react-dom": "^19.1.3",
|
"@types/react-dom": "^19.1.3",
|
||||||
|
"@types/react-i18next": "^8.1.0",
|
||||||
|
"sequelize": "^6.37.5",
|
||||||
"typescript": "^5.8.3"
|
"typescript": "^5.8.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@erp/core": "workspace:*",
|
"@erp/core": "workspace:*",
|
||||||
|
"@repo/rdx-ddd": "workspace:*",
|
||||||
|
"@repo/rdx-utils": "workspace:*",
|
||||||
"@repo/rdx-ui": "workspace:*",
|
"@repo/rdx-ui": "workspace:*",
|
||||||
"@repo/shadcn-ui": "workspace:*",
|
"@repo/shadcn-ui": "workspace:*",
|
||||||
"ag-grid-community": "^33.3.0",
|
"ag-grid-community": "^33.3.0",
|
||||||
"ag-grid-react": "^33.3.0",
|
"ag-grid-react": "^33.3.0",
|
||||||
|
"express": "^4.18.2",
|
||||||
"i18next": "^25.1.1",
|
"i18next": "^25.1.1",
|
||||||
"lucide-react": "^0.503.0",
|
"lucide-react": "^0.503.0",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { UniqueID } from "@/core/common/domain";
|
import { UniqueID } from "@/core/common/domain";
|
||||||
import { ITransactionManager } from "@/core/common/infrastructure/database";
|
import { ITransactionManager } from "@/core/common/infrastructure/database";
|
||||||
import { logger } from "@/core/logger";
|
import { logger } from "@/lib/logger";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { IInvoiceService, Invoice } from "../domain";
|
import { IInvoiceService, Invoice } from "../domain";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { ITransactionManager } from "@/core/common/infrastructure/database";
|
import { ITransactionManager } from "@/core/common/infrastructure/database";
|
||||||
import { logger } from "@/core/logger";
|
import { logger } from "@/lib/logger";
|
||||||
import { Collection, Result } from "@repo/rdx-utils";
|
import { Collection, Result } from "@repo/rdx-utils";
|
||||||
import { IInvoiceService, Invoice } from "../domain";
|
import { IInvoiceService, Invoice } from "../domain";
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { AggregateRoot, MoneyValue, UniqueID, UtcDate } from "@/core/common/domain";
|
import { AggregateRoot, MoneyValue, UniqueID, UtcDate } from "@repo/rdx-ddd";
|
||||||
import { Collection, Result } from "@repo/rdx-utils";
|
import { Collection, Result } from "@repo/rdx-utils";
|
||||||
import { InvoiceCustomer, InvoiceItem, InvoiceItems } from "../entities";
|
import { InvoiceCustomer, InvoiceItem, InvoiceItems } from "../entities";
|
||||||
import { InvoiceNumber, InvoiceSerie, InvoiceStatus } from "../value-objects";
|
import { InvoiceNumber, InvoiceSerie, InvoiceStatus } from "../value-objects";
|
||||||
|
|||||||
@ -1,9 +1,4 @@
|
|||||||
import {
|
import { EmailAddress, Name, PostalAddress, ValueObject } from "@repo/rdx-ddd";
|
||||||
type EmailAddress,
|
|
||||||
type Name,
|
|
||||||
type PostalAddress,
|
|
||||||
ValueObject,
|
|
||||||
} from "@/core/common/domain";
|
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { PhoneNumber } from "libphonenumber-js";
|
import { PhoneNumber } from "libphonenumber-js";
|
||||||
import { InvoiceAddressType } from "../../value-objects";
|
import { InvoiceAddressType } from "../../value-objects";
|
||||||
@ -26,12 +21,12 @@ export interface IInvoiceAddress {
|
|||||||
|
|
||||||
export class InvoiceAddress extends ValueObject<IInvoiceAddressProps> implements IInvoiceAddress {
|
export class InvoiceAddress extends ValueObject<IInvoiceAddressProps> implements IInvoiceAddress {
|
||||||
public static create(props: IInvoiceAddressProps) {
|
public static create(props: IInvoiceAddressProps) {
|
||||||
return Result.ok(new this(props));
|
return Result.ok(new InvoiceAddress(props));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static createShippingAddress(props: IInvoiceAddressProps) {
|
public static createShippingAddress(props: IInvoiceAddressProps) {
|
||||||
return Result.ok(
|
return Result.ok(
|
||||||
new this({
|
new InvoiceAddress({
|
||||||
...props,
|
...props,
|
||||||
type: InvoiceAddressType.create("shipping").data,
|
type: InvoiceAddressType.create("shipping").data,
|
||||||
})
|
})
|
||||||
@ -40,7 +35,7 @@ export class InvoiceAddress extends ValueObject<IInvoiceAddressProps> implements
|
|||||||
|
|
||||||
public static createBillingAddress(props: IInvoiceAddressProps) {
|
public static createBillingAddress(props: IInvoiceAddressProps) {
|
||||||
return Result.ok(
|
return Result.ok(
|
||||||
new this({
|
new InvoiceAddress({
|
||||||
...props,
|
...props,
|
||||||
type: InvoiceAddressType.create("billing").data,
|
type: InvoiceAddressType.create("billing").data,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { DomainEntity, Name, TINNumber, UniqueID } from "@/core/common/domain";
|
import { DomainEntity, Name, TINNumber, UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { InvoiceAddress } from "./invoice-address";
|
import { InvoiceAddress } from "./invoice-address";
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { DomainEntity, MoneyValue, Percentage, Quantity, UniqueID } from "@/core/common/domain";
|
import { DomainEntity, MoneyValue, Percentage, Quantity, UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { InvoiceItemDescription } from "../../value-objects";
|
import { InvoiceItemDescription } from "../../value-objects";
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ValueObject } from "@/core/common/domain";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
interface IInvoiceAddressTypeProps {
|
interface IInvoiceAddressTypeProps {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ValueObject } from "@/core/common/domain";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
import { Maybe, Result } from "@repo/rdx-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ValueObject } from "@/core/common/domain";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ValueObject } from "@/core/common/domain";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
import { Maybe, Result } from "@repo/rdx-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ValueObject } from "@/core/common/domain";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
interface IInvoiceStatusProps {
|
interface IInvoiceStatusProps {
|
||||||
@ -22,7 +22,7 @@ export class InvoiceStatus extends ValueObject<IInvoiceStatusProps> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static create(value: string): Result<InvoiceStatus, Error> {
|
static create(value: string): Result<InvoiceStatus, Error> {
|
||||||
if (!this.ALLOWED_STATUSES.includes(value)) {
|
if (!InvoiceStatus.ALLOWED_STATUSES.includes(value)) {
|
||||||
return Result.fail(new Error(`Estado de la factura no válido: ${value}`));
|
return Result.fail(new Error(`Estado de la factura no válido: ${value}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { IModuleServer, ModuleParams } from "@erp/core";
|
import { IModuleServer, ModuleParams } from "@erp/core";
|
||||||
|
import { invoicesRouter, models } from "./infrastructure";
|
||||||
|
|
||||||
export const invoicesModule: IModuleServer = {
|
export const invoicesAPIModule: IModuleServer = {
|
||||||
metadata: {
|
metadata: {
|
||||||
name: "invoices",
|
name: "invoices",
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
@ -9,14 +10,14 @@ export const invoicesModule: IModuleServer = {
|
|||||||
init(params: ModuleParams) {
|
init(params: ModuleParams) {
|
||||||
// const contacts = getService<ContactsService>("contacts");
|
// const contacts = getService<ContactsService>("contacts");
|
||||||
const { logger } = params;
|
const { logger } = params;
|
||||||
//invoicesRouter(params);
|
invoicesRouter(params);
|
||||||
logger.info({ message: "🚀 Invoices module initialized", label: "invoices" });
|
logger.info("🚀 Invoices module initialized", { label: "invoices" });
|
||||||
},
|
},
|
||||||
registerDependencies(params) {
|
registerDependencies(params) {
|
||||||
const { database, logger } = params;
|
const { database, logger } = params;
|
||||||
logger.info({ message: "🚀 Invoices module dependencies registered", label: "invoices" });
|
logger.info("🚀 Invoices module dependencies registered", { label: "invoices" });
|
||||||
return {
|
return {
|
||||||
//models,
|
models,
|
||||||
services: {
|
services: {
|
||||||
getInvoice: () => {},
|
getInvoice: () => {},
|
||||||
/*...*/
|
/*...*/
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { ModuleParams } from "@/core";
|
import { ModuleParams } from "@erp/core";
|
||||||
import { Application, NextFunction, Request, Response, Router } from "express";
|
import { Application, NextFunction, Request, Response, Router } from "express";
|
||||||
import { Sequelize } from "sequelize";
|
import { Sequelize } from "sequelize";
|
||||||
import { buildGetInvoiceController, buildListInvoicesController } from "../../presentation";
|
import { buildListInvoicesController } from "../../presentation";
|
||||||
|
|
||||||
export const invoicesRouter = (params: ModuleParams) => {
|
export const invoicesRouter = (params: ModuleParams) => {
|
||||||
const { app, database, baseRoutePath } = params as {
|
const { app, database, baseRoutePath } = params as {
|
||||||
@ -21,14 +21,14 @@ export const invoicesRouter = (params: ModuleParams) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
routes.get(
|
/*routes.get(
|
||||||
"/:invoiceId",
|
"/:invoiceId",
|
||||||
//checkTabContext,
|
//checkTabContext,
|
||||||
//checkUser,
|
//checkUser,
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
buildGetInvoiceController(database).execute(req, res, next);
|
buildGetInvoiceController(database).execute(req, res, next);
|
||||||
}
|
}
|
||||||
);
|
);*/
|
||||||
|
|
||||||
/*routes.post(
|
/*routes.post(
|
||||||
"/",
|
"/",
|
||||||
@ -1,18 +1,9 @@
|
|||||||
import { Invoice, InvoiceItem, InvoiceItemDescription } from "@/contexts/invoices/domain";
|
import { ISequelizeMapper, MapperParamsType, SequelizeMapper } from "@erp/core";
|
||||||
import {
|
import { MoneyValue, Percentage, Quantity, UniqueID } from "@repo/rdx-ddd";
|
||||||
type ISequelizeMapper,
|
import { Collection, Result } from "@repo/rdx-utils";
|
||||||
type MapperParamsType,
|
|
||||||
MoneyValue,
|
|
||||||
Percentage,
|
|
||||||
Quantity,
|
|
||||||
Result,
|
|
||||||
SequelizeMapper,
|
|
||||||
UniqueID,
|
|
||||||
} from "@/core";
|
|
||||||
import { InvoiceModel } from "../sequelize";
|
|
||||||
|
|
||||||
import { InferCreationAttributes } from "sequelize";
|
import { InferCreationAttributes } from "sequelize";
|
||||||
import { InvoiceItemCreationAttributes, InvoiceItemModel } from "../sequelize";
|
import { Invoice, InvoiceItem, InvoiceItemDescription } from "../../domain";
|
||||||
|
import { InvoiceItemCreationAttributes, InvoiceItemModel, InvoiceModel } from "../sequelize";
|
||||||
|
|
||||||
export interface IInvoiceItemMapper
|
export interface IInvoiceItemMapper
|
||||||
extends ISequelizeMapper<InvoiceItemModel, InvoiceItemCreationAttributes, InvoiceItem> {}
|
extends ISequelizeMapper<InvoiceItemModel, InvoiceItemCreationAttributes, InvoiceItem> {}
|
||||||
@ -21,6 +12,25 @@ export class InvoiceItemMapper
|
|||||||
extends SequelizeMapper<InvoiceItemModel, InvoiceItemCreationAttributes, InvoiceItem>
|
extends SequelizeMapper<InvoiceItemModel, InvoiceItemCreationAttributes, InvoiceItem>
|
||||||
implements IInvoiceItemMapper
|
implements IInvoiceItemMapper
|
||||||
{
|
{
|
||||||
|
mapArrayToDomain(
|
||||||
|
source: InvoiceItemModel[],
|
||||||
|
params?: MapperParamsType
|
||||||
|
): Result<Collection<InvoiceItem>, Error> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
mapArrayAndCountToDomain(
|
||||||
|
source: InvoiceItemModel[],
|
||||||
|
totalCount: number,
|
||||||
|
params?: MapperParamsType
|
||||||
|
): Result<Collection<InvoiceItem>, Error> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
mapCollectionToPersistence(
|
||||||
|
source: Collection<InvoiceItem>,
|
||||||
|
params?: MapperParamsType
|
||||||
|
): InferCreationAttributes<InvoiceItemModel, { omit: "invoice" }>[] {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
public mapToDomain(
|
public mapToDomain(
|
||||||
source: InvoiceItemModel,
|
source: InvoiceItemModel,
|
||||||
params?: MapperParamsType
|
params?: MapperParamsType
|
||||||
@ -1,12 +1,7 @@
|
|||||||
import { Invoice, InvoiceNumber, InvoiceSerie, InvoiceStatus } from "@/contexts/invoices/domain";
|
import { ISequelizeMapper, MapperParamsType, SequelizeMapper } from "@erp/core";
|
||||||
import {
|
import { UniqueID, UtcDate } from "@repo/rdx-ddd";
|
||||||
type ISequelizeMapper,
|
import { Result } from "@repo/rdx-utils";
|
||||||
type MapperParamsType,
|
import { Invoice, InvoiceNumber, InvoiceSerie, InvoiceStatus } from "../../domain";
|
||||||
Result,
|
|
||||||
SequelizeMapper,
|
|
||||||
UniqueID,
|
|
||||||
UtcDate,
|
|
||||||
} from "@/core";
|
|
||||||
import { InvoiceCreationAttributes, InvoiceModel } from "../sequelize";
|
import { InvoiceCreationAttributes, InvoiceModel } from "../sequelize";
|
||||||
import { InvoiceItemMapper } from "./invoice-item.mapper";
|
import { InvoiceItemMapper } from "./invoice-item.mapper";
|
||||||
|
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import { Collection, Result, SequelizeRepository, UniqueID } from "@/core";
|
import { SequelizeRepository } from "@erp/core";
|
||||||
import { logger } from "@/core/logger";
|
import { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { Collection, Result } from "@repo/rdx-utils";
|
||||||
import { Sequelize, Transaction } from "sequelize";
|
import { Sequelize, Transaction } from "sequelize";
|
||||||
import { IInvoiceRepository, Invoice } from "../../domain";
|
import { IInvoiceRepository, Invoice } from "../../domain";
|
||||||
import { IInvoiceMapper } from "../mappers/invoice.mapper";
|
import { IInvoiceMapper } from "../mappers/invoice.mapper";
|
||||||
@ -37,6 +38,8 @@ export class InvoiceRepository extends SequelizeRepository<Invoice> implements I
|
|||||||
|
|
||||||
async findAll(transaction?: Transaction): Promise<Result<Collection<Invoice>, Error>> {
|
async findAll(transaction?: Transaction): Promise<Result<Collection<Invoice>, Error>> {
|
||||||
try {
|
try {
|
||||||
|
console.error(this._database.models);
|
||||||
|
|
||||||
const rawInvoices = await InvoiceModel.findAll({
|
const rawInvoices = await InvoiceModel.findAll({
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
@ -47,18 +50,11 @@ export class InvoiceRepository extends SequelizeRepository<Invoice> implements I
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
/*if (!rawInvoices === true) {
|
console.error("aqui");
|
||||||
return Result.fail(new Error("Invoice not exists"));
|
|
||||||
}*/
|
|
||||||
|
|
||||||
logger.debug({
|
|
||||||
message: "rawInvoices",
|
|
||||||
label: "InvoiceRepository",
|
|
||||||
meta: { data: rawInvoices },
|
|
||||||
});
|
|
||||||
|
|
||||||
return this._mapper.mapArrayToDomain(rawInvoices);
|
return this._mapper.mapArrayToDomain(rawInvoices);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
|
console.error("Error in findAll", error);
|
||||||
return this._handleDatabaseError(error, this._customErrorMapper);
|
return this._handleDatabaseError(error, this._customErrorMapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,8 +78,6 @@ export class InvoiceRepository extends SequelizeRepository<Invoice> implements I
|
|||||||
if (!rawInvoice === true) {
|
if (!rawInvoice === true) {
|
||||||
return Result.fail(new Error(`Invoice with id ${id.toString()} not exists`));
|
return Result.fail(new Error(`Invoice with id ${id.toString()} not exists`));
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._mapper.mapToDomain(rawInvoice);
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
return this._handleDatabaseError(error, this._customErrorMapper);
|
return this._handleDatabaseError(error, this._customErrorMapper);
|
||||||
}
|
}
|
||||||
@ -1,44 +0,0 @@
|
|||||||
import { CreateInvoiceUseCase } from "@/contexts/invoices/application/create-invoice.use-case";
|
|
||||||
import { ExpressController, UniqueID } from "@/core";
|
|
||||||
import { ICreateInvoiceRequestDTO } from "../../../../common/dto";
|
|
||||||
import { ICreateInvoicePresenter } from "./presenter";
|
|
||||||
|
|
||||||
export class CreateInvoiceController extends ExpressController {
|
|
||||||
public constructor(
|
|
||||||
private readonly createInvoice: CreateInvoiceUseCase,
|
|
||||||
private readonly presenter: ICreateInvoicePresenter
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async executeImpl() {
|
|
||||||
const createDTO: ICreateInvoiceRequestDTO = this.req.body;
|
|
||||||
|
|
||||||
// Validar ID
|
|
||||||
const invoiceIdOrError = UniqueID.create(createDTO.id);
|
|
||||||
if (invoiceIdOrError.isFailure) return this.invalidInputError("Invoice ID not valid");
|
|
||||||
|
|
||||||
const invoiceOrError = await this.createInvoice.execute(invoiceIdOrError.data, createDTO);
|
|
||||||
|
|
||||||
if (invoiceOrError.isFailure) {
|
|
||||||
return this.handleError(invoiceOrError.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.ok(this.presenter.toDTO(invoiceOrError.data));
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleError(error: Error) {
|
|
||||||
const message = error.message;
|
|
||||||
|
|
||||||
if (
|
|
||||||
message.includes("Database connection lost") ||
|
|
||||||
message.includes("Database request timed out")
|
|
||||||
) {
|
|
||||||
return this.unavailableError(
|
|
||||||
"Database service is currently unavailable. Please try again later."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.conflictError(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
import { CreateInvoiceUseCase } from "@/contexts/invoices/application/create-invoice.use-case";
|
|
||||||
import { InvoiceService } from "@/contexts/invoices/domain";
|
|
||||||
import { InvoiceRepository, invoiceMapper } from "@/contexts/invoices/intrastructure";
|
|
||||||
import { SequelizeTransactionManager } from "@/core";
|
|
||||||
import { Sequelize } from "sequelize";
|
|
||||||
import { CreateInvoiceController } from "./create-invoice.controller";
|
|
||||||
import { createInvoicePresenter } from "./presenter";
|
|
||||||
|
|
||||||
export const buildCreateInvoiceController = (database: Sequelize) => {
|
|
||||||
const transactionManager = new SequelizeTransactionManager(database);
|
|
||||||
const invoiceRepository = new InvoiceRepository(database, invoiceMapper);
|
|
||||||
const invoiceService = new InvoiceService(invoiceRepository);
|
|
||||||
|
|
||||||
const useCase = new CreateInvoiceUseCase(invoiceService, transactionManager);
|
|
||||||
const presenter = createInvoicePresenter;
|
|
||||||
|
|
||||||
return new CreateInvoiceController(useCase, presenter);
|
|
||||||
};
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
import { IInvoiceParticipant } from "@/contexts/invoicing/domain";
|
|
||||||
import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext";
|
|
||||||
import { ICreateInvoice_Participant_Response_DTO } from "@shared/contexts";
|
|
||||||
import { InvoiceParticipantAddressPresenter } from "./InvoiceParticipantAddress.presenter";
|
|
||||||
|
|
||||||
export const InvoiceParticipantPresenter = (
|
|
||||||
participant: IInvoiceParticipant,
|
|
||||||
context: IInvoicingContext,
|
|
||||||
): ICreateInvoice_Participant_Response_DTO | undefined => {
|
|
||||||
return {
|
|
||||||
id: participant.id.toString(),
|
|
||||||
tin: participant.tin.toString(),
|
|
||||||
first_name: participant.firstName.toString(),
|
|
||||||
last_name: participant.lastName.toString(),
|
|
||||||
company_name: participant.companyName.toString(),
|
|
||||||
|
|
||||||
billing_address: InvoiceParticipantAddressPresenter(
|
|
||||||
participant.billingAddress!,
|
|
||||||
context,
|
|
||||||
),
|
|
||||||
shipping_address: InvoiceParticipantAddressPresenter(
|
|
||||||
participant.shippingAddress!,
|
|
||||||
context,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
import { InvoiceParticipantAddress } from "@/contexts/invoicing/domain";
|
|
||||||
import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext";
|
|
||||||
import { ICreateInvoice_AddressParticipant_Response_DTO } from "@shared/contexts";
|
|
||||||
|
|
||||||
export const InvoiceParticipantAddressPresenter = (
|
|
||||||
address: InvoiceParticipantAddress,
|
|
||||||
context: IInvoicingContext,
|
|
||||||
): ICreateInvoice_AddressParticipant_Response_DTO => {
|
|
||||||
return {
|
|
||||||
id: address.id.toString(),
|
|
||||||
street: address.street.toString(),
|
|
||||||
city: address.city.toString(),
|
|
||||||
postal_code: address.postalCode.toString(),
|
|
||||||
province: address.province.toString(),
|
|
||||||
country: address.country.toString(),
|
|
||||||
email: address.email.toString(),
|
|
||||||
phone: address.phone.toString(),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
import { Invoice } from "@/contexts/invoices/domain";
|
|
||||||
import { ICreateInvoiceResponseDTO } from "../../../../../common/dto";
|
|
||||||
|
|
||||||
export interface ICreateInvoicePresenter {
|
|
||||||
toDTO: (invoice: Invoice) => ICreateInvoiceResponseDTO;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createInvoicePresenter: ICreateInvoicePresenter = {
|
|
||||||
toDTO: (invoice: Invoice): ICreateInvoiceResponseDTO => ({
|
|
||||||
id: invoice.id.toString(),
|
|
||||||
|
|
||||||
invoice_status: invoice.status.toString(),
|
|
||||||
invoice_number: invoice.invoiceNumber.toString(),
|
|
||||||
invoice_series: invoice.invoiceSeries.toString(),
|
|
||||||
issue_date: invoice.issueDate.toDateString(),
|
|
||||||
operation_date: invoice.operationDate.toDateString(),
|
|
||||||
language_code: "es",
|
|
||||||
currency: invoice.invoiceCurrency || "EUR",
|
|
||||||
subtotal: invoice.calculateSubtotal().toPrimitive(),
|
|
||||||
total: invoice.calculateTotal().toPrimitive(),
|
|
||||||
|
|
||||||
//sender: {}, //await InvoiceParticipantPresenter(invoice.senderId, context),
|
|
||||||
|
|
||||||
//customer: InvoiceParticipantPresenter(invoice.recipient, context),
|
|
||||||
|
|
||||||
//items: invoiceItemPresenter(invoice.items, context),
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export * from "./create-invoice.presenter";
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
//export * from "./create-invoice";
|
|
||||||
//export * from "./delete-invoice";
|
|
||||||
export * from "./get-invoice";
|
|
||||||
export * from "./list-invoices";
|
|
||||||
///export * from "./update-invoice";
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
import { InvoiceItem } from "@/contexts/invoicing/domain/InvoiceItems";
|
|
||||||
import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext";
|
|
||||||
import { ICollection, IMoney_Response_DTO } from "@shared/contexts";
|
|
||||||
|
|
||||||
export const invoiceItemPresenter = (
|
|
||||||
items: ICollection<InvoiceItem>,
|
|
||||||
context: IInvoicingContext
|
|
||||||
) =>
|
|
||||||
items.totalCount > 0
|
|
||||||
? items.items.map((item: InvoiceItem) => ({
|
|
||||||
description: item.description.toString(),
|
|
||||||
quantity: item.quantity.toString(),
|
|
||||||
unit_measure: "",
|
|
||||||
unit_price: item.unitPrice.toPrimitive() as IMoney_Response_DTO,
|
|
||||||
subtotal: item.calculateSubtotal().toPrimitive() as IMoney_Response_DTO,
|
|
||||||
tax_amount: item.calculateTaxAmount().toPrimitive() as IMoney_Response_DTO,
|
|
||||||
total: item.calculateTotal().toPrimitive() as IMoney_Response_DTO,
|
|
||||||
}))
|
|
||||||
: [];
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user