Compare commits
No commits in common. "55b8bb847316a5dd63ec720a8090979b8ce247d3" and "6187a77dd920ba3725ddf0e44acd33b79805156e" have entirely different histories.
55b8bb8473
...
6187a77dd9
@ -33,8 +33,8 @@
|
|||||||
"typescript": "^6.0.2"
|
"typescript": "^6.0.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@erp/auth": "workspace:*",
|
||||||
"@erp/core": "workspace:*",
|
"@erp/core": "workspace:*",
|
||||||
"@erp/identity": "workspace:*",
|
|
||||||
"@repo/i18next": "workspace:*",
|
"@repo/i18next": "workspace:*",
|
||||||
"@repo/rdx-criteria": "workspace:*",
|
"@repo/rdx-criteria": "workspace:*",
|
||||||
"@repo/rdx-ddd": "workspace:*",
|
"@repo/rdx-ddd": "workspace:*",
|
||||||
@ -52,4 +52,4 @@
|
|||||||
"use-debounce": "^10.1.1",
|
"use-debounce": "^10.1.1",
|
||||||
"zod": "^4.3.6"
|
"zod": "^4.3.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -27,7 +27,7 @@ export type CatalogsPublicServicesType = ReturnType<typeof buildCatalogsPublicSe
|
|||||||
export const catalogsAPIModule: IModuleServer = {
|
export const catalogsAPIModule: IModuleServer = {
|
||||||
name: "catalogs",
|
name: "catalogs",
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
dependencies: ["identity"],
|
dependencies: [],
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fase de SETUP
|
* Fase de SETUP
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
export * from "./express";
|
|
||||||
export * from "./payment-methods";
|
export * from "./payment-methods";
|
||||||
export * from "./payment-terms";
|
export * from "./payment-terms";
|
||||||
export * from "./tax-definitions";
|
export * from "./tax-definitions";
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type StartParams, validateRequest } from "@erp/core/api";
|
import { mockUser, requireAuthenticated, requireCompanyContext } from "@erp/auth/api";
|
||||||
import { requireIdentityTenant } from "@erp/identity/api";
|
import { type RequestWithAuth, type StartParams, validateRequest } from "@erp/core/api";
|
||||||
import { type NextFunction, type Request, type Response, Router } from "express";
|
import { type NextFunction, type Request, type Response, Router } from "express";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -30,7 +30,21 @@ export const paymentMethodsRouter = (params: StartParams) => {
|
|||||||
|
|
||||||
// ----------------------------------------------
|
// ----------------------------------------------
|
||||||
|
|
||||||
router.use(...requireIdentityTenant(params));
|
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "production") {
|
||||||
|
// 🔐 Autenticación + Tenancy para TODO el router
|
||||||
|
router.use(
|
||||||
|
(req: Request, res: Response, next: NextFunction) =>
|
||||||
|
mockUser(req as RequestWithAuth, res, next) // Debe ir antes de las rutas protegidas
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
router.use([
|
||||||
|
(req: Request, res: Response, next: NextFunction) =>
|
||||||
|
requireAuthenticated()(req as RequestWithAuth, res, next), // Debe ir antes de las rutas protegidas
|
||||||
|
|
||||||
|
(req: Request, res: Response, next: NextFunction) =>
|
||||||
|
requireCompanyContext()(req as RequestWithAuth, res, next), // Debe ir antes de las rutas protegidas
|
||||||
|
]);
|
||||||
|
|
||||||
// ----------------------------------------------
|
// ----------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type StartParams, validateRequest } from "@erp/core/api";
|
import { mockUser, requireAuthenticated, requireCompanyContext } from "@erp/auth/api";
|
||||||
import { requireIdentityTenant } from "@erp/identity/api";
|
import { type RequestWithAuth, type StartParams, validateRequest } from "@erp/core/api";
|
||||||
import type { NextFunction, Request, Response } from "express";
|
import type { NextFunction, Request, Response } from "express";
|
||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
|
|
||||||
@ -29,7 +29,18 @@ export const paymentTermsRouter = (params: StartParams) => {
|
|||||||
|
|
||||||
const router = Router({ mergeParams: true });
|
const router = Router({ mergeParams: true });
|
||||||
|
|
||||||
router.use(...requireIdentityTenant(params));
|
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "production") {
|
||||||
|
router.use((req: Request, res: Response, next: NextFunction) =>
|
||||||
|
mockUser(req as RequestWithAuth, res, next)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
router.use([
|
||||||
|
(req: Request, res: Response, next: NextFunction) =>
|
||||||
|
requireAuthenticated()(req as RequestWithAuth, res, next),
|
||||||
|
(req: Request, res: Response, next: NextFunction) =>
|
||||||
|
requireCompanyContext()(req as RequestWithAuth, res, next),
|
||||||
|
]);
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
"/",
|
"/",
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type StartParams, validateRequest } from "@erp/core/api";
|
import { mockUser, requireAuthenticated, requireCompanyContext } from "@erp/auth/api";
|
||||||
import { requireIdentityTenant } from "@erp/identity/api";
|
import { type RequestWithAuth, type StartParams, validateRequest } from "@erp/core/api";
|
||||||
import type { NextFunction, Request, Response } from "express";
|
import type { NextFunction, Request, Response } from "express";
|
||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
|
|
||||||
@ -29,7 +29,18 @@ export const taxDefinitionsRouter = (params: StartParams) => {
|
|||||||
|
|
||||||
const router = Router({ mergeParams: true });
|
const router = Router({ mergeParams: true });
|
||||||
|
|
||||||
router.use(...requireIdentityTenant(params));
|
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "production") {
|
||||||
|
router.use((req: Request, res: Response, next: NextFunction) =>
|
||||||
|
mockUser(req as RequestWithAuth, res, next)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
router.use([
|
||||||
|
(req: Request, res: Response, next: NextFunction) =>
|
||||||
|
requireAuthenticated()(req as RequestWithAuth, res, next),
|
||||||
|
(req: Request, res: Response, next: NextFunction) =>
|
||||||
|
requireCompanyContext()(req as RequestWithAuth, res, next),
|
||||||
|
]);
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
"/",
|
"/",
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type StartParams, validateRequest } from "@erp/core/api";
|
import { mockUser, requireAuthenticated, requireCompanyContext } from "@erp/auth/api";
|
||||||
import { requireIdentityTenant } from "@erp/identity/api";
|
import { type RequestWithAuth, type StartParams, validateRequest } from "@erp/core/api";
|
||||||
import type { NextFunction, Request, Response } from "express";
|
import type { NextFunction, Request, Response } from "express";
|
||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
|
|
||||||
@ -29,7 +29,18 @@ export const taxRegimesRouter = (params: StartParams) => {
|
|||||||
|
|
||||||
const router = Router({ mergeParams: true });
|
const router = Router({ mergeParams: true });
|
||||||
|
|
||||||
router.use(...requireIdentityTenant(params));
|
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "production") {
|
||||||
|
router.use((req: Request, res: Response, next: NextFunction) =>
|
||||||
|
mockUser(req as RequestWithAuth, res, next)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
router.use([
|
||||||
|
(req: Request, res: Response, next: NextFunction) =>
|
||||||
|
requireAuthenticated()(req as RequestWithAuth, res, next),
|
||||||
|
(req: Request, res: Response, next: NextFunction) =>
|
||||||
|
requireCompanyContext()(req as RequestWithAuth, res, next),
|
||||||
|
]);
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
"/",
|
"/",
|
||||||
|
|||||||
@ -81,23 +81,11 @@ export const useCreateProformaController = (options?: UseCreateProformaControlle
|
|||||||
|
|
||||||
const setCustomer = (customer: CustomerSelectionOption) => {
|
const setCustomer = (customer: CustomerSelectionOption) => {
|
||||||
setSelectedCustomer(customer);
|
setSelectedCustomer(customer);
|
||||||
|
|
||||||
// Necesitamos consultar todos los datos del cliente para
|
|
||||||
// poder rellenar los campos de la proforma
|
|
||||||
|
|
||||||
form.setValue("customerId", customer.id, {
|
form.setValue("customerId", customer.id, {
|
||||||
shouldDirty: true,
|
shouldDirty: true,
|
||||||
shouldTouch: true,
|
shouldTouch: true,
|
||||||
shouldValidate: true,
|
shouldValidate: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
/*form.setValue("")
|
|
||||||
|
|
||||||
form.setValue("taxRegimeCode", customer.taxRegimeCode ?? "", {
|
|
||||||
shouldDirty: true,
|
|
||||||
shouldTouch: true,
|
|
||||||
shouldValidate: true,
|
|
||||||
});*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearCustomer = () => {
|
const clearCustomer = () => {
|
||||||
|
|||||||
@ -6,7 +6,7 @@ export const buildProformaCreateDefault = (): ProformaCreateForm => {
|
|||||||
return {
|
return {
|
||||||
customerId: "",
|
customerId: "",
|
||||||
invoiceDate: DateHelper.buildTodayIsoDate(),
|
invoiceDate: DateHelper.buildTodayIsoDate(),
|
||||||
series: "F26",
|
series: "",
|
||||||
languageCode: "es",
|
languageCode: "es",
|
||||||
currencyCode: "EUR",
|
currencyCode: "EUR",
|
||||||
};
|
};
|
||||||
|
|||||||
@ -34,9 +34,9 @@
|
|||||||
"typescript": "^6.0.2"
|
"typescript": "^6.0.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@erp/catalogs": "workspace:*",
|
"@erp/auth": "workspace:*",
|
||||||
"@erp/core": "workspace:*",
|
"@erp/core": "workspace:*",
|
||||||
"@erp/identity": "workspace:*",
|
"@erp/catalogs": "workspace:*",
|
||||||
"@hookform/resolvers": "^5.2.2",
|
"@hookform/resolvers": "^5.2.2",
|
||||||
"@repo/i18next": "workspace:*",
|
"@repo/i18next": "workspace:*",
|
||||||
"@repo/rdx-criteria": "workspace:*",
|
"@repo/rdx-criteria": "workspace:*",
|
||||||
@ -56,4 +56,4 @@
|
|||||||
"use-debounce": "^10.1.1",
|
"use-debounce": "^10.1.1",
|
||||||
"zod": "^4.3.6"
|
"zod": "^4.3.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -10,7 +10,7 @@ export * from "./infrastructure/persistence/sequelize";
|
|||||||
export const customersAPIModule: IModuleServer = {
|
export const customersAPIModule: IModuleServer = {
|
||||||
name: "customers",
|
name: "customers",
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
dependencies: ["catalogs", "identity"],
|
dependencies: ["catalogs"],
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fase de SETUP
|
* Fase de SETUP
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type StartParams, validateRequest } from "@erp/core/api";
|
import { mockUser, requireAuthenticated, requireCompanyContext } from "@erp/auth/api";
|
||||||
import { requireIdentityTenant } from "@erp/identity/api";
|
import { type RequestWithAuth, type StartParams, validateRequest } from "@erp/core/api";
|
||||||
import { type NextFunction, type Request, type Response, Router } from "express";
|
import { type NextFunction, type Request, type Response, Router } from "express";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -29,7 +29,21 @@ export const customersRouter = (params: StartParams) => {
|
|||||||
// ----------------------------------------------
|
// ----------------------------------------------
|
||||||
|
|
||||||
// 🔐 Autenticación + Tenancy para TODO el router
|
// 🔐 Autenticación + Tenancy para TODO el router
|
||||||
router.use(...requireIdentityTenant(params));
|
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "production") {
|
||||||
|
router.use(
|
||||||
|
(req: Request, res: Response, next: NextFunction) =>
|
||||||
|
mockUser(req as RequestWithAuth, res, next) // Debe ir antes de las rutas protegidas
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//router.use(/*authenticateJWT(),*/ enforceTenant() /*checkTabContext*/);
|
||||||
|
router.use([
|
||||||
|
(req: Request, res: Response, next: NextFunction) =>
|
||||||
|
requireAuthenticated()(req as RequestWithAuth, res, next), // Debe ir antes de las rutas protegidas
|
||||||
|
|
||||||
|
(req: Request, res: Response, next: NextFunction) =>
|
||||||
|
requireCompanyContext()(req as RequestWithAuth, res, next), // Debe ir antes de las rutas protegidas
|
||||||
|
]);
|
||||||
|
|
||||||
// ----------------------------------------------
|
// ----------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@ -2,9 +2,6 @@
|
|||||||
* Representa un cliente seleccionable desde cualquier módulo.
|
* Representa un cliente seleccionable desde cualquier módulo.
|
||||||
* Debe ser lo suficientemente rico para mostrar en UI,
|
* Debe ser lo suficientemente rico para mostrar en UI,
|
||||||
* pero sin arrastrar todo el shape de Customer.
|
* pero sin arrastrar todo el shape de Customer.
|
||||||
*
|
|
||||||
* No usar objetos de dominio, todo tipos primitivos y strings,
|
|
||||||
* para desacoplar de la capa de dominio.
|
|
||||||
*/
|
*/
|
||||||
export interface CustomerSelectionOption {
|
export interface CustomerSelectionOption {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
export * from "./use-get-customer-controller";
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
import { useCustomerGetQuery } from "../../../../web/shared";
|
|
||||||
import { buildCustomerData } from "../utils";
|
|
||||||
|
|
||||||
export const useGetCustomerController = (customerId: string, options?: { enabled?: boolean }) => {
|
|
||||||
const {
|
|
||||||
data,
|
|
||||||
isLoading,
|
|
||||||
isError: isLoadError,
|
|
||||||
error: loadError,
|
|
||||||
refetch,
|
|
||||||
} = useCustomerGetQuery({
|
|
||||||
id: customerId,
|
|
||||||
enabled: options?.enabled ?? true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const customerData = data ? buildCustomerData(data) : undefined;
|
|
||||||
|
|
||||||
return {
|
|
||||||
customerData,
|
|
||||||
isLoading,
|
|
||||||
isLoadError,
|
|
||||||
loadError,
|
|
||||||
|
|
||||||
refetch,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
/**
|
|
||||||
* Representa un cliente con todo el shape de Customer.
|
|
||||||
*
|
|
||||||
* No usar objetos de dominio, todo tipos primitivos y strings,
|
|
||||||
* para desacoplar de la capa de dominio.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export interface CustomerData {
|
|
||||||
id: string;
|
|
||||||
status: string;
|
|
||||||
reference: string | null;
|
|
||||||
|
|
||||||
isCompany: boolean;
|
|
||||||
name: string;
|
|
||||||
tradeName: string | null;
|
|
||||||
tin: string | null;
|
|
||||||
|
|
||||||
address: {
|
|
||||||
street: string | null;
|
|
||||||
street2: string | null;
|
|
||||||
city: string | null;
|
|
||||||
province: string | null;
|
|
||||||
postalCode: string | null;
|
|
||||||
country: string | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
contact: {
|
|
||||||
emailPrimary: string | null;
|
|
||||||
emailSecondary: string | null;
|
|
||||||
phonePrimary: string | null;
|
|
||||||
phoneSecondary: string | null;
|
|
||||||
mobilePrimary: string | null;
|
|
||||||
mobileSecondary: string | null;
|
|
||||||
|
|
||||||
fax: string | null;
|
|
||||||
website: string | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
legalRecord: string | null;
|
|
||||||
|
|
||||||
paymentMethod: {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
} | null;
|
|
||||||
|
|
||||||
paymentTerm: {
|
|
||||||
id: string;
|
|
||||||
description: string;
|
|
||||||
} | null;
|
|
||||||
|
|
||||||
taxRegime: {
|
|
||||||
code: string;
|
|
||||||
description: string;
|
|
||||||
} | null;
|
|
||||||
|
|
||||||
fiscalDefaults: {
|
|
||||||
usesEquivalenceSurcharge: boolean;
|
|
||||||
usesRetention: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
languageCode: string;
|
|
||||||
currencyCode: string;
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export * from './customer-data.entity';
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export * from "./controllers";
|
|
||||||
@ -1,71 +0,0 @@
|
|||||||
import type { Customer } from "../../../../web/shared";
|
|
||||||
import type { CustomerData } from "../entities";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mapper explícito para desacoplar UI del shape de customers/shared.
|
|
||||||
*/
|
|
||||||
export const buildCustomerData = (customer: Customer): CustomerData => {
|
|
||||||
return {
|
|
||||||
id: customer.id,
|
|
||||||
status: customer.status,
|
|
||||||
reference: customer.reference,
|
|
||||||
|
|
||||||
isCompany: customer.isCompany,
|
|
||||||
name: customer.name,
|
|
||||||
tradeName: customer.tradeName,
|
|
||||||
tin: customer.tin,
|
|
||||||
|
|
||||||
address: {
|
|
||||||
street: customer.address.street,
|
|
||||||
street2: null,
|
|
||||||
city: customer.address.city,
|
|
||||||
province: customer.address.province,
|
|
||||||
postalCode: customer.address.postalCode,
|
|
||||||
country: customer.address.country,
|
|
||||||
},
|
|
||||||
|
|
||||||
contact: {
|
|
||||||
emailPrimary: customer.contact.primaryEmail,
|
|
||||||
emailSecondary: customer.contact.secondaryEmail,
|
|
||||||
phonePrimary: customer.contact.primaryPhone,
|
|
||||||
phoneSecondary: customer.contact.secondaryPhone,
|
|
||||||
mobilePrimary: customer.contact.primaryMobile,
|
|
||||||
mobileSecondary: customer.contact.secondaryMobile,
|
|
||||||
|
|
||||||
fax: customer.contact.fax,
|
|
||||||
website: customer.contact.website,
|
|
||||||
},
|
|
||||||
|
|
||||||
legalRecord: customer.legalRecord,
|
|
||||||
|
|
||||||
paymentMethod: customer.paymentMethod
|
|
||||||
? {
|
|
||||||
id: customer.paymentMethod.id,
|
|
||||||
name: customer.paymentMethod.name,
|
|
||||||
description: customer.paymentMethod.description,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
|
|
||||||
paymentTerm: customer.paymentTerm
|
|
||||||
? {
|
|
||||||
id: customer.paymentTerm.id,
|
|
||||||
description: customer.paymentTerm.description,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
|
|
||||||
taxRegime: customer.taxRegime
|
|
||||||
? {
|
|
||||||
code: customer.taxRegime.code,
|
|
||||||
description: customer.taxRegime.description,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
|
|
||||||
fiscalDefaults: {
|
|
||||||
usesEquivalenceSurcharge: customer.fiscalDefaults.usesEquivalenceSurcharge,
|
|
||||||
usesRetention: customer.fiscalDefaults.usesRetention,
|
|
||||||
},
|
|
||||||
|
|
||||||
languageCode: customer.languageCode,
|
|
||||||
currencyCode: customer.currencyCode,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export * from "./build-customer-data";
|
|
||||||
@ -2,8 +2,7 @@
|
|||||||
"extends": "../../tsconfig.json",
|
"extends": "../../tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"paths": {
|
"paths": {
|
||||||
"@erp/customers/*": ["./src/*"],
|
"@erp/customers/*": ["./src/*"]
|
||||||
"@erp/identity/*": ["../identity/src/*"]
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||||
|
|||||||
@ -34,9 +34,7 @@
|
|||||||
"zod": "^4.3.6"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bcrypt": "^6.0.0",
|
|
||||||
"@types/express": "^4.17.21",
|
"@types/express": "^4.17.21",
|
||||||
"@types/jsonwebtoken": "^9.0.10",
|
|
||||||
"@types/react": "^19.2.14",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
|
|||||||
@ -4,4 +4,3 @@ export * from "./companies";
|
|||||||
export * from "./company-memberships";
|
export * from "./company-memberships";
|
||||||
export * from "./permissions";
|
export * from "./permissions";
|
||||||
export * from "./roles";
|
export * from "./roles";
|
||||||
export * from "./services";
|
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
import type { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export type AuthenticatedOnlyMiddlewares = readonly [RequestHandler, RequestHandler];
|
|
||||||
|
|
||||||
export type TenantRequiredMiddlewares = readonly [RequestHandler, RequestHandler, RequestHandler];
|
|
||||||
|
|
||||||
export interface IIdentityAuthPublicServices {
|
|
||||||
authenticatedOnly(): AuthenticatedOnlyMiddlewares;
|
|
||||||
tenantRequired(): TenantRequiredMiddlewares;
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
import type { IIdentityAuthPublicServices } from "./identity-auth-public-services.interface";
|
|
||||||
|
|
||||||
export interface IIdentityPublicServices {
|
|
||||||
auth: IIdentityAuthPublicServices;
|
|
||||||
}
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
export * from "./identity-auth-public-services.interface";
|
|
||||||
export * from "./identity-public-services.interface";
|
|
||||||
@ -1,16 +1,13 @@
|
|||||||
import type { IModuleServer } from "@erp/core/api";
|
import type { IModuleServer } from "@erp/core/api";
|
||||||
|
|
||||||
import type { IIdentityPublicServices } from "./application";
|
|
||||||
export * from "./application";
|
export * from "./application";
|
||||||
export * from "./domain";
|
export * from "./domain";
|
||||||
export * from "./infrastructure";
|
export * from "./infrastructure";
|
||||||
|
|
||||||
import { identityAuthRouter, models } from "./infrastructure";
|
import { identityAuthRouter, models } from "./infrastructure";
|
||||||
import { buildIdentityDependencies, buildIdentityPublicServices } from "./infrastructure/di";
|
import { buildIdentityDependencies } from "./infrastructure/di";
|
||||||
|
|
||||||
export * from "./infrastructure/persistence/sequelize";
|
export * from "./infrastructure/persistence/sequelize";
|
||||||
export type { IIdentityAuthPublicServices, IIdentityPublicServices } from "./application";
|
|
||||||
export type IdentityPublicServicesType = IIdentityPublicServices;
|
|
||||||
|
|
||||||
export const identityAPIModule: IModuleServer = {
|
export const identityAPIModule: IModuleServer = {
|
||||||
name: "identity",
|
name: "identity",
|
||||||
@ -31,7 +28,8 @@ export const identityAPIModule: IModuleServer = {
|
|||||||
const internal = buildIdentityDependencies(params);
|
const internal = buildIdentityDependencies(params);
|
||||||
|
|
||||||
// 2) Servicios públicos (Application Services)
|
// 2) Servicios públicos (Application Services)
|
||||||
const identityServices: IIdentityPublicServices = buildIdentityPublicServices(internal);
|
const identityServices = {};
|
||||||
|
//const identityServices: IIdentityPublicServices = {}; //buildIdentityPublicServices(params, internal);
|
||||||
|
|
||||||
logger.info("🚀 Identity module dependencies registered", {
|
logger.info("🚀 Identity module dependencies registered", {
|
||||||
label: this.name,
|
label: this.name,
|
||||||
|
|||||||
@ -1,35 +0,0 @@
|
|||||||
import type {
|
|
||||||
IIdentityAuthPublicServices,
|
|
||||||
IIdentityPublicServices,
|
|
||||||
} from "../../application";
|
|
||||||
import {
|
|
||||||
authenticateUser,
|
|
||||||
requireAuthenticated,
|
|
||||||
requireCompanyContext,
|
|
||||||
} from "../express/middlewares";
|
|
||||||
|
|
||||||
import type { IdentityInternalDeps } from "./identity.di";
|
|
||||||
|
|
||||||
class IdentityAuthPublicServices implements IIdentityAuthPublicServices {
|
|
||||||
public constructor(
|
|
||||||
private readonly deps: IdentityInternalDeps["auth"]["authenticateUserDependencies"]
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public authenticatedOnly() {
|
|
||||||
return [authenticateUser(this.deps), requireAuthenticated()] as const;
|
|
||||||
}
|
|
||||||
|
|
||||||
public tenantRequired() {
|
|
||||||
return [
|
|
||||||
authenticateUser(this.deps),
|
|
||||||
requireAuthenticated(),
|
|
||||||
requireCompanyContext(),
|
|
||||||
] as const;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildIdentityPublicServices(deps: IdentityInternalDeps): IIdentityPublicServices {
|
|
||||||
return {
|
|
||||||
auth: new IdentityAuthPublicServices(deps.auth.authenticateUserDependencies),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -2,7 +2,6 @@ import { type ModuleParams, buildTransactionManager } from "@erp/core/api";
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
AccountAuthenticator,
|
AccountAuthenticator,
|
||||||
type IAccessTokenVerifier,
|
|
||||||
type GetCurrentSessionUseCase,
|
type GetCurrentSessionUseCase,
|
||||||
GetCurrentSessionUseCase as GetCurrentSessionUseCaseImpl,
|
GetCurrentSessionUseCase as GetCurrentSessionUseCaseImpl,
|
||||||
type LoginWithPasswordUseCase,
|
type LoginWithPasswordUseCase,
|
||||||
@ -13,7 +12,6 @@ import {
|
|||||||
RefreshSessionUseCase as RefreshSessionUseCaseImpl,
|
RefreshSessionUseCase as RefreshSessionUseCaseImpl,
|
||||||
SessionIssuer,
|
SessionIssuer,
|
||||||
} from "../../application/authentication";
|
} from "../../application/authentication";
|
||||||
import type { IAccountRepository } from "../../application/accounts";
|
|
||||||
import { identityAuthenticateRequest } from "../express/middlewares";
|
import { identityAuthenticateRequest } from "../express/middlewares";
|
||||||
import {
|
import {
|
||||||
SequelizeAccountDomainMapper,
|
SequelizeAccountDomainMapper,
|
||||||
@ -32,10 +30,6 @@ import {
|
|||||||
export type IdentityInternalDeps = {
|
export type IdentityInternalDeps = {
|
||||||
auth: {
|
auth: {
|
||||||
refreshTokenExpiration: string;
|
refreshTokenExpiration: string;
|
||||||
authenticateUserDependencies: {
|
|
||||||
accessTokenVerifier: IAccessTokenVerifier;
|
|
||||||
accountRepository: IAccountRepository;
|
|
||||||
};
|
|
||||||
authenticateRequest: ReturnType<typeof identityAuthenticateRequest>;
|
authenticateRequest: ReturnType<typeof identityAuthenticateRequest>;
|
||||||
useCases: {
|
useCases: {
|
||||||
loginWithPassword: () => LoginWithPasswordUseCase;
|
loginWithPassword: () => LoginWithPasswordUseCase;
|
||||||
@ -85,10 +79,6 @@ export const buildIdentityDependencies = (params: ModuleParams): IdentityInterna
|
|||||||
return {
|
return {
|
||||||
auth: {
|
auth: {
|
||||||
refreshTokenExpiration: config.auth.jwt.refreshExpiration,
|
refreshTokenExpiration: config.auth.jwt.refreshExpiration,
|
||||||
authenticateUserDependencies: {
|
|
||||||
accessTokenVerifier,
|
|
||||||
accountRepository,
|
|
||||||
},
|
|
||||||
authenticateRequest: identityAuthenticateRequest({
|
authenticateRequest: identityAuthenticateRequest({
|
||||||
accessTokenVerifier,
|
accessTokenVerifier,
|
||||||
accountRepository,
|
accountRepository,
|
||||||
|
|||||||
@ -1,2 +1 @@
|
|||||||
export * from "./identity.di";
|
export * from "./identity.di";
|
||||||
export * from "./identity-public-services";
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
export * from "./authenticate-user.middleware";
|
export * from "./authenticate-user.middleware";
|
||||||
export * from "./require-authenticated.middleware";
|
export * from "./require-authenticated.middleware";
|
||||||
export * from "./require-company-context.middleware";
|
export * from "./require-company-context.middleware";
|
||||||
export * from "./require-identity-middlewares";
|
|
||||||
export * from "./identity-authenticate-request";
|
export * from "./identity-authenticate-request";
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import { ExpressController, UnauthorizedApiError, type RequestWithAuth } from "@erp/core/api";
|
import { ExpressController, UnauthorizedApiError, type RequestWithAuth } from "@erp/core/api";
|
||||||
import type { NextFunction, Request, Response } from "express";
|
import type { NextFunction, Response } from "express";
|
||||||
|
|
||||||
export function requireAuthenticated() {
|
export function requireAuthenticated() {
|
||||||
return (req: Request, res: Response, next: NextFunction) => {
|
return (req: RequestWithAuth, res: Response, next: NextFunction) => {
|
||||||
if (!(req as RequestWithAuth).user) {
|
if (!req.user) {
|
||||||
return ExpressController.errorResponse(new UnauthorizedApiError("Unauthorized"), req, res);
|
return ExpressController.errorResponse(new UnauthorizedApiError("Unauthorized"), req, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import { ExpressController, ForbiddenApiError, type RequestWithAuth } from "@erp/core/api";
|
import { ExpressController, ForbiddenApiError, type RequestWithAuth } from "@erp/core/api";
|
||||||
import type { NextFunction, Request, Response } from "express";
|
import type { NextFunction, Response } from "express";
|
||||||
|
|
||||||
export function requireCompanyContext() {
|
export function requireCompanyContext() {
|
||||||
return (req: Request, res: Response, next: NextFunction) => {
|
return (req: RequestWithAuth, res: Response, next: NextFunction) => {
|
||||||
/**
|
/**
|
||||||
* TODO: validar membership real cuando exista persistencia de CompanyMembership.
|
* TODO: validar membership real cuando exista persistencia de CompanyMembership.
|
||||||
*/
|
*/
|
||||||
if (!(req as RequestWithAuth).user?.companyId) {
|
if (!req.user?.companyId) {
|
||||||
return ExpressController.errorResponse(
|
return ExpressController.errorResponse(
|
||||||
new ForbiddenApiError("Company context required"),
|
new ForbiddenApiError("Company context required"),
|
||||||
req,
|
req,
|
||||||
@ -17,3 +17,4 @@ export function requireCompanyContext() {
|
|||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +0,0 @@
|
|||||||
import type { StartParams } from "@erp/core/api";
|
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
|
|
||||||
import type { IIdentityPublicServices } from "../../../application";
|
|
||||||
|
|
||||||
export function requireIdentityAuthenticated(params: StartParams): RequestHandler[] {
|
|
||||||
const identityServices = params.getService<IIdentityPublicServices>("identity:general");
|
|
||||||
return [...identityServices.auth.authenticatedOnly()];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function requireIdentityTenant(params: StartParams): RequestHandler[] {
|
|
||||||
const identityServices = params.getService<IIdentityPublicServices>("identity:general");
|
|
||||||
return [...identityServices.auth.tenantRequired()];
|
|
||||||
}
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { type MapperParamsType, SequelizeDomainMapper } from "@erp/core/api";
|
import { type MapperParamsType, SequelizeDomainMapper } from "@erp/core/api";
|
||||||
import {
|
import {
|
||||||
UniqueID,
|
UniqueID,
|
||||||
UtcDateTime,
|
UtcDate,
|
||||||
ValidationErrorCollection,
|
ValidationErrorCollection,
|
||||||
type ValidationErrorDetail,
|
type ValidationErrorDetail,
|
||||||
extractOrPushError,
|
extractOrPushError,
|
||||||
@ -10,7 +10,11 @@ import {
|
|||||||
} from "@repo/rdx-ddd";
|
} from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import { RefreshToken, RefreshTokenHash, type RefreshTokenInternalProps } from "../../../../domain";
|
import {
|
||||||
|
RefreshToken,
|
||||||
|
RefreshTokenHash,
|
||||||
|
type RefreshTokenInternalProps,
|
||||||
|
} from "../../../../domain";
|
||||||
import type { RefreshTokenCreationAttributes, RefreshTokenModel } from "../models";
|
import type { RefreshTokenCreationAttributes, RefreshTokenModel } from "../models";
|
||||||
|
|
||||||
function toUtcIsoString(value: Date | string): string {
|
function toUtcIsoString(value: Date | string): string {
|
||||||
@ -41,13 +45,13 @@ export class SequelizeRefreshTokenDomainMapper extends SequelizeDomainMapper<
|
|||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
const expiresAt = extractOrPushError(
|
const expiresAt = extractOrPushError(
|
||||||
UtcDateTime.createFromISO(toUtcIsoString(source.expires_at)),
|
UtcDate.createFromISO(toUtcIsoString(source.expires_at)),
|
||||||
"expires_at",
|
"expires_at",
|
||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
const revokedAt = extractOrPushError(
|
const revokedAt = extractOrPushError(
|
||||||
maybeFromNullableResult(source.revoked_at, (value) =>
|
maybeFromNullableResult(source.revoked_at, (value) =>
|
||||||
UtcDateTime.createFromISO(toUtcIsoString(value))
|
UtcDate.createFromISO(toUtcIsoString(value))
|
||||||
),
|
),
|
||||||
"revoked_at",
|
"revoked_at",
|
||||||
errors
|
errors
|
||||||
@ -58,7 +62,7 @@ export class SequelizeRefreshTokenDomainMapper extends SequelizeDomainMapper<
|
|||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
const createdAt = extractOrPushError(
|
const createdAt = extractOrPushError(
|
||||||
UtcDateTime.createFromISO(toUtcIsoString(source.created_at)),
|
UtcDate.createFromISO(toUtcIsoString(source.created_at)),
|
||||||
"created_at",
|
"created_at",
|
||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
@ -94,9 +98,7 @@ export class SequelizeRefreshTokenDomainMapper extends SequelizeDomainMapper<
|
|||||||
token_hash: source.tokenHash.toPrimitive(),
|
token_hash: source.tokenHash.toPrimitive(),
|
||||||
expires_at: source.expiresAt.toISOString(),
|
expires_at: source.expiresAt.toISOString(),
|
||||||
revoked_at: maybeToNullable(source.revokedAt, (revokedAt) => revokedAt.toISOString()),
|
revoked_at: maybeToNullable(source.revokedAt, (revokedAt) => revokedAt.toISOString()),
|
||||||
replaced_by_token_id: maybeToNullable(source.replacedByTokenId, (value) =>
|
replaced_by_token_id: maybeToNullable(source.replacedByTokenId, (value) => value.toPrimitive()),
|
||||||
value.toPrimitive()
|
|
||||||
),
|
|
||||||
created_at: source.createdAt.toISOString(),
|
created_at: source.createdAt.toISOString(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user