Clientes y facturas de cliente
This commit is contained in:
parent
327756413d
commit
3846199cbe
@ -75,7 +75,7 @@
|
|||||||
"uuid": "^11.0.5",
|
"uuid": "^11.0.5",
|
||||||
"winston": "^3.17.0",
|
"winston": "^3.17.0",
|
||||||
"winston-daily-rotate-file": "^5.0.0",
|
"winston-daily-rotate-file": "^5.0.0",
|
||||||
"zod": "^3.25.67"
|
"zod": "^4.1.11"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { DateTime } from "luxon";
|
import { DateTime } from "luxon";
|
||||||
import http from "node:http";
|
import http from "node:http";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { createApp } from "./app";
|
import { createApp } from "./app";
|
||||||
import { ENV } from "./config";
|
import { ENV } from "./config";
|
||||||
import { tryConnectToDatabase } from "./config/database";
|
import { tryConnectToDatabase } from "./config/database";
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { IModuleServer, ModuleParams } from "@erp/core/api";
|
import { IModuleServer, ModuleParams } from "@erp/core/api";
|
||||||
import { logger } from "../logger";
|
import { logger } from "../logger";
|
||||||
import { initModels, registerModels } from "./model-loader";
|
import { initModels, registerModels } from "./model-loader";
|
||||||
import { registerService } from "./service-registry";
|
import { getService, listServices, registerService } from "./service-registry";
|
||||||
|
|
||||||
const registeredModules: Map<string, IModuleServer> = new Map();
|
const registeredModules: Map<string, IModuleServer> = new Map();
|
||||||
const initializedModules = new Set<string>();
|
const initializedModules = new Set<string>();
|
||||||
@ -81,7 +81,13 @@ async function loadModule(name: string, params: ModuleParams, stack: string[]) {
|
|||||||
|
|
||||||
// 3) Registrar dependencias que expone (permite async)
|
// 3) Registrar dependencias que expone (permite async)
|
||||||
const pkgApi = await withPhase(name, "registerDependencies", async () => {
|
const pkgApi = await withPhase(name, "registerDependencies", async () => {
|
||||||
return await Promise.resolve(pkg.registerDependencies?.(params));
|
return await Promise.resolve(
|
||||||
|
pkg.registerDependencies?.({
|
||||||
|
...params,
|
||||||
|
listServices,
|
||||||
|
getService,
|
||||||
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 4) Registrar modelos de Sequelize, si existen
|
// 4) Registrar modelos de Sequelize, si existen
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import customerInvoicesAPIModule from "@erp/customer-invoices/api";
|
import customerInvoicesAPIModule from "@erp/customer-invoices/api";
|
||||||
import customersAPIModule from "@erp/customers/api";
|
import customersAPIModule from "@erp/customers/api";
|
||||||
//import verifactuAPIModule from "@erp/verifactu/api";
|
import verifactuAPIModule from "@erp/verifactu/api";
|
||||||
|
|
||||||
import { registerModule } from "./lib";
|
import { registerModule } from "./lib";
|
||||||
|
|
||||||
@ -8,5 +8,5 @@ export const registerModules = () => {
|
|||||||
//registerModule(authAPIModule);
|
//registerModule(authAPIModule);
|
||||||
registerModule(customersAPIModule);
|
registerModule(customersAPIModule);
|
||||||
registerModule(customerInvoicesAPIModule);
|
registerModule(customerInvoicesAPIModule);
|
||||||
//registerModule(verifactuAPIModule);
|
registerModule(verifactuAPIModule);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
"@repo/rdx-utils": "workspace:*",
|
"@repo/rdx-utils": "workspace:*",
|
||||||
"@repo/rdx-ui": "workspace:*",
|
"@repo/rdx-ui": "workspace:*",
|
||||||
"@repo/shadcn-ui": "workspace:*",
|
"@repo/shadcn-ui": "workspace:*",
|
||||||
|
"@hookform/resolvers": "^5.0.1",
|
||||||
"@tanstack/react-query": "^5.75.4",
|
"@tanstack/react-query": "^5.75.4",
|
||||||
"axios": "^1.9.0",
|
"axios": "^1.9.0",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
@ -35,6 +36,6 @@
|
|||||||
"react-i18next": "^15.5.1",
|
"react-i18next": "^15.5.1",
|
||||||
"react-router-dom": "^6.26.0",
|
"react-router-dom": "^6.26.0",
|
||||||
"sequelize": "^6.37.5",
|
"sequelize": "^6.37.5",
|
||||||
"zod": "^3.25.67"
|
"zod": "^4.1.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { TaxCatalogProvider } from "@erp/core";
|
import { TaxCatalogProvider } from "@erp/core";
|
||||||
import { Percentage, ValueObject } from "@repo/rdx-ddd";
|
import { Percentage, ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
const DEFAULT_SCALE = 2;
|
const DEFAULT_SCALE = 2;
|
||||||
const DEFAULT_MIN_VALUE = 0;
|
const DEFAULT_MIN_VALUE = 0;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { ZodSchema } from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { InternalApiError, ValidationApiError } from "../errors";
|
import { InternalApiError, ValidationApiError } from "../errors";
|
||||||
import { ExpressController } from "../express-controller";
|
import { ExpressController } from "../express-controller";
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ export type ValidateRequestWithSchemaOptions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const validateRequest = <T extends "body" | "query" | "params">(
|
export const validateRequest = <T extends "body" | "query" | "params">(
|
||||||
schema: ZodSchema,
|
schema: z.ZodObject<any>,
|
||||||
source: T = "body" as T,
|
source: T = "body" as T,
|
||||||
options: ValidateRequestWithSchemaOptions = { sanitize: true }
|
options: ValidateRequestWithSchemaOptions = { sanitize: true }
|
||||||
): RequestHandler => {
|
): RequestHandler => {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { AmountBaseSchema } from "./base.schemas";
|
import { AmountBaseSchema } from "./base.schemas";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cadena con valor numérico:
|
* Cadena con valor numérico:
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Esquema del DTO para Criteria.fromPrimitives(...)
|
Esquema del DTO para Criteria.fromPrimitives(...)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { MetadataSchema } from "./metadata.dto";
|
import { MetadataSchema } from "./metadata.dto";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const MetadataSchema = z
|
export const MetadataSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { NumericStringSchema } from "./base.schemas";
|
import { NumericStringSchema } from "./base.schemas";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { NumericStringSchema } from "./base.schemas";
|
import { NumericStringSchema } from "./base.schemas";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
export * from "./use-datasource";
|
export * from "./use-datasource";
|
||||||
|
export * from "./use-hook-form";
|
||||||
export * from "./use-pagination";
|
export * from "./use-pagination";
|
||||||
export * from "./use-query-key";
|
export * from "./use-query-key";
|
||||||
export * from "./use-toggle";
|
export * from "./use-toggle";
|
||||||
|
|||||||
1
modules/core/src/web/hooks/use-hook-form/index.ts
Normal file
1
modules/core/src/web/hooks/use-hook-form/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from "./use-hook-form";
|
||||||
44
modules/core/src/web/hooks/use-hook-form/use-hook-form.ts
Normal file
44
modules/core/src/web/hooks/use-hook-form/use-hook-form.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { FieldValues, UseFormProps, UseFormReturn, useForm } from "react-hook-form";
|
||||||
|
import * as z4 from "zod/v4/core";
|
||||||
|
|
||||||
|
type UseHookFormProps<T extends FieldValues = FieldValues> = UseFormProps<T> & {
|
||||||
|
resolverSchema: z4.$ZodType<T, any>;
|
||||||
|
initialValues: UseFormProps<T>["defaultValues"];
|
||||||
|
onDirtyChange?: (isDirty: boolean) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useHookForm<T extends FieldValues = FieldValues>({
|
||||||
|
resolverSchema,
|
||||||
|
initialValues,
|
||||||
|
disabled,
|
||||||
|
onDirtyChange,
|
||||||
|
...rest
|
||||||
|
}: UseHookFormProps<T>): UseFormReturn<T> {
|
||||||
|
const form = useForm<T>({
|
||||||
|
...rest,
|
||||||
|
resolver: zodResolver(resolverSchema),
|
||||||
|
defaultValues: initialValues,
|
||||||
|
disabled,
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
formState: { isDirty },
|
||||||
|
} = form;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onDirtyChange?.(isDirty);
|
||||||
|
}, [isDirty, onDirtyChange]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const applyReset = async () => {
|
||||||
|
const values = typeof initialValues === "function" ? await initialValues() : initialValues;
|
||||||
|
|
||||||
|
form.reset(values);
|
||||||
|
};
|
||||||
|
applyReset();
|
||||||
|
}, [initialValues, form]);
|
||||||
|
|
||||||
|
return form;
|
||||||
|
}
|
||||||
@ -20,7 +20,7 @@
|
|||||||
"react-hook-form": "^7.58.1",
|
"react-hook-form": "^7.58.1",
|
||||||
"react-i18next": "^15.5.1",
|
"react-i18next": "^15.5.1",
|
||||||
"sequelize": "^6.37.5",
|
"sequelize": "^6.37.5",
|
||||||
"zod": "^3.25.67"
|
"zod": "^4.1.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@hookform/devtools": "^4.4.0",
|
"@hookform/devtools": "^4.4.0",
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { DomainValidationError } from "@erp/core/api";
|
import { DomainValidationError } from "@erp/core/api";
|
||||||
import { ValueObject } from "@repo/rdx-ddd";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
import { Maybe, Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
interface CustomerInvoiceItemDescriptionProps {
|
interface CustomerInvoiceItemDescriptionProps {
|
||||||
value: string;
|
value: string;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { DomainValidationError } from "@erp/core/api";
|
import { DomainValidationError } from "@erp/core/api";
|
||||||
import { ValueObject } from "@repo/rdx-ddd";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
interface ICustomerInvoiceNumberProps {
|
interface ICustomerInvoiceNumberProps {
|
||||||
value: string;
|
value: string;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { DomainValidationError } from "@erp/core/api";
|
import { DomainValidationError } from "@erp/core/api";
|
||||||
import { ValueObject } from "@repo/rdx-ddd";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
import { Maybe, Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
interface ICustomerInvoiceSerieProps {
|
interface ICustomerInvoiceSerieProps {
|
||||||
value: string;
|
value: string;
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
import { IModuleServer, ModuleParams } from "@erp/core/api";
|
import { IModuleServer, ModuleParams } from "@erp/core/api";
|
||||||
|
import { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { Transaction } from "sequelize";
|
||||||
import { customerInvoicesRouter, models } from "./infrastructure";
|
import { customerInvoicesRouter, models } from "./infrastructure";
|
||||||
|
import { buildCustomerInvoiceDependencies } from "./infrastructure/dependencies";
|
||||||
|
|
||||||
export const customerInvoicesAPIModule: IModuleServer = {
|
export const customerInvoicesAPIModule: IModuleServer = {
|
||||||
name: "customer-invoices",
|
name: "customer-invoices",
|
||||||
@ -12,16 +15,33 @@ export const customerInvoicesAPIModule: IModuleServer = {
|
|||||||
customerInvoicesRouter(params);
|
customerInvoicesRouter(params);
|
||||||
logger.info("🚀 CustomerInvoices module initialized", { label: this.name });
|
logger.info("🚀 CustomerInvoices module initialized", { label: this.name });
|
||||||
},
|
},
|
||||||
|
|
||||||
async registerDependencies(params) {
|
async registerDependencies(params) {
|
||||||
const { database, logger } = params;
|
const { logger, listServices } = params; /* = ModuleParams & {
|
||||||
|
getService: (name: string) => any;
|
||||||
|
};*/
|
||||||
|
|
||||||
logger.info("🚀 CustomerInvoices module dependencies registered", {
|
logger.info("🚀 CustomerInvoices module dependencies registered", {
|
||||||
label: this.name,
|
label: this.name,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
logger.info(listServices());
|
||||||
|
//getService()
|
||||||
|
|
||||||
|
const deps = buildCustomerInvoiceDependencies(params);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
models,
|
models,
|
||||||
services: {
|
services: {
|
||||||
getCustomerInvoice: () => {},
|
getInvoiceByIdInCompany: (
|
||||||
/*...*/
|
companyId: UniqueID,
|
||||||
|
invoiceId: UniqueID,
|
||||||
|
transaction?: Transaction
|
||||||
|
) => {
|
||||||
|
const { service } = deps;
|
||||||
|
|
||||||
|
return service.getInvoiceByIdInCompany(companyId, invoiceId, transaction);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@ -45,10 +45,12 @@ export type CustomerInvoiceDeps = {
|
|||||||
//delete: () => DeleteCustomerInvoiceUseCase;
|
//delete: () => DeleteCustomerInvoiceUseCase;
|
||||||
report: () => ReportCustomerInvoiceUseCase;
|
report: () => ReportCustomerInvoiceUseCase;
|
||||||
};
|
};
|
||||||
|
getService: (name: string) => any;
|
||||||
|
listServices: () => string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export function buildCustomerInvoiceDependencies(params: ModuleParams): CustomerInvoiceDeps {
|
export function buildCustomerInvoiceDependencies(params: ModuleParams): CustomerInvoiceDeps {
|
||||||
const { database } = params;
|
const { database, listServices, getService } = params;
|
||||||
const transactionManager = new SequelizeTransactionManager(database);
|
const transactionManager = new SequelizeTransactionManager(database);
|
||||||
const catalogs = { taxes: spainTaxCatalogProvider };
|
const catalogs = { taxes: spainTaxCatalogProvider };
|
||||||
|
|
||||||
@ -157,5 +159,7 @@ export function buildCustomerInvoiceDependencies(params: ModuleParams): Customer
|
|||||||
report: () =>
|
report: () =>
|
||||||
new ReportCustomerInvoiceUseCase(service, transactionManager, presenterRegistry),
|
new ReportCustomerInvoiceUseCase(service, transactionManager, presenterRegistry),
|
||||||
},
|
},
|
||||||
|
listServices,
|
||||||
|
getService,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { NumericStringSchema, PercentageSchema } from "@erp/core";
|
import { NumericStringSchema, PercentageSchema } from "@erp/core";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const CreateCustomerInvoiceItemRequestSchema = z.object({
|
export const CreateCustomerInvoiceItemRequestSchema = z.object({
|
||||||
id: z.uuid(),
|
id: z.uuid(),
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { CriteriaSchema } from "@erp/core";
|
import { CriteriaSchema } from "@erp/core";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const CustomerInvoiceListRequestSchema = CriteriaSchema;
|
export const CustomerInvoiceListRequestSchema = CriteriaSchema;
|
||||||
export type CustomerInvoiceListRequestDTO = z.infer<typeof CustomerInvoiceListRequestSchema>;
|
export type CustomerInvoiceListRequestDTO = z.infer<typeof CustomerInvoiceListRequestSchema>;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Este DTO es utilizado por el endpoint:
|
* Este DTO es utilizado por el endpoint:
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const GetCustomerInvoiceByIdRequestSchema = z.object({
|
export const GetCustomerInvoiceByIdRequestSchema = z.object({
|
||||||
invoice_id: z.string(),
|
invoice_id: z.string(),
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const ReportCustomerInvoiceByIdRequestSchema = z.object({
|
export const ReportCustomerInvoiceByIdRequestSchema = z.object({
|
||||||
invoice_id: z.string(),
|
invoice_id: z.string(),
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const UpdateCustomerInvoiceByIdParamsRequestSchema = z.object({
|
export const UpdateCustomerInvoiceByIdParamsRequestSchema = z.object({
|
||||||
customer_id: z.string(),
|
customer_id: z.string(),
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import {
|
|||||||
PercentageSchema,
|
PercentageSchema,
|
||||||
QuantitySchema,
|
QuantitySchema,
|
||||||
} from "@erp/core";
|
} from "@erp/core";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const CreateCustomerInvoiceResponseSchema = z.object({
|
export const CreateCustomerInvoiceResponseSchema = z.object({
|
||||||
id: z.uuid(),
|
id: z.uuid(),
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { MetadataSchema, MoneySchema, PercentageSchema, QuantitySchema } from "@erp/core";
|
import { MetadataSchema, MoneySchema, PercentageSchema, QuantitySchema } from "@erp/core";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const GetCustomerInvoiceByIdResponseSchema = z.object({
|
export const GetCustomerInvoiceByIdResponseSchema = z.object({
|
||||||
id: z.uuid(),
|
id: z.uuid(),
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { MetadataSchema, MoneySchema, createListViewResponseSchema } from "@erp/core";
|
import { MetadataSchema, MoneySchema, createListViewResponseSchema } from "@erp/core";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const ListCustomerInvoicesResponseSchema = createListViewResponseSchema(
|
export const ListCustomerInvoicesResponseSchema = createListViewResponseSchema(
|
||||||
z.object({
|
z.object({
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { AmountSchema, MetadataSchema, PercentageSchema, QuantitySchema } from "@erp/core";
|
import { AmountSchema, MetadataSchema, PercentageSchema, QuantitySchema } from "@erp/core";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const UpdateCustomerInvoiceByIdResponseSchema = z.object({
|
export const UpdateCustomerInvoiceByIdResponseSchema = z.object({
|
||||||
id: z.uuid(),
|
id: z.uuid(),
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
export * from "./use-create-customer-invoice-mutation";
|
export * from "./use-create-customer-invoice-mutation";
|
||||||
|
export * from "./use-customer-invoice-query";
|
||||||
export * from "./use-customer-invoices-context";
|
export * from "./use-customer-invoices-context";
|
||||||
export * from "./use-customer-invoices-query";
|
export * from "./use-customer-invoices-query";
|
||||||
export * from "./use-detail-columns";
|
export * from "./use-detail-columns";
|
||||||
|
|||||||
@ -0,0 +1,49 @@
|
|||||||
|
import { useDataSource } from "@erp/core/hooks";
|
||||||
|
import { DefaultError, type QueryKey, useQuery } from "@tanstack/react-query";
|
||||||
|
import { CustomerInvoiceData } from "../schemas";
|
||||||
|
|
||||||
|
export const CUSTOMER_INVOICE_QUERY_KEY = (id: string): QueryKey =>
|
||||||
|
["customer_invoice", id] as const;
|
||||||
|
|
||||||
|
type CustomerInvoiceQueryOptions = {
|
||||||
|
enabled?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useCustomerInvoiceQuery(invoiceId?: string, options?: CustomerInvoiceQueryOptions) {
|
||||||
|
const dataSource = useDataSource();
|
||||||
|
const enabled = (options?.enabled ?? true) && !!invoiceId;
|
||||||
|
|
||||||
|
return useQuery<CustomerInvoiceData, DefaultError>({
|
||||||
|
queryKey: CUSTOMER_INVOICE_QUERY_KEY(invoiceId ?? "unknown"),
|
||||||
|
queryFn: async (context) => {
|
||||||
|
const { signal } = context;
|
||||||
|
if (!invoiceId) {
|
||||||
|
if (!invoiceId) throw new Error("invoiceId is required");
|
||||||
|
}
|
||||||
|
return await dataSource.getOne<CustomerInvoiceData>("customer-invoices", invoiceId, {
|
||||||
|
signal,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
enabled,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
export function useQuery<
|
||||||
|
TQueryFnData = unknown,
|
||||||
|
TError = unknown,
|
||||||
|
TData = TQueryFnData,
|
||||||
|
TQueryKey extends QueryKey = QueryKey
|
||||||
|
>
|
||||||
|
|
||||||
|
TQueryFnData: the type returned from the queryFn.
|
||||||
|
TError: the type of Errors to expect from the queryFn.
|
||||||
|
TData: the type our data property will eventually have.
|
||||||
|
Only relevant if you use the select option,
|
||||||
|
because then the data property can be different
|
||||||
|
from what the queryFn returns.
|
||||||
|
Otherwise, it will default to whatever the queryFn returns.
|
||||||
|
TQueryKey: the type of our queryKey, only relevant
|
||||||
|
if you use the queryKey that is passed to your queryFn.
|
||||||
|
|
||||||
|
*/
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { CreateCustomerInvoiceRequestSchema } from "../../../common/dto";
|
import { CreateCustomerInvoiceRequestSchema } from "../../../common/dto";
|
||||||
|
|
||||||
export const CustomerInvoiceItemDataFormSchema = CreateCustomerInvoiceRequestSchema.extend({
|
export const CustomerInvoiceItemDataFormSchema = CreateCustomerInvoiceRequestSchema.extend({
|
||||||
|
|||||||
@ -0,0 +1,152 @@
|
|||||||
|
import { useHookForm, useUrlParamId } from "@erp/core/hooks";
|
||||||
|
import { AppBreadcrumb, AppContent } from "@repo/rdx-ui/components";
|
||||||
|
import { Button } from "@repo/shadcn-ui/components";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { useCustomerInvoiceQuery } from "../../hooks";
|
||||||
|
import { useTranslation } from "../../i18n";
|
||||||
|
|
||||||
|
export const CustomerInvoiceUpdate = () => {
|
||||||
|
const invoiceId = useUrlParamId();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
// 1) Estado de carga del cliente (query)
|
||||||
|
const {
|
||||||
|
data: invoiceData,
|
||||||
|
isLoading: isLoadingInvoice,
|
||||||
|
isError: isLoadError,
|
||||||
|
error: loadError,
|
||||||
|
} = useCustomerInvoiceQuery(invoiceId, { enabled: !!invoiceId });
|
||||||
|
|
||||||
|
// 2) Estado de actualización (mutación)
|
||||||
|
const {
|
||||||
|
mutate,
|
||||||
|
isPending: isUpdating,
|
||||||
|
isError: isUpdateError,
|
||||||
|
error: updateError,
|
||||||
|
} = useUpdateCustomerInvoice();
|
||||||
|
|
||||||
|
// 3) Form hook
|
||||||
|
const form = useHookForm<CustomerInvoiceFormData>({
|
||||||
|
resolverSchema: CustomerInvoiceFormSchema,
|
||||||
|
initialValues: customerInvoiceData ?? defaultCustomerInvoiceFormData,
|
||||||
|
disabled: isUpdating,
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleSubmit = (data: any) => {
|
||||||
|
// Handle form submission logic here
|
||||||
|
console.log("Form submitted with data:", data);
|
||||||
|
mutate(data);
|
||||||
|
|
||||||
|
// Navigate to the list page after submission
|
||||||
|
navigate("/customer-invoices/list");
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isError) {
|
||||||
|
console.error("Error creating customer invoice:", error);
|
||||||
|
// Optionally, you can show an error message to the user
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the component
|
||||||
|
// You can also handle loading state if needed
|
||||||
|
// For example, you can disable the submit button while the mutation is in progress
|
||||||
|
// const isLoading = useCreateCustomerInvoiceMutation().isLoading;
|
||||||
|
|
||||||
|
// Return the JSX for the component
|
||||||
|
// You can customize the form and its fields as needed
|
||||||
|
// For example, you can use a form library like react-hook-form or Formik to handle form state and validation
|
||||||
|
// Here, we are using a simple form with a submit button
|
||||||
|
|
||||||
|
// Note: Make sure to replace the form fields with your actual invoice fields
|
||||||
|
// and handle validation as needed.
|
||||||
|
// This is just a basic example to demonstrate the structure of the component.
|
||||||
|
|
||||||
|
// If you are using a form library, you can pass the handleSubmit function to the form's onSubmit prop
|
||||||
|
// and use the form library's methods to handle form state and validation.
|
||||||
|
|
||||||
|
// Example of a simple form submission handler
|
||||||
|
// You can replace this with your actual form handling logic
|
||||||
|
// const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||||
|
// event.preventDefault();
|
||||||
|
// const formData = new FormData(event.currentTarget);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<AppBreadcrumb />
|
||||||
|
<AppContent>
|
||||||
|
<div className='flex items-center justify-between space-y-2'>
|
||||||
|
<div>
|
||||||
|
<h2 className='text-2xl font-bold tracking-tight'>{t("pages.create.title")}</h2>
|
||||||
|
<p className='text-muted-foreground'>{t("pages.create.description")}</p>
|
||||||
|
</div>
|
||||||
|
<div className='flex items-center justify-end mb-4'>
|
||||||
|
<Button className='cursor-pointer' onClick={() => navigate("/customer-invoices/list")}>
|
||||||
|
{t("pages.create.back_to_list")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='flex flex-1 flex-col gap-4 p-4'>
|
||||||
|
<CustomerInvoiceEditForm onSubmit={handleSubmit} isPending={isPending} />
|
||||||
|
</div>
|
||||||
|
</AppContent>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className='flex items-center justify-between space-y-2'>
|
||||||
|
<div>
|
||||||
|
<h2 className='text-2xl font-bold tracking-tight'>
|
||||||
|
{t('customerInvoices.list.title' />
|
||||||
|
</h2>
|
||||||
|
<p className='text-muted-foreground'>
|
||||||
|
{t('CustomerInvoices.list.subtitle' />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className='flex items-center space-x-2'>
|
||||||
|
<Button onClick={() => navigate("/CustomerInvoices/add")}>
|
||||||
|
<PlusIcon className='w-4 h-4 mr-2' />
|
||||||
|
{t("customerInvoices.create.title")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Tabs value={status} onValueChange={setStatus}>
|
||||||
|
<div className='flex flex-col items-start justify-between mb-4 sm:flex-row sm:items-center'>
|
||||||
|
<div className='w-full mb-4 sm:w-auto sm:mb-0'>
|
||||||
|
<TabsList className='hidden sm:flex'>
|
||||||
|
{CustomerInvoiceStatuses.map((s) => (
|
||||||
|
<TabsTrigger key={s.value} value={s.value}>
|
||||||
|
{s.label}
|
||||||
|
</TabsTrigger>
|
||||||
|
))}
|
||||||
|
</TabsList>
|
||||||
|
<div className='flex items-center w-full space-x-2 sm:hidden'>
|
||||||
|
<Label>{t("customerInvoices.list.tabs_title")}</Label>
|
||||||
|
<Select value={status} onValueChange={setStatus}>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder='Seleccionar estado' />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{CustomerInvoiceStatuses.map((s) => (
|
||||||
|
<SelectItem key={s.value} value={s.value}>
|
||||||
|
{s.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{CustomerInvoiceStatuses.map((s) => (
|
||||||
|
<TabsContent key={s.value} value={s.value}>
|
||||||
|
<CustomerInvoicesGrid />
|
||||||
|
</TabsContent>
|
||||||
|
))}
|
||||||
|
</Tabs>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
*/
|
||||||
@ -1,13 +1,16 @@
|
|||||||
//import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
import { ListCustomerInvoicesResponseDTO } from "@erp/customer-invoices/common";
|
import {
|
||||||
|
GetCustomerInvoiceByIdResponseSchema,
|
||||||
|
ListCustomerInvoicesResponseDTO,
|
||||||
|
} from "@erp/customer-invoices/common";
|
||||||
|
|
||||||
/*export const CustomerCreateSchema = CreateCustomerRequestSchema;
|
/*export const CustomerCreateSchema = CreateCustomerRequestSchema;
|
||||||
export const CustomerUpdateSchema = UpdateCustomerByIdRequestSchema;
|
export const CustomerUpdateSchema = UpdateCustomerByIdRequestSchema;*/
|
||||||
export const CustomerSchema = GetCustomerByIdResponseSchema.omit({
|
export const CustomerSchema = GetCustomerInvoiceByIdResponseSchema.omit({
|
||||||
metadata: true,
|
metadata: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
export type CustomerData = z.infer<typeof CustomerSchema>;*/
|
export type CustomerInvoiceData = z.infer<typeof CustomerSchema>;
|
||||||
|
|
||||||
export type CustomerInvoicesListData = ListCustomerInvoicesResponseDTO;
|
export type CustomerInvoicesListData = ListCustomerInvoicesResponseDTO;
|
||||||
|
|||||||
@ -1 +1,9 @@
|
|||||||
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
|
export const CustomerInvoiceFormSchema = z.object({
|
||||||
|
invoice_number: z.string().optional(),
|
||||||
|
status: z.string().optional(),
|
||||||
|
series: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const CustomerInvoiceFormData = z.infer<typeof CustomerInvoiceFormSchema>;
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
"react-hook-form": "^7.58.1",
|
"react-hook-form": "^7.58.1",
|
||||||
"react-i18next": "^15.5.1",
|
"react-i18next": "^15.5.1",
|
||||||
"sequelize": "^6.37.5",
|
"sequelize": "^6.37.5",
|
||||||
"zod": "^3.25.67"
|
"zod": "^4.1.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^4.17.21",
|
"@types/express": "^4.17.21",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { DomainValidationError, ValueObject } from "@repo/rdx-ddd";
|
import { DomainValidationError, ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
interface ICustomerNumberProps {
|
interface ICustomerNumberProps {
|
||||||
value: string;
|
value: string;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { DomainValidationError, ValueObject } from "@repo/rdx-ddd";
|
import { DomainValidationError, ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
import { Maybe, Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
interface ICustomerSerieProps {
|
interface ICustomerSerieProps {
|
||||||
value: string;
|
value: string;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { RequestWithAuth, enforceTenant, enforceUser, mockUser } from "@erp/auth/api";
|
import { RequestWithAuth, enforceTenant, enforceUser, mockUser } from "@erp/auth/api";
|
||||||
import { ILogger, ModuleParams, validateRequest } from "@erp/core/api";
|
import { ModuleParams, validateRequest } from "@erp/core/api";
|
||||||
|
import { ILogger } from "@repo/rdx-logger";
|
||||||
import { Application, NextFunction, Request, Response, Router } from "express";
|
import { Application, NextFunction, Request, Response, Router } from "express";
|
||||||
import { Sequelize } from "sequelize";
|
import { Sequelize } from "sequelize";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const CreateCustomerRequestSchema = z.object({
|
export const CreateCustomerRequestSchema = z.object({
|
||||||
id: z.string().nonempty(),
|
id: z.string().nonempty(),
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { CriteriaSchema } from "@erp/core";
|
import { CriteriaSchema } from "@erp/core";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const CustomerListRequestSchema = CriteriaSchema;
|
export const CustomerListRequestSchema = CriteriaSchema;
|
||||||
export type CustomerListRequestDTO = z.infer<typeof CustomerListRequestSchema>;
|
export type CustomerListRequestDTO = z.infer<typeof CustomerListRequestSchema>;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Este DTO es utilizado por el endpoint:
|
* Este DTO es utilizado por el endpoint:
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Este DTO es utilizado por el endpoint:
|
* Este DTO es utilizado por el endpoint:
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const UpdateCustomerByIdParamsRequestSchema = z.object({
|
export const UpdateCustomerByIdParamsRequestSchema = z.object({
|
||||||
customer_id: z.string(),
|
customer_id: z.string(),
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { MetadataSchema } from "@erp/core";
|
import { MetadataSchema } from "@erp/core";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const CreateCustomerResponseSchema = z.object({
|
export const CreateCustomerResponseSchema = z.object({
|
||||||
id: z.uuid(),
|
id: z.uuid(),
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { MetadataSchema } from "@erp/core";
|
import { MetadataSchema } from "@erp/core";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const GetCustomerByIdResponseSchema = z.object({
|
export const GetCustomerByIdResponseSchema = z.object({
|
||||||
id: z.uuid(),
|
id: z.uuid(),
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { MetadataSchema, createListViewResponseSchema } from "@erp/core";
|
import { MetadataSchema, createListViewResponseSchema } from "@erp/core";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const ListCustomersResponseSchema = createListViewResponseSchema(
|
export const ListCustomersResponseSchema = createListViewResponseSchema(
|
||||||
z.object({
|
z.object({
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { MetadataSchema } from "@erp/core";
|
import { MetadataSchema } from "@erp/core";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const UpdateCustomerByIdResponseSchema = z.object({
|
export const UpdateCustomerByIdResponseSchema = z.object({
|
||||||
id: z.uuid(),
|
id: z.uuid(),
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
export * from "./use-create-customer-mutation";
|
export * from "./use-create-customer-mutation";
|
||||||
export * from "./use-customer-form";
|
|
||||||
export * from "./use-customer-query";
|
export * from "./use-customer-query";
|
||||||
export * from "./use-customers-context";
|
export * from "./use-customers-context";
|
||||||
export * from "./use-customers-query";
|
export * from "./use-customers-query";
|
||||||
|
|||||||
@ -9,7 +9,7 @@ type CreateCustomerPayload = {
|
|||||||
data: CustomerFormData;
|
data: CustomerFormData;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useCreateCustomerMutation() {
|
export function useCreateCustomer() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const dataSource = useDataSource();
|
const dataSource = useDataSource();
|
||||||
const schema = CreateCustomerRequestSchema;
|
const schema = CreateCustomerRequestSchema;
|
||||||
|
|||||||
@ -1,36 +0,0 @@
|
|||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
|
||||||
import { useEffect } from "react";
|
|
||||||
import { useForm } from "react-hook-form";
|
|
||||||
import { CustomerFormData, CustomerFormSchema } from "../schemas";
|
|
||||||
|
|
||||||
type UseCustomerFormProps = {
|
|
||||||
initialValues: CustomerFormData;
|
|
||||||
disabled?: boolean;
|
|
||||||
onDirtyChange?: (isDirty: boolean) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function useCustomerForm({ initialValues, disabled, onDirtyChange }: UseCustomerFormProps) {
|
|
||||||
const form = useForm({
|
|
||||||
resolver: zodResolver(CustomerFormSchema),
|
|
||||||
defaultValues: initialValues,
|
|
||||||
disabled,
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
|
||||||
formState: { isDirty },
|
|
||||||
} = form;
|
|
||||||
|
|
||||||
// Avisar cuando cambia el dirty state
|
|
||||||
useEffect(() => {
|
|
||||||
if (onDirtyChange) {
|
|
||||||
onDirtyChange(isDirty);
|
|
||||||
}
|
|
||||||
}, [isDirty, onDirtyChange]);
|
|
||||||
|
|
||||||
// Resetear el form si cambian los valores iniciales
|
|
||||||
useEffect(() => {
|
|
||||||
form.reset(initialValues);
|
|
||||||
}, [initialValues, form]);
|
|
||||||
|
|
||||||
return form;
|
|
||||||
}
|
|
||||||
@ -12,22 +12,19 @@ export function useCustomerQuery(customerId?: string, options?: CustomerQueryOpt
|
|||||||
const dataSource = useDataSource();
|
const dataSource = useDataSource();
|
||||||
const enabled = (options?.enabled ?? true) && !!customerId;
|
const enabled = (options?.enabled ?? true) && !!customerId;
|
||||||
|
|
||||||
const queryResult = useQuery<CustomerData, DefaultError>({
|
return useQuery<CustomerData, DefaultError>({
|
||||||
queryKey: CUSTOMER_QUERY_KEY(customerId ?? "unknown"),
|
queryKey: CUSTOMER_QUERY_KEY(customerId ?? "unknown"),
|
||||||
queryFn: async (context) => {
|
queryFn: async (context) => {
|
||||||
const { signal } = context;
|
const { signal } = context;
|
||||||
if (!customerId) {
|
if (!customerId) {
|
||||||
if (!customerId) throw new Error("customerId is required");
|
if (!customerId) throw new Error("customerId is required");
|
||||||
}
|
}
|
||||||
const customer = await dataSource.getOne<CustomerData>("customers", customerId, {
|
return await dataSource.getOne<CustomerData>("customers", customerId, {
|
||||||
signal,
|
signal,
|
||||||
});
|
});
|
||||||
return customer;
|
|
||||||
},
|
},
|
||||||
enabled,
|
enabled,
|
||||||
});
|
});
|
||||||
|
|
||||||
return queryResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -14,7 +14,7 @@ type UpdateCustomerPayload = {
|
|||||||
data: Partial<CustomerFormData>;
|
data: Partial<CustomerFormData>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useUpdateCustomerMutation() {
|
export function useUpdateCustomer() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const dataSource = useDataSource();
|
const dataSource = useDataSource();
|
||||||
const schema = UpdateCustomerByIdRequestSchema;
|
const schema = UpdateCustomerByIdRequestSchema;
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import { AppBreadcrumb, AppContent } from "@repo/rdx-ui/components";
|
import { AppBreadcrumb, AppContent } from "@repo/rdx-ui/components";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
import { FormCommitButtonGroup, UnsavedChangesProvider } from "@erp/core/hooks";
|
import { FormCommitButtonGroup, UnsavedChangesProvider, useHookForm } from "@erp/core/hooks";
|
||||||
import { showErrorToast, showSuccessToast } from "@repo/rdx-ui/helpers";
|
import { showErrorToast, showSuccessToast } from "@repo/rdx-ui/helpers";
|
||||||
import { FieldErrors, FormProvider } from "react-hook-form";
|
import { FieldErrors, FormProvider } from "react-hook-form";
|
||||||
import { CustomerEditForm, ErrorAlert } from "../../components";
|
import { CustomerEditForm, ErrorAlert } from "../../components";
|
||||||
import { useCreateCustomerMutation, useCustomerForm } from "../../hooks";
|
import { useCreateCustomer } from "../../hooks";
|
||||||
import { useTranslation } from "../../i18n";
|
import { useTranslation } from "../../i18n";
|
||||||
import { CustomerFormData, defaultCustomerFormData } from "../../schemas";
|
import { CustomerFormData, CustomerFormSchema, defaultCustomerFormData } from "../../schemas";
|
||||||
|
|
||||||
export const CustomerCreate = () => {
|
export const CustomerCreate = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -19,11 +19,13 @@ export const CustomerCreate = () => {
|
|||||||
isPending: isCreating,
|
isPending: isCreating,
|
||||||
isError: isCreateError,
|
isError: isCreateError,
|
||||||
error: createError,
|
error: createError,
|
||||||
} = useCreateCustomerMutation();
|
} = useCreateCustomer();
|
||||||
|
|
||||||
// 2) Form hook
|
// 2) Form hook
|
||||||
const form = useCustomerForm({
|
const form = useHookForm<CustomerFormData>({
|
||||||
|
resolverSchema: CustomerFormSchema,
|
||||||
initialValues: defaultCustomerFormData,
|
initialValues: defaultCustomerFormData,
|
||||||
|
disabled: isCreating,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3) Submit con navegación condicionada por éxito
|
// 3) Submit con navegación condicionada por éxito
|
||||||
|
|||||||
@ -2,7 +2,12 @@ import { AppBreadcrumb, AppContent, BackHistoryButton } from "@repo/rdx-ui/compo
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
import { formHasAnyDirty, pickFormDirtyValues } from "@erp/core/client";
|
import { formHasAnyDirty, pickFormDirtyValues } from "@erp/core/client";
|
||||||
import { FormCommitButtonGroup, UnsavedChangesProvider, useUrlParamId } from "@erp/core/hooks";
|
import {
|
||||||
|
FormCommitButtonGroup,
|
||||||
|
UnsavedChangesProvider,
|
||||||
|
useHookForm,
|
||||||
|
useUrlParamId,
|
||||||
|
} from "@erp/core/hooks";
|
||||||
import { showErrorToast, showSuccessToast, showWarningToast } from "@repo/rdx-ui/helpers";
|
import { showErrorToast, showSuccessToast, showWarningToast } from "@repo/rdx-ui/helpers";
|
||||||
import { FieldErrors, FormProvider } from "react-hook-form";
|
import { FieldErrors, FormProvider } from "react-hook-form";
|
||||||
import {
|
import {
|
||||||
@ -11,9 +16,9 @@ import {
|
|||||||
ErrorAlert,
|
ErrorAlert,
|
||||||
NotFoundCard,
|
NotFoundCard,
|
||||||
} from "../../components";
|
} from "../../components";
|
||||||
import { useCustomerForm, useCustomerQuery, useUpdateCustomerMutation } from "../../hooks";
|
import { useCustomerQuery, useUpdateCustomer } from "../../hooks";
|
||||||
import { useTranslation } from "../../i18n";
|
import { useTranslation } from "../../i18n";
|
||||||
import { CustomerFormData, defaultCustomerFormData } from "../../schemas";
|
import { CustomerFormData, CustomerFormSchema, defaultCustomerFormData } from "../../schemas";
|
||||||
|
|
||||||
export const CustomerUpdate = () => {
|
export const CustomerUpdate = () => {
|
||||||
const customerId = useUrlParamId();
|
const customerId = useUrlParamId();
|
||||||
@ -34,11 +39,13 @@ export const CustomerUpdate = () => {
|
|||||||
isPending: isUpdating,
|
isPending: isUpdating,
|
||||||
isError: isUpdateError,
|
isError: isUpdateError,
|
||||||
error: updateError,
|
error: updateError,
|
||||||
} = useUpdateCustomerMutation();
|
} = useUpdateCustomer();
|
||||||
|
|
||||||
// 3) Form hook
|
// 3) Form hook
|
||||||
const form = useCustomerForm({
|
const form = useHookForm<CustomerFormData>({
|
||||||
|
resolverSchema: CustomerFormSchema,
|
||||||
initialValues: customerData ?? defaultCustomerFormData,
|
initialValues: customerData ?? defaultCustomerFormData,
|
||||||
|
disabled: isUpdating,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 4) Submit con navegación condicionada por éxito
|
// 4) Submit con navegación condicionada por éxito
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CreateCustomerRequestSchema,
|
CreateCustomerRequestSchema,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const CustomerFormSchema = z.object({
|
export const CustomerFormSchema = z.object({
|
||||||
reference: z.string().optional(),
|
reference: z.string().optional(),
|
||||||
|
|||||||
@ -3,17 +3,23 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"types": "src/index.ts",
|
"types": "src/index.ts",
|
||||||
"exports": { "./api": "./src/api/index.ts" },
|
"exports": {
|
||||||
|
"./api": "./src/api/index.ts",
|
||||||
|
"./common": "./src/common/index.ts"
|
||||||
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"sequelize": "^6.37.5",
|
"sequelize": "^6.37.5",
|
||||||
"express": "^4.18.2"
|
"express": "^4.18.2",
|
||||||
|
"zod": "^4.1.11"
|
||||||
},
|
},
|
||||||
"devDependencies": { "@types/express": "^4.17.21" },
|
"devDependencies": { "@types/express": "^4.17.21" },
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@erp/auth": "workspace:*",
|
"@erp/auth": "workspace:*",
|
||||||
"@erp/core": "workspace:*",
|
"@erp/core": "workspace:*",
|
||||||
"@repo/rdx-ddd": "workspace:*",
|
"@repo/rdx-ddd": "workspace:*",
|
||||||
|
"@repo/rdx-criteria": "workspace:*",
|
||||||
"@repo/rdx-utils": "workspace:*",
|
"@repo/rdx-utils": "workspace:*",
|
||||||
"@repo/rdx-logger": "workspace:*"
|
"@repo/rdx-logger": "workspace:*",
|
||||||
|
"@erp/customer-invoices": "workspace:*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./verifactu-record.full.presenter";
|
||||||
|
//export * from "./verifactu-record.full.representer";
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
import { Presenter } from "@erp/core/api";
|
||||||
|
import { GetVerifactuRecordByIdResponseDTO } from "@erp/verifactu-records/common";
|
||||||
|
import { VerifactuRecord } from "../../../domain";
|
||||||
|
|
||||||
|
export class VerifactuRecordFullPresenter extends Presenter<
|
||||||
|
VerifactuRecord,
|
||||||
|
GetVerifactuRecordByIdResponseDTO
|
||||||
|
> {
|
||||||
|
toOutput(record: VerifactuRecord): GetVerifactuRecordByIdResponseDTO {
|
||||||
|
return {
|
||||||
|
id: record.id.toString(),
|
||||||
|
invoice_id: record.invoiceId.toString(),
|
||||||
|
|
||||||
|
estado: record.estado.toPrimitive(),
|
||||||
|
url: record.url.toPrimitive(),
|
||||||
|
// qr1: toEmptyString(record.qr1, (value) => value.toString()),
|
||||||
|
|
||||||
|
metadata: {
|
||||||
|
entity: "verifactu-records",
|
||||||
|
link: "",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,7 +17,7 @@ export class SendInvoiceUseCase {
|
|||||||
|
|
||||||
public async execute(params: SendInvoiceUseCaseInput) {
|
public async execute(params: SendInvoiceUseCaseInput) {
|
||||||
const { invoice_id } = params;
|
const { invoice_id } = params;
|
||||||
|
console.log("CASO DE USO -----ESTO ES UNA PRUEBA>>>>>>", invoice_id);
|
||||||
const idOrError = UniqueID.create(invoice_id);
|
const idOrError = UniqueID.create(invoice_id);
|
||||||
|
|
||||||
if (idOrError.isFailure) {
|
if (idOrError.isFailure) {
|
||||||
@ -25,14 +25,41 @@ export class SendInvoiceUseCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const invoiceId = idOrError.data;
|
const invoiceId = idOrError.data;
|
||||||
|
console.log("CASO DE USO -----VALIDADO>>>>>>", invoiceId);
|
||||||
return this.transactionManager.complete(async (transaction: Transaction) => {
|
return this.transactionManager.complete(async (transaction: Transaction) => {
|
||||||
try {
|
try {
|
||||||
const invoiceOrError = await this.service.sendInvoiceToVerifactu(invoiceId, transaction);
|
console.log(
|
||||||
|
"CASO DE USO -----LLamar servicio de invoices para recuperar el invoice>>>>>>",
|
||||||
|
invoiceId
|
||||||
|
);
|
||||||
|
const invoice = {
|
||||||
|
serie: "A",
|
||||||
|
numero: "1",
|
||||||
|
fecha_expedicion: "12-09-2025",
|
||||||
|
tipo_factura: "F1",
|
||||||
|
descripcion: "Venta de bienes",
|
||||||
|
nif: "A15022510",
|
||||||
|
nombre: "Empresa de prueba SL",
|
||||||
|
lineas: [
|
||||||
|
{
|
||||||
|
base_imponible: "200",
|
||||||
|
tipo_impositivo: "21",
|
||||||
|
cuota_repercutida: "42",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
base_imponible: "100",
|
||||||
|
tipo_impositivo: "10",
|
||||||
|
cuota_repercutida: "10",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
importe_total: "352.00",
|
||||||
|
};
|
||||||
|
const invoiceOrError = await this.service.sendInvoiceToVerifactu(invoice, transaction);
|
||||||
if (invoiceOrError.isFailure) {
|
if (invoiceOrError.isFailure) {
|
||||||
return Result.fail(invoiceOrError.error);
|
return Result.fail(invoiceOrError.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const invoice = invoiceOrError.data;
|
const invoice2 = invoiceOrError.data;
|
||||||
return Result.ok({});
|
return Result.ok({});
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
return Result.fail(error as Error);
|
return Result.fail(error as Error);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { DomainValidationError } from "@erp/core/api";
|
import { DomainValidationError } from "@erp/core/api";
|
||||||
import { ValueObject } from "@repo/rdx-ddd";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
import { Maybe, Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
interface VerifactuRecordUrlProps {
|
interface VerifactuRecordUrlProps {
|
||||||
value: string;
|
value: string;
|
||||||
|
|||||||
@ -42,29 +42,6 @@ export class VerifactuRecordService {
|
|||||||
// return Result.fail(invoiceResult.error);
|
// return Result.fail(invoiceResult.error);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const invoice = {
|
|
||||||
serie: "A",
|
|
||||||
numero: "1",
|
|
||||||
fecha_expedicion: "12-09-2025",
|
|
||||||
tipo_factura: "F1",
|
|
||||||
descripcion: "Venta de bienes",
|
|
||||||
nif: "A15022510",
|
|
||||||
nombre: "Empresa de prueba SL",
|
|
||||||
lineas: [
|
|
||||||
{
|
|
||||||
base_imponible: "200",
|
|
||||||
tipo_impositivo: "21",
|
|
||||||
cuota_repercutida: "42",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
base_imponible: "100",
|
|
||||||
tipo_impositivo: "10",
|
|
||||||
cuota_repercutida: "10",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
importe_total: "352.00",
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log("ESTO ES UNA PRUEBA>>>>>>");
|
console.log("ESTO ES UNA PRUEBA>>>>>>");
|
||||||
|
|
||||||
return Result.ok(invoice);
|
return Result.ok(invoice);
|
||||||
|
|||||||
@ -4,11 +4,9 @@ import { models, verifactuRouter } from "./infrastructure";
|
|||||||
export const verifactuAPIModule: IModuleServer = {
|
export const verifactuAPIModule: IModuleServer = {
|
||||||
name: "verifactu",
|
name: "verifactu",
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
dependencies: ["customers-invoices"],
|
dependencies: ["customer-invoices"],
|
||||||
|
|
||||||
async init(params: ModuleParams) {
|
async init(params: ModuleParams) {
|
||||||
// const contacts = getService<ContactsService>("contacts");
|
|
||||||
console.log("111111111111111111111111111A>>>>>>>>>>>>>>>>>>>");
|
|
||||||
const { logger } = params;
|
const { logger } = params;
|
||||||
verifactuRouter(params);
|
verifactuRouter(params);
|
||||||
logger.info("🚀 Verifactu module initialized", { label: this.name });
|
logger.info("🚀 Verifactu module initialized", { label: this.name });
|
||||||
|
|||||||
@ -2,116 +2,62 @@
|
|||||||
|
|
||||||
import type { IMapperRegistry, IPresenterRegistry, ModuleParams } from "@erp/core/api";
|
import type { IMapperRegistry, IPresenterRegistry, ModuleParams } from "@erp/core/api";
|
||||||
|
|
||||||
import { JsonTaxCatalogProvider } from "@erp/core";
|
|
||||||
import {
|
import {
|
||||||
InMemoryMapperRegistry,
|
InMemoryMapperRegistry,
|
||||||
InMemoryPresenterRegistry,
|
InMemoryPresenterRegistry,
|
||||||
SequelizeTransactionManager,
|
SequelizeTransactionManager,
|
||||||
} from "@erp/core/api";
|
} from "@erp/core/api";
|
||||||
import { SendCustomerInvoiceUseCase } from "../application";
|
import { SendInvoiceUseCase } from "../application";
|
||||||
import { CustomerInvoiceItemsReportPersenter } from "../application/presenters/queries/customer-invoice-items.report.presenter";
|
import { VerifactuRecordFullPresenter } from "../application/presenters/domain/verifactu-record.full.presenter";
|
||||||
import { CustomerInvoiceService } from "../domain";
|
import { VerifactuRecordService } from "../domain";
|
||||||
import { CustomerInvoiceDomainMapper, CustomerInvoiceListMapper } from "./mappers";
|
//import { VerifactuRecordItemsReportPersenter } from "../application/presenters/queries/verifactu-record-items.report.presenter";
|
||||||
import { CustomerInvoiceRepository } from "./sequelize";
|
import { VerifactuRecordDomainMapper } from "./mappers";
|
||||||
|
import { VerifactuRecordRepository } from "./sequelize";
|
||||||
|
|
||||||
export type CustomerInvoiceDeps = {
|
export type VerifactuRecordDeps = {
|
||||||
transactionManager: SequelizeTransactionManager;
|
transactionManager: SequelizeTransactionManager;
|
||||||
mapperRegistry: IMapperRegistry;
|
mapperRegistry: IMapperRegistry;
|
||||||
presenterRegistry: IPresenterRegistry;
|
presenterRegistry: IPresenterRegistry;
|
||||||
repo: CustomerInvoiceRepository;
|
repo: VerifactuRecordRepository;
|
||||||
service: CustomerInvoiceService;
|
service: VerifactuRecordService;
|
||||||
catalogs: {
|
|
||||||
taxes: JsonTaxCatalogProvider;
|
|
||||||
};
|
|
||||||
build: {
|
build: {
|
||||||
send: () => SendCustomerInvoiceUseCase;
|
send: () => SendInvoiceUseCase;
|
||||||
};
|
};
|
||||||
|
getService: (name: string) => any;
|
||||||
|
listServices: () => string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export function buildVerifactuDependencies(params: ModuleParams): CustomerInvoiceDeps {
|
export function buildVerifactuDependencies(params: ModuleParams): VerifactuRecordDeps {
|
||||||
const { database } = params;
|
const { database, listServices, getService } = params;
|
||||||
const transactionManager = new SequelizeTransactionManager(database);
|
const transactionManager = new SequelizeTransactionManager(database);
|
||||||
|
|
||||||
// Mapper Registry
|
// Mapper Registry
|
||||||
const mapperRegistry = new InMemoryMapperRegistry();
|
const mapperRegistry = new InMemoryMapperRegistry();
|
||||||
mapperRegistry
|
mapperRegistry.registerDomainMapper(
|
||||||
.registerDomainMapper(
|
{ resource: "verifactu-record" },
|
||||||
{ resource: "customer-invoice" },
|
new VerifactuRecordDomainMapper({})
|
||||||
new CustomerInvoiceDomainMapper({ taxCatalog: catalogs.taxes })
|
);
|
||||||
)
|
/* .registerQueryMappers([
|
||||||
.registerQueryMappers([
|
|
||||||
{
|
{
|
||||||
key: { resource: "customer-invoice", query: "LIST" },
|
key: { resource: "verifactu-record", query: "LIST" },
|
||||||
mapper: new CustomerInvoiceListMapper(),
|
mapper: new VerifactuRecordListMapper(),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
*/
|
||||||
|
|
||||||
// Repository & Services
|
// Repository & Services
|
||||||
const repo = new CustomerInvoiceRepository({ mapperRegistry, database });
|
const repo = new VerifactuRecordRepository({ mapperRegistry, database });
|
||||||
const service = new CustomerInvoiceService(repo);
|
const service = new VerifactuRecordService(repo);
|
||||||
|
|
||||||
// Presenter Registry
|
// Presenter Registry
|
||||||
const presenterRegistry = new InMemoryPresenterRegistry();
|
const presenterRegistry = new InMemoryPresenterRegistry();
|
||||||
presenterRegistry.registerPresenters([
|
presenterRegistry.registerPresenters([
|
||||||
{
|
{
|
||||||
key: {
|
key: {
|
||||||
resource: "customer-invoice-items",
|
resource: "verifactu-record",
|
||||||
projection: "FULL",
|
projection: "FULL",
|
||||||
},
|
},
|
||||||
presenter: new CustomerInvoiceItemsFullPresenter(presenterRegistry),
|
presenter: new VerifactuRecordFullPresenter(presenterRegistry),
|
||||||
},
|
|
||||||
{
|
|
||||||
key: {
|
|
||||||
resource: "recipient-invoice",
|
|
||||||
projection: "FULL",
|
|
||||||
},
|
|
||||||
presenter: new RecipientInvoiceFullPresenter(presenterRegistry),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: {
|
|
||||||
resource: "customer-invoice",
|
|
||||||
projection: "FULL",
|
|
||||||
},
|
|
||||||
presenter: new CustomerInvoiceFullPresenter(presenterRegistry),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: {
|
|
||||||
resource: "customer-invoice",
|
|
||||||
projection: "LIST",
|
|
||||||
},
|
|
||||||
presenter: new ListCustomerInvoicesPresenter(presenterRegistry),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: {
|
|
||||||
resource: "customer-invoice",
|
|
||||||
projection: "REPORT",
|
|
||||||
format: "JSON",
|
|
||||||
},
|
|
||||||
presenter: new CustomerInvoiceReportPresenter(presenterRegistry),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: {
|
|
||||||
resource: "customer-invoice-items",
|
|
||||||
projection: "REPORT",
|
|
||||||
format: "JSON",
|
|
||||||
},
|
|
||||||
presenter: new CustomerInvoiceItemsReportPersenter(presenterRegistry),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: {
|
|
||||||
resource: "customer-invoice",
|
|
||||||
projection: "REPORT",
|
|
||||||
format: "HTML",
|
|
||||||
},
|
|
||||||
presenter: new CustomerInvoiceReportHTMLPresenter(presenterRegistry),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: {
|
|
||||||
resource: "customer-invoice",
|
|
||||||
projection: "REPORT",
|
|
||||||
format: "PDF",
|
|
||||||
},
|
|
||||||
presenter: new CustomerInvoiceReportPDFPresenter(presenterRegistry),
|
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -121,21 +67,20 @@ export function buildVerifactuDependencies(params: ModuleParams): CustomerInvoic
|
|||||||
mapperRegistry,
|
mapperRegistry,
|
||||||
presenterRegistry,
|
presenterRegistry,
|
||||||
service,
|
service,
|
||||||
catalogs,
|
|
||||||
build: {
|
build: {
|
||||||
list: () => new ListCustomerInvoicesUseCase(service, transactionManager, presenterRegistry),
|
send: () => new SendInvoiceUseCase(service, transactionManager, presenterRegistry),
|
||||||
get: () => new GetCustomerInvoiceUseCase(service, transactionManager, presenterRegistry),
|
// get: () => new GetVerifactuRecordUseCase(service, transactionManager, presenterRegistry),
|
||||||
create: () =>
|
/* create: () =>
|
||||||
new CreateCustomerInvoiceUseCase(
|
new CreateVerifactuRecordUseCase(
|
||||||
service,
|
service,
|
||||||
transactionManager,
|
transactionManager,
|
||||||
presenterRegistry,
|
presenterRegistry,
|
||||||
catalogs.taxes
|
|
||||||
),
|
),
|
||||||
// update: () => new UpdateCustomerInvoiceUseCase(service, transactionManager),
|
*/
|
||||||
// delete: () => new DeleteCustomerInvoiceUseCase(service, transactionManager),
|
// update: () => new UpdateVerifactuRecordUseCase(service, transactionManager),
|
||||||
report: () =>
|
// delete: () => new DeleteVerifactuRecordUseCase(service, transactionManager),
|
||||||
new ReportCustomerInvoiceUseCase(service, transactionManager, presenterRegistry),
|
|
||||||
},
|
},
|
||||||
|
listServices,
|
||||||
|
getService,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,8 +15,6 @@ export class SendInvoiceVerifactuController extends ExpressController {
|
|||||||
}
|
}
|
||||||
const { invoice_id } = this.req.params;
|
const { invoice_id } = this.req.params;
|
||||||
|
|
||||||
console.log("CONTROLLER -----ESTO ES UNA PRUEBA>>>>>>");
|
|
||||||
|
|
||||||
const result = await this.useCase.execute({ invoice_id });
|
const result = await this.useCase.execute({ invoice_id });
|
||||||
|
|
||||||
return result.match(
|
return result.match(
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import { RequestWithAuth, enforceTenant, enforceUser, mockUser } from "@erp/auth/api";
|
import { RequestWithAuth, enforceTenant, enforceUser, mockUser } from "@erp/auth/api";
|
||||||
import { ILogger, ModuleParams, validateRequest } from "@erp/core/api";
|
import { ModuleParams, validateRequest } from "@erp/core/api";
|
||||||
|
import { SendInvoiceByIdRequestSchema } from "@erp/verifactu/common";
|
||||||
|
import { ILogger } from "@repo/rdx-logger";
|
||||||
import { Application, NextFunction, Request, Response, Router } from "express";
|
import { Application, NextFunction, Request, Response, Router } from "express";
|
||||||
import { Sequelize } from "sequelize";
|
import { Sequelize } from "sequelize";
|
||||||
import { SendCustomerInvoiceByIdRequestSchema } from "../../../common/dto";
|
|
||||||
import { buildVerifactuDependencies } from "../dependencies";
|
import { buildVerifactuDependencies } from "../dependencies";
|
||||||
import { SendInvoiceVerifactuController } from "./controllers";
|
import { SendInvoiceVerifactuController } from "./controllers";
|
||||||
|
|
||||||
@ -14,7 +15,6 @@ export const verifactuRouter = (params: ModuleParams) => {
|
|||||||
logger: ILogger;
|
logger: ILogger;
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA>>>>>>>>>>>>>>>>>>>");
|
|
||||||
const deps = buildVerifactuDependencies(params);
|
const deps = buildVerifactuDependencies(params);
|
||||||
|
|
||||||
const router: Router = Router({ mergeParams: true });
|
const router: Router = Router({ mergeParams: true });
|
||||||
@ -40,11 +40,17 @@ export const verifactuRouter = (params: ModuleParams) => {
|
|||||||
router.get(
|
router.get(
|
||||||
"/:invoice_id/sendVerifactu",
|
"/:invoice_id/sendVerifactu",
|
||||||
//checkTabContext,
|
//checkTabContext,
|
||||||
validateRequest(SendCustomerInvoiceByIdRequestSchema, "params"),
|
validateRequest(SendInvoiceByIdRequestSchema, "params"),
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
const useCase = deps.build.report();
|
const { listServices } = deps;
|
||||||
|
const useCase = deps.build.send();
|
||||||
|
|
||||||
|
logger.info(listServices());
|
||||||
|
|
||||||
const controller = new SendInvoiceVerifactuController(useCase);
|
const controller = new SendInvoiceVerifactuController(useCase);
|
||||||
return controller.execute(req, res, next);
|
return controller.execute(req, res, next);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
app.use(`${baseRoutePath}/verifactu`, router);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
export * from "./verifactu-record.mapper";
|
||||||
@ -1,5 +1,4 @@
|
|||||||
import { ISequelizeDomainMapper, MapperParamsType, SequelizeDomainMapper } from "@erp/core/api";
|
import { ISequelizeDomainMapper, MapperParamsType, SequelizeDomainMapper } from "@erp/core/api";
|
||||||
import { VerifactuRecordEstado } from "@erp/customer-invoices/api/domain/aggregates/value-objects";
|
|
||||||
import {
|
import {
|
||||||
UniqueID,
|
UniqueID,
|
||||||
ValidationErrorCollection,
|
ValidationErrorCollection,
|
||||||
|
|||||||
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./domain";
|
||||||
|
//export * from "./queries";
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
import { MetadataSchema, MoneySchema, PercentageSchema, QuantitySchema } from "@erp/core";
|
||||||
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
|
export const GetVerifactuRecordByIdResponseSchema = z.object({
|
||||||
|
id: z.uuid(),
|
||||||
|
company_id: z.uuid(),
|
||||||
|
|
||||||
|
invoice_number: z.string(),
|
||||||
|
status: z.string(),
|
||||||
|
series: z.string(),
|
||||||
|
|
||||||
|
invoice_date: z.string(),
|
||||||
|
operation_date: z.string(),
|
||||||
|
|
||||||
|
notes: z.string(),
|
||||||
|
|
||||||
|
language_code: z.string(),
|
||||||
|
currency_code: z.string(),
|
||||||
|
|
||||||
|
customer_id: z.string(),
|
||||||
|
recipient: z.object({
|
||||||
|
id: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
tin: z.string(),
|
||||||
|
street: z.string(),
|
||||||
|
street2: z.string(),
|
||||||
|
city: z.string(),
|
||||||
|
province: z.string(),
|
||||||
|
postal_code: z.string(),
|
||||||
|
country: z.string(),
|
||||||
|
}),
|
||||||
|
|
||||||
|
taxes: z.string(),
|
||||||
|
|
||||||
|
payment_method: z
|
||||||
|
.object({
|
||||||
|
payment_id: z.string(),
|
||||||
|
payment_description: z.string(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
|
||||||
|
subtotal_amount: MoneySchema,
|
||||||
|
discount_percentage: PercentageSchema,
|
||||||
|
discount_amount: MoneySchema,
|
||||||
|
taxable_amount: MoneySchema,
|
||||||
|
taxes_amount: MoneySchema,
|
||||||
|
total_amount: MoneySchema,
|
||||||
|
|
||||||
|
items: z.array(
|
||||||
|
z.object({
|
||||||
|
id: z.uuid(),
|
||||||
|
isNonValued: z.string(),
|
||||||
|
position: z.string(),
|
||||||
|
description: z.string(),
|
||||||
|
quantity: QuantitySchema,
|
||||||
|
unit_amount: MoneySchema,
|
||||||
|
|
||||||
|
taxes: z.string(),
|
||||||
|
|
||||||
|
subtotal_amount: MoneySchema,
|
||||||
|
discount_percentage: PercentageSchema,
|
||||||
|
discount_amount: MoneySchema,
|
||||||
|
taxable_amount: MoneySchema,
|
||||||
|
taxes_amount: MoneySchema,
|
||||||
|
total_amount: MoneySchema,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
|
||||||
|
metadata: MetadataSchema.optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type GetVerifactuRecordByIdResponseDTO = z.infer<
|
||||||
|
typeof GetVerifactuRecordByIdResponseSchema
|
||||||
|
>;
|
||||||
@ -1 +1,2 @@
|
|||||||
export * from "./send-customer-invoice-by-id.request.dto";
|
export * from "./get-verifactu-record-by-id.response.dto";
|
||||||
|
export * from "./send-invoice-by-id.request.dto";
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
import * as z from "zod/v4";
|
|
||||||
|
|
||||||
export const SendCustomerInvoiceByIdRequestSchema = z.object({
|
|
||||||
invoice_id: z.string(),
|
|
||||||
});
|
|
||||||
|
|
||||||
export type SendCustomerInvoiceByIdRequestDTO = z.infer<
|
|
||||||
typeof SendCustomerInvoiceByIdRequestSchema
|
|
||||||
>;
|
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
|
export const SendInvoiceByIdRequestSchema = z.object({
|
||||||
|
invoice_id: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type SendInvoiceByIdRequestDTO = z.infer<typeof SendInvoiceByIdRequestSchema>;
|
||||||
@ -20,6 +20,6 @@
|
|||||||
"dinero.js": "^1.9.1",
|
"dinero.js": "^1.9.1",
|
||||||
"libphonenumber-js": "^1.11.20",
|
"libphonenumber-js": "^1.11.20",
|
||||||
"shallow-equal-object": "^1.1.1",
|
"shallow-equal-object": "^1.1.1",
|
||||||
"zod": "^3.24.4"
|
"zod": "^4.1.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { isPossiblePhoneNumber, parsePhoneNumberWithError } from "libphonenumber-js";
|
import { isPossiblePhoneNumber, parsePhoneNumberWithError } from "libphonenumber-js";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result, generateUUIDv4 } from "@repo/rdx-utils";
|
import { Result, generateUUIDv4 } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { translateZodValidationError } from "../helpers";
|
import { translateZodValidationError } from "../helpers";
|
||||||
import { ValueObject } from "./value-object";
|
import { ValueObject } from "./value-object";
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
"i18next": "^25.1.1",
|
"i18next": "^25.1.1",
|
||||||
"react-hook-form": "^7.58.1",
|
"react-hook-form": "^7.58.1",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"zod": "^3.25.67"
|
"zod": "^4.1.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "1.9.4",
|
"@biomejs/biome": "1.9.4",
|
||||||
@ -59,6 +59,6 @@
|
|||||||
"react-router-dom": "^6.26.0",
|
"react-router-dom": "^6.26.0",
|
||||||
"recharts": "^2.15.3",
|
"recharts": "^2.15.3",
|
||||||
"sonner": "^2.0.3",
|
"sonner": "^2.0.3",
|
||||||
"zod": "^3.24.4"
|
"zod": "^4.1.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,7 +51,7 @@ import {
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts";
|
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
import { Badge } from "@repo/shadcn-ui/components/badge";
|
import { Badge } from "@repo/shadcn-ui/components/badge";
|
||||||
import { Button } from "@repo/shadcn-ui/components/button";
|
import { Button } from "@repo/shadcn-ui/components/button";
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user