diff --git a/apps/server/package.json b/apps/server/package.json index 44857d6e..bfa6ad74 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -7,7 +7,7 @@ "start": "NODE_ENV=production node --env-file=.env.production dist/index.js", "dev": "node --import=tsx --watch src/index.ts", "clean": "rimraf .turbo node_modules dist", - "typecheck": "tsc --noEmit", + "typecheck": "tsc -p tsconfig.json --noEmit", "check": "biome check .", "lint": "biome lint .", "format": "biome format --write" diff --git a/apps/web/package.json b/apps/web/package.json index 15460834..f49f172f 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -4,6 +4,7 @@ "version": "0.6.7", "type": "module", "scripts": { + "typecheck": "tsc -p tsconfig.json --noEmit", "dev": "vite --host --clearScreen false", "build": "tsc && vite build", "build:rodax": "tsc && vite build --mode rodax", @@ -24,13 +25,13 @@ "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", - "date-fns": "^4.1.0", "typescript": "~6.0.2", "vite": "^8.0.8" }, "dependencies": { "@erp/auth": "workspace:*", "@erp/core": "workspace:*", + "@erp/catalogs": "workspace:*", "@erp/customer-invoices": "workspace:*", "@erp/customers": "workspace:*", "@fontsource-variable/geist": "^5.2.8", @@ -41,6 +42,7 @@ "@tailwindcss/vite": "^4.2.2", "@tanstack/react-query": "^5.98.0", "axios": "^1.15.0", + "date-fns": "^4.1.0", "dinero.js": "1.9.1", "lucide-react": "^1.8.0", "react": "^19.2.5", diff --git a/apps/web/src/register-modules.tsx b/apps/web/src/register-modules.tsx index b871def5..bea18ef5 100644 --- a/apps/web/src/register-modules.tsx +++ b/apps/web/src/register-modules.tsx @@ -1,11 +1,13 @@ -import { AuthModuleManifiest } from "@erp/auth/client"; -import CoreModuleManifiest, { type IModuleClient } from "@erp/core/client"; -import { CustomerInvoicesModuleManifiest } from "@erp/customer-invoices/client"; -import { CustomersModuleManifiest } from "@erp/customers/client"; +import { AuthModuleManifest } from "@erp/auth/client"; +import { CatalogsModuleManifest } from "@erp/catalogs/client"; +import CoreModuleManifest, { type IModuleClient } from "@erp/core/client"; +import { CustomerInvoicesModuleManifest } from "@erp/customer-invoices/client"; +import { CustomersModuleManifest } from "@erp/customers/client"; export const modules: IModuleClient[] = [ - AuthModuleManifiest, - CoreModuleManifiest, - CustomersModuleManifiest, - CustomerInvoicesModuleManifiest, + AuthModuleManifest, + CoreModuleManifest, + CatalogsModuleManifest, + CustomersModuleManifest, + CustomerInvoicesModuleManifest, ]; diff --git a/biome.json b/biome.json index 72e95f47..a2478208 100644 --- a/biome.json +++ b/biome.json @@ -10,11 +10,6 @@ "ignoreUnknown": true, "includes": [ "**", - "!!**/supplier-invoices", - "!!**/suppliers", - "!!**/auth", - "!!**/rdx-criteria", - "!!**/shadcn-ui", "!!**/node_modules", "!!**/.next", "!!**/dist", @@ -50,10 +45,7 @@ "noInferrableTypes": "error", "noNamespace": "error", "noNegationElse": "warn", - "noNonNullAssertion": { - "level": "info", - "fix": "none" - }, + "noNonNullAssertion": "info", "noParameterAssign": "error", "noUnusedTemplateLiteral": "error", "noUselessElse": "warn", diff --git a/modules/auth/package.json b/modules/auth/package.json index 9d5eea80..5b2e2401 100644 --- a/modules/auth/package.json +++ b/modules/auth/package.json @@ -24,6 +24,7 @@ "@types/react-dom": "^19.2.3", "react": "^19.2.5", "react-dom": "^19.2.5", + "rimraf": "^6.1.3", "typescript": "^6.0.2" }, "dependencies": { diff --git a/modules/auth/src/api/lib/passport/passport-auth-provider.ts b/modules/auth/src/api/lib/passport/passport-auth-provider.ts index ee3bd93f..e2e97d4d 100644 --- a/modules/auth/src/api/lib/passport/passport-auth-provider.ts +++ b/modules/auth/src/api/lib/passport/passport-auth-provider.ts @@ -1,13 +1,14 @@ -import { NextFunction, Response } from "express"; - +import { logger } from "@erp/core/api"; +import type { NextFunction, Response } from "express"; import passport from "passport"; import { ExtractJwt, Strategy as JwtStrategy } from "passport-jwt"; -import { TabContext } from "../../../../../../apps/server/archive/contexts/auth/domain"; -import { + +import type { TabContext } from "../../../../../../apps/server/archive/contexts/auth/domain"; +import type { IAuthService, ITabContextService, } from "../../../../../../apps/server/archive/contexts/auth/domain/services"; -import { TabContextRequest } from "../../../../../../apps/server/archive/contexts/auth/infraestructure/express/types"; +import type { TabContextRequest } from "../../../../../../apps/server/archive/contexts/auth/infraestructure/express/types"; const SECRET_KEY = process.env.JWT_SECRET || "supersecretkey"; @@ -48,7 +49,7 @@ export class PassportAuthProvider { const checkUserId = user.id.equals(userIdVO.data); const checkRoles = true; //user.hasRoles(roles); - if (!checkUserId || !checkRoles) { + if (!(checkUserId && checkRoles)) { return Result.fail(new Error("Invalid token data")); } diff --git a/modules/auth/src/web/manifest.ts b/modules/auth/src/web/manifest.ts index d9b5bbf0..c44d73b0 100644 --- a/modules/auth/src/web/manifest.ts +++ b/modules/auth/src/web/manifest.ts @@ -8,7 +8,7 @@ import { AuthRoutes } from "./auth-routes"; const MODULE_NAME = "auth"; const MODULE_VERSION = "1.0.0"; -export const AuthModuleManifiest: IModuleClient = { +export const AuthModuleManifest: IModuleClient = { name: MODULE_NAME, version: MODULE_VERSION, dependencies: ["core"], @@ -22,4 +22,4 @@ export const AuthModuleManifiest: IModuleClient = { }, }; -export default AuthModuleManifiest; +export default AuthModuleManifest; diff --git a/modules/catalogs/package.json b/modules/catalogs/package.json index 82e99b05..0013e5fc 100644 --- a/modules/catalogs/package.json +++ b/modules/catalogs/package.json @@ -1,7 +1,7 @@ { "name": "@erp/catalogs", "description": "Catalogs module", - "version": "0.1.0", + "version": "0.6.7", "private": true, "type": "module", "sideEffects": false, @@ -12,21 +12,45 @@ "clean": "rimraf .turbo node_modules dist" }, "exports": { - ".": "./src/api/index.ts", - "./api": "./src/api/index.ts" + ".": "./src/common/index.ts", + "./common": "./src/common/index.ts", + "./api": "./src/api/index.ts", + "./client": "./src/web/manifest.ts", + "./client/payment-methods": "./src/web/payment-methods/index.ts", + "./client/payment-terms": "./src/web/payment-terms/index.ts" }, - "dependencies": { - "@erp/core": "workspace:*", - "@erp/auth": "workspace:*", - "@repo/rdx-ddd": "workspace:*", - "@repo/rdx-utils": "workspace:*", - "@repo/rdx-criteria": "workspace:*", - "express": "^4.22.1", - "sequelize": "^6.37.8", - "zod": "^4.3.6" + "peerDependencies": { + "react": "^19.2.5", + "react-dom": "^19.2.5" }, "devDependencies": { "@types/express": "^4.17.21", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@types/react-router-dom": "^5.3.3", + "react": "^19.2.5", + "react-dom": "^19.2.5", + "rimraf": "^6.1.3", "typescript": "^6.0.2" + }, + "dependencies": { + "@erp/auth": "workspace:*", + "@erp/core": "workspace:*", + "@repo/i18next": "workspace:*", + "@repo/rdx-criteria": "workspace:*", + "@repo/rdx-ddd": "workspace:*", + "@repo/rdx-logger": "workspace:*", + "@repo/rdx-ui": "workspace:*", + "@repo/rdx-utils": "workspace:*", + "@repo/shadcn-ui": "workspace:*", + "@tanstack/react-query": "^5.98.0", + "express": "^4.22.1", + "lucide-react": "^1.8.0", + "react-hook-form": "^7.72.1", + "react-i18next": "^17.0.2", + "react-router-dom": "^7.14.0", + "sequelize": "^6.37.8", + "use-debounce": "^10.1.1", + "zod": "^4.3.6" } } \ No newline at end of file diff --git a/modules/catalogs/src/api/domain/payment-methods/index.ts b/modules/catalogs/src/api/domain/payment-methods/index.ts index f1da9c9d..16cffcb8 100644 --- a/modules/catalogs/src/api/domain/payment-methods/index.ts +++ b/modules/catalogs/src/api/domain/payment-methods/index.ts @@ -1,4 +1,3 @@ export * from "./errors"; export * from "./payment-method.aggregate"; export * from "./payment-method-name"; -export * from "./payment-method-type"; diff --git a/modules/catalogs/src/api/domain/payment-methods/payment-method-type.ts b/modules/catalogs/src/api/domain/payment-methods/payment-method-type.ts deleted file mode 100644 index 8ea739de..00000000 --- a/modules/catalogs/src/api/domain/payment-methods/payment-method-type.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Result } from "@repo/rdx-utils"; - -import { InvalidPaymentMethodTypeError } from "./errors"; - -export const PAYMENT_METHOD_TYPES = [ - "cash", - "bank_transfer", - "card", - "direct_debit", - "other", -] as const; - -export type PaymentMethodTypeValue = (typeof PAYMENT_METHOD_TYPES)[number]; - -export class PaymentMethodType { - private constructor(private readonly value: PaymentMethodTypeValue) {} - - public static create(type: string): Result { - const normalized = String(type).trim() as PaymentMethodTypeValue; - - if (!PAYMENT_METHOD_TYPES.includes(normalized)) { - return Result.fail( - new InvalidPaymentMethodTypeError( - `Payment method type must be one of: ${PAYMENT_METHOD_TYPES.join(", ")}` - ) - ); - } - - return Result.ok(new PaymentMethodType(normalized)); - } - - public static fromPersistence(type: PaymentMethodTypeValue): PaymentMethodType { - return new PaymentMethodType(type); - } - - public toString(): PaymentMethodTypeValue { - return this.value; - } - - public toPrimitive(): PaymentMethodTypeValue { - return this.value; - } -} diff --git a/modules/catalogs/src/api/domain/payment-terms/payment-term.aggregate.ts b/modules/catalogs/src/api/domain/payment-terms/payment-term.aggregate.ts index d4ff8a1f..0ba8eb3b 100644 --- a/modules/catalogs/src/api/domain/payment-terms/payment-term.aggregate.ts +++ b/modules/catalogs/src/api/domain/payment-terms/payment-term.aggregate.ts @@ -214,15 +214,4 @@ export class PaymentTerm extends AggregateRoot { this.props.isActive = true; return Result.ok(true); } - - private static sameDescription(current: Maybe, next: Maybe): boolean { - return current.match( - (currentValue: TextValue) => - next.match( - (nextValue: TextValue) => currentValue.toPrimitive() === nextValue.toPrimitive(), - () => false - ), - () => next.isNone() - ); - } } diff --git a/modules/catalogs/src/api/infrastructure/payment-methods/persistence/sequelize/mappers/sequelize-payment-method-summary.mapper.ts b/modules/catalogs/src/api/infrastructure/payment-methods/persistence/sequelize/mappers/sequelize-payment-method-summary.mapper.ts index 8a42b0cd..35e66afb 100644 --- a/modules/catalogs/src/api/infrastructure/payment-methods/persistence/sequelize/mappers/sequelize-payment-method-summary.mapper.ts +++ b/modules/catalogs/src/api/infrastructure/payment-methods/persistence/sequelize/mappers/sequelize-payment-method-summary.mapper.ts @@ -8,7 +8,7 @@ import { } from "@repo/rdx-ddd"; import { Result } from "@repo/rdx-utils"; -import type { PaymentMethodSummary } from "../../../../../application/payment-methods/models"; +import type { PaymentMethodSummary } from "../../../../../application"; import type { PaymentMethodModel } from "../models"; export class SequelizePaymentMethodSummaryMapper extends SequelizeQueryMapper< diff --git a/modules/catalogs/src/common/dto/payment-methods/response/list-payment-methods.response.dto.ts b/modules/catalogs/src/common/dto/payment-methods/response/list-payment-methods.response.dto.ts index 9c4b1187..d84d66db 100644 --- a/modules/catalogs/src/common/dto/payment-methods/response/list-payment-methods.response.dto.ts +++ b/modules/catalogs/src/common/dto/payment-methods/response/list-payment-methods.response.dto.ts @@ -1,6 +1,9 @@ -import { z } from "zod/v4"; +import { createPaginatedListSchema } from "@erp/core"; +import type { z } from "zod/v4"; import { PaymentMethodSummarySchema } from "../shared"; -export const ListPaymentMethodsResponseSchema = z.array(PaymentMethodSummarySchema); +export const ListPaymentMethodsResponseSchema = createPaginatedListSchema( + PaymentMethodSummarySchema +); export type ListPaymentMethodsResponseDTO = z.infer; diff --git a/modules/catalogs/src/common/dto/payment-terms/response/list-payment-terms.response.dto.ts b/modules/catalogs/src/common/dto/payment-terms/response/list-payment-terms.response.dto.ts index fbca28b4..23e5d475 100644 --- a/modules/catalogs/src/common/dto/payment-terms/response/list-payment-terms.response.dto.ts +++ b/modules/catalogs/src/common/dto/payment-terms/response/list-payment-terms.response.dto.ts @@ -1,6 +1,7 @@ -import { z } from "zod/v4"; +import { createPaginatedListSchema } from "@erp/core"; +import type { z } from "zod/v4"; import { PaymentTermSummarySchema } from "../shared/payment-term-summary.dto"; -export const ListPaymentTermsResponseSchema = z.array(PaymentTermSummarySchema); +export const ListPaymentTermsResponseSchema = createPaginatedListSchema(PaymentTermSummarySchema); export type ListPaymentTermsResponseDTO = z.infer; diff --git a/modules/catalogs/src/web/index.ts b/modules/catalogs/src/web/index.ts new file mode 100644 index 00000000..2666407f --- /dev/null +++ b/modules/catalogs/src/web/index.ts @@ -0,0 +1,6 @@ +export { + CatalogsModuleManifest, + default, +} from "./manifest"; +export * from "./payment-methods"; +export * from "./payment-terms"; diff --git a/modules/catalogs/src/web/manifest.ts b/modules/catalogs/src/web/manifest.ts new file mode 100644 index 00000000..4f1160d7 --- /dev/null +++ b/modules/catalogs/src/web/manifest.ts @@ -0,0 +1,18 @@ +import type { IModuleClient, ModuleClientParams } from "@erp/core/client"; + +export const MODULE_NAME = "Catalogs"; +const MODULE_VERSION = "1.0.0"; + +export const CatalogsModuleManifest: IModuleClient = { + name: MODULE_NAME, + version: MODULE_VERSION, + dependencies: ["auth", "Core"], + protected: true, + layout: "app", + + routes: (params: ModuleClientParams) => { + return []; + }, +}; + +export default CatalogsModuleManifest; diff --git a/modules/catalogs/src/web/payment-methods/index.ts b/modules/catalogs/src/web/payment-methods/index.ts new file mode 100644 index 00000000..db220ed0 --- /dev/null +++ b/modules/catalogs/src/web/payment-methods/index.ts @@ -0,0 +1,2 @@ +export * from "./shared"; +export * from "./utils"; diff --git a/modules/catalogs/src/web/payment-methods/shared/adapters/index.ts b/modules/catalogs/src/web/payment-methods/shared/adapters/index.ts new file mode 100644 index 00000000..24346c83 --- /dev/null +++ b/modules/catalogs/src/web/payment-methods/shared/adapters/index.ts @@ -0,0 +1 @@ +export * from './list-payment-methods.adapter'; diff --git a/modules/catalogs/src/web/payment-methods/shared/adapters/list-payment-methods.adapter.ts b/modules/catalogs/src/web/payment-methods/shared/adapters/list-payment-methods.adapter.ts new file mode 100644 index 00000000..24560b31 --- /dev/null +++ b/modules/catalogs/src/web/payment-methods/shared/adapters/list-payment-methods.adapter.ts @@ -0,0 +1,53 @@ +import type { ListPaymentMethodsResponseDTO } from "../../../../common"; +import type { ListPaymentMethodsResult } from "../api"; +import type { PaymentMethodList, PaymentMethodListRow } from "../entities"; + +/** + * Adaptador para transformar los datos de la API de ListPaymentMethodsResult + * a la entidad PaymentMethodList utilizada en la aplicación. + * Reglas de adaptación: + * - page, per_page, total_pages, total_items se asignan directamente. + * - items se transforma utilizando PaymentMethodListRowAdapter para cada elemento. + * + * @param pageDto - lista de proformas desde la API. + * @param context - Contexto adicional opcional para la adaptación. + * @returns {PaymentMethodList} Objeto adaptado a PaymentMehodList. + */ + +export const ListPaymentMethodsAdapter = { + fromDto(dto: ListPaymentMethodsResult, context?: unknown): PaymentMethodList { + return { + page: dto.page, + perPage: dto.per_page, + totalPages: dto.total_pages, + totalItems: dto.total_items, + items: dto.items.map((rowDto) => PaymentMehodListRowAdapter.fromDto(rowDto, context)), + }; + }, +}; + +/** + * Adaptador para transformar los items de la API de ListPaymentMehodsResult a la entidad PaymentMehodListRow. + * Reglas de adaptación: + * - id, company_id se asignan directamente. + * + * @param rowDto - item de proforma desde la API. + * @param context - Contexto adicional opcional para la adaptación. + * @returns {PaymentMethodListRow} Objeto adaptado a PaymentMehodListRow. + */ + +type ListPaymentMethodsItemOutput = ListPaymentMethodsResponseDTO["items"][number]; + +const PaymentMehodListRowAdapter = { + fromDto(dto: ListPaymentMethodsItemOutput, context?: unknown): PaymentMethodListRow { + return { + id: dto.id, + companyId: dto.company_id, + + name: dto.name, + + isSystem: dto.is_system, + isActive: dto.is_active, + }; + }, +}; diff --git a/modules/catalogs/src/web/payment-methods/shared/api/index.ts b/modules/catalogs/src/web/payment-methods/shared/api/index.ts new file mode 100644 index 00000000..c865736b --- /dev/null +++ b/modules/catalogs/src/web/payment-methods/shared/api/index.ts @@ -0,0 +1 @@ +export * from "./list-payment-methods-by-criteria.api"; diff --git a/modules/catalogs/src/web/payment-methods/shared/api/list-payment-methods-by-criteria.api.ts b/modules/catalogs/src/web/payment-methods/shared/api/list-payment-methods-by-criteria.api.ts new file mode 100644 index 00000000..ccf4d1e9 --- /dev/null +++ b/modules/catalogs/src/web/payment-methods/shared/api/list-payment-methods-by-criteria.api.ts @@ -0,0 +1,38 @@ +import type { CriteriaDTO } from "@erp/core"; +import type { IDataSource } from "@erp/core/client"; + +import type { ListPaymentMethodsResponseDTO } from "../../../../common"; + +/** + * Recupera una lista de métodos de pago del sistema utilizando la + * fuente de datos proporcionada y los criterios de búsqueda especificados. + * + * @param dataSource - La fuente de datos para interactuar con la API. + * @param params - Los parámetros necesarios para listar los métodos de pago, incluyendo los criterios de búsqueda. + * @returns Una promesa que resuelve con una lista de métodos de pago que cumplen con los criterios especificados. + * @throws Error si la recuperación de la lista de métodos de pago falla. + */ + +export type ListPaymentMethodsByCriteriaParams = { + criteria?: CriteriaDTO; + signal?: AbortSignal; +}; + +export type ListPaymentMethodsResult = ListPaymentMethodsResponseDTO; + +export function getListPaymentMethodsByCriteria( + dataSource: IDataSource, + params: ListPaymentMethodsByCriteriaParams +): Promise { + const { criteria, signal } = params || { + criteria: { + page: 1, + per_page: 9999, + }, + signal: undefined, + }; + return dataSource.getList("catalogs/payment-methods", { + signal, + ...criteria, + }); +} diff --git a/modules/catalogs/src/web/payment-methods/shared/entities/index.ts b/modules/catalogs/src/web/payment-methods/shared/entities/index.ts new file mode 100644 index 00000000..f37952e9 --- /dev/null +++ b/modules/catalogs/src/web/payment-methods/shared/entities/index.ts @@ -0,0 +1,3 @@ +export * from "./payment-method.entity"; +export * from "./payment-method-list.entity"; +export * from "./payment-method-list-row.entity"; diff --git a/modules/catalogs/src/web/payment-methods/shared/entities/payment-method-list-row.entity.ts b/modules/catalogs/src/web/payment-methods/shared/entities/payment-method-list-row.entity.ts new file mode 100644 index 00000000..cfe63a8d --- /dev/null +++ b/modules/catalogs/src/web/payment-methods/shared/entities/payment-method-list-row.entity.ts @@ -0,0 +1,16 @@ +/** + * Interface que representa una fila de la lista de + * formas de pago en el sistema, adaptada desde la respuesta de la API. + * Contiene los campos justos para mostrar + * la información básica de cada forma de pago en la lista. + */ + +export interface PaymentMethodListRow { + id: string; + companyId: string; + + name: string; + + isSystem: boolean; + isActive: boolean; +} diff --git a/modules/catalogs/src/web/payment-methods/shared/entities/payment-method-list.entity.ts b/modules/catalogs/src/web/payment-methods/shared/entities/payment-method-list.entity.ts new file mode 100644 index 00000000..622a8de0 --- /dev/null +++ b/modules/catalogs/src/web/payment-methods/shared/entities/payment-method-list.entity.ts @@ -0,0 +1,14 @@ +import type { PaymentMethodListRow } from "./payment-method-list-row.entity"; + +/** + * Interface que representa la respuesta paginada de una lista de formas de pago, + * adaptada desde la respuesta de la API. + */ + +export interface PaymentMethodList { + items: PaymentMethodListRow[]; + totalPages: number; + totalItems: number; + page: number; + perPage: number; +} diff --git a/modules/catalogs/src/web/payment-methods/shared/entities/payment-method.entity.ts b/modules/catalogs/src/web/payment-methods/shared/entities/payment-method.entity.ts new file mode 100644 index 00000000..c89eb030 --- /dev/null +++ b/modules/catalogs/src/web/payment-methods/shared/entities/payment-method.entity.ts @@ -0,0 +1,10 @@ +export interface PaymentMethod { + id: string; + companyId: string; + + name: string; + description: string | null; + + isSystem: boolean; + isActive: boolean; +} diff --git a/modules/catalogs/src/web/payment-methods/shared/hooks/index.ts b/modules/catalogs/src/web/payment-methods/shared/hooks/index.ts new file mode 100644 index 00000000..60b85610 --- /dev/null +++ b/modules/catalogs/src/web/payment-methods/shared/hooks/index.ts @@ -0,0 +1 @@ +export * from "./use-payment-method-list-query"; diff --git a/modules/catalogs/src/web/payment-methods/shared/hooks/keys.ts b/modules/catalogs/src/web/payment-methods/shared/hooks/keys.ts new file mode 100644 index 00000000..2f1cb914 --- /dev/null +++ b/modules/catalogs/src/web/payment-methods/shared/hooks/keys.ts @@ -0,0 +1,44 @@ +import type { QueryKey } from "@tanstack/react-query"; + +import type { ListPaymentMethodsRequestDTO } from "../../../../common"; + +/** + * Prefijo base para listados + */ +export const LIST_PAYMENT_METHODS_QUERY_KEY_PREFIX = ["payment-methods"] as const; + +/** + * Query key para listado de payment methods + */ +export const LIST_PAYMENT_METHODS_QUERY_KEY = (criteria?: ListPaymentMethodsRequestDTO): QueryKey => + [ + ...LIST_PAYMENT_METHODS_QUERY_KEY_PREFIX, + { + pageNumber: criteria?.pageNumber ?? 1, + pageSize: criteria?.pageSize ?? 5, + q: criteria?.q ?? "", + filters: criteria?.filters ?? [], + orderBy: criteria?.orderBy ?? "", + order: criteria?.order ?? "", + }, + ] as const; + +/** + * Query key para detalle de payment method + */ +export const PAYMENT_METHODS_DETAIL_QUERY_KEY_PREFIX = ["payment-methods:detail"] as const; +export const PAYMENT_METHOD_QUERY_KEY = (paymentMethodId?: string): QueryKey => [ + ...PAYMENT_METHODS_DETAIL_QUERY_KEY_PREFIX, + { paymentMethodId }, +]; + +/** + * Keys para mutaciones + */ +export const CREATE_PAYMENT_METHOD_MUTATION_KEY = ["payment-methods:create"] as const; +export const UPDATE_PAYMENT_METHOD_MUTATION_KEY = ["payment-methods:update"] as const; +export const DELETE_PAYMENT_METHOD_MUTATION_KEY = ["payment-methods:delete"] as const; + +/** + * Operaciones de dominio + */ diff --git a/modules/catalogs/src/web/payment-methods/shared/hooks/use-payment-method-list-query.ts b/modules/catalogs/src/web/payment-methods/shared/hooks/use-payment-method-list-query.ts new file mode 100644 index 00000000..79d13a30 --- /dev/null +++ b/modules/catalogs/src/web/payment-methods/shared/hooks/use-payment-method-list-query.ts @@ -0,0 +1,32 @@ +import type { CriteriaDTO } from "@erp/core"; +import { useDataSource } from "@erp/core/hooks"; +import { type DefaultError, type UseQueryResult, useQuery } from "@tanstack/react-query"; + +import { ListPaymentMethodsAdapter } from "../adapters"; +import { getListPaymentMethodsByCriteria } from "../api"; +import type { PaymentMethodList } from "../entities"; + +import { LIST_PAYMENT_METHODS_QUERY_KEY } from "./keys"; + +export interface PaymentMethodsListQueryOptions { + enabled?: boolean; + criteria?: Partial; +} + +export const usePaymentMethodsListQuery = ( + options?: PaymentMethodsListQueryOptions +): UseQueryResult => { + const dataSource = useDataSource(); + const enabled = options?.enabled ?? true; + const criteria = options?.criteria ?? {}; + + return useQuery({ + queryKey: LIST_PAYMENT_METHODS_QUERY_KEY(criteria), + queryFn: async ({ signal }) => { + const dto = await getListPaymentMethodsByCriteria(dataSource, { signal, criteria }); + return ListPaymentMethodsAdapter.fromDto(dto); + }, + enabled, + placeholderData: (previousData) => previousData, // Mantiene la página anterior durante refetch por cambio de criteria + }); +}; diff --git a/modules/catalogs/src/web/payment-methods/shared/index.ts b/modules/catalogs/src/web/payment-methods/shared/index.ts new file mode 100644 index 00000000..3a4614c9 --- /dev/null +++ b/modules/catalogs/src/web/payment-methods/shared/index.ts @@ -0,0 +1,2 @@ +export * from "./entities"; +export * from "./hooks"; diff --git a/modules/catalogs/src/web/payment-methods/utils/index.ts b/modules/catalogs/src/web/payment-methods/utils/index.ts new file mode 100644 index 00000000..e154ef11 --- /dev/null +++ b/modules/catalogs/src/web/payment-methods/utils/index.ts @@ -0,0 +1 @@ +export * from './payment-method-options.utils'; diff --git a/modules/catalogs/src/web/payment-methods/utils/payment-method-options.utils.ts b/modules/catalogs/src/web/payment-methods/utils/payment-method-options.utils.ts new file mode 100644 index 00000000..7392f1e5 --- /dev/null +++ b/modules/catalogs/src/web/payment-methods/utils/payment-method-options.utils.ts @@ -0,0 +1,12 @@ +import type { SelectFieldItem } from "@repo/rdx-ui/components"; + +import type { PaymentMethodListRow } from "../shared"; + +export const getPaymentMethodOptions = ( + paymentMethods: PaymentMethodListRow[] +): SelectFieldItem[] => { + return paymentMethods.map((paymentMethod) => ({ + value: paymentMethod.id, + label: paymentMethod.name, + })); +}; diff --git a/modules/catalogs/src/web/payment-terms/index.ts b/modules/catalogs/src/web/payment-terms/index.ts new file mode 100644 index 00000000..db220ed0 --- /dev/null +++ b/modules/catalogs/src/web/payment-terms/index.ts @@ -0,0 +1,2 @@ +export * from "./shared"; +export * from "./utils"; diff --git a/modules/catalogs/src/web/payment-terms/shared/adapters/index.ts b/modules/catalogs/src/web/payment-terms/shared/adapters/index.ts new file mode 100644 index 00000000..e83cfb8e --- /dev/null +++ b/modules/catalogs/src/web/payment-terms/shared/adapters/index.ts @@ -0,0 +1 @@ +export * from "./list-payment-terms.adapter"; diff --git a/modules/catalogs/src/web/payment-terms/shared/adapters/list-payment-terms.adapter.ts b/modules/catalogs/src/web/payment-terms/shared/adapters/list-payment-terms.adapter.ts new file mode 100644 index 00000000..867cef86 --- /dev/null +++ b/modules/catalogs/src/web/payment-terms/shared/adapters/list-payment-terms.adapter.ts @@ -0,0 +1,68 @@ +import type { ListPaymentTermsResponseDTO } from "../../../../common"; +import type { ListPaymentTermsResult } from "../api"; +import type { PaymentTermList, PaymentTermListRow } from "../entities"; + +/** + * Adaptador para transformar los datos de la API de ListPaymentTermsResult + * a la entidad PaymentTermList utilizada en la aplicación. + * Reglas de adaptación: + * - page, per_page, total_pages, total_items se asignan directamente. + * - items se transforma utilizando PaymentTermListRowAdapter para cada elemento. + * + * @param pageDto - lista de proformas desde la API. + * @param context - Contexto adicional opcional para la adaptación. + * @returns {PaymentTermList} Objeto adaptado a PaymentMehodList. + */ + +export const ListPaymentTermsAdapter = { + fromDto(dto: ListPaymentTermsResult, _context?: unknown): PaymentTermList { + return { + page: dto.page, + perPage: dto.per_page, + totalPages: dto.total_pages, + totalItems: dto.total_items, + items: dto.items.map((rowDto) => PaymentTermListRowAdapter.fromDto(rowDto, _context)), + }; + }, +}; + +/** + * Adaptador para transformar los items de la API de ListPaymentTermsResult a la entidad PaymentTermListRow. + * Reglas de adaptación: + * - id, company_id, se asignan directamente. + * + * @param rowDto - item de proforma desde la API. + * @param context - Contexto adicional opcional para la adaptación. + * @returns {PaymentTermListRow} Objeto adaptado a PaymentMehodListRow. + */ + +type ListPaymentTermsItemOutput = ListPaymentTermsResponseDTO["items"][number]; + +const PaymentTermListRowAdapter = { + fromDto(dto: ListPaymentTermsItemOutput, _context?: unknown): PaymentTermListRow { + return { + id: dto.id, + companyId: dto.company_id, + name: dto.name, + isSystem: dto.is_system, + isActive: dto.is_active, + //dueRules: dto.due_rules.map(PaymentTermDueRuleAdapter.fromDto), + }; + }, +}; + +/** */ +/* +const PaymentTermDueRuleAdapter = { + fromDto(dto: PaymentTermDueRuleDTO): PaymentTermDueRule { + return { + dueDays: Number(dto.due_days), + percentage: percentageDtoToNumber(dto.percentage), + }; + }, +}; + +const percentageDtoToNumber = (dto: { value: string; scale: string }): number => { + return Number(dto.value) / 10 ** Number(dto.scale); +}; +*/ diff --git a/modules/catalogs/src/web/payment-terms/shared/api/index.ts b/modules/catalogs/src/web/payment-terms/shared/api/index.ts new file mode 100644 index 00000000..dfd1838c --- /dev/null +++ b/modules/catalogs/src/web/payment-terms/shared/api/index.ts @@ -0,0 +1 @@ +export * from "./list-payment-terms-by-criteria.api"; diff --git a/modules/catalogs/src/web/payment-terms/shared/api/list-payment-terms-by-criteria.api.ts b/modules/catalogs/src/web/payment-terms/shared/api/list-payment-terms-by-criteria.api.ts new file mode 100644 index 00000000..ae41dfcf --- /dev/null +++ b/modules/catalogs/src/web/payment-terms/shared/api/list-payment-terms-by-criteria.api.ts @@ -0,0 +1,38 @@ +import type { CriteriaDTO } from "@erp/core"; +import type { IDataSource } from "@erp/core/client"; + +import type { ListPaymentTermsResponseDTO } from "../../../../common"; + +/** + * Recupera una lista de vencimientos del sistema utilizando la + * fuente de datos proporcionada y los criterios de búsqueda especificados. + * + * @param dataSource - La fuente de datos para interactuar con la API. + * @param params - Los parámetros necesarios para listar los vencimientos, incluyendo los criterios de búsqueda. + * @returns Una promesa que resuelve con una lista de vencimientos que cumplen con los criterios especificados. + * @throws Error si la recuperación de la lista de vencimientos falla. + */ + +export type ListPaymentTermsByCriteriaParams = { + criteria?: CriteriaDTO; + signal?: AbortSignal; +}; + +export type ListPaymentTermsResult = ListPaymentTermsResponseDTO; + +export function getListPaymentTermsByCriteria( + dataSource: IDataSource, + params: ListPaymentTermsByCriteriaParams +): Promise { + const { criteria, signal } = params || { + criteria: { + page: 1, + per_page: 9999, + }, + signal: undefined, + }; + return dataSource.getList("catalogs/payment-terms", { + signal, + ...criteria, + }); +} diff --git a/modules/catalogs/src/web/payment-terms/shared/entities/index.ts b/modules/catalogs/src/web/payment-terms/shared/entities/index.ts new file mode 100644 index 00000000..0f044761 --- /dev/null +++ b/modules/catalogs/src/web/payment-terms/shared/entities/index.ts @@ -0,0 +1,3 @@ +export * from "./payment-term.entity"; +export * from "./payment-term-list.entity"; +export * from "./payment-term-list-row.entity"; diff --git a/modules/catalogs/src/web/payment-terms/shared/entities/payment-term-list-row.entity.ts b/modules/catalogs/src/web/payment-terms/shared/entities/payment-term-list-row.entity.ts new file mode 100644 index 00000000..33b4e5ef --- /dev/null +++ b/modules/catalogs/src/web/payment-terms/shared/entities/payment-term-list-row.entity.ts @@ -0,0 +1,16 @@ +/** + * Interface que representa una fila de la lista de + * vencimientos en el sistema, adaptada desde la respuesta de la API. + * Contiene los campos justos para mostrar + * la información básica de cada vencimiento en la lista. + */ + +export interface PaymentTermListRow { + id: string; + companyId: string; + + name: string; + + isSystem: boolean; + isActive: boolean; +} diff --git a/modules/catalogs/src/web/payment-terms/shared/entities/payment-term-list.entity.ts b/modules/catalogs/src/web/payment-terms/shared/entities/payment-term-list.entity.ts new file mode 100644 index 00000000..6af7953a --- /dev/null +++ b/modules/catalogs/src/web/payment-terms/shared/entities/payment-term-list.entity.ts @@ -0,0 +1,14 @@ +import type { PaymentTermListRow } from "./payment-term-list-row.entity"; + +/** + * Interface que representa la respuesta paginada de una lista de vencimientos, + * adaptada desde la respuesta de la API. + */ + +export interface PaymentTermList { + items: PaymentTermListRow[]; + totalPages: number; + totalItems: number; + page: number; + perPage: number; +} diff --git a/modules/catalogs/src/web/payment-terms/shared/entities/payment-term.entity.ts b/modules/catalogs/src/web/payment-terms/shared/entities/payment-term.entity.ts new file mode 100644 index 00000000..9a74ca90 --- /dev/null +++ b/modules/catalogs/src/web/payment-terms/shared/entities/payment-term.entity.ts @@ -0,0 +1,16 @@ +export interface PaymentTerm { + id: string; + companyId: string; + + name: string; + description: string | null; + + isSystem: boolean; + isActive: boolean; + dueRules: PaymentTermDueRule[]; +} + +export interface PaymentTermDueRule { + dueDays: number; + percentage: number; +} diff --git a/modules/catalogs/src/web/payment-terms/shared/hooks/index.ts b/modules/catalogs/src/web/payment-terms/shared/hooks/index.ts new file mode 100644 index 00000000..f3bb8b7b --- /dev/null +++ b/modules/catalogs/src/web/payment-terms/shared/hooks/index.ts @@ -0,0 +1 @@ +export * from "./use-payment-term-list-query"; diff --git a/modules/catalogs/src/web/payment-terms/shared/hooks/keys.ts b/modules/catalogs/src/web/payment-terms/shared/hooks/keys.ts new file mode 100644 index 00000000..1df194e3 --- /dev/null +++ b/modules/catalogs/src/web/payment-terms/shared/hooks/keys.ts @@ -0,0 +1,44 @@ +import type { QueryKey } from "@tanstack/react-query"; + +import type { ListPaymentTermsRequestDTO } from "../../../../common"; + +/** + * Prefijo base para listados + */ +export const LIST_PAYMENT_TERMS_QUERY_KEY_PREFIX = ["payment-terms"] as const; + +/** + * Query key para listado de payment terms + */ +export const LIST_PAYMENT_TERMS_QUERY_KEY = (criteria?: ListPaymentTermsRequestDTO): QueryKey => + [ + ...LIST_PAYMENT_TERMS_QUERY_KEY_PREFIX, + { + pageNumber: criteria?.pageNumber ?? 1, + pageSize: criteria?.pageSize ?? 5, + q: criteria?.q ?? "", + filters: criteria?.filters ?? [], + orderBy: criteria?.orderBy ?? "", + order: criteria?.order ?? "", + }, + ] as const; + +/** + * Query key para detalle de payment term + */ +export const PAYMENT_TERMS_DETAIL_QUERY_KEY_PREFIX = ["payment-terms:detail"] as const; +export const PAYMENT_TERM_QUERY_KEY = (paymentTermId?: string): QueryKey => [ + ...PAYMENT_TERMS_DETAIL_QUERY_KEY_PREFIX, + { paymentTermId }, +]; + +/** + * Keys para mutaciones + */ +export const CREATE_PAYMENT_TERM_MUTATION_KEY = ["payment-terms:create"] as const; +export const UPDATE_PAYMENT_TERM_MUTATION_KEY = ["payment-terms:update"] as const; +export const DELETE_PAYMENT_TERM_MUTATION_KEY = ["payment-terms:delete"] as const; + +/** + * Operaciones de dominio + */ diff --git a/modules/catalogs/src/web/payment-terms/shared/hooks/use-payment-term-list-query.ts b/modules/catalogs/src/web/payment-terms/shared/hooks/use-payment-term-list-query.ts new file mode 100644 index 00000000..0a507dc0 --- /dev/null +++ b/modules/catalogs/src/web/payment-terms/shared/hooks/use-payment-term-list-query.ts @@ -0,0 +1,32 @@ +import type { CriteriaDTO } from "@erp/core"; +import { useDataSource } from "@erp/core/hooks"; +import { type DefaultError, type UseQueryResult, useQuery } from "@tanstack/react-query"; + +import { ListPaymentTermsAdapter } from "../adapters"; +import { getListPaymentTermsByCriteria } from "../api"; +import type { PaymentTermList } from "../entities"; + +import { LIST_PAYMENT_TERMS_QUERY_KEY } from "./keys"; + +export interface PaymentTermsListQueryOptions { + enabled?: boolean; + criteria?: Partial; +} + +export const usePaymentTermsListQuery = ( + options?: PaymentTermsListQueryOptions +): UseQueryResult => { + const dataSource = useDataSource(); + const enabled = options?.enabled ?? true; + const criteria = options?.criteria ?? {}; + + return useQuery({ + queryKey: LIST_PAYMENT_TERMS_QUERY_KEY(criteria), + queryFn: async ({ signal }) => { + const dto = await getListPaymentTermsByCriteria(dataSource, { signal, criteria }); + return ListPaymentTermsAdapter.fromDto(dto); + }, + enabled, + placeholderData: (previousData) => previousData, // Mantiene la página anterior durante refetch por cambio de criteria + }); +}; diff --git a/modules/catalogs/src/web/payment-terms/shared/index.ts b/modules/catalogs/src/web/payment-terms/shared/index.ts new file mode 100644 index 00000000..3a4614c9 --- /dev/null +++ b/modules/catalogs/src/web/payment-terms/shared/index.ts @@ -0,0 +1,2 @@ +export * from "./entities"; +export * from "./hooks"; diff --git a/modules/catalogs/src/web/payment-terms/utils/index.ts b/modules/catalogs/src/web/payment-terms/utils/index.ts new file mode 100644 index 00000000..834739eb --- /dev/null +++ b/modules/catalogs/src/web/payment-terms/utils/index.ts @@ -0,0 +1 @@ +export * from './payment-term-options.utils'; diff --git a/modules/catalogs/src/web/payment-terms/utils/payment-term-options.utils.ts b/modules/catalogs/src/web/payment-terms/utils/payment-term-options.utils.ts new file mode 100644 index 00000000..14082408 --- /dev/null +++ b/modules/catalogs/src/web/payment-terms/utils/payment-term-options.utils.ts @@ -0,0 +1,10 @@ +import type { SelectFieldItem } from "@repo/rdx-ui/components"; + +import type { PaymentTermListRow } from "../shared/entities"; + +export const getPaymentTermOptions = (paymentTerms: PaymentTermListRow[]): SelectFieldItem[] => { + return paymentTerms.map((paymentTerm) => ({ + value: paymentTerm.id, + label: paymentTerm.name, + })); +}; diff --git a/modules/catalogs/tsconfig.json b/modules/catalogs/tsconfig.json index 5a69e561..99485e0d 100644 --- a/modules/catalogs/tsconfig.json +++ b/modules/catalogs/tsconfig.json @@ -10,11 +10,16 @@ "lib": ["ES2022"], "module": "ESNext", "skipLibCheck": true, + + /* Bundler mode */ "moduleResolution": "bundler", "allowImportingTsExtensions": true, "isolatedModules": true, "moduleDetection": "force", "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, diff --git a/modules/core/package.json b/modules/core/package.json index 99b8a6c5..694cb921 100644 --- a/modules/core/package.json +++ b/modules/core/package.json @@ -31,6 +31,7 @@ "@types/react": "^19.2.14", "react": "^19.2.5", "react-dom": "^19.2.5", + "rimraf": "^6.1.3", "typescript": "^6.0.2" }, "dependencies": { diff --git a/modules/core/src/web/manifest.ts b/modules/core/src/web/manifest.ts index 0b5f1338..f52129d3 100644 --- a/modules/core/src/web/manifest.ts +++ b/modules/core/src/web/manifest.ts @@ -3,7 +3,7 @@ import type { IModuleClient, ModuleClientParams } from "./lib"; export const MODULE_NAME = "Core"; const MODULE_VERSION = "1.0.0"; -export const CoreModuleManifiest: IModuleClient = { +export const CoreModuleManifest: IModuleClient = { name: MODULE_NAME, version: MODULE_VERSION, dependencies: [], @@ -15,6 +15,6 @@ export const CoreModuleManifiest: IModuleClient = { }, }; -export default CoreModuleManifiest; +export default CoreModuleManifest; export * from "./lib"; diff --git a/modules/customer-invoices/package.json b/modules/customer-invoices/package.json index b8943940..800441c9 100644 --- a/modules/customer-invoices/package.json +++ b/modules/customer-invoices/package.json @@ -29,8 +29,10 @@ "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@types/react-router-dom": "^5.3.3", + "date-fns": "^4.1.0", "react": "^19.2.5", "react-dom": "^19.2.5", + "rimraf": "^6.1.3", "typescript": "^6.0.2" }, "dependencies": { @@ -39,6 +41,7 @@ "@dnd-kit/utilities": "^3.2.2", "@erp/auth": "workspace:*", "@erp/core": "workspace:*", + "@erp/catalogs": "workspace:*", "@erp/customers": "workspace:*", "@hookform/resolvers": "^5.2.2", "@lglab/react-qr-code": "^1.4.10", @@ -52,7 +55,6 @@ "@tanstack/react-query": "^5.98.0", "@tanstack/react-table": "^8.21.3", "class-variance-authority": "^0.7.1", - "date-fns": "^4.1.0", "dinero.js": "1.9.1", "express": "^4.22.1", "libphonenumber-js": "^1.12.41", diff --git a/modules/customer-invoices/src/common/dto/request/proformas/create-proforma.request.dto.ts b/modules/customer-invoices/src/common/dto/request/proformas/create-proforma.request.dto.ts index fd26b9ba..2edf77f3 100644 --- a/modules/customer-invoices/src/common/dto/request/proformas/create-proforma.request.dto.ts +++ b/modules/customer-invoices/src/common/dto/request/proformas/create-proforma.request.dto.ts @@ -46,6 +46,7 @@ export const CreateProformaRequestSchema = z.object({ global_discount_percentage: PercentageSchema, payment_method_id: z.uuid().nullable().optional(), + payment_term_id: z.uuid().nullable().optional(), items: z.array(CreateProformaItemRequestSchema), }); diff --git a/modules/customer-invoices/src/common/dto/request/proformas/update-proforma-by-id.request.dto.ts b/modules/customer-invoices/src/common/dto/request/proformas/update-proforma-by-id.request.dto.ts index 16bc3e90..74b80fc5 100644 --- a/modules/customer-invoices/src/common/dto/request/proformas/update-proforma-by-id.request.dto.ts +++ b/modules/customer-invoices/src/common/dto/request/proformas/update-proforma-by-id.request.dto.ts @@ -52,6 +52,7 @@ export const UpdateProformaByIdRequestSchema = z.object({ global_discount_percentage: PercentageSchema.optional(), payment_method_id: z.uuid().nullable().optional(), + payment_term_id: z.uuid().nullable().optional(), // retención como código??? retencion_15 diff --git a/modules/customer-invoices/src/common/dto/response/proformas/get-proforma-by-id.response.dto.ts b/modules/customer-invoices/src/common/dto/response/proformas/get-proforma-by-id.response.dto.ts index 88a00661..4f27d45f 100644 --- a/modules/customer-invoices/src/common/dto/response/proformas/get-proforma-by-id.response.dto.ts +++ b/modules/customer-invoices/src/common/dto/response/proformas/get-proforma-by-id.response.dto.ts @@ -8,7 +8,7 @@ import { } from "@erp/core"; import { z } from "zod/v4"; -import { PaymentMethodRefSchema, TaxesBreakdownSchema } from "../../shared"; +import { PaymentMethodRefSchema, PaymentTermRefSchema, TaxesBreakdownSchema } from "../../shared"; import { ProformaItemDetailSchema, ProformaRecipientSummarySchema, @@ -41,6 +41,7 @@ export const GetProformaByIdResponseSchema = z.object({ taxes: z.array(TaxesBreakdownSchema), payment_method: PaymentMethodRefSchema.nullable(), + payment_term: PaymentTermRefSchema.nullable(), subtotal_amount: MoneySchema, items_discount_amount: MoneySchema, diff --git a/modules/customer-invoices/src/common/dto/response/proformas/list-proformas.response.dto.ts b/modules/customer-invoices/src/common/dto/response/proformas/list-proformas.response.dto.ts index 6b1d611b..c4ea4894 100644 --- a/modules/customer-invoices/src/common/dto/response/proformas/list-proformas.response.dto.ts +++ b/modules/customer-invoices/src/common/dto/response/proformas/list-proformas.response.dto.ts @@ -4,5 +4,4 @@ import type { z } from "zod/v4"; import { ProformaSummarySchema } from "../../shared/proforma"; export const ListProformasResponseSchema = createPaginatedListSchema(ProformaSummarySchema); - export type ListProformasResponseDTO = z.infer; diff --git a/modules/customer-invoices/src/common/dto/shared/index.ts b/modules/customer-invoices/src/common/dto/shared/index.ts index 7e736965..a2fe0e3b 100644 --- a/modules/customer-invoices/src/common/dto/shared/index.ts +++ b/modules/customer-invoices/src/common/dto/shared/index.ts @@ -1,6 +1,7 @@ export * from "./issued-invoices"; export * from "./item-position.dto"; export * from "./payment-method-ref.dto"; +export * from "./payment-term-ref.dto"; export * from "./proforma"; export * from "./tax-combination-code.dto"; export * from "./taxes-breakdown.dto"; diff --git a/modules/customer-invoices/src/common/dto/shared/payment-term-ref.dto.ts b/modules/customer-invoices/src/common/dto/shared/payment-term-ref.dto.ts new file mode 100644 index 00000000..3fbe7b07 --- /dev/null +++ b/modules/customer-invoices/src/common/dto/shared/payment-term-ref.dto.ts @@ -0,0 +1,8 @@ +import { z } from "zod/v4"; + +export const PaymentTermRefSchema = z.object({ + id: z.uuid(), + description: z.string(), +}); + +export type PaymentTermRefDTO = z.infer; diff --git a/modules/customer-invoices/src/web/manifest.ts b/modules/customer-invoices/src/web/manifest.ts index 620945cf..ff36ef44 100644 --- a/modules/customer-invoices/src/web/manifest.ts +++ b/modules/customer-invoices/src/web/manifest.ts @@ -5,10 +5,10 @@ import { CustomerInvoiceRoutes } from "./customer-invoice-routes"; export const MODULE_NAME = "CustomerInvoices"; const MODULE_VERSION = "1.0.0"; -export const CustomerInvoicesModuleManifiest: IModuleClient = { +export const CustomerInvoicesModuleManifest: IModuleClient = { name: MODULE_NAME, version: MODULE_VERSION, - dependencies: ["auth", "Core", "Customers"], + dependencies: ["auth", "Core", "Catalogs", "Customers"], protected: true, layout: "app", @@ -17,4 +17,4 @@ export const CustomerInvoicesModuleManifiest: IModuleClient = { }, }; -export default CustomerInvoicesModuleManifiest; +export default CustomerInvoicesModuleManifest; diff --git a/modules/customer-invoices/src/web/proformas/shared/utils/calculate-proforma-due-dates.ts b/modules/customer-invoices/src/web/proformas/shared/utils/calculate-proforma-due-dates.ts new file mode 100644 index 00000000..50e1432e --- /dev/null +++ b/modules/customer-invoices/src/web/proformas/shared/utils/calculate-proforma-due-dates.ts @@ -0,0 +1,27 @@ +export interface CalculateProformaDueDatesParams { + issueDate: string | null; + total: number; + dueRules: PaymentTermDueRule[]; +} + +export interface ProformaDueDatePreview { + dueDate: string | null; + dueDays: number; + percentage: number; + amount: number; +} + +export const calculateProformaDueDates = ({ + issueDate, + total, + dueRules, +}: CalculateProformaDueDatesParams): ProformaDueDatePreview[] => { + return dueRules.map((rule) => { + return { + dueDays: rule.dueDays, + percentage: rule.percentage, + dueDate: issueDate ? addDaysToDateOnly(issueDate, rule.dueDays) : null, + amount: roundMoney(total * (rule.percentage / 100)), + }; + }); +}; diff --git a/modules/customer-invoices/src/web/proformas/shared/utils/index.ts b/modules/customer-invoices/src/web/proformas/shared/utils/index.ts index f9329bc3..c63eeb8d 100644 --- a/modules/customer-invoices/src/web/proformas/shared/utils/index.ts +++ b/modules/customer-invoices/src/web/proformas/shared/utils/index.ts @@ -1 +1,2 @@ +export * from "./calculate-proforma-due-dates"; export * from "./proforma-fiscal-options.utils"; diff --git a/modules/customer-invoices/src/web/proformas/update/controllers/index.ts b/modules/customer-invoices/src/web/proformas/update/controllers/index.ts index f4331ac6..e01d3f58 100644 --- a/modules/customer-invoices/src/web/proformas/update/controllers/index.ts +++ b/modules/customer-invoices/src/web/proformas/update/controllers/index.ts @@ -1,5 +1,6 @@ export * from "./use-update-proforma-controller"; export * from "./use-update-proforma-items-controller"; export * from "./use-update-proforma-page-controller"; +export * from "./use-update-proforma-payment-controller"; export * from "./use-update-proforma-tax-controller"; export * from "./use-update-proforma-totals-controller"; diff --git a/modules/customer-invoices/src/web/proformas/update/controllers/use-update-proforma-controller.ts b/modules/customer-invoices/src/web/proformas/update/controllers/use-update-proforma-controller.ts index 18aa1df5..2e59b4e5 100644 --- a/modules/customer-invoices/src/web/proformas/update/controllers/use-update-proforma-controller.ts +++ b/modules/customer-invoices/src/web/proformas/update/controllers/use-update-proforma-controller.ts @@ -25,6 +25,7 @@ import { } from "../utils"; import { useUpdateProformaItemsController } from "./use-update-proforma-items-controller"; +import { useUpdateProformaPaymentController } from "./use-update-proforma-payment-controller"; import { useUpdateProformaTaxController } from "./use-update-proforma-tax-controller"; import { useUpdateProformaTotalsController } from "./use-update-proforma-totals-controller"; @@ -251,6 +252,8 @@ export const useUpdateProformaController = ( form, }); + const paymentCtrl = useUpdateProformaPaymentController(); + return { // form formId, @@ -259,6 +262,7 @@ export const useUpdateProformaController = ( itemsCtrl, taxCtrl, totalsCtrl, + paymentCtrl, // currencyCode, diff --git a/modules/customer-invoices/src/web/proformas/update/controllers/use-update-proforma-payment-controller.ts b/modules/customer-invoices/src/web/proformas/update/controllers/use-update-proforma-payment-controller.ts new file mode 100644 index 00000000..0f0003c7 --- /dev/null +++ b/modules/customer-invoices/src/web/proformas/update/controllers/use-update-proforma-payment-controller.ts @@ -0,0 +1,40 @@ +import { + getPaymentMethodOptions, + usePaymentMethodsListQuery, +} from "@erp/catalogs/client/payment-methods"; +import { + getPaymentTermOptions, + usePaymentTermsListQuery, +} from "@erp/catalogs/client/payment-terms"; +import { useMemo } from "react"; + +export const useUpdateProformaPaymentController = () => { + const paymentMethodsQuery = usePaymentMethodsListQuery(); + + const paymentTermsQuery = usePaymentTermsListQuery(); + + const paymentMethodOptions = useMemo(() => { + return getPaymentMethodOptions(paymentMethodsQuery.data?.items ?? []); + }, [paymentMethodsQuery.data?.items]); + + const paymentTermOptions = useMemo(() => { + return getPaymentTermOptions(paymentTermsQuery.data?.items ?? []); + }, [paymentTermsQuery.data?.items]); + + return { + paymentMethodOptions, + paymentTermOptions, + + isLoading: paymentMethodsQuery.isLoading || paymentTermsQuery.isLoading, + + isFetching: paymentMethodsQuery.isFetching || paymentTermsQuery.isFetching, + + isError: paymentMethodsQuery.isError || paymentTermsQuery.isError, + + error: paymentMethodsQuery.error ?? paymentTermsQuery.error, + }; +}; + +export type UseUpdateProformaPaymentControllerResult = ReturnType< + typeof useUpdateProformaPaymentController +>; diff --git a/modules/customer-invoices/src/web/proformas/update/entities/proforma-update-form.entity.ts b/modules/customer-invoices/src/web/proformas/update/entities/proforma-update-form.entity.ts index 16c38e83..0b95121d 100644 --- a/modules/customer-invoices/src/web/proformas/update/entities/proforma-update-form.entity.ts +++ b/modules/customer-invoices/src/web/proformas/update/entities/proforma-update-form.entity.ts @@ -47,6 +47,7 @@ export interface ProformaUpdateForm { retentionPercentage: number | null; paymentMethodId: string | null; + paymentTermId: string | null; items: ProformaItemUpdateForm[]; } diff --git a/modules/customer-invoices/src/web/proformas/update/entities/proforma-update-form.schema.ts b/modules/customer-invoices/src/web/proformas/update/entities/proforma-update-form.schema.ts index 111c475a..2dd9085c 100644 --- a/modules/customer-invoices/src/web/proformas/update/entities/proforma-update-form.schema.ts +++ b/modules/customer-invoices/src/web/proformas/update/entities/proforma-update-form.schema.ts @@ -48,6 +48,7 @@ export const ProformaUpdateFormSchema = z retentionPercentage: z.number().nullable(), paymentMethodId: z.string().nullable(), + paymentTermId: z.string().nullable(), items: z.array(ProformaItemUpdateFormSchema).min(1), }) diff --git a/modules/customer-invoices/src/web/proformas/update/entities/proforma-update-patch.entity.ts b/modules/customer-invoices/src/web/proformas/update/entities/proforma-update-patch.entity.ts index a1609159..90b4d4fd 100644 --- a/modules/customer-invoices/src/web/proformas/update/entities/proforma-update-patch.entity.ts +++ b/modules/customer-invoices/src/web/proformas/update/entities/proforma-update-patch.entity.ts @@ -38,6 +38,7 @@ export type ProformaUpdatePatch = { retentionPercentage?: number | null; paymentMethodId?: string | null; + paymentTermId?: string | null; languageCode?: string; currencyCode?: string; diff --git a/modules/customer-invoices/src/web/proformas/update/ui/components/index.ts b/modules/customer-invoices/src/web/proformas/update/ui/components/index.ts index 203c7a6c..5dd68072 100644 --- a/modules/customer-invoices/src/web/proformas/update/ui/components/index.ts +++ b/modules/customer-invoices/src/web/proformas/update/ui/components/index.ts @@ -1 +1,2 @@ +export * from "./proforma-info-alert"; export * from "./proforma-update-skeleton"; diff --git a/modules/customer-invoices/src/web/proformas/update/ui/components/proforma-info-alert.tsx b/modules/customer-invoices/src/web/proformas/update/ui/components/proforma-info-alert.tsx new file mode 100644 index 00000000..28e2239b --- /dev/null +++ b/modules/customer-invoices/src/web/proformas/update/ui/components/proforma-info-alert.tsx @@ -0,0 +1,57 @@ +// packages/rdx-ui/src/components/feedback/info-alert.tsx +import { Alert, AlertDescription, AlertTitle } from "@repo/shadcn-ui/components"; +import { cn } from "@repo/shadcn-ui/lib/utils"; +import { InfoIcon } from "lucide-react"; +import type * as React from "react"; + +type ProformaInfoAlertProps = { + title: string; + description?: string; + children?: React.ReactNode; + className?: string; + iconClassName?: string; + titleClassName?: string; + descriptionClassName?: string; +}; + +export const ProformaInfoAlert = ({ + title, + description, + children, + className, + iconClassName, + titleClassName, + descriptionClassName, +}: ProformaInfoAlertProps) => { + return ( + +
+ +
+ +
+ + {title} + + + {(description || children) && ( + + {description ?? children} + + )} +
+
+ ); +}; diff --git a/modules/customer-invoices/src/web/proformas/update/ui/editors/index.ts b/modules/customer-invoices/src/web/proformas/update/ui/editors/index.ts index 270e132b..ee2b492a 100644 --- a/modules/customer-invoices/src/web/proformas/update/ui/editors/index.ts +++ b/modules/customer-invoices/src/web/proformas/update/ui/editors/index.ts @@ -1,2 +1,10 @@ +export * from "./proforma-payment-editor"; +export * from "./proforma-settings-editor"; +export * from "./proforma-taxes-card"; export * from "./proforma-update-editor-form"; +export * from "./proforma-update-header-editor"; +export * from "./proforma-update-item-row-editor"; +export * from "./proforma-update-items-editor"; +export * from "./proforma-update-items-totals"; export * from "./proforma-update-recipient-editor"; +export * from "./proforma-update-tax-editor"; diff --git a/modules/customer-invoices/src/web/proformas/update/ui/editors/proforma-payment-editor.tsx b/modules/customer-invoices/src/web/proformas/update/ui/editors/proforma-payment-editor.tsx new file mode 100644 index 00000000..fd19e61b --- /dev/null +++ b/modules/customer-invoices/src/web/proformas/update/ui/editors/proforma-payment-editor.tsx @@ -0,0 +1,69 @@ +import { + FormSectionCard, + FormSectionGrid, + SelectField, + type SelectFieldItem, +} from "@repo/rdx-ui/components"; +import { CreditCardIcon } from "lucide-react"; + +import { useTranslation } from "../../../../i18n"; + +interface ProformaUpdatePaymentEditorProps { + paymentMethodOptions: SelectFieldItem[]; + paymentTermOptions: SelectFieldItem[]; + + disabled?: boolean; + readOnly?: boolean; + + className?: string; +} + +export const ProformaUpdatePaymentEditor = ({ + paymentMethodOptions, + paymentTermOptions, + disabled = false, + readOnly = false, + className, +}: ProformaUpdatePaymentEditorProps) => { + const { t } = useTranslation(); + + return ( + } + title={t("form_groups.proformas.payment.title", "Condiciones de pago")} + > + + + + + + + ); +}; diff --git a/modules/customer-invoices/src/web/proformas/update/ui/editors/proforma-settings-editor.tsx b/modules/customer-invoices/src/web/proformas/update/ui/editors/proforma-settings-editor.tsx new file mode 100644 index 00000000..8d7d317d --- /dev/null +++ b/modules/customer-invoices/src/web/proformas/update/ui/editors/proforma-settings-editor.tsx @@ -0,0 +1,51 @@ +import { FormSectionCard, FormSectionGrid, SelectField } from "@repo/rdx-ui/components"; +import { Settings2Icon } from "lucide-react"; + +import { useTranslation } from "../../../../i18n"; + +interface ProformaUpdateSettingsEditorProps { + disabled?: boolean; + readOnly?: boolean; + + className?: string; +} + +export const ProformaUpdateSettingsEditor = ({ + disabled = false, + readOnly = false, + className, +}: ProformaUpdateSettingsEditorProps) => { + const { t } = useTranslation(); + + return ( + } + title={t("form_groups.proformas.settings.title", "Configuración")} + > + + + + + + + ); +}; diff --git a/modules/customer-invoices/src/web/proformas/update/ui/editors/proforma-update-editor-form.tsx b/modules/customer-invoices/src/web/proformas/update/ui/editors/proforma-update-editor-form.tsx index d2b5798a..75b767b7 100644 --- a/modules/customer-invoices/src/web/proformas/update/ui/editors/proforma-update-editor-form.tsx +++ b/modules/customer-invoices/src/web/proformas/update/ui/editors/proforma-update-editor-form.tsx @@ -5,15 +5,21 @@ import { PercentageField } from "@repo/rdx-ui/components"; import { preventEnterKeySubmitForm } from "@repo/rdx-ui/helpers"; import { Button } from "@repo/shadcn-ui/components"; -import { ProformaUpdateRecipientEditor } from "."; +import { + ProformaUpdatePaymentEditor, + ProformaUpdateRecipientEditor, + ProformaUpdateSettingsEditor, +} from "."; import { useTranslation } from "../../../../i18n"; import type { UseUpdateProformaItemsControllerResult, + UseUpdateProformaPaymentControllerResult, UseUpdateProformaTaxControllerResult, UseUpdateProformaTotalsControllerResult, } from "../../controllers"; import { ProformaTotalsSummary } from "../blocks"; +import { ProformaInfoAlert } from "../components"; import { ProformaUpdateHeaderEditor } from "./proforma-update-header-editor"; import { ProformaUpdateItemsEditor } from "./proforma-update-items-editor"; @@ -32,6 +38,7 @@ type ProformaUpdateEditorProps = { itemsCtrl: UseUpdateProformaItemsControllerResult; taxCtrl: UseUpdateProformaTaxControllerResult; totalsCtrl: UseUpdateProformaTotalsControllerResult; + paymentCtrl: UseUpdateProformaPaymentControllerResult; currencyCode?: string; languageCode?: string; @@ -48,6 +55,7 @@ export const ProformaUpdateEditorForm = ({ itemsCtrl, taxCtrl, totalsCtrl, + paymentCtrl, currencyCode, languageCode, }: ProformaUpdateEditorProps) => { @@ -55,43 +63,64 @@ export const ProformaUpdateEditorForm = ({ return (
-
- + +
+
+
+ - -
- - - -
- - - } - showRec={taxCtrl.hasRecPercentage} - showRetention={taxCtrl.hasRetentionPercentage} - totals={totalsCtrl.totals} - /> +
+ + + +
+ + } + showRec={taxCtrl.hasRecPercentage} + showRetention={taxCtrl.hasRetentionPercentage} + totals={totalsCtrl.totals} + /> +
+
+
+ + + +
diff --git a/modules/customer-invoices/src/web/proformas/update/ui/editors/proforma-update-header-editor.tsx b/modules/customer-invoices/src/web/proformas/update/ui/editors/proforma-update-header-editor.tsx index 2e1511a2..b61ba65d 100644 --- a/modules/customer-invoices/src/web/proformas/update/ui/editors/proforma-update-header-editor.tsx +++ b/modules/customer-invoices/src/web/proformas/update/ui/editors/proforma-update-header-editor.tsx @@ -58,15 +58,6 @@ export const ProformaUpdateHeaderEditor = ({ } /> - - } title={t("form_groups.proformas.taxes.title", "Impuestos")} > -
- 1. Régimen fiscal - - Selecciona el régimen fiscal que aplica a esta proforma. - - - - + + + (value === null || value === "" ? null : Number(value))} + disabled={disabled} + inputClassName="bg-background" + items={getProformaTaxOptions()} + label={t("form_fields.proformas.default_tax_percentage.label", "IVA por defecto")} + name="taxPercentage" + onChange={(value) => { + const parsed = parseProformaTaxPercentage(value as number | null); + if (parsed !== null) { + taxCtrl.updateTaxPercentage(parsed); + } + }} + placeholder={t( + "form_fields.proformas.default_tax_percentage.placeholder", + "Selecciona IVA" + )} + readOnly={readOnly || taxCtrl.usesPerLineTax} + serialize={(value) => (typeof value === "number" ? String(value) : "")} + /> + + + checked ? taxCtrl.disablePerLineTaxes() : taxCtrl.enablePerLineTaxes() + } + /> + + + {t( + "form_fields.proformas.has_equivalence_surcharge.label", + "Recargo de equivalencia" )} - readOnly={readOnly || taxCtrl.usesPerLineTax} - /> - - -
- - - - - {" "} - {t( - "proformas.update.taxes.disable_per_line", - "Mismo IVA en todas las líneas de la proforma" - )} - - - Puedes usar un tipo único para todos las líneas de detalle o permitir que cada línea - tenga su propio IVA. - - - - checked ? taxCtrl.disablePerLineTaxes() : taxCtrl.enablePerLineTaxes() - } - /> - - - -
- - (value === null || value === "" ? null : Number(value))} - disabled={disabled} - inputClassName="bg-background" - items={getProformaTaxOptions()} - label={t("form_fields.proformas.default_tax_percentage.label", "IVA por defecto")} - name="taxPercentage" - onChange={(value) => { - const parsed = parseProformaTaxPercentage(value as number | null); - if (parsed !== null) { - taxCtrl.updateTaxPercentage(parsed); - } - }} - placeholder={t( - "form_fields.proformas.default_tax_percentage.placeholder", - "Selecciona IVA" - )} - readOnly={readOnly || taxCtrl.usesPerLineTax} - serialize={(value) => (typeof value === "number" ? String(value) : "")} - /> - -
- -
- Impuestos adicionales - - Activa opciones fiscales adicionales como recargo de equivalencia o retenciones - (IRPF), según el tipo de cliente y normativa aplicable. - + {taxCtrl.hasRecPercentage ? ( + + {PercentageHelper.formatPercent(taxCtrl.recPercentage ?? 0)} + + ) : null} + + } + name="hasRecPercentage" + onCheckedChange={taxCtrl.updateRecPercentage} + readOnly={readOnly} + /> - - - {t( - "form_fields.proformas.has_equivalence_surcharge.label", - "Recargo de equivalencia" - )} + - {taxCtrl.hasRecPercentage ? ( - - {PercentageHelper.formatPercent(taxCtrl.recPercentage ?? 0)} - - ) : null} - - } - name="hasRecPercentage" - onCheckedChange={taxCtrl.updateRecPercentage} - readOnly={readOnly} - /> - - - - (value === null || value === "" ? null : Number(value))} - disabled={disabled || !taxCtrl.hasRetentionPercentage} - inputClassName="bg-background" - items={getProformaRetentionOptions()} - label={t("form_fields.proformas.retention_percentage.label", "Retención")} - name="retentionPercentage" - onChange={(value) => { - const parsed = parseProformaRetentionPercentage(value as number | null); - if (parsed !== null) { - taxCtrl.updateRetentionPercentage(parsed); - } - }} - placeholder={t( - "form_fields.proformas.default_tax_percentage.placeholder", - "Selecciona IVA" - )} - readOnly={readOnly || taxCtrl.usesPerLineTax} - serialize={(value) => (typeof value === "number" ? String(value) : "")} - /> - -
-
-
+ (value === null || value === "" ? null : Number(value))} + disabled={disabled || !taxCtrl.hasRetentionPercentage} + inputClassName="bg-background" + items={getProformaRetentionOptions()} + label={t("form_fields.proformas.retention_percentage.label", "Retención")} + name="retentionPercentage" + onChange={(value) => { + const parsed = parseProformaRetentionPercentage(value as number | null); + if (parsed !== null) { + taxCtrl.updateRetentionPercentage(parsed); + } + }} + placeholder={t( + "form_fields.proformas.default_tax_percentage.placeholder", + "Selecciona IVA" + )} + readOnly={readOnly || taxCtrl.usesPerLineTax} + serialize={(value) => (typeof value === "number" ? String(value) : "")} + /> + ); }; diff --git a/modules/customer-invoices/src/web/proformas/update/ui/pages/proforma-update-page.tsx b/modules/customer-invoices/src/web/proformas/update/ui/pages/proforma-update-page.tsx index 73aa69cb..5751aa15 100644 --- a/modules/customer-invoices/src/web/proformas/update/ui/pages/proforma-update-page.tsx +++ b/modules/customer-invoices/src/web/proformas/update/ui/pages/proforma-update-page.tsx @@ -61,7 +61,7 @@ export const ProformaUpdatePage = () => { return ( - + navigateBack()} @@ -84,7 +84,7 @@ export const ProformaUpdatePage = () => { /> - + {updateCtrl.isUpdateError && ( { onCreateCustomerClick={() => null} onReset={updateCtrl.resetForm} onSubmit={updateCtrl.onSubmit} + paymentCtrl={updateCtrl.paymentCtrl} selectedCustomer={updateCtrl.selectedCustomer} taxCtrl={updateCtrl.taxCtrl} totalsCtrl={updateCtrl.totalsCtrl} diff --git a/modules/customer-invoices/src/web/proformas/update/utils/build-update-proforma-by-id-params.ts b/modules/customer-invoices/src/web/proformas/update/utils/build-update-proforma-by-id-params.ts index 39697d47..dd8b4970 100644 --- a/modules/customer-invoices/src/web/proformas/update/utils/build-update-proforma-by-id-params.ts +++ b/modules/customer-invoices/src/web/proformas/update/utils/build-update-proforma-by-id-params.ts @@ -80,6 +80,10 @@ export const buildUpdateProformaByIdParams = ( data.payment_method_id = patch.paymentMethodId; } + if (ObjectHelper.hasOwn(patch, "paymentTermId")) { + data.payment_term_id = patch.paymentTermId; + } + if (ObjectHelper.hasOwn(patch, "globalDiscountPercentage")) { data.global_discount_percentage = PercentageDTOHelper.fromNumber( patch.globalDiscountPercentage!, diff --git a/modules/customers/package.json b/modules/customers/package.json index aaa70909..a48cb22a 100644 --- a/modules/customers/package.json +++ b/modules/customers/package.json @@ -30,6 +30,7 @@ "@types/react-router-dom": "^5.3.3", "react": "^19.2.5", "react-dom": "^19.2.5", + "rimraf": "^6.1.3", "typescript": "^6.0.2" }, "dependencies": { @@ -47,7 +48,6 @@ "@tanstack/react-table": "^8.21.3", "express": "^4.22.1", "lucide-react": "^1.8.0", - "react-data-table-component": "^7.7.0", "react-hook-form": "^7.72.1", "react-i18next": "^17.0.2", "react-router-dom": "^7.14.0", diff --git a/modules/customers/src/web/manifest.ts b/modules/customers/src/web/manifest.ts index fa51c445..70a0953c 100644 --- a/modules/customers/src/web/manifest.ts +++ b/modules/customers/src/web/manifest.ts @@ -5,7 +5,7 @@ import { CustomerRoutes } from "./customer-routes"; export const MODULE_NAME = "Customers"; const MODULE_VERSION = "1.0.0"; -export const CustomersModuleManifiest: IModuleClient = { +export const CustomersModuleManifest: IModuleClient = { name: MODULE_NAME, version: MODULE_VERSION, dependencies: ["auth", "Core"], @@ -17,4 +17,4 @@ export const CustomersModuleManifiest: IModuleClient = { }, }; -export default CustomersModuleManifiest; +export default CustomersModuleManifest; diff --git a/modules/factuges/package.json b/modules/factuges/package.json index 67989806..f1391e7e 100644 --- a/modules/factuges/package.json +++ b/modules/factuges/package.json @@ -17,6 +17,7 @@ }, "devDependencies": { "@types/express": "^4.17.21", + "rimraf": "^6.1.3", "typescript": "^6.0.2" }, "dependencies": { diff --git a/modules/supplier-invoices/package.json b/modules/supplier-invoices/package.json index 0a578377..133cc703 100644 --- a/modules/supplier-invoices/package.json +++ b/modules/supplier-invoices/package.json @@ -18,6 +18,7 @@ }, "devDependencies": { "@types/express": "^4.17.21", + "rimraf": "^6.1.3", "typescript": "^6.0.2" }, "dependencies": { diff --git a/modules/supplier-invoices/src/api/infrastucture/persistence/sequelize/mappers/domain/sequelize-supplier-invoice-domain.mapper.ts b/modules/supplier-invoices/src/api/infrastucture/persistence/sequelize/mappers/domain/sequelize-supplier-invoice-domain.mapper.ts index 81d18b8b..0bd0dd88 100644 --- a/modules/supplier-invoices/src/api/infrastucture/persistence/sequelize/mappers/domain/sequelize-supplier-invoice-domain.mapper.ts +++ b/modules/supplier-invoices/src/api/infrastucture/persistence/sequelize/mappers/domain/sequelize-supplier-invoice-domain.mapper.ts @@ -498,3 +498,4 @@ export class SequelizeSupplierInvoiceDomainMapper extends SequelizeDomainMapper< ); } } +11111111 \ No newline at end of file diff --git a/modules/supplier/package.json b/modules/supplier/package.json index a3f2d553..6be359b6 100644 --- a/modules/supplier/package.json +++ b/modules/supplier/package.json @@ -30,6 +30,7 @@ "@types/react-router-dom": "^5.3.3", "react": "^19.2.5", "react-dom": "^19.2.5", + "rimraf": "^6.1.3", "typescript": "^6.0.2" }, "dependencies": { @@ -47,7 +48,6 @@ "@tanstack/react-table": "^8.21.3", "express": "^4.22.1", "lucide-react": "^1.8.0", - "react-data-table-component": "^7.7.0", "react-hook-form": "^7.72.1", "react-i18next": "^17.0.2", "react-router-dom": "^7.14.0", diff --git a/package.json b/package.json index 2f31ee54..5a04d230 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "packages/*" ], "scripts": { - "build": "turbo build", + "build": "turbo run build", "build:templates": "bash scripts/build-templates.sh", "build:api": "bash scripts/build-api.sh rodax --api", "dev": "turbo dev", @@ -24,7 +24,7 @@ "format:check": "biome format .", "check": "biome check .", "check:write": "biome check --write .", - "typecheck": "turbo run typecheck" + "typecheck": "tsc -p tsconfig.json --noEmit" }, "devDependencies": { "@biomejs/biome": "2.4.11", @@ -39,7 +39,7 @@ "rimraf": "^6.1.3", "ts-node": "^10.9.2", "tailwindcss": "^4.2.2", - "turbo": "^2.9.6", + "turbo": "^2.9.14", "typescript": "6.0.2" }, "engines": { diff --git a/packages/i18n/package.json b/packages/i18n/package.json index e539fd9e..a06cd8c9 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -12,15 +12,16 @@ "exports": { ".": "./src/i18n.ts" }, + "devDependencies": { + "@repo/typescript-config": "workspace:*", + "@types/node": "^25.6.0", + "rimraf": "^6.1.3", + "typescript": "^6.0.2" + }, "dependencies": { "i18next": "26.0.4", "i18next-browser-languagedetector": "^8.2.1", "i18next-http-backend": "^3.0.4", "react-i18next": "^17.0.2" - }, - "devDependencies": { - "@repo/typescript-config": "workspace:*", - "@types/node": "^25.6.0", - "typescript": "^6.0.2" } } \ No newline at end of file diff --git a/packages/rdx-ddd/package.json b/packages/rdx-ddd/package.json index 02e5e518..ffb93fea 100644 --- a/packages/rdx-ddd/package.json +++ b/packages/rdx-ddd/package.json @@ -17,6 +17,7 @@ "@repo/typescript-config": "workspace:*", "@types/dinero.js": "1.9.1", "@types/node": "^25.6.0", + "rimraf": "^6.1.3", "typescript": "^6.0.2" }, "dependencies": { diff --git a/packages/rdx-logger/package.json b/packages/rdx-logger/package.json index 9effcb7c..82573696 100644 --- a/packages/rdx-logger/package.json +++ b/packages/rdx-logger/package.json @@ -14,6 +14,7 @@ ".": "./src/index.ts" }, "devDependencies": { + "rimraf": "^6.1.3", "typescript": "^6.0.2" }, "dependencies": { diff --git a/packages/rdx-ui/package.json b/packages/rdx-ui/package.json index d8dcafcb..920e754e 100644 --- a/packages/rdx-ui/package.json +++ b/packages/rdx-ui/package.json @@ -5,9 +5,11 @@ "type": "module", "sideEffects": false, "scripts": { + "typecheck": "tsc -p tsconfig.json --noEmit", "ui:lint": "biome lint --fix", "check": "biome check .", - "lint": "biome lint ." + "lint": "biome lint .", + "clean": "rimraf .turbo node_modules dist" }, "exports": { "./helpers": "./src/helpers/index.ts", @@ -20,10 +22,6 @@ "./src/hooks/index.ts" ] }, - "peerDependencies": { - "react": "^19.2.5", - "react-dom": "^19.2.5" - }, "devDependencies": { "@biomejs/biome": "^2.4.11", "@repo/i18next": "workspace:*", @@ -34,10 +32,10 @@ "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", + "date-fns": "^4.1.0", "esbuild-plugin-react18": "^0.2.6", "esbuild-plugin-react18-css": "^0.0.4", - "react": "^19.2.5", - "react-dom": "^19.2.5", + "rimraf": "^6.1.3", "tailwindcss": "^4.2.2", "tsup": "^8.5.1", "tw-animate-css": "^1.4.0", @@ -58,6 +56,8 @@ "cmdk": "^1.1.1", "esbuild-raw-plugin": "^0.3.1", "lucide-react": "^1.8.0", + "react": "^19.2.5", + "react-dom": "^19.2.5", "react-hook-form": "^7.72.1", "react-i18next": "^17.0.2", "react-router": "^7.14.0", diff --git a/packages/rdx-ui/src/components/form/form-field-label.tsx b/packages/rdx-ui/src/components/form/form-field-label.tsx index 011a55b6..011dc563 100644 --- a/packages/rdx-ui/src/components/form/form-field-label.tsx +++ b/packages/rdx-ui/src/components/form/form-field-label.tsx @@ -1,8 +1,12 @@ import { FieldLabel } from "@repo/shadcn-ui/components"; +import type { ReactNode } from "react"; interface FormFieldLabelProps extends React.ComponentProps { required?: boolean; optional?: boolean; + className?: string; + htmlFor?: string; + children: ReactNode; } export const FormFieldLabel = ({ diff --git a/packages/rdx-ui/src/components/form/form-section-card.tsx b/packages/rdx-ui/src/components/form/form-section-card.tsx index 8bb3217b..9a05b24d 100644 --- a/packages/rdx-ui/src/components/form/form-section-card.tsx +++ b/packages/rdx-ui/src/components/form/form-section-card.tsx @@ -33,28 +33,30 @@ export const FormSectionCard = ({ return ( - -
- {icon ? ( -
- {" "} - {icon}{" "} -
- ) : null} - -
- {title ? {title} : null} - {description ? ( - {description} + {hasHeader && ( + +
+ {icon ? ( +
+ {" "} + {icon}{" "} +
) : null} + +
+ {title ? {title} : null} + {description ? ( + {description} + ) : null} +
-
- + + )} {children} diff --git a/packages/rdx-ui/src/components/form/select-field.tsx b/packages/rdx-ui/src/components/form/select-field.tsx index 756090b2..805a07e3 100644 --- a/packages/rdx-ui/src/components/form/select-field.tsx +++ b/packages/rdx-ui/src/components/form/select-field.tsx @@ -13,14 +13,14 @@ import { Controller, type FieldPath, type FieldValues, useFormContext } from "re import { FormFieldLabel } from "./form-field-label.tsx"; -interface SelectFieldItem { +export type SelectFieldItem = { value: string; label: string; -} +}; -type SelectFieldValue = string | null; +export type SelectFieldValue = string | null; -type SelectFieldProps = { +export type SelectFieldProps = { name: FieldPath; label?: string; @@ -104,7 +104,7 @@ export function SelectField({