This commit is contained in:
David Arranz 2026-07-03 09:37:12 +02:00
parent 6187a77dd9
commit 6310944a85
10 changed files with 177 additions and 11 deletions

View File

@ -6,7 +6,7 @@ export const buildProformaCreateDefault = (): ProformaCreateForm => {
return {
customerId: "",
invoiceDate: DateHelper.buildTodayIsoDate(),
series: "",
series: "F26",
languageCode: "es",
currencyCode: "EUR",
};

View File

@ -2,6 +2,9 @@
* Representa un cliente seleccionable desde cualquier módulo.
* Debe ser lo suficientemente rico para mostrar en UI,
* pero sin arrastrar todo el shape de Customer.
*
* No usar objetos de dominio, todo tipos primitivos y strings,
* para desacoplar de la capa de dominio.
*/
export interface CustomerSelectionOption {
id: string;

View File

@ -0,0 +1 @@
export * from "./use-get-customer-controller";

View File

@ -0,0 +1,26 @@
import { useCustomerGetQuery } from "../../../../web/shared";
import { buildCustomerData } from "../utils";
export const useGetCustomerController = (customerId: string, options?: { enabled?: boolean }) => {
const {
data,
isLoading,
isError: isLoadError,
error: loadError,
refetch,
} = useCustomerGetQuery({
id: customerId,
enabled: options?.enabled ?? true,
});
const customerData = data ? buildCustomerData(data) : undefined;
return {
customerData,
isLoading,
isLoadError,
loadError,
refetch,
};
};

View File

@ -0,0 +1,64 @@
/**
* Representa un cliente con todo el shape de Customer.
*
* No usar objetos de dominio, todo tipos primitivos y strings,
* para desacoplar de la capa de dominio.
*/
export interface CustomerData {
id: string;
status: string;
reference: string | null;
isCompany: boolean;
name: string;
tradeName: string | null;
tin: string | null;
address: {
street: string | null;
street2: string | null;
city: string | null;
province: string | null;
postalCode: string | null;
country: string | null;
};
contact: {
emailPrimary: string | null;
emailSecondary: string | null;
phonePrimary: string | null;
phoneSecondary: string | null;
mobilePrimary: string | null;
mobileSecondary: string | null;
fax: string | null;
website: string | null;
};
legalRecord: string | null;
paymentMethod: {
id: string;
name: string;
description: string;
} | null;
paymentTerm: {
id: string;
description: string;
} | null;
taxRegime: {
code: string;
description: string;
} | null;
fiscalDefaults: {
usesEquivalenceSurcharge: boolean;
usesRetention: boolean;
};
languageCode: string;
currencyCode: string;
}

View File

@ -0,0 +1 @@
export * from './customer-data.entity';

View File

@ -0,0 +1 @@
export * from "./controllers";

View File

@ -0,0 +1,71 @@
import type { Customer } from "../../../../web/shared";
import type { CustomerData } from "../entities";
/**
* Mapper explícito para desacoplar UI del shape de customers/shared.
*/
export const buildCustomerData = (customer: Customer): CustomerData => {
return {
id: customer.id,
status: customer.status,
reference: customer.reference,
isCompany: customer.isCompany,
name: customer.name,
tradeName: customer.tradeName,
tin: customer.tin,
address: {
street: customer.address.street,
street2: null,
city: customer.address.city,
province: customer.address.province,
postalCode: customer.address.postalCode,
country: customer.address.country,
},
contact: {
emailPrimary: customer.contact.primaryEmail,
emailSecondary: customer.contact.secondaryEmail,
phonePrimary: customer.contact.primaryPhone,
phoneSecondary: customer.contact.secondaryPhone,
mobilePrimary: customer.contact.primaryMobile,
mobileSecondary: customer.contact.secondaryMobile,
fax: customer.contact.fax,
website: customer.contact.website,
},
legalRecord: customer.legalRecord,
paymentMethod: customer.paymentMethod
? {
id: customer.paymentMethod.id,
name: customer.paymentMethod.name,
description: customer.paymentMethod.description,
}
: null,
paymentTerm: customer.paymentTerm
? {
id: customer.paymentTerm.id,
description: customer.paymentTerm.description,
}
: null,
taxRegime: customer.taxRegime
? {
code: customer.taxRegime.code,
description: customer.taxRegime.description,
}
: null,
fiscalDefaults: {
usesEquivalenceSurcharge: customer.fiscalDefaults.usesEquivalenceSurcharge,
usesRetention: customer.fiscalDefaults.usesRetention,
},
languageCode: customer.languageCode,
currencyCode: customer.currencyCode,
};
};

View File

@ -0,0 +1 @@
export * from './build-customer-selection-option';

View File

@ -1,7 +1,7 @@
import { type MapperParamsType, SequelizeDomainMapper } from "@erp/core/api";
import {
UniqueID,
UtcDate,
UtcDateTime,
ValidationErrorCollection,
type ValidationErrorDetail,
extractOrPushError,
@ -10,11 +10,7 @@ import {
} from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils";
import {
RefreshToken,
RefreshTokenHash,
type RefreshTokenInternalProps,
} from "../../../../domain";
import { RefreshToken, RefreshTokenHash, type RefreshTokenInternalProps } from "../../../../domain";
import type { RefreshTokenCreationAttributes, RefreshTokenModel } from "../models";
function toUtcIsoString(value: Date | string): string {
@ -45,13 +41,13 @@ export class SequelizeRefreshTokenDomainMapper extends SequelizeDomainMapper<
errors
);
const expiresAt = extractOrPushError(
UtcDate.createFromISO(toUtcIsoString(source.expires_at)),
UtcDateTime.createFromISO(toUtcIsoString(source.expires_at)),
"expires_at",
errors
);
const revokedAt = extractOrPushError(
maybeFromNullableResult(source.revoked_at, (value) =>
UtcDate.createFromISO(toUtcIsoString(value))
UtcDateTime.createFromISO(toUtcIsoString(value))
),
"revoked_at",
errors
@ -62,7 +58,7 @@ export class SequelizeRefreshTokenDomainMapper extends SequelizeDomainMapper<
errors
);
const createdAt = extractOrPushError(
UtcDate.createFromISO(toUtcIsoString(source.created_at)),
UtcDateTime.createFromISO(toUtcIsoString(source.created_at)),
"created_at",
errors
);
@ -98,7 +94,9 @@ export class SequelizeRefreshTokenDomainMapper extends SequelizeDomainMapper<
token_hash: source.tokenHash.toPrimitive(),
expires_at: source.expiresAt.toISOString(),
revoked_at: maybeToNullable(source.revokedAt, (revokedAt) => revokedAt.toISOString()),
replaced_by_token_id: maybeToNullable(source.replacedByTokenId, (value) => value.toPrimitive()),
replaced_by_token_id: maybeToNullable(source.replacedByTokenId, (value) =>
value.toPrimitive()
),
created_at: source.createdAt.toISOString(),
});
}