v0.9.1
This commit is contained in:
parent
0129c5963c
commit
a810312f01
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/factuges-server",
|
"name": "@erp/factuges-server",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsup src/index.ts --config tsup.config.ts",
|
"build": "tsup src/index.ts --config tsup.config.ts",
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/factuges-web",
|
"name": "@erp/factuges-web",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"typecheck": "tsc -p tsconfig.json --noEmit",
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/auth",
|
"name": "@erp/auth",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/catalogs",
|
"name": "@erp/catalogs",
|
||||||
"description": "Catalogs module",
|
"description": "Catalogs module",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/companies",
|
"name": "@erp/companies",
|
||||||
"description": "Companies module",
|
"description": "Companies module",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/core",
|
"name": "@erp/core",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/customer-invoices",
|
"name": "@erp/customer-invoices",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import type { UniqueID } from "@repo/rdx-ddd";
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Maybe, Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
type IProformaCreateProps,
|
type IProformaCreateProps,
|
||||||
@ -55,11 +55,11 @@ export class ProformaCreator implements IProformaCreator {
|
|||||||
return Result.fail(numberResult.error);
|
return Result.fail(numberResult.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const invoiceNumber = numberResult.data;
|
const proformaReference = numberResult.data;
|
||||||
|
|
||||||
// 2. Crear agregado
|
// 2. Crear agregado
|
||||||
const proformaResult = Proforma.create(
|
const proformaResult = Proforma.create(
|
||||||
{ ...resolvedProps.data, proformaReference: invoiceNumber, companyId },
|
{ ...resolvedProps.data, proformaReference, companyId },
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -81,11 +81,17 @@ export class ProformaCreator implements IProformaCreator {
|
|||||||
|
|
||||||
private async resolveCreateProps(
|
private async resolveCreateProps(
|
||||||
props: ProformaCreateInputProps
|
props: ProformaCreateInputProps
|
||||||
): Promise<Result<Omit<IProformaCreateProps, "invoiceNumber">, Error>> {
|
): Promise<Result<Omit<IProformaCreateProps, "proformaReference">, Error>> {
|
||||||
|
// TODO: Esto hay que cambiarlo en el futuro para buscar valores por defecto, desde la empresa o desde el cliente
|
||||||
|
const _newProps = {
|
||||||
|
...props,
|
||||||
|
taxRegimeCode: props.taxRegimeCode.isNone() ? Maybe.some("01") : props.taxRegimeCode,
|
||||||
|
};
|
||||||
|
|
||||||
// Tax Regime => comprobar que existe
|
// Tax Regime => comprobar que existe
|
||||||
const taxRegimeResult = await this.deps.taxResolver.ensureTaxRegimeByCode({
|
const taxRegimeResult = await this.deps.taxResolver.ensureTaxRegimeByCode({
|
||||||
companyId: props.companyId,
|
companyId: _newProps.companyId,
|
||||||
code: props.taxRegimeCode,
|
code: _newProps.taxRegimeCode,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (taxRegimeResult.isFailure) {
|
if (taxRegimeResult.isFailure) {
|
||||||
@ -94,8 +100,8 @@ export class ProformaCreator implements IProformaCreator {
|
|||||||
|
|
||||||
// Payment method => comprobar que existe
|
// Payment method => comprobar que existe
|
||||||
const paymentMethodResult = await this.deps.paymentResolver.ensurePaymentMethodById({
|
const paymentMethodResult = await this.deps.paymentResolver.ensurePaymentMethodById({
|
||||||
companyId: props.companyId,
|
companyId: _newProps.companyId,
|
||||||
id: props.paymentMethodId,
|
id: _newProps.paymentMethodId,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (paymentMethodResult.isFailure) {
|
if (paymentMethodResult.isFailure) {
|
||||||
@ -107,8 +113,8 @@ export class ProformaCreator implements IProformaCreator {
|
|||||||
|
|
||||||
for (const item of props.items) {
|
for (const item of props.items) {
|
||||||
const taxes = await this.deps.taxResolver.ensureItemTaxes({
|
const taxes = await this.deps.taxResolver.ensureItemTaxes({
|
||||||
companyId: props.companyId,
|
companyId: _newProps.companyId,
|
||||||
atDate: props.proformaDate,
|
atDate: _newProps.proformaDate,
|
||||||
taxCodes: item.taxes,
|
taxCodes: item.taxes,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -123,7 +129,7 @@ export class ProformaCreator implements IProformaCreator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Result.ok({
|
return Result.ok({
|
||||||
...props,
|
..._newProps,
|
||||||
items: resolvedItems,
|
items: resolvedItems,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import {
|
|||||||
} from "@repo/rdx-ddd";
|
} from "@repo/rdx-ddd";
|
||||||
import {
|
import {
|
||||||
focusFirstInputFormError,
|
focusFirstInputFormError,
|
||||||
|
getFirstFormErrorMessage,
|
||||||
showErrorToast,
|
showErrorToast,
|
||||||
showSuccessToast,
|
showSuccessToast,
|
||||||
showWarningToast,
|
showWarningToast,
|
||||||
@ -15,6 +16,7 @@ import {
|
|||||||
import { useEffect, useId, useMemo, useState } from "react";
|
import { useEffect, useId, useMemo, useState } from "react";
|
||||||
import type { FieldErrors } from "react-hook-form";
|
import type { FieldErrors } from "react-hook-form";
|
||||||
|
|
||||||
|
import { useTranslation } from "../../../i18n";
|
||||||
import type { Proforma } from "../../shared";
|
import type { Proforma } from "../../shared";
|
||||||
import {
|
import {
|
||||||
buildInvoiceSeriesSelectItems,
|
buildInvoiceSeriesSelectItems,
|
||||||
@ -42,6 +44,7 @@ const normalizeSubmitError = (error: unknown): Error | ValidationErrorCollection
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const useCreateProformaController = (options?: UseCreateProformaControllerOptions) => {
|
export const useCreateProformaController = (options?: UseCreateProformaControllerOptions) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const formId = useId();
|
const formId = useId();
|
||||||
const [selectedCustomer, setSelectedCustomer] = useState<CustomerSelectionOption | null>(null);
|
const [selectedCustomer, setSelectedCustomer] = useState<CustomerSelectionOption | null>(null);
|
||||||
|
|
||||||
@ -70,9 +73,7 @@ export const useCreateProformaController = (options?: UseCreateProformaControlle
|
|||||||
const defaultSeries = useMemo(() => {
|
const defaultSeries = useMemo(() => {
|
||||||
const invoiceSeries = seriesQuery.data ?? [];
|
const invoiceSeries = seriesQuery.data ?? [];
|
||||||
|
|
||||||
return (
|
return invoiceSeries.find((series) => series.isDefault)?.code ?? invoiceSeries[0]?.code ?? "";
|
||||||
invoiceSeries.find((series) => series.isDefault)?.code ?? invoiceSeries[0]?.code ?? ""
|
|
||||||
);
|
|
||||||
}, [seriesQuery.data]);
|
}, [seriesQuery.data]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -140,8 +141,13 @@ export const useCreateProformaController = (options?: UseCreateProformaControlle
|
|||||||
|
|
||||||
if (isValidationErrorCollection(normalizedError)) {
|
if (isValidationErrorCollection(normalizedError)) {
|
||||||
applyValidationErrorCollection(form, normalizedError);
|
applyValidationErrorCollection(form, normalizedError);
|
||||||
focusFirstInputFormError(form);
|
focusFirstInputFormError(form.formState.errors, form);
|
||||||
showWarningToast("Revisa los campos", "Hay errores de validación en el formulario.");
|
const errorMessage = getFirstFormErrorMessage(form.formState.errors, form);
|
||||||
|
showWarningToast(
|
||||||
|
"Revisa los campos",
|
||||||
|
errorMessage ??
|
||||||
|
t("forms.validation.message", "Hay errores de validación en el formulario.")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,8 +155,12 @@ export const useCreateProformaController = (options?: UseCreateProformaControlle
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
(_errors: FieldErrors<ProformaCreateForm>) => {
|
(_errors: FieldErrors<ProformaCreateForm>) => {
|
||||||
focusFirstInputFormError(form);
|
focusFirstInputFormError(_errors, form);
|
||||||
showWarningToast("Revisa los campos", "Hay errores de validación en el formulario.");
|
const errorMessage = getFirstFormErrorMessage(_errors, form);
|
||||||
|
showWarningToast(
|
||||||
|
"Revisa los campos",
|
||||||
|
errorMessage ?? t("forms.validation.message", "Hay errores de validación en el formulario.")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -4,9 +4,13 @@ import { buildProformaUpdateDefault } from "../utils";
|
|||||||
|
|
||||||
import { mapProformaItemsToProformaItemsUpdateForm } from "./map-proforma-items-to-proforma-items-update-form.adapter";
|
import { mapProformaItemsToProformaItemsUpdateForm } from "./map-proforma-items-to-proforma-items-update-form.adapter";
|
||||||
|
|
||||||
interface FiscalDefaults {
|
interface FiscalState {
|
||||||
taxMode: ProformaTaxMode;
|
taxMode: ProformaTaxMode;
|
||||||
|
|
||||||
|
hasTaxPercentage: boolean;
|
||||||
|
hasRecPercentage: boolean;
|
||||||
|
hasRetentionPercentage: boolean;
|
||||||
|
|
||||||
defaultTaxPercentage: number | null;
|
defaultTaxPercentage: number | null;
|
||||||
defaultRecPercentage: number | null;
|
defaultRecPercentage: number | null;
|
||||||
defaultRetentionPercentage: number | null;
|
defaultRetentionPercentage: number | null;
|
||||||
@ -18,7 +22,7 @@ interface FiscalDefaults {
|
|||||||
|
|
||||||
export const mapProformaToProformaUpdateForm = (proforma: Proforma): ProformaUpdateForm => {
|
export const mapProformaToProformaUpdateForm = (proforma: Proforma): ProformaUpdateForm => {
|
||||||
const proformaDefaults = buildProformaUpdateDefault();
|
const proformaDefaults = buildProformaUpdateDefault();
|
||||||
const fiscalDefaults = resolveFiscalDefaults(proforma, proformaDefaults);
|
const fiscalState = resolveFiscalState(proforma, proformaDefaults);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
proformaReference: proforma.proformaReference,
|
proformaReference: proforma.proformaReference,
|
||||||
@ -40,18 +44,17 @@ export const mapProformaToProformaUpdateForm = (proforma: Proforma): ProformaUpd
|
|||||||
globalDiscountPercentage:
|
globalDiscountPercentage:
|
||||||
proforma.globalDiscountPercentage ?? proformaDefaults.globalDiscountPercentage,
|
proforma.globalDiscountPercentage ?? proformaDefaults.globalDiscountPercentage,
|
||||||
|
|
||||||
taxMode: fiscalDefaults.taxMode,
|
taxMode: fiscalState.taxMode,
|
||||||
taxRegimeCode: proforma.taxRegimeCode ?? proformaDefaults.taxRegimeCode,
|
taxRegimeCode: proforma.taxRegimeCode ?? proformaDefaults.taxRegimeCode,
|
||||||
|
|
||||||
hasTaxPercentage:
|
hasTaxPercentage: fiscalState.hasTaxPercentage,
|
||||||
fiscalDefaults.taxMode === "single" && fiscalDefaults.defaultTaxPercentage !== null,
|
taxPercentage: fiscalState.defaultTaxPercentage,
|
||||||
taxPercentage: fiscalDefaults.defaultTaxPercentage,
|
|
||||||
|
|
||||||
hasRecPercentage: fiscalDefaults.defaultRecPercentage !== null,
|
hasRecPercentage: fiscalState.hasRecPercentage,
|
||||||
recPercentage: fiscalDefaults.defaultRecPercentage,
|
recPercentage: fiscalState.defaultRecPercentage,
|
||||||
|
|
||||||
hasRetentionPercentage: fiscalDefaults.defaultRetentionPercentage !== null,
|
hasRetentionPercentage: fiscalState.defaultRetentionPercentage !== null,
|
||||||
retentionPercentage: fiscalDefaults.defaultRetentionPercentage,
|
retentionPercentage: fiscalState.defaultRetentionPercentage,
|
||||||
|
|
||||||
paymentMethodId: proforma.paymentMethodId,
|
paymentMethodId: proforma.paymentMethodId,
|
||||||
paymentTermId: proforma.paymentTermId,
|
paymentTermId: proforma.paymentTermId,
|
||||||
@ -60,20 +63,26 @@ export const mapProformaToProformaUpdateForm = (proforma: Proforma): ProformaUpd
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const resolveFiscalDefaults = (
|
const resolveFiscalState = (
|
||||||
proforma: Proforma,
|
proforma: Proforma,
|
||||||
proformaDefaults: ProformaUpdateForm
|
proformaDefaults: ProformaUpdateForm
|
||||||
): FiscalDefaults => {
|
): FiscalState => {
|
||||||
// Caso habitual: una sola combinación de impuestos
|
// Caso habitual: una sola combinación de impuestos
|
||||||
if (proforma.taxes.length === 1) {
|
if (proforma.taxes.length === 1) {
|
||||||
const taxSummary = proforma.taxes[0];
|
const taxSummary = proforma.taxes[0];
|
||||||
|
|
||||||
|
const hasTaxPercentage = taxSummary.ivaCode !== null;
|
||||||
|
const hasRecPercentage = taxSummary.recCode !== null;
|
||||||
|
const hasRetentionPercentage = taxSummary.retentionCode !== null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
taxMode: "single",
|
taxMode: "single",
|
||||||
defaultTaxPercentage: taxSummary.ivaCode === null ? null : taxSummary.ivaPercentage,
|
defaultTaxPercentage: hasTaxPercentage ? taxSummary.ivaPercentage : null,
|
||||||
defaultRecPercentage: taxSummary.recCode === null ? null : taxSummary.recPercentage,
|
defaultRecPercentage: hasRecPercentage ? taxSummary.recPercentage : null,
|
||||||
defaultRetentionPercentage:
|
defaultRetentionPercentage: hasRetentionPercentage ? taxSummary.retentionPercentage : null,
|
||||||
taxSummary.retentionCode === null ? null : taxSummary.retentionPercentage,
|
hasTaxPercentage,
|
||||||
|
hasRecPercentage,
|
||||||
|
hasRetentionPercentage,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,17 +90,26 @@ const resolveFiscalDefaults = (
|
|||||||
if (proforma.taxes.length === 0) {
|
if (proforma.taxes.length === 0) {
|
||||||
return {
|
return {
|
||||||
taxMode: "single",
|
taxMode: "single",
|
||||||
defaultTaxPercentage: proformaDefaults.taxPercentage,
|
defaultTaxPercentage: null,
|
||||||
defaultRecPercentage: proformaDefaults.recPercentage,
|
defaultRecPercentage: null,
|
||||||
defaultRetentionPercentage: proformaDefaults.retentionPercentage,
|
defaultRetentionPercentage: null,
|
||||||
|
hasTaxPercentage: false,
|
||||||
|
hasRecPercentage: false,
|
||||||
|
hasRetentionPercentage: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proforma con varias combinaciones de impuestos
|
// Proforma con varias combinaciones de impuestos
|
||||||
|
const taxSummary = proforma.taxes[0];
|
||||||
|
const hasRecPercentage = taxSummary.recCode !== null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
taxMode: "perLine",
|
taxMode: "perLine",
|
||||||
defaultTaxPercentage: proformaDefaults.taxPercentage,
|
defaultTaxPercentage: null,
|
||||||
defaultRecPercentage: proformaDefaults.recPercentage,
|
defaultRecPercentage: hasRecPercentage ? taxSummary.recPercentage : null,
|
||||||
defaultRetentionPercentage: proformaDefaults.retentionPercentage,
|
defaultRetentionPercentage: null,
|
||||||
|
hasTaxPercentage: false,
|
||||||
|
hasRecPercentage,
|
||||||
|
hasRetentionPercentage: false,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import type { CustomerSelectionOption } from "@erp/customers";
|
|||||||
import { type ValidationErrorCollection, isValidationErrorCollection } from "@repo/rdx-ddd";
|
import { type ValidationErrorCollection, isValidationErrorCollection } from "@repo/rdx-ddd";
|
||||||
import {
|
import {
|
||||||
focusFirstInputFormError,
|
focusFirstInputFormError,
|
||||||
|
getFirstFormErrorMessage,
|
||||||
showErrorToast,
|
showErrorToast,
|
||||||
showSuccessToast,
|
showSuccessToast,
|
||||||
showWarningToast,
|
showWarningToast,
|
||||||
@ -14,7 +15,6 @@ import type { FieldErrors } from "react-hook-form";
|
|||||||
|
|
||||||
import { useTranslation } from "../../../i18n";
|
import { useTranslation } from "../../../i18n";
|
||||||
import type { UpdateProformaByIdParams } from "../../shared";
|
import type { UpdateProformaByIdParams } from "../../shared";
|
||||||
import type { Proforma } from "../../shared/entities";
|
|
||||||
import {
|
import {
|
||||||
buildInvoiceSeriesSelectItems,
|
buildInvoiceSeriesSelectItems,
|
||||||
ensureCurrentValueInSelectItems,
|
ensureCurrentValueInSelectItems,
|
||||||
@ -22,6 +22,7 @@ import {
|
|||||||
useProformaGetQuery,
|
useProformaGetQuery,
|
||||||
useProformaUpdateMutation,
|
useProformaUpdateMutation,
|
||||||
} from "../../shared";
|
} from "../../shared";
|
||||||
|
import type { Proforma } from "../../shared/entities";
|
||||||
import { mapProformaToProformaUpdateForm, mapProformaToSelectedCustomer } from "../adapters";
|
import { mapProformaToProformaUpdateForm, mapProformaToSelectedCustomer } from "../adapters";
|
||||||
import { type ProformaUpdateForm, ProformaUpdateFormSchema } from "../entities";
|
import { type ProformaUpdateForm, ProformaUpdateFormSchema } from "../entities";
|
||||||
import {
|
import {
|
||||||
@ -147,8 +148,8 @@ export const useUpdateProformaController = (
|
|||||||
|
|
||||||
if (!formHasAnyDirty(form.formState.dirtyFields)) {
|
if (!formHasAnyDirty(form.formState.dirtyFields)) {
|
||||||
showWarningToast(
|
showWarningToast(
|
||||||
t("proformas.update.no_changes.title"),
|
t("pages.update.no_changes.title", "Sin cambios"),
|
||||||
t("proformas.update.no_changes.message")
|
t("pages.update.no_changes.message", "No has realizado ningún cambio.")
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -181,8 +182,8 @@ export const useUpdateProformaController = (
|
|||||||
|
|
||||||
if (options?.successToasts !== false) {
|
if (options?.successToasts !== false) {
|
||||||
showSuccessToast(
|
showSuccessToast(
|
||||||
t("proformas.update.success.title"),
|
t("pages.update.success.title", "Guardado"),
|
||||||
t("proformas.update.success.message")
|
t("pages.update.success.message", "Los cambios se han guardado correctamente.")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,7 +209,7 @@ export const useUpdateProformaController = (
|
|||||||
|
|
||||||
console.log("Errores de validación aplicados al form:", form.formState.errors);
|
console.log("Errores de validación aplicados al form:", form.formState.errors);
|
||||||
|
|
||||||
focusFirstInputFormError(form);
|
focusFirstInputFormError(form.formState.errors, form);
|
||||||
|
|
||||||
if (options?.errorToasts !== false) {
|
if (options?.errorToasts !== false) {
|
||||||
showWarningToast(
|
showWarningToast(
|
||||||
@ -230,11 +231,12 @@ export const useUpdateProformaController = (
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
(_errors: FieldErrors<ProformaUpdateForm>) => {
|
(_errors: FieldErrors<ProformaUpdateForm>) => {
|
||||||
focusFirstInputFormError(form);
|
focusFirstInputFormError(_errors, form);
|
||||||
|
const errorMessage = getFirstFormErrorMessage(_errors, form);
|
||||||
|
|
||||||
showWarningToast(
|
showWarningToast(
|
||||||
t("forms.validation.title", "Revisa los campos"),
|
t("forms.validation.title", "Revisa los campos"),
|
||||||
t("forms.validation.message", "Hay errores de validación en el formulario.")
|
errorMessage ?? t("forms.validation.message", "Hay errores de validación en el formulario.")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@ -230,6 +230,14 @@ export const useUpdateProformaItemsController = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const itemErrors = React.useMemo<ProformaItemError[]>(() => {
|
const itemErrors = React.useMemo<ProformaItemError[]>(() => {
|
||||||
|
//console.log("itemErrors => ", errors.items);
|
||||||
|
if (!errors.items) return [];
|
||||||
|
|
||||||
|
if (errors.items.root) {
|
||||||
|
return [errors.items.root];
|
||||||
|
//console.error("Errores de validación en items.root:", errors.items.root);
|
||||||
|
}
|
||||||
|
|
||||||
if (!Array.isArray(errors.items)) return [];
|
if (!Array.isArray(errors.items)) return [];
|
||||||
|
|
||||||
return errors.items.map((error) => error ?? {});
|
return errors.items.map((error) => error ?? {});
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import { ProformaItemUpdateFormSchema } from "./proforma-item-update-form.schema
|
|||||||
|
|
||||||
export const ProformaUpdateFormSchema = z
|
export const ProformaUpdateFormSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
proformaReference: z.string(),
|
||||||
series: z.string(),
|
series: z.string(),
|
||||||
|
|
||||||
proformaDate: z.string().min(1),
|
proformaDate: z.string().min(1),
|
||||||
@ -50,7 +51,9 @@ export const ProformaUpdateFormSchema = z
|
|||||||
paymentMethodId: z.string().nullable(),
|
paymentMethodId: z.string().nullable(),
|
||||||
paymentTermId: z.string().nullable(),
|
paymentTermId: z.string().nullable(),
|
||||||
|
|
||||||
items: z.array(ProformaItemUpdateFormSchema).min(1),
|
items: z
|
||||||
|
.array(ProformaItemUpdateFormSchema)
|
||||||
|
.min(1, "Debe haber al menos un item en la proforma"),
|
||||||
})
|
})
|
||||||
.refine(
|
.refine(
|
||||||
(formValues) => {
|
(formValues) => {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { FormSectionCard } from "@repo/rdx-ui/components";
|
import { FormSectionCard } from "@repo/rdx-ui/components";
|
||||||
|
import { cn } from "@repo/shadcn-ui/lib/utils";
|
||||||
import { ListIcon } from "lucide-react";
|
import { ListIcon } from "lucide-react";
|
||||||
import type { ComponentProps } from "react";
|
import type { ComponentProps } from "react";
|
||||||
|
|
||||||
@ -24,10 +25,13 @@ export const ProformaUpdateItemsEditor = ({
|
|||||||
...props
|
...props
|
||||||
}: ProformaUpdateItemsEditorProps) => {
|
}: ProformaUpdateItemsEditorProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { totals } = totalsCtrl;
|
const { totals } = totalsCtrl;
|
||||||
|
const { itemErrors } = itemsCtrl;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormSectionCard
|
<FormSectionCard
|
||||||
|
className={cn(itemErrors.length ? "bg-red-100" : "")}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
icon={<ListIcon className="size-3" />}
|
icon={<ListIcon className="size-3" />}
|
||||||
title={t("form_groups.items.title", "Líneas de detalle")}
|
title={t("form_groups.items.title", "Líneas de detalle")}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/customers",
|
"name": "@erp/customers",
|
||||||
"description": "Customers",
|
"description": "Customers",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -274,12 +274,13 @@ export default (database: Sequelize) => {
|
|||||||
{ name: "idx_company_idx", fields: ["id", "company_id"], unique: true }, // <- para consulta get
|
{ name: "idx_company_idx", fields: ["id", "company_id"], unique: true }, // <- para consulta get
|
||||||
{ name: "idx_factuges", fields: ["factuges_id"], unique: true }, // <- para el proceso python
|
{ name: "idx_factuges", fields: ["factuges_id"], unique: true }, // <- para el proceso python
|
||||||
|
|
||||||
// Para búsquedas simples => se hace con el "CriteriaToSequelizeConverter"
|
// Quiksearch => "CriteriaToSequelizeConverter" construye la sentencia SQL de búsqueda FULLTEXT
|
||||||
/*{
|
// a partir de este índice. Las columnas deben coincidir con los campos de búsqueda rápida definidos en el repositorio.
|
||||||
name: "ft_customer",
|
{
|
||||||
|
name: "idx_qs_customer",
|
||||||
type: "FULLTEXT",
|
type: "FULLTEXT",
|
||||||
fields: ["name", "trade_name", "reference", "tin", "email_primary", "mobile_primary"],
|
fields: ["name", "trade_name", "reference", "tin", "email_primary", "mobile_primary"],
|
||||||
},*/
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
whereMergeStrategy: "and", // <- cómo tratar el merge de un scope
|
whereMergeStrategy: "and", // <- cómo tratar el merge de un scope
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/factuges",
|
"name": "@erp/factuges",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/identity",
|
"name": "@erp/identity",
|
||||||
"description": "Identity module",
|
"description": "Identity module",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/supplier-invoices",
|
"name": "@erp/supplier-invoices",
|
||||||
"description": "Supplier invoices",
|
"description": "Supplier invoices",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/suppliers",
|
"name": "@erp/suppliers",
|
||||||
"description": "Suppliers",
|
"description": "Suppliers",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "uecko-erp-2025",
|
"name": "uecko-erp-2025",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"apps/*",
|
"apps/*",
|
||||||
"modules/*",
|
"modules/*",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/i18next",
|
"name": "@repo/i18next",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/rdx-criteria",
|
"name": "@repo/rdx-criteria",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/rdx-ddd",
|
"name": "@repo/rdx-ddd",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/rdx-logger",
|
"name": "@repo/rdx-logger",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/rdx-ui",
|
"name": "@repo/rdx-ui",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import type { FieldValues, Path, UseFormReturn } from "react-hook-form";
|
import type { FieldErrors, FieldValues, Path, UseFormReturn } from "react-hook-form";
|
||||||
|
|
||||||
export const focusFirstInputFormError = <T extends FieldValues>(form: UseFormReturn<T>) => {
|
export const focusFirstInputFormError = <T extends FieldValues>(
|
||||||
const errors = form.formState.errors;
|
errors: FieldErrors<T>,
|
||||||
|
form: UseFormReturn<T>
|
||||||
|
) => {
|
||||||
const firstKey = Object.keys(errors)[0] as keyof T | undefined;
|
const firstKey = Object.keys(errors)[0] as keyof T | undefined;
|
||||||
|
|
||||||
if (firstKey) {
|
if (firstKey) {
|
||||||
|
|||||||
@ -0,0 +1,17 @@
|
|||||||
|
import type { FieldErrors, FieldValues, UseFormReturn } from "react-hook-form";
|
||||||
|
|
||||||
|
export const getFirstFormErrorMessage = <T extends FieldValues>(
|
||||||
|
errors: FieldErrors<T>,
|
||||||
|
form: UseFormReturn<T>
|
||||||
|
) => {
|
||||||
|
const firstKey = Object.keys(errors)[0] as keyof T | undefined;
|
||||||
|
const firstError = errors[firstKey] as
|
||||||
|
| { message?: string; root?: { message?: string } }
|
||||||
|
| undefined;
|
||||||
|
|
||||||
|
return firstError?.message
|
||||||
|
? firstError.message
|
||||||
|
: firstError?.root?.message
|
||||||
|
? firstError.root?.message
|
||||||
|
: undefined;
|
||||||
|
};
|
||||||
@ -1,2 +1,3 @@
|
|||||||
export * from "./focus-first-input-form-error.ts";
|
export * from "./focus-first-input-form-error.ts";
|
||||||
|
export * from "./get-first-form-error-message.ts";
|
||||||
export * from "./prevent-enter-key-submit-form.ts";
|
export * from "./prevent-enter-key-submit-form.ts";
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/rdx-utils",
|
"name": "@repo/rdx-utils",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/shadcn-ui",
|
"name": "@repo/shadcn-ui",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true,
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/typescript-config",
|
"name": "@repo/typescript-config",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user