.
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";
|
||||
|
||||
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 { 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 bcrypt from "bcrypt";
|
||||
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 { 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 { 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 { 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";
|
||||
|
||||
interface IInvoiceStatusProps {
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
"build": "tsc && tsup",
|
||||
"dev": "node --import=tsx --watch src/index.ts",
|
||||
"start:dev": "node --import=tsx --watch src/index.ts",
|
||||
"start:prod": "node dist/index.js",
|
||||
"clean": "rm -rf dist node_modules",
|
||||
@ -41,6 +42,7 @@
|
||||
"dependencies": {
|
||||
"@erp/auth": "workspace:*",
|
||||
"@erp/core": "workspace:*",
|
||||
"@erp/invoices": "workspace:*",
|
||||
"bcrypt": "^5.1.1",
|
||||
"cls-rtracer": "^2.6.3",
|
||||
"cors": "^2.8.5",
|
||||
@ -49,9 +51,7 @@
|
||||
"express": "^4.18.2",
|
||||
"helmet": "^8.0.0",
|
||||
"http": "0.0.1-security",
|
||||
"http-status": "^2.1.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"libphonenumber-js": "^1.11.20",
|
||||
"luxon": "^3.5.0",
|
||||
"module-alias": "^2.2.3",
|
||||
"mysql2": "^3.12.0",
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { globalErrorHandler } from "@erp/core";
|
||||
//import { initPackages } from "@/core/package-loader";
|
||||
import dotenv from "dotenv";
|
||||
import express, { Application } from "express";
|
||||
import helmet from "helmet";
|
||||
import responseTime from "response-time";
|
||||
import { globalErrorHandler } from "./core/common/presentation";
|
||||
import { logger } from "./core/logger";
|
||||
import { logger } from "./lib/logger";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { logger } from "@/core/logger";
|
||||
import { logger } from "@/lib/logger";
|
||||
import dotenv from "dotenv";
|
||||
import { Sequelize } from "sequelize";
|
||||
import { registerModels } from "./register-models";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
@ -50,20 +49,19 @@ export async function tryConnectToDatabase() {
|
||||
|
||||
if (!database) {
|
||||
const error = new Error("❌ Database not found.");
|
||||
logger.error({
|
||||
message: error.message,
|
||||
logger.error(error.message, {
|
||||
label: "tryConnectToDatabase",
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
logger.info({ message: `🔸 Connecting to database...`, label: "tryConnectToDatabase" });
|
||||
logger.info("🔸 Connecting to database...", {
|
||||
label: "tryConnectToDatabase",
|
||||
});
|
||||
|
||||
try {
|
||||
await database.authenticate();
|
||||
await registerModels(database);
|
||||
|
||||
logger.info({
|
||||
message: `✔️${" "}Database connection established successfully.`,
|
||||
logger.info(`✔️${" "}Database connection established successfully.`, {
|
||||
label: "tryConnectToDatabase",
|
||||
meta: {
|
||||
host: process.env.DB_HOST,
|
||||
@ -74,8 +72,7 @@ export async function tryConnectToDatabase() {
|
||||
});
|
||||
return database;
|
||||
} catch (error) {
|
||||
logger.error({
|
||||
message: `❌ Unable to connect to the database: ${(error as Error).message}`,
|
||||
logger.error(`❌ Unable to connect to the database: ${(error as Error).message}`, {
|
||||
error,
|
||||
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 "./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 os from "node:os";
|
||||
import { logger } from "@/core/logger";
|
||||
import { DateTime } from "luxon";
|
||||
import { createApp } from "./app";
|
||||
import { ENV } from "./config";
|
||||
import { tryConnectToDatabase } from "./config/database";
|
||||
import { initModules } from "./core/helpers";
|
||||
import { initModules } from "./lib/modules";
|
||||
import { registerModules } from "./register-modules";
|
||||
|
||||
// Guardamos información del estado del servidor
|
||||
@ -91,7 +91,7 @@ const server = http
|
||||
})
|
||||
)
|
||||
.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("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}`);
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
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);
|
||||
//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 { registerModule } from "./core/helpers";
|
||||
//import { authAPIModule } from "@erp/auth";
|
||||
import { invoicesAPIModule } from "@erp/invoices";
|
||||
import { registerModule } from "./lib/modules";
|
||||
|
||||
export const registerModules = () => {
|
||||
//registerPackage(ContactsPackage);
|
||||
registerModule(authAPIModule);
|
||||
//registerModule(authAPIModule);
|
||||
registerModule(invoicesAPIModule);
|
||||
};
|
||||
|
||||
@ -9,12 +9,6 @@
|
||||
"outDir": "dist"
|
||||
},
|
||||
//"files": ["src/index.ts"], // Esta opción compila sólo los archivos listados (y sus dependencias importadas).
|
||||
"include": [
|
||||
"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"
|
||||
],
|
||||
"include": ["src"],
|
||||
"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 { logger } = params;
|
||||
//invoicesRouter(params);
|
||||
logger.info({ message: "🚀 Auth module initialized", label: "invoices" });
|
||||
logger.info("🚀 Auth module initialized", { label: "auth" });
|
||||
},
|
||||
registerDependencies(params: ModuleParams) {
|
||||
const { database, logger } = params;
|
||||
logger.info({ message: "🚀 Auth module dependencies registered", label: "invoices" });
|
||||
logger.info("🚀 Auth module dependencies registered", { label: "auth" });
|
||||
return {
|
||||
//models,
|
||||
services: {
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
"./components/*": "./src/web/components/*.tsx"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"express": "^4.18.2",
|
||||
"joi": "^17.13.3",
|
||||
"react": "^18 || ^19",
|
||||
"react-dom": "^18 || ^19",
|
||||
@ -20,17 +21,22 @@
|
||||
"@biomejs/biome": "1.9.4",
|
||||
"@testing-library/react-hooks": "^8.0.1",
|
||||
"@types/axios": "^0.14.4",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/jest": "29.5.14",
|
||||
"@types/react": "^19.1.2",
|
||||
"@types/react-dom": "^19.1.3",
|
||||
"typescript": "^5.8.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@repo/rdx-ddd": "workspace:*",
|
||||
"@repo/rdx-utils": "workspace:*",
|
||||
"@repo/rdx-criteria": "workspace:*",
|
||||
"@tanstack/react-query": "^5.75.4",
|
||||
"axios": "^1.9.0",
|
||||
"express": "^4.18.2",
|
||||
"http-status": "^2.1.0",
|
||||
"joi": "^17.13.3",
|
||||
"libphonenumber-js": "^1.11.20",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-router-dom": "^6.26.0",
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
export * from "./dto";
|
||||
export * from "./infrastructure";
|
||||
export * from "./logger";
|
||||
export * from "./modules";
|
||||
export * from "./dto";
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { logger } from "@/core/logger";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import httpStatus from "http-status";
|
||||
import { ApiError } from "./api-error";
|
||||
@ -9,7 +8,6 @@ export abstract class ExpressController {
|
||||
protected next!: NextFunction;
|
||||
|
||||
static errorResponse(apiError: ApiError, res: Response) {
|
||||
logger.error(`[${apiError.status}] ${apiError.title}: ${apiError.detail}`);
|
||||
return res.status(apiError.status).json(apiError);
|
||||
}
|
||||
|
||||
@ -159,7 +157,6 @@ export abstract class ExpressController {
|
||||
this.executeImpl();
|
||||
} catch (error: unknown) {
|
||||
const _error = error as Error;
|
||||
logger.error(`Unhandled error in controller: ${_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 { 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 { Model } from "sequelize";
|
||||
|
||||
@ -50,6 +50,10 @@ export abstract class SequelizeMapper<
|
||||
params?: MapperParamsType
|
||||
): Result<Collection<TEntity>, Error> {
|
||||
try {
|
||||
if (source.length === 0) {
|
||||
return Result.ok(new Collection([], totalCount));
|
||||
}
|
||||
|
||||
const items = source.map(
|
||||
(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 { ModelDefined, Sequelize, Transaction } from "sequelize";
|
||||
import { logger } from "../logger";
|
||||
|
||||
export abstract class SequelizeRepository<T> implements IAggregateRootRepository<T> {
|
||||
protected readonly _database!: Sequelize;
|
||||
@ -141,7 +140,7 @@ export abstract class SequelizeRepository<T> implements IAggregateRootRepository
|
||||
): Result<never, 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
|
||||
if (errorMapper) {
|
||||
@ -2,4 +2,5 @@ export interface ILogger {
|
||||
info(message: string, meta?: any): void;
|
||||
warn(message: string, meta?: any): void;
|
||||
error(message: string, error?: Error | any): void;
|
||||
debug(message: string, meta?: any): void;
|
||||
}
|
||||
|
||||
@ -16,25 +16,33 @@
|
||||
"peerDependencies": {
|
||||
"ag-grid-community": "^33.3.0",
|
||||
"ag-grid-react": "^33.3.0",
|
||||
"express": "^4.18.2",
|
||||
"i18next": "^25.1.1",
|
||||
"lucide-react": "^0.503.0",
|
||||
"react": "^18 || ^19",
|
||||
"react-dom": "^18 || ^19",
|
||||
"react-i18next": "^15.5.1",
|
||||
"react-router-dom": "^6.26.0"
|
||||
"react-router-dom": "^6.26.0",
|
||||
"sequelize": "^6.37.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "1.9.4",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/react": "^19.1.2",
|
||||
"@types/react-dom": "^19.1.3",
|
||||
"@types/react-i18next": "^8.1.0",
|
||||
"sequelize": "^6.37.5",
|
||||
"typescript": "^5.8.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@erp/core": "workspace:*",
|
||||
"@repo/rdx-ddd": "workspace:*",
|
||||
"@repo/rdx-utils": "workspace:*",
|
||||
"@repo/rdx-ui": "workspace:*",
|
||||
"@repo/shadcn-ui": "workspace:*",
|
||||
"ag-grid-community": "^33.3.0",
|
||||
"ag-grid-react": "^33.3.0",
|
||||
"express": "^4.18.2",
|
||||
"i18next": "^25.1.1",
|
||||
"lucide-react": "^0.503.0",
|
||||
"react": "^19.1.0",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { UniqueID } from "@/core/common/domain";
|
||||
import { ITransactionManager } from "@/core/common/infrastructure/database";
|
||||
import { logger } from "@/core/logger";
|
||||
import { logger } from "@/lib/logger";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { IInvoiceService, Invoice } from "../domain";
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
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 { 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 { InvoiceCustomer, InvoiceItem, InvoiceItems } from "../entities";
|
||||
import { InvoiceNumber, InvoiceSerie, InvoiceStatus } from "../value-objects";
|
||||
|
||||
@ -1,9 +1,4 @@
|
||||
import {
|
||||
type EmailAddress,
|
||||
type Name,
|
||||
type PostalAddress,
|
||||
ValueObject,
|
||||
} from "@/core/common/domain";
|
||||
import { EmailAddress, Name, PostalAddress, ValueObject } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { PhoneNumber } from "libphonenumber-js";
|
||||
import { InvoiceAddressType } from "../../value-objects";
|
||||
@ -26,12 +21,12 @@ export interface IInvoiceAddress {
|
||||
|
||||
export class InvoiceAddress extends ValueObject<IInvoiceAddressProps> implements IInvoiceAddress {
|
||||
public static create(props: IInvoiceAddressProps) {
|
||||
return Result.ok(new this(props));
|
||||
return Result.ok(new InvoiceAddress(props));
|
||||
}
|
||||
|
||||
public static createShippingAddress(props: IInvoiceAddressProps) {
|
||||
return Result.ok(
|
||||
new this({
|
||||
new InvoiceAddress({
|
||||
...props,
|
||||
type: InvoiceAddressType.create("shipping").data,
|
||||
})
|
||||
@ -40,7 +35,7 @@ export class InvoiceAddress extends ValueObject<IInvoiceAddressProps> implements
|
||||
|
||||
public static createBillingAddress(props: IInvoiceAddressProps) {
|
||||
return Result.ok(
|
||||
new this({
|
||||
new InvoiceAddress({
|
||||
...props,
|
||||
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 { 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 { 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";
|
||||
|
||||
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 { 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 { 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 { 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";
|
||||
|
||||
interface IInvoiceStatusProps {
|
||||
@ -22,7 +22,7 @@ export class InvoiceStatus extends ValueObject<IInvoiceStatusProps> {
|
||||
};
|
||||
|
||||
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}`));
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { IModuleServer, ModuleParams } from "@erp/core";
|
||||
import { invoicesRouter, models } from "./infrastructure";
|
||||
|
||||
export const invoicesModule: IModuleServer = {
|
||||
export const invoicesAPIModule: IModuleServer = {
|
||||
metadata: {
|
||||
name: "invoices",
|
||||
version: "1.0.0",
|
||||
@ -9,14 +10,14 @@ export const invoicesModule: IModuleServer = {
|
||||
init(params: ModuleParams) {
|
||||
// const contacts = getService<ContactsService>("contacts");
|
||||
const { logger } = params;
|
||||
//invoicesRouter(params);
|
||||
logger.info({ message: "🚀 Invoices module initialized", label: "invoices" });
|
||||
invoicesRouter(params);
|
||||
logger.info("🚀 Invoices module initialized", { label: "invoices" });
|
||||
},
|
||||
registerDependencies(params) {
|
||||
const { database, logger } = params;
|
||||
logger.info({ message: "🚀 Invoices module dependencies registered", label: "invoices" });
|
||||
logger.info("🚀 Invoices module dependencies registered", { label: "invoices" });
|
||||
return {
|
||||
//models,
|
||||
models,
|
||||
services: {
|
||||
getInvoice: () => {},
|
||||
/*...*/
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { ModuleParams } from "@/core";
|
||||
import { ModuleParams } from "@erp/core";
|
||||
import { Application, NextFunction, Request, Response, Router } from "express";
|
||||
import { Sequelize } from "sequelize";
|
||||
import { buildGetInvoiceController, buildListInvoicesController } from "../../presentation";
|
||||
import { buildListInvoicesController } from "../../presentation";
|
||||
|
||||
export const invoicesRouter = (params: ModuleParams) => {
|
||||
const { app, database, baseRoutePath } = params as {
|
||||
@ -21,14 +21,14 @@ export const invoicesRouter = (params: ModuleParams) => {
|
||||
}
|
||||
);
|
||||
|
||||
routes.get(
|
||||
/*routes.get(
|
||||
"/:invoiceId",
|
||||
//checkTabContext,
|
||||
//checkUser,
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
buildGetInvoiceController(database).execute(req, res, next);
|
||||
}
|
||||
);
|
||||
);*/
|
||||
|
||||
/*routes.post(
|
||||
"/",
|
||||
@ -1,18 +1,9 @@
|
||||
import { Invoice, InvoiceItem, InvoiceItemDescription } from "@/contexts/invoices/domain";
|
||||
import {
|
||||
type ISequelizeMapper,
|
||||
type MapperParamsType,
|
||||
MoneyValue,
|
||||
Percentage,
|
||||
Quantity,
|
||||
Result,
|
||||
SequelizeMapper,
|
||||
UniqueID,
|
||||
} from "@/core";
|
||||
import { InvoiceModel } from "../sequelize";
|
||||
|
||||
import { ISequelizeMapper, MapperParamsType, SequelizeMapper } from "@erp/core";
|
||||
import { MoneyValue, Percentage, Quantity, UniqueID } from "@repo/rdx-ddd";
|
||||
import { Collection, Result } from "@repo/rdx-utils";
|
||||
import { InferCreationAttributes } from "sequelize";
|
||||
import { InvoiceItemCreationAttributes, InvoiceItemModel } from "../sequelize";
|
||||
import { Invoice, InvoiceItem, InvoiceItemDescription } from "../../domain";
|
||||
import { InvoiceItemCreationAttributes, InvoiceItemModel, InvoiceModel } from "../sequelize";
|
||||
|
||||
export interface IInvoiceItemMapper
|
||||
extends ISequelizeMapper<InvoiceItemModel, InvoiceItemCreationAttributes, InvoiceItem> {}
|
||||
@ -21,6 +12,25 @@ export class InvoiceItemMapper
|
||||
extends SequelizeMapper<InvoiceItemModel, InvoiceItemCreationAttributes, InvoiceItem>
|
||||
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(
|
||||
source: InvoiceItemModel,
|
||||
params?: MapperParamsType
|
||||
@ -1,12 +1,7 @@
|
||||
import { Invoice, InvoiceNumber, InvoiceSerie, InvoiceStatus } from "@/contexts/invoices/domain";
|
||||
import {
|
||||
type ISequelizeMapper,
|
||||
type MapperParamsType,
|
||||
Result,
|
||||
SequelizeMapper,
|
||||
UniqueID,
|
||||
UtcDate,
|
||||
} from "@/core";
|
||||
import { ISequelizeMapper, MapperParamsType, SequelizeMapper } from "@erp/core";
|
||||
import { UniqueID, UtcDate } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { Invoice, InvoiceNumber, InvoiceSerie, InvoiceStatus } from "../../domain";
|
||||
import { InvoiceCreationAttributes, InvoiceModel } from "../sequelize";
|
||||
import { InvoiceItemMapper } from "./invoice-item.mapper";
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Collection, Result, SequelizeRepository, UniqueID } from "@/core";
|
||||
import { logger } from "@/core/logger";
|
||||
import { SequelizeRepository } from "@erp/core";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Collection, Result } from "@repo/rdx-utils";
|
||||
import { Sequelize, Transaction } from "sequelize";
|
||||
import { IInvoiceRepository, Invoice } from "../../domain";
|
||||
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>> {
|
||||
try {
|
||||
console.error(this._database.models);
|
||||
|
||||
const rawInvoices = await InvoiceModel.findAll({
|
||||
include: [
|
||||
{
|
||||
@ -47,18 +50,11 @@ export class InvoiceRepository extends SequelizeRepository<Invoice> implements I
|
||||
transaction,
|
||||
});
|
||||
|
||||
/*if (!rawInvoices === true) {
|
||||
return Result.fail(new Error("Invoice not exists"));
|
||||
}*/
|
||||
|
||||
logger.debug({
|
||||
message: "rawInvoices",
|
||||
label: "InvoiceRepository",
|
||||
meta: { data: rawInvoices },
|
||||
});
|
||||
console.error("aqui");
|
||||
|
||||
return this._mapper.mapArrayToDomain(rawInvoices);
|
||||
} catch (error: unknown) {
|
||||
console.error("Error in findAll", error);
|
||||
return this._handleDatabaseError(error, this._customErrorMapper);
|
||||
}
|
||||
}
|
||||
@ -82,8 +78,6 @@ export class InvoiceRepository extends SequelizeRepository<Invoice> implements I
|
||||
if (!rawInvoice === true) {
|
||||
return Result.fail(new Error(`Invoice with id ${id.toString()} not exists`));
|
||||
}
|
||||
|
||||
return this._mapper.mapToDomain(rawInvoice);
|
||||
} catch (error: any) {
|
||||
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