Paso de factuges a proforma
This commit is contained in:
parent
4786eb189e
commit
41f30cde9d
@ -3,7 +3,13 @@ import type { UniqueID } from "@repo/rdx-ddd";
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import type { Transaction } from "sequelize";
|
import type { Transaction } from "sequelize";
|
||||||
|
|
||||||
import { type IProformaCreatorParams, buildProformaCreator } from "../../../application";
|
import {
|
||||||
|
type IProformaCreatorParams,
|
||||||
|
type IProformaFullSnapshot,
|
||||||
|
buildProformaCreator,
|
||||||
|
buildProformaFinder,
|
||||||
|
buildProformaSnapshotBuilders,
|
||||||
|
} from "../../../application";
|
||||||
import type { Proforma } from "../../../domain";
|
import type { Proforma } from "../../../domain";
|
||||||
|
|
||||||
import { buildProformaNumberGenerator } from "./proforma-number-generator.di";
|
import { buildProformaNumberGenerator } from "./proforma-number-generator.di";
|
||||||
@ -24,7 +30,16 @@ export type ProformaPublicServices = {
|
|||||||
) => Promise<Result<Proforma, Error>>;
|
) => Promise<Result<Proforma, Error>>;
|
||||||
|
|
||||||
listProformas: (filters: unknown, context: unknown) => null;
|
listProformas: (filters: unknown, context: unknown) => null;
|
||||||
getProformaById: (id: unknown, context: unknown) => null;
|
getProformaById: (
|
||||||
|
id: UniqueID,
|
||||||
|
context: ProformaServicesContext
|
||||||
|
) => Promise<Result<Proforma, Error>>;
|
||||||
|
|
||||||
|
getProformaSnapshotById: (
|
||||||
|
id: UniqueID,
|
||||||
|
context: ProformaServicesContext
|
||||||
|
) => Promise<Result<IProformaFullSnapshot, Error>>;
|
||||||
|
|
||||||
generateProformaReport: (id: unknown, options: unknown, context: unknown) => null;
|
generateProformaReport: (id: unknown, options: unknown, context: unknown) => null;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -40,9 +55,11 @@ export function buildProformaServices(
|
|||||||
|
|
||||||
const repository = buildProformaRepository({ database, mappers: persistenceMappers });
|
const repository = buildProformaRepository({ database, mappers: persistenceMappers });
|
||||||
const numberService = buildProformaNumberGenerator();
|
const numberService = buildProformaNumberGenerator();
|
||||||
|
const snapshotsBuilder = buildProformaSnapshotBuilders();
|
||||||
|
|
||||||
// Application helpers
|
// Application helpers
|
||||||
const creator = buildProformaCreator({ numberService, repository });
|
const creator = buildProformaCreator({ numberService, repository });
|
||||||
|
const finder = buildProformaFinder(repository);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createProforma: async (
|
createProforma: async (
|
||||||
@ -64,8 +81,29 @@ export function buildProformaServices(
|
|||||||
listProformas: (filters, context) => null,
|
listProformas: (filters, context) => null,
|
||||||
//internal.useCases.listProformas().execute(filters, context),
|
//internal.useCases.listProformas().execute(filters, context),
|
||||||
|
|
||||||
getProformaById: (id, context) => null,
|
getProformaById: async (id: UniqueID, context: ProformaServicesContext) => {
|
||||||
//internal.useCases.getProformaById().execute(id, context),
|
const { transaction, companyId } = context;
|
||||||
|
const proformaResult = await finder.findProformaById(companyId, id, transaction);
|
||||||
|
|
||||||
|
if (proformaResult.isFailure) {
|
||||||
|
return Result.fail(proformaResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok(proformaResult.data);
|
||||||
|
},
|
||||||
|
|
||||||
|
getProformaSnapshotById: async (id: UniqueID, context: ProformaServicesContext) => {
|
||||||
|
const { transaction, companyId } = context;
|
||||||
|
const proformaResult = await finder.findProformaById(companyId, id, transaction);
|
||||||
|
|
||||||
|
if (proformaResult.isFailure) {
|
||||||
|
return Result.fail(proformaResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fullSnapshot = snapshotsBuilder.full.toOutput(proformaResult.data);
|
||||||
|
|
||||||
|
return Result.ok(fullSnapshot);
|
||||||
|
},
|
||||||
|
|
||||||
generateProformaReport: (id, options, context) => null,
|
generateProformaReport: (id, options, context) => null,
|
||||||
//internal.useCases.reportProforma().execute(id, options, context),
|
//internal.useCases.reportProforma().execute(id, options, context),
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import {
|
|||||||
} from "@repo/rdx-ddd";
|
} from "@repo/rdx-ddd";
|
||||||
import { type Maybe, Result } from "@repo/rdx-utils";
|
import { type Maybe, Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import type { CustomerStatus, CustomerTaxesProps } from "../value-objects";
|
import { type CustomerStatus, CustomerTaxes } from "../value-objects";
|
||||||
|
|
||||||
export interface ICustomerCreateProps {
|
export interface ICustomerCreateProps {
|
||||||
companyId: UniqueID;
|
companyId: UniqueID;
|
||||||
@ -43,7 +43,7 @@ export interface ICustomerCreateProps {
|
|||||||
|
|
||||||
legalRecord: Maybe<TextValue>;
|
legalRecord: Maybe<TextValue>;
|
||||||
|
|
||||||
defaultTaxes: CustomerTaxesProps;
|
defaultTaxes: CustomerTaxes;
|
||||||
|
|
||||||
languageCode: LanguageCode;
|
languageCode: LanguageCode;
|
||||||
currencyCode: CurrencyCode;
|
currencyCode: CurrencyCode;
|
||||||
@ -86,19 +86,20 @@ export interface ICustomer {
|
|||||||
readonly website: Maybe<URLAddress>;
|
readonly website: Maybe<URLAddress>;
|
||||||
readonly legalRecord: Maybe<TextValue>;
|
readonly legalRecord: Maybe<TextValue>;
|
||||||
|
|
||||||
readonly defaultTaxes: CustomerTaxesProps;
|
readonly defaultTaxes: CustomerTaxes;
|
||||||
|
|
||||||
readonly languageCode: LanguageCode;
|
readonly languageCode: LanguageCode;
|
||||||
readonly currencyCode: CurrencyCode;
|
readonly currencyCode: CurrencyCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
type CustomerInternalProps = Omit<ICustomerCreateProps, "address"> & {
|
type CustomerInternalProps = Omit<ICustomerCreateProps, "address" | "defaultTaxes"> & {
|
||||||
readonly address: PostalAddress;
|
readonly address: PostalAddress;
|
||||||
|
readonly defaultTaxes: CustomerTaxes;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Customer extends AggregateRoot<CustomerInternalProps> implements ICustomer {
|
export class Customer extends AggregateRoot<CustomerInternalProps> implements ICustomer {
|
||||||
static create(props: ICustomerCreateProps, id?: UniqueID): Result<Customer, Error> {
|
static create(props: ICustomerCreateProps, id?: UniqueID): Result<Customer, Error> {
|
||||||
const { address, ...internalProps } = props;
|
const { address, defaultTaxes, ...internalProps } = props;
|
||||||
|
|
||||||
const postalAddressResult = PostalAddress.create(address);
|
const postalAddressResult = PostalAddress.create(address);
|
||||||
|
|
||||||
@ -106,9 +107,15 @@ export class Customer extends AggregateRoot<CustomerInternalProps> implements IC
|
|||||||
return Result.fail(postalAddressResult.error);
|
return Result.fail(postalAddressResult.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const taxes = CustomerTaxes.create(defaultTaxes);
|
||||||
|
if (taxes.isFailure) {
|
||||||
|
return Result.fail(taxes.error);
|
||||||
|
}
|
||||||
|
|
||||||
const contact = new Customer(
|
const contact = new Customer(
|
||||||
{
|
{
|
||||||
...internalProps,
|
...internalProps,
|
||||||
|
defaultTaxes: taxes.data,
|
||||||
address: postalAddressResult.data,
|
address: postalAddressResult.data,
|
||||||
},
|
},
|
||||||
id
|
id
|
||||||
@ -220,7 +227,7 @@ export class Customer extends AggregateRoot<CustomerInternalProps> implements IC
|
|||||||
return this.props.legalRecord;
|
return this.props.legalRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get defaultTaxes(): CustomerTaxesProps {
|
public get defaultTaxes(): CustomerTaxes {
|
||||||
return this.props.defaultTaxes;
|
return this.props.defaultTaxes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import type { Tax } from "@erp/core/api";
|
import type { TaxCatalogProvider } from "@erp/core";
|
||||||
|
import { Tax } from "@erp/core/api";
|
||||||
import { ValueObject } from "@repo/rdx-ddd";
|
import { ValueObject } from "@repo/rdx-ddd";
|
||||||
import { type Maybe, Result } from "@repo/rdx-utils";
|
import { Maybe, Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
export type CustomerTaxesProps = {
|
export type CustomerTaxesProps = {
|
||||||
iva: Maybe<Tax>; // si existe
|
iva: Maybe<Tax>; // si existe
|
||||||
@ -16,30 +17,131 @@ export interface ICustomerItemTaxes {
|
|||||||
toKey(): string; // Clave para representar un trío.
|
toKey(): string; // Clave para representar un trío.
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CustomerTaxes
|
export class CustomerTaxes extends ValueObject<CustomerTaxesProps> implements ICustomerItemTaxes {
|
||||||
extends ValueObject<CustomerTaxesProps>
|
|
||||||
implements ICustomerItemTaxes
|
|
||||||
{
|
|
||||||
static create(props: CustomerTaxesProps) {
|
static create(props: CustomerTaxesProps) {
|
||||||
return Result.ok(new CustomerTaxes(props));
|
return Result.ok(new CustomerTaxes(props));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reconstruye una instancia de CustomerTaxes a partir de una clave serializada.
|
||||||
|
* Este método es la operación inversa de toKey().
|
||||||
|
*
|
||||||
|
* @param key Clave en formato "ivaCode;recCode;retentionCode"
|
||||||
|
* Donde cada código puede ser "#" si el impuesto no existe
|
||||||
|
* Ejemplo: "iva_21;rec_02;#" o "#;#;#"
|
||||||
|
* @param provider Proveedor del catálogo de impuestos (ej: SpainTaxCatalogProvider)
|
||||||
|
* @returns Result<CustomerTaxes> Éxito con la instancia creada o fallo con mensaje de error
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const key = "iva_21;rec_02;ret_1500";
|
||||||
|
* const result = CustomerTaxes.fromKey(key, SpainTaxCatalogProvider());
|
||||||
|
* if (result.isOk()) {
|
||||||
|
* const customerTaxes = result.value;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
static fromKey(key: string, provider: TaxCatalogProvider): Result<CustomerTaxes, Error> {
|
||||||
|
// Validar que la clave no esté vacía
|
||||||
|
if (!key || typeof key !== "string") {
|
||||||
|
return Result.fail(new Error("La clave debe ser una cadena no vacía."));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dividir la clave por punto y coma para obtener los tres códigos
|
||||||
|
const codes = key.split(";");
|
||||||
|
|
||||||
|
// Validar que la clave tiene exactamente 3 partes (IVA, REC, Retención)
|
||||||
|
if (codes.length !== 3) {
|
||||||
|
return Result.fail(
|
||||||
|
new Error(
|
||||||
|
`Formato de clave inválido. Se esperaban 3 códigos separados por ";", se recibieron ${codes.length}.`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [ivaCode, recCode, retentionCode] = codes;
|
||||||
|
|
||||||
|
// Función auxiliar para resolver un código a un impuesto (Maybe<Tax>)
|
||||||
|
// Si el código es "#", retorna Maybe.none(), si no, busca en el catálogo
|
||||||
|
const resolveTaxFromCode = (code: string): Result<Maybe<Tax>> => {
|
||||||
|
const trimmedCode = code.trim();
|
||||||
|
|
||||||
|
// Si el código es "#", significa que no existe este tipo de impuesto
|
||||||
|
if (trimmedCode === "#") {
|
||||||
|
return Result.ok(Maybe.none<Tax>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si el código no es "#", buscamos en el catálogo usando Tax.createFromCode
|
||||||
|
const taxResult = Tax.createFromCode(trimmedCode, provider);
|
||||||
|
|
||||||
|
// Si hay un error creando el impuesto, propagamos el error
|
||||||
|
if (taxResult.isFailure) {
|
||||||
|
return Result.fail(taxResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si se creó exitosamente, lo envolvemos en Maybe.some()
|
||||||
|
return Result.ok(Maybe.some(taxResult.data));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Resolver el IVA desde su código
|
||||||
|
const ivaResult = resolveTaxFromCode(ivaCode);
|
||||||
|
if (ivaResult.isFailure) {
|
||||||
|
return Result.fail(
|
||||||
|
new Error(`Error al resolver IVA desde código "${ivaCode}": ${ivaResult.error.message}`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolver el REC desde su código
|
||||||
|
const recResult = resolveTaxFromCode(recCode);
|
||||||
|
if (recResult.isFailure) {
|
||||||
|
return Result.fail(
|
||||||
|
new Error(`Error al resolver REC desde código "${recCode}": ${recResult.error.message}`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolver la Retención desde su código
|
||||||
|
const retentionResult = resolveTaxFromCode(retentionCode);
|
||||||
|
if (retentionResult.isFailure) {
|
||||||
|
return Result.fail(
|
||||||
|
new Error(
|
||||||
|
`Error al resolver Retención desde código "${retentionCode}": ${retentionResult.error.message}`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crear la instancia de CustomerTaxes con los impuestos resueltos
|
||||||
|
return Result.ok(
|
||||||
|
new CustomerTaxes({
|
||||||
|
iva: ivaResult.data,
|
||||||
|
rec: recResult.data,
|
||||||
|
retention: retentionResult.data,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Genera una clave única que representa la combinación de impuestos.
|
||||||
|
* Extrae el código de cada impuesto o usa "#" si no existe.
|
||||||
|
* @returns {string} Clave en formato: "ivaCode;recCode;retentionCode"
|
||||||
|
*/
|
||||||
toKey(): string {
|
toKey(): string {
|
||||||
|
// Extrae el código del IVA, o "#" si no existe
|
||||||
const ivaCode = this.props.iva.match(
|
const ivaCode = this.props.iva.match(
|
||||||
(iva) => iva.code,
|
(iva) => iva.code,
|
||||||
() => "#"
|
() => "#"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Extrae el código de la retención de cliente (REC), o "#" si no existe
|
||||||
const recCode = this.props.rec.match(
|
const recCode = this.props.rec.match(
|
||||||
(rec) => rec.code,
|
(rec) => rec.code,
|
||||||
() => "#"
|
() => "#"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Extrae el código de la retención, o "#" si no existe
|
||||||
const retentionCode = this.props.retention.match(
|
const retentionCode = this.props.retention.match(
|
||||||
(retention) => retention.code,
|
(retention) => retention.code,
|
||||||
() => "#"
|
() => "#"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Retorna la clave combinada separada por punto y coma
|
||||||
return `${ivaCode};${recCode};${retentionCode}`;
|
return `${ivaCode};${recCode};${retentionCode}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import type { ICatalogs } from "@erp/core/api";
|
||||||
|
|
||||||
import { SequelizeCustomerDomainMapper, SequelizeCustomerSummaryMapper } from "../mappers";
|
import { SequelizeCustomerDomainMapper, SequelizeCustomerSummaryMapper } from "../mappers";
|
||||||
|
|
||||||
export interface ICustomerPersistenceMappers {
|
export interface ICustomerPersistenceMappers {
|
||||||
@ -7,9 +9,13 @@ export interface ICustomerPersistenceMappers {
|
|||||||
//createMapper: CreateCustomerInputMapper;
|
//createMapper: CreateCustomerInputMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const buildCustomerPersistenceMappers = (): ICustomerPersistenceMappers => {
|
export const buildCustomerPersistenceMappers = (
|
||||||
|
catalogs: ICatalogs
|
||||||
|
): ICustomerPersistenceMappers => {
|
||||||
|
const { taxCatalog } = catalogs;
|
||||||
|
|
||||||
// Mappers para el repositorio
|
// Mappers para el repositorio
|
||||||
const domainMapper = new SequelizeCustomerDomainMapper();
|
const domainMapper = new SequelizeCustomerDomainMapper({ taxCatalog });
|
||||||
const summaryMapper = new SequelizeCustomerSummaryMapper();
|
const summaryMapper = new SequelizeCustomerSummaryMapper();
|
||||||
|
|
||||||
// Mappers el DTO a las props validadas (CustomerProps) y luego construir agregado
|
// Mappers el DTO a las props validadas (CustomerProps) y luego construir agregado
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { SetupParams } from "@erp/core/api";
|
import { type SetupParams, buildCatalogs } from "@erp/core/api";
|
||||||
import type { TINNumber, UniqueID } from "@repo/rdx-ddd";
|
import type { TINNumber, UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import type { Transaction } from "sequelize";
|
import type { Transaction } from "sequelize";
|
||||||
@ -34,9 +34,10 @@ export function buildCustomerServices(
|
|||||||
deps: CustomersInternalDeps
|
deps: CustomersInternalDeps
|
||||||
): CustomerPublicServices {
|
): CustomerPublicServices {
|
||||||
const { database } = params;
|
const { database } = params;
|
||||||
|
const catalogs = buildCatalogs();
|
||||||
|
|
||||||
// Infrastructure
|
// Infrastructure
|
||||||
const persistenceMappers = buildCustomerPersistenceMappers();
|
const persistenceMappers = buildCustomerPersistenceMappers(catalogs);
|
||||||
const repository = buildCustomerRepository({ database, mappers: persistenceMappers });
|
const repository = buildCustomerRepository({ database, mappers: persistenceMappers });
|
||||||
|
|
||||||
const finder = buildCustomerFinder({ repository });
|
const finder = buildCustomerFinder({ repository });
|
||||||
|
|||||||
@ -42,7 +42,7 @@ export function buildCustomersDependencies(params: ModuleParams): CustomersInter
|
|||||||
// Infrastructure
|
// Infrastructure
|
||||||
const transactionManager = buildTransactionManager(database);
|
const transactionManager = buildTransactionManager(database);
|
||||||
const catalogs = buildCatalogs();
|
const catalogs = buildCatalogs();
|
||||||
const persistenceMappers = buildCustomerPersistenceMappers();
|
const persistenceMappers = buildCustomerPersistenceMappers(catalogs);
|
||||||
|
|
||||||
const repository = buildCustomerRepository({ database, mappers: persistenceMappers });
|
const repository = buildCustomerRepository({ database, mappers: persistenceMappers });
|
||||||
//const numberService = buildCustomerNumberGenerator();
|
//const numberService = buildCustomerNumberGenerator();
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import type { TaxCatalogProvider } from "@erp/core";
|
||||||
import { type MapperParamsType, SequelizeDomainMapper } from "@erp/core/api";
|
import { type MapperParamsType, SequelizeDomainMapper } from "@erp/core/api";
|
||||||
import {
|
import {
|
||||||
City,
|
City,
|
||||||
@ -12,7 +13,6 @@ import {
|
|||||||
Province,
|
Province,
|
||||||
Street,
|
Street,
|
||||||
TINNumber,
|
TINNumber,
|
||||||
type TaxCode,
|
|
||||||
TextValue,
|
TextValue,
|
||||||
URLAddress,
|
URLAddress,
|
||||||
UniqueID,
|
UniqueID,
|
||||||
@ -22,9 +22,14 @@ import {
|
|||||||
maybeFromNullableResult,
|
maybeFromNullableResult,
|
||||||
maybeToNullable,
|
maybeToNullable,
|
||||||
} from "@repo/rdx-ddd";
|
} from "@repo/rdx-ddd";
|
||||||
import { Collection, Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import { Customer, CustomerStatus, type ICustomerCreateProps } from "../../../domain";
|
import {
|
||||||
|
Customer,
|
||||||
|
CustomerStatus,
|
||||||
|
CustomerTaxes,
|
||||||
|
type ICustomerCreateProps,
|
||||||
|
} from "../../../domain";
|
||||||
import type { CustomerCreationAttributes, CustomerModel } from "../../sequelize";
|
import type { CustomerCreationAttributes, CustomerModel } from "../../sequelize";
|
||||||
|
|
||||||
export class SequelizeCustomerDomainMapper extends SequelizeDomainMapper<
|
export class SequelizeCustomerDomainMapper extends SequelizeDomainMapper<
|
||||||
@ -32,6 +37,13 @@ export class SequelizeCustomerDomainMapper extends SequelizeDomainMapper<
|
|||||||
CustomerCreationAttributes,
|
CustomerCreationAttributes,
|
||||||
Customer
|
Customer
|
||||||
> {
|
> {
|
||||||
|
private readonly taxCatalog: TaxCatalogProvider;
|
||||||
|
|
||||||
|
constructor(params: { taxCatalog: TaxCatalogProvider }) {
|
||||||
|
super();
|
||||||
|
this.taxCatalog = params.taxCatalog;
|
||||||
|
}
|
||||||
|
|
||||||
public mapToDomain(source: CustomerModel, params?: MapperParamsType): Result<Customer, Error> {
|
public mapToDomain(source: CustomerModel, params?: MapperParamsType): Result<Customer, Error> {
|
||||||
try {
|
try {
|
||||||
const errors: ValidationErrorDetail[] = [];
|
const errors: ValidationErrorDetail[] = [];
|
||||||
@ -167,16 +179,11 @@ export class SequelizeCustomerDomainMapper extends SequelizeDomainMapper<
|
|||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
|
|
||||||
// source.default_taxes is stored as a comma-separated string
|
const defaultTaxes = extractOrPushError(
|
||||||
const defaultTaxes = new Collection<TaxCode>();
|
CustomerTaxes.fromKey(source.default_taxes, this.taxCatalog),
|
||||||
/*if (!isNullishOrEmpty(source.default_taxes)) {
|
"default_taxes",
|
||||||
source.default_taxes!.split(",").map((taxCode, index) => {
|
errors
|
||||||
const tax = extractOrPushError(TaxCode.create(taxCode), `default_taxes.${index}`, errors);
|
);
|
||||||
if (tax) {
|
|
||||||
defaultTaxes.add(tax!);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// Now, create the PostalAddress VO
|
// Now, create the PostalAddress VO
|
||||||
const postalAddressProps = {
|
const postalAddressProps = {
|
||||||
@ -256,7 +263,7 @@ export class SequelizeCustomerDomainMapper extends SequelizeDomainMapper<
|
|||||||
website: maybeToNullable(source.website, (website) => website.toPrimitive()),
|
website: maybeToNullable(source.website, (website) => website.toPrimitive()),
|
||||||
|
|
||||||
legal_record: maybeToNullable(source.legalRecord, (legalRecord) => legalRecord.toPrimitive()),
|
legal_record: maybeToNullable(source.legalRecord, (legalRecord) => legalRecord.toPrimitive()),
|
||||||
default_taxes: source.defaultTaxes.map((taxItem) => taxItem.toPrimitive()).join(", "),
|
default_taxes: source.defaultTaxes.toKey(),
|
||||||
|
|
||||||
status: source.isActive ? "active" : "inactive",
|
status: source.isActive ? "active" : "inactive",
|
||||||
language_code: source.languageCode.toPrimitive(),
|
language_code: source.languageCode.toPrimitive(),
|
||||||
|
|||||||
@ -51,7 +51,7 @@ export class CustomerModel extends Model<
|
|||||||
|
|
||||||
declare legal_record: CreationOptional<string | null>;
|
declare legal_record: CreationOptional<string | null>;
|
||||||
|
|
||||||
declare default_taxes: CreationOptional<string | null>;
|
declare default_taxes: string;
|
||||||
declare status: string;
|
declare status: string;
|
||||||
declare language_code: CreationOptional<string>;
|
declare language_code: CreationOptional<string>;
|
||||||
declare currency_code: CreationOptional<string>;
|
declare currency_code: CreationOptional<string>;
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import type { JsonTaxCatalogProvider } from "@erp/core";
|
|||||||
import { DiscountPercentage, Tax } from "@erp/core/api";
|
import { DiscountPercentage, Tax } from "@erp/core/api";
|
||||||
import {
|
import {
|
||||||
type IProformaItemCreateProps,
|
type IProformaItemCreateProps,
|
||||||
InvoicePaymentMethod,
|
|
||||||
InvoiceSerie,
|
InvoiceSerie,
|
||||||
ItemAmount,
|
ItemAmount,
|
||||||
ItemDescription,
|
ItemDescription,
|
||||||
@ -45,6 +44,10 @@ export interface IProformaFromFactuGESProps {
|
|||||||
tin: TINNumber;
|
tin: TINNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
paymentLookup: {
|
||||||
|
factuges_id: string;
|
||||||
|
};
|
||||||
|
|
||||||
customerDraft: {
|
customerDraft: {
|
||||||
//reference: Maybe<Name>;
|
//reference: Maybe<Name>;
|
||||||
|
|
||||||
@ -88,11 +91,14 @@ export interface IProformaFromFactuGESProps {
|
|||||||
languageCode: LanguageCode;
|
languageCode: LanguageCode;
|
||||||
currencyCode: CurrencyCode;
|
currencyCode: CurrencyCode;
|
||||||
|
|
||||||
paymentMethod: Maybe<InvoicePaymentMethod>;
|
|
||||||
|
|
||||||
items: IProformaItemCreateProps[];
|
items: IProformaItemCreateProps[];
|
||||||
globalDiscountPercentage: DiscountPercentage;
|
globalDiscountPercentage: DiscountPercentage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
paymentDraft: {
|
||||||
|
factuges_id: string;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICreateProformaFromFactugesInputMapper {
|
export interface ICreateProformaFromFactugesInputMapper {
|
||||||
@ -132,14 +138,24 @@ export class CreateProformaFromFactugesInputMapper
|
|||||||
errors,
|
errors,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const paymentProps = this.mapPaymentProps(dto, {
|
||||||
|
companyId,
|
||||||
|
currencyCode,
|
||||||
|
errors,
|
||||||
|
});
|
||||||
|
|
||||||
this.throwIfValidationErrors(errors);
|
this.throwIfValidationErrors(errors);
|
||||||
|
|
||||||
return Result.ok({
|
return Result.ok({
|
||||||
customerLookup: {
|
customerLookup: {
|
||||||
tin: customerProps.tin,
|
tin: customerProps.tin,
|
||||||
},
|
},
|
||||||
|
paymentLookup: {
|
||||||
|
factuges_id: paymentProps.factuges_id,
|
||||||
|
},
|
||||||
customerDraft: customerProps,
|
customerDraft: customerProps,
|
||||||
proformaDraft: proformaProps,
|
proformaDraft: proformaProps,
|
||||||
|
paymentDraft: paymentProps,
|
||||||
});
|
});
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
const error = isValidationErrorCollection(err)
|
const error = isValidationErrorCollection(err)
|
||||||
@ -149,7 +165,24 @@ export class CreateProformaFromFactugesInputMapper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public mapProformaProps(
|
private mapPaymentProps(
|
||||||
|
dto: CreateProformaFromFactugesRequestDTO,
|
||||||
|
params: {
|
||||||
|
companyId: UniqueID;
|
||||||
|
currencyCode: CurrencyCode;
|
||||||
|
errors: ValidationErrorDetail[];
|
||||||
|
}
|
||||||
|
): IProformaFromFactuGESProps["paymentDraft"] {
|
||||||
|
const errors: ValidationErrorDetail[] = [];
|
||||||
|
const { companyId } = params;
|
||||||
|
|
||||||
|
return {
|
||||||
|
factuges_id: String(dto.payment_method_id),
|
||||||
|
description: String(dto.payment_method_description),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapProformaProps(
|
||||||
dto: CreateProformaFromFactugesRequestDTO,
|
dto: CreateProformaFromFactugesRequestDTO,
|
||||||
params: {
|
params: {
|
||||||
companyId: UniqueID;
|
companyId: UniqueID;
|
||||||
@ -208,14 +241,6 @@ export class CreateProformaFromFactugesInputMapper
|
|||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
|
|
||||||
const paymentMethod = extractOrPushError(
|
|
||||||
maybeFromNullableResult(dto.payment_method, (value) =>
|
|
||||||
InvoicePaymentMethod.create({ paymentDescription: value })
|
|
||||||
),
|
|
||||||
"payment_method",
|
|
||||||
errors
|
|
||||||
);
|
|
||||||
|
|
||||||
const globalDiscountPercentage = extractOrPushError(
|
const globalDiscountPercentage = extractOrPushError(
|
||||||
DiscountPercentage.create({ value: Number(dto.global_discount_percentage_value) }),
|
DiscountPercentage.create({ value: Number(dto.global_discount_percentage_value) }),
|
||||||
"global_discount_percentage_value",
|
"global_discount_percentage_value",
|
||||||
@ -257,7 +282,6 @@ export class CreateProformaFromFactugesInputMapper
|
|||||||
languageCode: languageCode!,
|
languageCode: languageCode!,
|
||||||
currencyCode: currencyCode!,
|
currencyCode: currencyCode!,
|
||||||
|
|
||||||
paymentMethod: paymentMethod!,
|
|
||||||
globalDiscountPercentage: globalDiscountPercentage!,
|
globalDiscountPercentage: globalDiscountPercentage!,
|
||||||
|
|
||||||
items: itemsProps, // ← IProformaItemProps[]
|
items: itemsProps, // ← IProformaItemProps[]
|
||||||
@ -443,10 +467,10 @@ export class CreateProformaFromFactugesInputMapper
|
|||||||
);
|
);
|
||||||
|
|
||||||
const discountPercentage = extractOrPushError(
|
const discountPercentage = extractOrPushError(
|
||||||
maybeFromNullableResult(item.discount_percentage_value, (value) =>
|
maybeFromNullableResult(item.item_discount_percentage_value, (value) =>
|
||||||
DiscountPercentage.create({ value: Number(value) })
|
DiscountPercentage.create({ value: Number(value) })
|
||||||
),
|
),
|
||||||
`items[${index}].discount_percentage_value`,
|
`items[${index}].item_discount_percentage_value`,
|
||||||
params.errors
|
params.errors
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
import type { JsonTaxCatalogProvider } from "@erp/core";
|
import type { JsonTaxCatalogProvider } from "@erp/core";
|
||||||
import { type ITransactionManager, Tax, isEntityNotFoundError } from "@erp/core/api";
|
import { type ITransactionManager, Tax, isEntityNotFoundError } from "@erp/core/api";
|
||||||
import type { ProformaPublicServices } from "@erp/customer-invoices/api";
|
import type { ProformaPublicServices } from "@erp/customer-invoices/api";
|
||||||
import { type InvoiceRecipient, InvoiceStatus } from "@erp/customer-invoices/api/domain";
|
import {
|
||||||
|
InvoicePaymentMethod,
|
||||||
|
type InvoiceRecipient,
|
||||||
|
InvoiceStatus,
|
||||||
|
} from "@erp/customer-invoices/api/domain";
|
||||||
import type { CustomerPublicServices } from "@erp/customers/api";
|
import type { CustomerPublicServices } from "@erp/customers/api";
|
||||||
import {
|
import {
|
||||||
type Customer,
|
type Customer,
|
||||||
@ -11,7 +15,6 @@ import {
|
|||||||
} from "@erp/customers/api/domain";
|
} from "@erp/customers/api/domain";
|
||||||
import { type Name, type PhoneNumber, type TextValue, UniqueID } from "@repo/rdx-ddd";
|
import { type Name, type PhoneNumber, type TextValue, UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
import { Maybe, Result } from "@repo/rdx-utils";
|
||||||
import type { IProformaCreatorParams } from "node_modules/@erp/customer-invoices/src/api/application";
|
|
||||||
import type { Transaction } from "sequelize";
|
import type { Transaction } from "sequelize";
|
||||||
|
|
||||||
import type { CreateProformaFromFactugesRequestDTO } from "../../../common";
|
import type { CreateProformaFromFactugesRequestDTO } from "../../../common";
|
||||||
@ -20,6 +23,14 @@ import type {
|
|||||||
IProformaFromFactuGESProps,
|
IProformaFromFactuGESProps,
|
||||||
} from "../mappers";
|
} from "../mappers";
|
||||||
|
|
||||||
|
import paymentsCatalog from "./payments.json";
|
||||||
|
|
||||||
|
type FakePaymentMethod = {
|
||||||
|
id: UniqueID;
|
||||||
|
description: string;
|
||||||
|
factuges_id: string;
|
||||||
|
};
|
||||||
|
|
||||||
type CreateProformaFromFactugesUseCaseInput = {
|
type CreateProformaFromFactugesUseCaseInput = {
|
||||||
companyId: UniqueID;
|
companyId: UniqueID;
|
||||||
dto: CreateProformaFromFactugesRequestDTO;
|
dto: CreateProformaFromFactugesRequestDTO;
|
||||||
@ -33,6 +44,8 @@ type CreateProformaFromFactugesUseCaseDeps = {
|
|||||||
transactionManager: ITransactionManager;
|
transactionManager: ITransactionManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type CreateProformaProps = Parameters<ProformaPublicServices["createProforma"]>["1"];
|
||||||
|
|
||||||
export class CreateProformaFromFactugesUseCase {
|
export class CreateProformaFromFactugesUseCase {
|
||||||
private readonly dtoMapper: ICreateProformaFromFactugesInputMapper;
|
private readonly dtoMapper: ICreateProformaFromFactugesInputMapper;
|
||||||
private readonly customerServices: CustomerPublicServices;
|
private readonly customerServices: CustomerPublicServices;
|
||||||
@ -57,7 +70,8 @@ export class CreateProformaFromFactugesUseCase {
|
|||||||
return Result.fail(mappedPropsResult.error);
|
return Result.fail(mappedPropsResult.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { customerLookup, customerDraft, proformaDraft } = mappedPropsResult.data;
|
const { customerLookup, paymentLookup, customerDraft, proformaDraft, paymentDraft } =
|
||||||
|
mappedPropsResult.data;
|
||||||
|
|
||||||
return this.transactionManager.complete(async (transaction: Transaction) => {
|
return this.transactionManager.complete(async (transaction: Transaction) => {
|
||||||
try {
|
try {
|
||||||
@ -71,17 +85,35 @@ export class CreateProformaFromFactugesUseCase {
|
|||||||
|
|
||||||
const customer = customerResult.data;
|
const customer = customerResult.data;
|
||||||
|
|
||||||
// Crear la proforma para ese cliente
|
const paymentResult = await this.resolvePayment(paymentLookup, paymentDraft, {
|
||||||
const createPropsResult = this.buildProformaCreateProps(proformaDraft, customer.id, {
|
|
||||||
companyId,
|
companyId,
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
if (customerResult.isFailure) {
|
||||||
|
return Result.fail(customerResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const payment = paymentResult.data;
|
||||||
|
|
||||||
|
// Crear la proforma para ese cliente
|
||||||
|
const createPropsResult = this.buildProformaCreateProps({
|
||||||
|
proformaDraft,
|
||||||
|
payment,
|
||||||
|
customerId: customer.id,
|
||||||
|
context: {
|
||||||
|
companyId,
|
||||||
|
transaction,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
if (createPropsResult.isFailure) {
|
if (createPropsResult.isFailure) {
|
||||||
return Result.fail(createPropsResult.error);
|
return Result.fail(createPropsResult.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const newId = UniqueID.generateNewID();
|
||||||
|
|
||||||
const createResult = await this.proformaServices.createProforma(
|
const createResult = await this.proformaServices.createProforma(
|
||||||
UniqueID.generateNewID(),
|
newId,
|
||||||
createPropsResult.data,
|
createPropsResult.data,
|
||||||
{
|
{
|
||||||
companyId,
|
companyId,
|
||||||
@ -93,38 +125,56 @@ export class CreateProformaFromFactugesUseCase {
|
|||||||
return Result.fail(createResult.error);
|
return Result.fail(createResult.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const proforma = createResult.data;
|
const readResult = await this.proformaServices.getProformaSnapshotById(
|
||||||
|
createResult.data.id,
|
||||||
|
{
|
||||||
|
companyId,
|
||||||
|
transaction,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const snapshot = {
|
if (readResult.isFailure) {
|
||||||
|
return Result.fail(readResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const snapshot = readResult.data;
|
||||||
|
|
||||||
|
const result = {
|
||||||
customer_id: customer.id.toString(),
|
customer_id: customer.id.toString(),
|
||||||
proforma_id: proforma.id.toString(),
|
proforma_id: snapshot.id.toString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return Result.ok(snapshot);
|
return Result.ok(result);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
return Result.fail(error as Error);
|
return Result.fail(error as Error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildProformaCreateProps(
|
private buildProformaCreateProps(deps: {
|
||||||
proformaDraft: IProformaFromFactuGESProps["proformaDraft"],
|
proformaDraft: IProformaFromFactuGESProps["proformaDraft"];
|
||||||
customerId: UniqueID,
|
customerId: UniqueID;
|
||||||
|
payment: FakePaymentMethod;
|
||||||
context: {
|
context: {
|
||||||
companyId: UniqueID;
|
companyId: UniqueID;
|
||||||
transaction: Transaction;
|
transaction: Transaction;
|
||||||
}
|
};
|
||||||
): Result<IProformaCreatorParams["props"], Error> {
|
}): Result<CreateProformaProps, Error> {
|
||||||
|
const { proformaDraft, payment, customerId, context } = deps;
|
||||||
const { companyId } = context;
|
const { companyId } = context;
|
||||||
|
|
||||||
const defaultStatus = InvoiceStatus.fromApproved();
|
const defaultStatus = InvoiceStatus.fromApproved();
|
||||||
const recipient = Maybe.none<InvoiceRecipient>();
|
const recipient = Maybe.none<InvoiceRecipient>();
|
||||||
|
const paymentMethod = Maybe.some(
|
||||||
|
InvoicePaymentMethod.create({ paymentDescription: payment.description }, payment.id).data
|
||||||
|
);
|
||||||
|
|
||||||
return Result.ok({
|
return Result.ok({
|
||||||
...proformaDraft,
|
...proformaDraft,
|
||||||
companyId,
|
companyId,
|
||||||
customerId,
|
customerId,
|
||||||
status: defaultStatus,
|
status: defaultStatus,
|
||||||
|
paymentMethod,
|
||||||
recipient,
|
recipient,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -176,6 +226,33 @@ export class CreateProformaFromFactugesUseCase {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async resolvePayment(
|
||||||
|
paymentLookup: IProformaFromFactuGESProps["paymentLookup"],
|
||||||
|
paymentDraft: IProformaFromFactuGESProps["paymentDraft"],
|
||||||
|
context: {
|
||||||
|
companyId: UniqueID;
|
||||||
|
transaction: Transaction;
|
||||||
|
}
|
||||||
|
): Promise<Result<FakePaymentMethod, Error>> {
|
||||||
|
const { companyId, transaction } = context;
|
||||||
|
|
||||||
|
const existingPaymentResult = paymentsCatalog.find(
|
||||||
|
(payment) =>
|
||||||
|
payment.factuges_id === paymentLookup.factuges_id &&
|
||||||
|
payment.company_id === companyId.toString()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingPaymentResult) {
|
||||||
|
return Result.ok({
|
||||||
|
id: UniqueID.create(existingPaymentResult.id).data,
|
||||||
|
description: existingPaymentResult.description,
|
||||||
|
factuges_id: existingPaymentResult.factuges_id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.fail(new Error("Forma de pago no existe!!!"));
|
||||||
|
}
|
||||||
|
|
||||||
private buildCustomerCreateProps(
|
private buildCustomerCreateProps(
|
||||||
customerDraft: IProformaFromFactuGESProps["customerDraft"],
|
customerDraft: IProformaFromFactuGESProps["customerDraft"],
|
||||||
context: {
|
context: {
|
||||||
|
|||||||
20
modules/factuges/src/api/application/use-cases/payments.json
Normal file
20
modules/factuges/src/api/application/use-cases/payments.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "019c2834-a766-7787-a626-fa89cac3a8a1",
|
||||||
|
"company_id": "5e4dc5b3-96b9-4968-9490-14bd032fec5f",
|
||||||
|
"factuges_id": "6",
|
||||||
|
"description": "TRANSFERENCIA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "57ed228f-88bd-431d-b5e6-0ed9cff01684",
|
||||||
|
"company_id": "5e4dc5b3-96b9-4968-9490-14bd032fec5f",
|
||||||
|
"factuges_id": "14",
|
||||||
|
"description": "DOMICILIACION BANCARIA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "336e477f-9260-4cb7-b6fd-76f3b088a395",
|
||||||
|
"company_id": "5e4dc5b3-96b9-4968-9490-14bd032fec5f",
|
||||||
|
"factuges_id": "15",
|
||||||
|
"description": "TRANSFERENCIA BANCARIA"
|
||||||
|
}
|
||||||
|
]
|
||||||
@ -43,7 +43,6 @@ export const factugesRouter = (
|
|||||||
router.post(
|
router.post(
|
||||||
"/",
|
"/",
|
||||||
//checkTabContext,
|
//checkTabContext,
|
||||||
|
|
||||||
validateRequest(CreateProformaFromFactugesRequestSchema, "body"),
|
validateRequest(CreateProformaFromFactugesRequestSchema, "body"),
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
const useCase = deps.useCases.createProforma(publicServices);
|
const useCase = deps.useCases.createProforma(publicServices);
|
||||||
|
|||||||
@ -7,16 +7,31 @@ export const CreateProformaItemFromFactugesRequestSchema = z.object({
|
|||||||
quantity_value: NumericStringSchema.default(""), // Ya viene escalado
|
quantity_value: NumericStringSchema.default(""), // Ya viene escalado
|
||||||
unit_value: NumericStringSchema.default(""),
|
unit_value: NumericStringSchema.default(""),
|
||||||
|
|
||||||
discount_percentage_value: NumericStringSchema.default(""),
|
subtotal_amuount_value: NumericStringSchema.default(""),
|
||||||
|
item_discount_percentage_value: NumericStringSchema.default(""),
|
||||||
|
item_discount_amount_value: NumericStringSchema.default(""),
|
||||||
|
|
||||||
|
global_discount_percentage_value: NumericStringSchema.default(""),
|
||||||
|
global_discount_amount_value: NumericStringSchema.default(""),
|
||||||
|
|
||||||
|
total_discount_amount_value: NumericStringSchema.default(""),
|
||||||
|
taxable_amount_value: NumericStringSchema.default(""),
|
||||||
|
|
||||||
|
total_value: NumericStringSchema.default(""),
|
||||||
|
|
||||||
iva_code: z.string().default(""),
|
iva_code: z.string().default(""),
|
||||||
iva_percentage_value: NumericStringSchema.default(""),
|
iva_percentage_value: NumericStringSchema.default(""),
|
||||||
|
iva_amount_value: NumericStringSchema.default(""),
|
||||||
|
|
||||||
rec_code: z.string().default(""),
|
rec_code: z.string().default(""),
|
||||||
rec_percentage_value: NumericStringSchema.default(""),
|
rec_percentage_value: NumericStringSchema.default(""),
|
||||||
|
rec_amount_value: NumericStringSchema.default(""),
|
||||||
|
|
||||||
retention_code: z.string().default(""),
|
retention_code: z.string().default(""),
|
||||||
retention_percentage_value: NumericStringSchema.default(""),
|
retention_percentage_value: NumericStringSchema.default(""),
|
||||||
|
retention_amount_value: NumericStringSchema.default(""),
|
||||||
|
|
||||||
|
taxes_amount_value: NumericStringSchema.default(""),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type CreateProformaItemFromFactugesRequestDTO = z.infer<
|
export type CreateProformaItemFromFactugesRequestDTO = z.infer<
|
||||||
@ -24,23 +39,23 @@ export type CreateProformaItemFromFactugesRequestDTO = z.infer<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
export const CreateProformaFromFactugesRequestSchema = z.object({
|
export const CreateProformaFromFactugesRequestSchema = z.object({
|
||||||
//factuges_id: z.string(),
|
|
||||||
|
|
||||||
//id: z.uuid(),
|
//id: z.uuid(),
|
||||||
|
factuges_id: z.string(),
|
||||||
|
//company_id: z.uuid(),
|
||||||
|
//is_proforma: z.string().default("1"),
|
||||||
|
|
||||||
|
//status: z.string(),
|
||||||
series: z.string(),
|
series: z.string(),
|
||||||
//invoice_number: z.string(),
|
|
||||||
|
|
||||||
reference: z.string().default(""),
|
reference: z.string().default(""),
|
||||||
|
description: z.string().default(""),
|
||||||
|
|
||||||
invoice_date: z.string(),
|
invoice_date: z.string(),
|
||||||
operation_date: z.string().default(""),
|
operation_date: z.string().default(""),
|
||||||
|
|
||||||
description: z.string().default(""),
|
|
||||||
notes: z.string().default(""),
|
notes: z.string().default(""),
|
||||||
|
language_code: z.string().default("es"),
|
||||||
|
|
||||||
customer: z.object({
|
customer: z.object({
|
||||||
//factuges_id: z.string(),
|
|
||||||
is_company: z.string(),
|
is_company: z.string(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
tin: z.string(),
|
tin: z.string(),
|
||||||
@ -51,7 +66,7 @@ export const CreateProformaFromFactugesRequestSchema = z.object({
|
|||||||
postal_code: z.string(),
|
postal_code: z.string(),
|
||||||
country: z.string(),
|
country: z.string(),
|
||||||
|
|
||||||
language_code: z.string(),
|
language_code: z.string().default("es"),
|
||||||
|
|
||||||
phone_primary: z.string(),
|
phone_primary: z.string(),
|
||||||
phone_secondary: z.string(),
|
phone_secondary: z.string(),
|
||||||
@ -63,9 +78,16 @@ export const CreateProformaFromFactugesRequestSchema = z.object({
|
|||||||
website: z.string(),
|
website: z.string(),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
subtotal_amount_value: NumericStringSchema,
|
||||||
global_discount_percentage_value: NumericStringSchema,
|
global_discount_percentage_value: NumericStringSchema,
|
||||||
|
|
||||||
payment_method: z.string().default(""),
|
discount_amount_value: NumericStringSchema,
|
||||||
|
taxable_amount_value: NumericStringSchema,
|
||||||
|
taxes_amount_value: NumericStringSchema,
|
||||||
|
total_amount_value: NumericStringSchema,
|
||||||
|
|
||||||
|
payment_method_id: z.string(),
|
||||||
|
payment_method_description: z.string(),
|
||||||
|
|
||||||
items: z.array(CreateProformaItemFromFactugesRequestSchema),
|
items: z.array(CreateProformaItemFromFactugesRequestSchema),
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user