Clientes y facturas de cliente
This commit is contained in:
parent
26442edd60
commit
e93d48b930
@ -26,7 +26,8 @@
|
|||||||
"noForEach": "off",
|
"noForEach": "off",
|
||||||
"noBannedTypes": "info",
|
"noBannedTypes": "info",
|
||||||
"noUselessFragments": "off",
|
"noUselessFragments": "off",
|
||||||
"useOptionalChain": "off"
|
"useOptionalChain": "off",
|
||||||
|
"noThisInStatic": "off"
|
||||||
},
|
},
|
||||||
"suspicious": {
|
"suspicious": {
|
||||||
"noImplicitAnyLet": "info",
|
"noImplicitAnyLet": "info",
|
||||||
|
|||||||
@ -141,11 +141,6 @@ export class Tax extends ValueObject<TaxProps> {
|
|||||||
return `${this.toNumber().toFixed(this.scale)}%`;
|
return `${this.toNumber().toFixed(this.scale)}%`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Calcula el importe del impuesto sobre una base imponible */
|
|
||||||
calculateAmount(baseAmount: number): number {
|
|
||||||
return (baseAmount * this.toNumber()) / 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
isZero(): boolean {
|
isZero(): boolean {
|
||||||
return this.toNumber() === 0;
|
return this.toNumber() === 0;
|
||||||
}
|
}
|
||||||
@ -159,6 +154,7 @@ export class Tax extends ValueObject<TaxProps> {
|
|||||||
greaterThan(other: Tax): boolean {
|
greaterThan(other: Tax): boolean {
|
||||||
return this.toNumber() > other.toNumber();
|
return this.toNumber() > other.toNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
lessThan(other: Tax): boolean {
|
lessThan(other: Tax): boolean {
|
||||||
return this.toNumber() < other.toNumber();
|
return this.toNumber() < other.toNumber();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,8 @@
|
|||||||
import { Collection } from "@repo/rdx-utils";
|
import { Collection } from "@repo/rdx-utils";
|
||||||
import { Tax } from "./tax";
|
import { Tax } from "./tax";
|
||||||
|
|
||||||
export interface TaxesProps {
|
|
||||||
items?: Tax[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Taxes extends Collection<Tax> {
|
export class Taxes extends Collection<Tax> {
|
||||||
constructor(props: TaxesProps) {
|
public static create<T extends Taxes>(this: new (items: Tax[]) => T, items: Tax[]): T {
|
||||||
const { items } = props;
|
return new this(items);
|
||||||
super(items);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static create(props: TaxesProps): Taxes {
|
|
||||||
return new Taxes(props);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,45 +44,4 @@ export abstract class SequelizeDomainMapper<TModel extends Model, TModelAttribut
|
|||||||
|
|
||||||
return Result.ok(results.objects);
|
return Result.ok(results.objects);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*protected _safeMap<T>(operation: () => T, key: string): Result<T, Error> {
|
|
||||||
try {
|
|
||||||
return Result.ok(operation());
|
|
||||||
} catch (error: unknown) {
|
|
||||||
return Result.fail(error as Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected _mapsValue(
|
|
||||||
row: TModel,
|
|
||||||
key: string,
|
|
||||||
customMapFn: (value: any, params: MapperParamsType) => Result<any, Error>,
|
|
||||||
params: MapperParamsType = { defaultValue: null }
|
|
||||||
): Result<any, Error> {
|
|
||||||
return customMapFn(row?.dataValues[key] ?? params.defaultValue, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected _mapsAssociation(
|
|
||||||
row: TModel,
|
|
||||||
associationName: string,
|
|
||||||
customMapper: DomainMapperWithBulk<any, any>,
|
|
||||||
params: MapperParamsType = {}
|
|
||||||
): Result<any, Error> {
|
|
||||||
if (!customMapper) {
|
|
||||||
Result.fail(Error(`Custom mapper undefined for ${associationName}`));
|
|
||||||
}
|
|
||||||
|
|
||||||
const { filter, ...otherParams } = params;
|
|
||||||
let associationRows = row?.dataValues[associationName] ?? [];
|
|
||||||
|
|
||||||
if (filter) {
|
|
||||||
associationRows = Array.isArray(associationRows)
|
|
||||||
? associationRows.filter(filter)
|
|
||||||
: filter(associationRows);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Array.isArray(associationRows)
|
|
||||||
? customMapper.mapToDomainCollection(associationRows, associationRows.length, otherParams)
|
|
||||||
: customMapper.mapToDomain(associationRows, otherParams);
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -149,7 +149,7 @@ export class CreateCustomerInvoicePropsMapper {
|
|||||||
|
|
||||||
discountPercentage: discountPercentage!,
|
discountPercentage: discountPercentage!,
|
||||||
|
|
||||||
taxes: Taxes.create({ items: [] }),
|
taxes: Taxes.create([]),
|
||||||
items: items,
|
items: items,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -219,7 +219,7 @@ export class CreateCustomerInvoicePropsMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private mapTaxes(item: CreateCustomerInvoiceItemRequestDTO, itemIndex: number) {
|
private mapTaxes(item: CreateCustomerInvoiceItemRequestDTO, itemIndex: number) {
|
||||||
const taxes = Taxes.create({ items: [] });
|
const taxes = Taxes.create([]);
|
||||||
|
|
||||||
item.taxes.split(",").every((tax_code, taxIndex) => {
|
item.taxes.split(",").every((tax_code, taxIndex) => {
|
||||||
const taxResult = Tax.createFromCode(tax_code, this.taxCatalog);
|
const taxResult = Tax.createFromCode(tax_code, this.taxCatalog);
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import {
|
|||||||
} from "@repo/rdx-ddd";
|
} from "@repo/rdx-ddd";
|
||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
import { Maybe, Result } from "@repo/rdx-utils";
|
||||||
import { CustomerInvoiceItems, InvoicePaymentMethod } from "../entities";
|
import { CustomerInvoiceItems, InvoicePaymentMethod } from "../entities";
|
||||||
import { InvoiceTaxes } from "../entities/invoice-taxes";
|
|
||||||
import {
|
import {
|
||||||
CustomerInvoiceNumber,
|
CustomerInvoiceNumber,
|
||||||
CustomerInvoiceSerie,
|
CustomerInvoiceSerie,
|
||||||
@ -23,9 +22,10 @@ export interface CustomerInvoiceProps {
|
|||||||
companyId: UniqueID;
|
companyId: UniqueID;
|
||||||
|
|
||||||
isProforma: boolean;
|
isProforma: boolean;
|
||||||
invoiceNumber: CustomerInvoiceNumber;
|
|
||||||
status: CustomerInvoiceStatus;
|
status: CustomerInvoiceStatus;
|
||||||
|
|
||||||
series: Maybe<CustomerInvoiceSerie>;
|
series: Maybe<CustomerInvoiceSerie>;
|
||||||
|
invoiceNumber: Maybe<CustomerInvoiceNumber>;
|
||||||
|
|
||||||
invoiceDate: UtcDate;
|
invoiceDate: UtcDate;
|
||||||
operationDate: Maybe<UtcDate>;
|
operationDate: Maybe<UtcDate>;
|
||||||
@ -33,6 +33,7 @@ export interface CustomerInvoiceProps {
|
|||||||
customerId: UniqueID;
|
customerId: UniqueID;
|
||||||
recipient: Maybe<InvoiceRecipient>;
|
recipient: Maybe<InvoiceRecipient>;
|
||||||
|
|
||||||
|
reference: Maybe<string>;
|
||||||
notes: Maybe<TextValue>;
|
notes: Maybe<TextValue>;
|
||||||
|
|
||||||
languageCode: LanguageCode;
|
languageCode: LanguageCode;
|
||||||
@ -44,9 +45,9 @@ export interface CustomerInvoiceProps {
|
|||||||
|
|
||||||
discountPercentage: Percentage;
|
discountPercentage: Percentage;
|
||||||
|
|
||||||
verifactu_qr: string;
|
/*verifactu_qr: string;
|
||||||
verifactu_url: string;
|
verifactu_url: string;
|
||||||
verifactu_status: string;
|
verifactu_status: string;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICustomerInvoice {
|
export interface ICustomerInvoice {
|
||||||
@ -139,6 +140,10 @@ export class CustomerInvoice
|
|||||||
return this.props.operationDate;
|
return this.props.operationDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get reference(): Maybe<string> {
|
||||||
|
return this.props.reference;
|
||||||
|
}
|
||||||
|
|
||||||
public get notes(): Maybe<TextValue> {
|
public get notes(): Maybe<TextValue> {
|
||||||
return this.props.notes;
|
return this.props.notes;
|
||||||
}
|
}
|
||||||
@ -168,7 +173,7 @@ export class CustomerInvoice
|
|||||||
return this._items;
|
return this._items;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get taxes(): InvoiceTaxes {
|
public get taxes() {
|
||||||
return this.items.getTaxesAmountByTaxes();
|
return this.items.getTaxesAmountByTaxes();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +197,12 @@ export class CustomerInvoice
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _getTaxesAmount(taxableAmount: InvoiceAmount): InvoiceAmount {
|
private _getTaxesAmount(taxableAmount: InvoiceAmount): InvoiceAmount {
|
||||||
return this._taxes.getTaxesAmount(taxableAmount);
|
let amount = InvoiceAmount.zero(this.currencyCode.code);
|
||||||
|
|
||||||
|
for (const tax of this.taxes) {
|
||||||
|
amount = amount.add(tax.taxesAmount);
|
||||||
|
}
|
||||||
|
return amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getTotalAmount(taxableAmount: InvoiceAmount, taxesAmount: InvoiceAmount): InvoiceAmount {
|
private _getTotalAmount(taxableAmount: InvoiceAmount, taxesAmount: InvoiceAmount): InvoiceAmount {
|
||||||
@ -249,7 +259,7 @@ export class CustomerInvoice
|
|||||||
...this.props,
|
...this.props,
|
||||||
status: CustomerInvoiceStatus.createEmitted(),
|
status: CustomerInvoiceStatus.createEmitted(),
|
||||||
isProforma: false,
|
isProforma: false,
|
||||||
invoiceNumber: newInvoiceNumber,
|
invoiceNumber: Maybe.some(newInvoiceNumber),
|
||||||
},
|
},
|
||||||
this.id
|
this.id
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import { Tax } from "@erp/core/api";
|
|||||||
import { CurrencyCode, LanguageCode } from "@repo/rdx-ddd";
|
import { CurrencyCode, LanguageCode } from "@repo/rdx-ddd";
|
||||||
import { Collection } from "@repo/rdx-utils";
|
import { Collection } from "@repo/rdx-utils";
|
||||||
import { ItemAmount } from "../../value-objects";
|
import { ItemAmount } from "../../value-objects";
|
||||||
import { InvoiceTax, InvoiceTaxes } from "../invoice-taxes";
|
|
||||||
import { CustomerInvoiceItem } from "./customer-invoice-item";
|
import { CustomerInvoiceItem } from "./customer-invoice-item";
|
||||||
|
|
||||||
export interface CustomerInvoiceItemsProps {
|
export interface CustomerInvoiceItemsProps {
|
||||||
@ -73,31 +72,33 @@ export class CustomerInvoiceItems extends Collection<CustomerInvoiceItem> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTaxesAmountByTaxes(): InvoiceTaxes {
|
public getTaxesAmountByTaxes() {
|
||||||
InvoiceTaxes.create({});
|
const resultMap = new Map<Tax, { taxableAmount: ItemAmount; taxesAmount: ItemAmount }>();
|
||||||
|
|
||||||
const taxesMap = new Map<Tax, ItemAmount>();
|
|
||||||
const currencyCode = this._currencyCode.code;
|
const currencyCode = this._currencyCode.code;
|
||||||
|
|
||||||
for (const item of this.getAll()) {
|
for (const item of this.getAll()) {
|
||||||
for (const { tax, taxesAmount } of item.getTaxesAmountByTaxes()) {
|
for (const { taxableAmount, tax, taxesAmount } of item.getTaxesAmountByTaxes()) {
|
||||||
const current = taxesMap.get(tax) ?? ItemAmount.zero(currencyCode);
|
const { taxableAmount: taxableCurrent, taxesAmount: taxesCurrent } = resultMap.get(tax) ?? {
|
||||||
taxesMap.set(tax, current.add(taxesAmount));
|
taxableAmount: ItemAmount.zero(currencyCode),
|
||||||
|
taxesAmount: ItemAmount.zero(currencyCode),
|
||||||
|
};
|
||||||
|
resultMap.set(tax, {
|
||||||
|
taxableAmount: taxableCurrent.add(taxableAmount),
|
||||||
|
taxesAmount: taxesCurrent.add(taxesAmount),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const items: InvoiceTax[] = [];
|
const items = [];
|
||||||
for (const [tax, taxesAmount] of taxesMap) {
|
for (const [tax, { taxableAmount, taxesAmount }] of resultMap) {
|
||||||
items.push(
|
items.push({
|
||||||
InvoiceTax.create({
|
taxableAmount,
|
||||||
tax,
|
tax,
|
||||||
taxesAmount,
|
taxesAmount,
|
||||||
}).data
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return InvoiceTaxes.create({
|
return items;
|
||||||
items: items,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,36 +0,0 @@
|
|||||||
import { Tax } from "@erp/core/api";
|
|
||||||
import { DomainEntity, UniqueID } from "@repo/rdx-ddd";
|
|
||||||
import { Result } from "@repo/rdx-utils";
|
|
||||||
import { ItemAmount } from "../../value-objects";
|
|
||||||
|
|
||||||
export interface ItemTaxProps {
|
|
||||||
tax: Tax;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ItemTax extends DomainEntity<ItemTaxProps> {
|
|
||||||
static create(props: ItemTaxProps, id?: UniqueID): Result<ItemTax, Error> {
|
|
||||||
const itemTax = new ItemTax(props, id);
|
|
||||||
|
|
||||||
// Reglas de negocio / validaciones
|
|
||||||
// ...
|
|
||||||
// ...
|
|
||||||
|
|
||||||
return Result.ok(itemTax);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get tax(): Tax {
|
|
||||||
return this.props.tax;
|
|
||||||
}
|
|
||||||
|
|
||||||
getProps(): ItemTaxProps {
|
|
||||||
return this.props;
|
|
||||||
}
|
|
||||||
|
|
||||||
toPrimitive() {
|
|
||||||
return this.getProps();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getTaxAmount(taxableAmount: ItemAmount): ItemAmount {
|
|
||||||
return taxableAmount.percentage(this.tax.percentage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,24 +1,14 @@
|
|||||||
import { Collection } from "@repo/rdx-utils";
|
import { Tax, Taxes } from "@erp/core/api";
|
||||||
import { ItemAmount } from "../../value-objects";
|
import { ItemAmount } from "../../value-objects";
|
||||||
import { ItemTax } from "./item-tax";
|
|
||||||
|
|
||||||
export interface ItemTaxesProps {
|
export class ItemTaxes extends Taxes {
|
||||||
items?: ItemTax[];
|
constructor(items: Tax[] = [], totalItems: number | null = null) {
|
||||||
}
|
super(items, totalItems);
|
||||||
|
|
||||||
export class ItemTaxes extends Collection<ItemTax> {
|
|
||||||
constructor(props: ItemTaxesProps) {
|
|
||||||
const { items = [] } = props;
|
|
||||||
super(items);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static create(props: ItemTaxesProps): ItemTaxes {
|
|
||||||
return new ItemTaxes(props);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTaxesAmount(taxableAmount: ItemAmount): ItemAmount {
|
public getTaxesAmount(taxableAmount: ItemAmount): ItemAmount {
|
||||||
return this.getAll().reduce(
|
return this.getAll().reduce(
|
||||||
(total, tax) => total.add(tax.getTaxAmount(taxableAmount)),
|
(total, tax) => total.add(taxableAmount.percentage(tax.percentage)),
|
||||||
ItemAmount.zero(taxableAmount.currencyCode)
|
ItemAmount.zero(taxableAmount.currencyCode)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -26,21 +16,22 @@ export class ItemTaxes extends Collection<ItemTax> {
|
|||||||
public getTaxesAmountByTaxCode(taxCode: string, taxableAmount: ItemAmount): ItemAmount {
|
public getTaxesAmountByTaxCode(taxCode: string, taxableAmount: ItemAmount): ItemAmount {
|
||||||
const currencyCode = taxableAmount.currencyCode;
|
const currencyCode = taxableAmount.currencyCode;
|
||||||
|
|
||||||
return this.filter((itemTax) => itemTax.tax.code === taxCode).reduce((totalAmount, itemTax) => {
|
return this.filter((itemTax) => itemTax.code === taxCode).reduce((totalAmount, itemTax) => {
|
||||||
return itemTax.getTaxAmount(taxableAmount).add(totalAmount);
|
return taxableAmount.percentage(itemTax.percentage).add(totalAmount);
|
||||||
}, ItemAmount.zero(currencyCode));
|
}, ItemAmount.zero(currencyCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTaxesAmountByTaxes(taxableAmount: ItemAmount): {
|
public getTaxesAmountByTaxes(taxableAmount: ItemAmount) {
|
||||||
return this.getAll().map((taxItem) => ({
|
return this.getAll().map((taxItem) => ({
|
||||||
tax: taxItem.tax,
|
taxableAmount,
|
||||||
taxesAmount: this.getTaxesAmountByTaxCode(taxItem.tax.code, taxableAmount),
|
tax: taxItem,
|
||||||
|
taxesAmount: this.getTaxesAmountByTaxCode(taxItem.code, taxableAmount),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCodesToString(): string {
|
public getCodesToString(): string {
|
||||||
return this.getAll()
|
return this.getAll()
|
||||||
.map((taxItem) => taxItem.tax.code)
|
.map((taxItem) => taxItem.code)
|
||||||
.join(", ");
|
.join(", ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -146,9 +146,7 @@ export class CustomerInvoiceItemDomainMapper
|
|||||||
|
|
||||||
// 5) Construcción del elemento de dominio
|
// 5) Construcción del elemento de dominio
|
||||||
|
|
||||||
const taxes = ItemTaxes.create({
|
const taxes = ItemTaxes.create(taxesResults.data.getAll());
|
||||||
items: taxesResults.data.getAll(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const createResult = CustomerInvoiceItem.create(
|
const createResult = CustomerInvoiceItem.create(
|
||||||
{
|
{
|
||||||
@ -231,6 +229,8 @@ export class CustomerInvoiceItemDomainMapper
|
|||||||
|
|
||||||
total_amount_value: allAmounts.totalAmount.value,
|
total_amount_value: allAmounts.totalAmount.value,
|
||||||
total_amount_scale: allAmounts.totalAmount.scale,
|
total_amount_scale: allAmounts.totalAmount.scale,
|
||||||
|
|
||||||
|
taxes: taxesResults.data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,4 @@
|
|||||||
import {
|
import { ISequelizeDomainMapper, MapperParamsType, SequelizeDomainMapper } from "@erp/core/api";
|
||||||
ISequelizeDomainMapper,
|
|
||||||
InfrastructureError,
|
|
||||||
MapperParamsType,
|
|
||||||
SequelizeDomainMapper,
|
|
||||||
} from "@erp/core/api";
|
|
||||||
import {
|
import {
|
||||||
CurrencyCode,
|
CurrencyCode,
|
||||||
LanguageCode,
|
LanguageCode,
|
||||||
@ -17,7 +12,7 @@ import {
|
|||||||
maybeFromNullableVO,
|
maybeFromNullableVO,
|
||||||
toNullable,
|
toNullable,
|
||||||
} from "@repo/rdx-ddd";
|
} from "@repo/rdx-ddd";
|
||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
import { Collection, Maybe, Result } from "@repo/rdx-utils";
|
||||||
import {
|
import {
|
||||||
CustomerInvoice,
|
CustomerInvoice,
|
||||||
CustomerInvoiceItems,
|
CustomerInvoiceItems,
|
||||||
@ -27,7 +22,6 @@ import {
|
|||||||
CustomerInvoiceStatus,
|
CustomerInvoiceStatus,
|
||||||
InvoicePaymentMethod,
|
InvoicePaymentMethod,
|
||||||
} from "../../../domain";
|
} from "../../../domain";
|
||||||
import { InvoiceTaxes } from "../../../domain/entities/invoice-taxes";
|
|
||||||
import { CustomerInvoiceCreationAttributes, CustomerInvoiceModel } from "../../sequelize";
|
import { CustomerInvoiceCreationAttributes, CustomerInvoiceModel } from "../../sequelize";
|
||||||
import { CustomerInvoiceItemDomainMapper as CustomerInvoiceItemFullMapper } from "./customer-invoice-item.mapper";
|
import { CustomerInvoiceItemDomainMapper as CustomerInvoiceItemFullMapper } from "./customer-invoice-item.mapper";
|
||||||
import { InvoiceRecipientDomainMapper as InvoiceRecipientFullMapper } from "./invoice-recipient.mapper";
|
import { InvoiceRecipientDomainMapper as InvoiceRecipientFullMapper } from "./invoice-recipient.mapper";
|
||||||
@ -132,7 +126,7 @@ export class CustomerInvoiceDomainMapper
|
|||||||
);
|
);
|
||||||
|
|
||||||
const invoiceNumber = extractOrPushError(
|
const invoiceNumber = extractOrPushError(
|
||||||
CustomerInvoiceNumber.create(source.invoice_number),
|
maybeFromNullableVO(source.invoice_number, (value) => CustomerInvoiceNumber.create(value)),
|
||||||
"invoice_number",
|
"invoice_number",
|
||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
@ -149,6 +143,12 @@ export class CustomerInvoiceDomainMapper
|
|||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const reference = extractOrPushError(
|
||||||
|
maybeFromNullableVO(source.reference, (value) => Result.ok(String(value))),
|
||||||
|
"reference",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
|
||||||
const notes = extractOrPushError(
|
const notes = extractOrPushError(
|
||||||
maybeFromNullableVO(source.notes, (value) => TextValue.create(value)),
|
maybeFromNullableVO(source.notes, (value) => TextValue.create(value)),
|
||||||
"notes",
|
"notes",
|
||||||
@ -186,6 +186,7 @@ export class CustomerInvoiceDomainMapper
|
|||||||
invoiceNumber,
|
invoiceNumber,
|
||||||
invoiceDate,
|
invoiceDate,
|
||||||
operationDate,
|
operationDate,
|
||||||
|
reference,
|
||||||
notes,
|
notes,
|
||||||
languageCode,
|
languageCode,
|
||||||
currencyCode,
|
currencyCode,
|
||||||
@ -274,10 +275,6 @@ export class CustomerInvoiceDomainMapper
|
|||||||
const recipient = recipientResult.data;
|
const recipient = recipientResult.data;
|
||||||
const paymentMethod = paymentMethodResult.data;
|
const paymentMethod = paymentMethodResult.data;
|
||||||
|
|
||||||
const taxes = InvoiceTaxes.create({
|
|
||||||
items: taxesResults.data.getAll(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const items = CustomerInvoiceItems.create({
|
const items = CustomerInvoiceItems.create({
|
||||||
languageCode: attributes.languageCode!,
|
languageCode: attributes.languageCode!,
|
||||||
currencyCode: attributes.currencyCode!,
|
currencyCode: attributes.currencyCode!,
|
||||||
@ -297,6 +294,7 @@ export class CustomerInvoiceDomainMapper
|
|||||||
customerId: attributes.customerId!,
|
customerId: attributes.customerId!,
|
||||||
recipient: recipient,
|
recipient: recipient,
|
||||||
|
|
||||||
|
reference: attributes.reference!,
|
||||||
notes: attributes.notes!,
|
notes: attributes.notes!,
|
||||||
|
|
||||||
languageCode: attributes.languageCode!,
|
languageCode: attributes.languageCode!,
|
||||||
@ -306,7 +304,6 @@ export class CustomerInvoiceDomainMapper
|
|||||||
|
|
||||||
paymentMethod: paymentMethod!,
|
paymentMethod: paymentMethod!,
|
||||||
|
|
||||||
taxes: taxes,
|
|
||||||
items,
|
items,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -345,8 +342,11 @@ export class CustomerInvoiceDomainMapper
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const items = itemsResult.data;
|
||||||
|
|
||||||
// 1) Taxes
|
// 1) Taxes
|
||||||
const taxesResult = this._taxesMapper.mapToPersistenceArray(source.taxes, {
|
|
||||||
|
const taxesResult = this._taxesMapper.mapToPersistenceArray(new Collection(source.taxes), {
|
||||||
errors,
|
errors,
|
||||||
parent: source,
|
parent: source,
|
||||||
...params,
|
...params,
|
||||||
@ -358,18 +358,31 @@ export class CustomerInvoiceDomainMapper
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const taxes = taxesResult.data;
|
||||||
|
|
||||||
// 3) Calcular totales
|
// 3) Calcular totales
|
||||||
const allAmounts = source.getAllAmounts();
|
const allAmounts = source.getAllAmounts();
|
||||||
|
|
||||||
// 4) Construir parte
|
// 4) Cliente
|
||||||
const invoiceValues: Partial<CustomerInvoiceCreationAttributes> = {
|
const recipient = this._mapRecipientToPersistence(source);
|
||||||
|
|
||||||
|
// 7) Si hubo errores de mapeo, devolvemos colección de validación
|
||||||
|
if (errors.length > 0) {
|
||||||
|
return Result.fail(
|
||||||
|
new ValidationErrorCollection("Customer invoice mapping to persistence failed", errors)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const invoiceValues: CustomerInvoiceCreationAttributes = {
|
||||||
id: source.id.toPrimitive(),
|
id: source.id.toPrimitive(),
|
||||||
company_id: source.companyId.toPrimitive(),
|
company_id: source.companyId.toPrimitive(),
|
||||||
|
|
||||||
is_proforma: source.isProforma,
|
is_proforma: source.isProforma,
|
||||||
status: source.status.toPrimitive(),
|
status: source.status.toPrimitive(),
|
||||||
series: toNullable(source.series, (series) => series.toPrimitive()),
|
series: toNullable(source.series, (series) => series.toPrimitive()),
|
||||||
invoice_number: source.invoiceNumber.toPrimitive(),
|
invoice_number: toNullable(source.invoiceNumber, (invoiceNumber) =>
|
||||||
|
invoiceNumber.toPrimitive()
|
||||||
|
),
|
||||||
invoice_date: source.invoiceDate.toPrimitive(),
|
invoice_date: source.invoiceDate.toPrimitive(),
|
||||||
operation_date: toNullable(source.operationDate, (operationDate) =>
|
operation_date: toNullable(source.operationDate, (operationDate) =>
|
||||||
operationDate.toPrimitive()
|
operationDate.toPrimitive()
|
||||||
@ -377,6 +390,7 @@ export class CustomerInvoiceDomainMapper
|
|||||||
language_code: source.languageCode.toPrimitive(),
|
language_code: source.languageCode.toPrimitive(),
|
||||||
currency_code: source.currencyCode.toPrimitive(),
|
currency_code: source.currencyCode.toPrimitive(),
|
||||||
|
|
||||||
|
reference: toNullable(source.reference, (reference) => reference),
|
||||||
notes: toNullable(source.notes, (notes) => notes.toPrimitive()),
|
notes: toNullable(source.notes, (notes) => notes.toPrimitive()),
|
||||||
|
|
||||||
subtotal_amount_value: allAmounts.subtotalAmount.value,
|
subtotal_amount_value: allAmounts.subtotalAmount.value,
|
||||||
@ -397,61 +411,58 @@ export class CustomerInvoiceDomainMapper
|
|||||||
total_amount_value: allAmounts.totalAmount.value,
|
total_amount_value: allAmounts.totalAmount.value,
|
||||||
total_amount_scale: allAmounts.totalAmount.scale,
|
total_amount_scale: allAmounts.totalAmount.scale,
|
||||||
|
|
||||||
customer_id: source.customerId.toPrimitive(),
|
|
||||||
|
|
||||||
payment_method_id: toNullable(source.paymentMethod, (payment) => payment.toObjectString().id),
|
payment_method_id: toNullable(source.paymentMethod, (payment) => payment.toObjectString().id),
|
||||||
payment_method_description: toNullable(
|
payment_method_description: toNullable(
|
||||||
source.paymentMethod,
|
source.paymentMethod,
|
||||||
(payment) => payment.toObjectString().payment_description
|
(payment) => payment.toObjectString().payment_description
|
||||||
),
|
),
|
||||||
|
|
||||||
|
customer_id: source.customerId.toPrimitive(),
|
||||||
|
...recipient,
|
||||||
|
taxes,
|
||||||
|
items,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 5) Cliente / Recipient ??
|
return Result.ok<CustomerInvoiceCreationAttributes>(invoiceValues);
|
||||||
// Si es proforma no guardamos los campos como históricos (snapshots)
|
}
|
||||||
if (source.isProforma) {
|
|
||||||
Object.assign(invoiceValues, {
|
protected _mapRecipientToPersistence(source: CustomerInvoice, params?: MapperParamsType) {
|
||||||
customer_tin: null,
|
const { errors } = params as {
|
||||||
customer_name: null,
|
errors: ValidationErrorDetail[];
|
||||||
customer_street: null,
|
};
|
||||||
customer_street2: null,
|
|
||||||
customer_city: null,
|
const recipient = source.recipient.getOrUndefined();
|
||||||
customer_province: null,
|
|
||||||
customer_postal_code: null,
|
if (!source.isProforma && !recipient) {
|
||||||
customer_country: null,
|
errors.push({
|
||||||
|
path: "recipient",
|
||||||
|
message: "[CustomerInvoiceDomainMapper] Issued customer invoice w/o recipient data",
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
const recipient = source.recipient.getOrUndefined();
|
|
||||||
if (!recipient) {
|
|
||||||
return Result.fail(
|
|
||||||
new InfrastructureError(
|
|
||||||
"[CustomerInvoiceDomainMapper] Issued customer invoice w/o recipient data"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.assign(invoiceValues, {
|
|
||||||
customer_tin: recipient.tin.toPrimitive(),
|
|
||||||
customer_name: recipient.name.toPrimitive(),
|
|
||||||
customer_street: toNullable(recipient.street, (v) => v.toPrimitive()),
|
|
||||||
customer_street2: toNullable(recipient.street2, (v) => v.toPrimitive()),
|
|
||||||
customer_city: toNullable(recipient.city, (v) => v.toPrimitive()),
|
|
||||||
customer_province: toNullable(recipient.province, (v) => v.toPrimitive()),
|
|
||||||
customer_postal_code: toNullable(recipient.postalCode, (v) => v.toPrimitive()),
|
|
||||||
customer_country: toNullable(recipient.country, (v) => v.toPrimitive()),
|
|
||||||
} as Partial<CustomerInvoiceCreationAttributes>);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7) Si hubo errores de mapeo, devolvemos colección de validación
|
const recipientValues = {
|
||||||
if (errors.length > 0) {
|
customer_tin: !source.isProforma ? recipient!.tin.toPrimitive() : null,
|
||||||
return Result.fail(
|
customer_name: !source.isProforma ? recipient!.name.toPrimitive() : null,
|
||||||
new ValidationErrorCollection("Customer invoice mapping to persistence failed", errors)
|
customer_street: !source.isProforma
|
||||||
);
|
? toNullable(recipient!.street, (v) => v.toPrimitive())
|
||||||
}
|
: null,
|
||||||
|
customer_street2: !source.isProforma
|
||||||
|
? toNullable(recipient!.street2, (v) => v.toPrimitive())
|
||||||
|
: null,
|
||||||
|
customer_city: !source.isProforma
|
||||||
|
? toNullable(recipient!.city, (v) => v.toPrimitive())
|
||||||
|
: null,
|
||||||
|
customer_province: !source.isProforma
|
||||||
|
? toNullable(recipient!.province, (v) => v.toPrimitive())
|
||||||
|
: null,
|
||||||
|
customer_postal_code: !source.isProforma
|
||||||
|
? toNullable(recipient!.postalCode, (v) => v.toPrimitive())
|
||||||
|
: null,
|
||||||
|
customer_country: !source.isProforma
|
||||||
|
? toNullable(recipient!.country, (v) => v.toPrimitive())
|
||||||
|
: null,
|
||||||
|
};
|
||||||
|
|
||||||
return Result.ok<CustomerInvoiceCreationAttributes>({
|
return recipientValues;
|
||||||
...invoiceValues,
|
|
||||||
items: itemsResult.data,
|
|
||||||
taxes: taxesResult.data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +1,15 @@
|
|||||||
import { JsonTaxCatalogProvider } from "@erp/core";
|
import { JsonTaxCatalogProvider } from "@erp/core";
|
||||||
import { MapperParamsType, SequelizeDomainMapper, Tax } from "@erp/core/api";
|
import { MapperParamsType, SequelizeDomainMapper, Tax } from "@erp/core/api";
|
||||||
import {
|
import { UniqueID, ValidationErrorDetail } from "@repo/rdx-ddd";
|
||||||
ValidationErrorCollection,
|
|
||||||
ValidationErrorDetail,
|
|
||||||
extractOrPushError,
|
|
||||||
} from "@repo/rdx-ddd";
|
|
||||||
|
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { InferCreationAttributes } from "sequelize";
|
import { CustomerInvoice, CustomerInvoiceItemProps, ItemAmount } from "../../../domain";
|
||||||
import { CustomerInvoice, CustomerInvoiceProps } from "../../../domain";
|
|
||||||
import { InvoiceTax } from "../../../domain/entities/invoice-taxes";
|
|
||||||
import { CustomerInvoiceTaxCreationAttributes, CustomerInvoiceTaxModel } from "../../sequelize";
|
import { CustomerInvoiceTaxCreationAttributes, CustomerInvoiceTaxModel } from "../../sequelize";
|
||||||
|
|
||||||
export class TaxesDomainMapper extends SequelizeDomainMapper<
|
export class TaxesDomainMapper extends SequelizeDomainMapper<
|
||||||
CustomerInvoiceTaxModel,
|
CustomerInvoiceTaxModel,
|
||||||
CustomerInvoiceTaxCreationAttributes,
|
CustomerInvoiceTaxCreationAttributes,
|
||||||
InvoiceTax
|
{ taxableAmount: ItemAmount; tax: Tax; taxesAmount: ItemAmount }
|
||||||
> {
|
> {
|
||||||
private _taxCatalog: JsonTaxCatalogProvider;
|
private _taxCatalog: JsonTaxCatalogProvider;
|
||||||
|
|
||||||
@ -35,60 +29,57 @@ export class TaxesDomainMapper extends SequelizeDomainMapper<
|
|||||||
public mapToDomain(
|
public mapToDomain(
|
||||||
source: CustomerInvoiceTaxModel,
|
source: CustomerInvoiceTaxModel,
|
||||||
params?: MapperParamsType
|
params?: MapperParamsType
|
||||||
): Result<InvoiceTax, Error> {
|
): Result<
|
||||||
const { errors, index, attributes } = params as {
|
{
|
||||||
index: number;
|
taxableAmount: ItemAmount;
|
||||||
errors: ValidationErrorDetail[];
|
tax: Tax;
|
||||||
attributes: Partial<CustomerInvoiceProps>;
|
taxesAmount: ItemAmount;
|
||||||
|
},
|
||||||
|
Error
|
||||||
|
> {
|
||||||
|
const { attributes } = params as {
|
||||||
|
attributes: Partial<CustomerInvoiceItemProps>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const tax = extractOrPushError(
|
return Result.ok({
|
||||||
Tax.createFromCode(source.tax_code, this._taxCatalog),
|
taxableAmount: ItemAmount.create({
|
||||||
`taxes[${index}].tax_code`,
|
value: source.taxable_amount_value,
|
||||||
errors
|
currency_code: attributes.currencyCode!.code,
|
||||||
);
|
}).data,
|
||||||
|
tax: Tax.createFromCode(source.tax_code, this._taxCatalog).data,
|
||||||
// Creación del objeto de dominio
|
taxesAmount: ItemAmount.create({
|
||||||
const createResult = InvoiceTax.create({
|
value: source.taxes_amount_value,
|
||||||
tax: tax!,
|
currency_code: attributes.currencyCode!.code,
|
||||||
|
}).data,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (createResult.isFailure) {
|
|
||||||
return Result.fail(
|
|
||||||
new ValidationErrorCollection("Invoice tax creation failed", [
|
|
||||||
{ path: `taxes[${index}]`, message: createResult.error.message },
|
|
||||||
])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return createResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public mapToPersistence(
|
public mapToPersistence(
|
||||||
source: InvoiceTax,
|
source: {
|
||||||
|
taxableAmount: ItemAmount;
|
||||||
|
tax: Tax;
|
||||||
|
taxesAmount: ItemAmount;
|
||||||
|
},
|
||||||
params?: MapperParamsType
|
params?: MapperParamsType
|
||||||
): Result<InferCreationAttributes<CustomerInvoiceTaxModel, {}>, Error> {
|
): Result<CustomerInvoiceTaxCreationAttributes, Error> {
|
||||||
const { errors, parent } = params as {
|
const { errors, parent } = params as {
|
||||||
index: number;
|
|
||||||
parent: CustomerInvoice;
|
parent: CustomerInvoice;
|
||||||
errors: ValidationErrorDetail[];
|
errors: ValidationErrorDetail[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const taxableAmount = parent.getTaxableAmount()
|
source;
|
||||||
const taxesAmount =
|
|
||||||
|
|
||||||
return Result.ok({
|
return Result.ok({
|
||||||
tax_id: source.id.toPrimitive(),
|
tax_id: UniqueID.generateNewID().toPrimitive(),
|
||||||
invoice_id: parent.id.toPrimitive(),
|
invoice_id: parent.id.toPrimitive(),
|
||||||
|
|
||||||
tax_code: source.tax.code,
|
tax_code: source.tax.code,
|
||||||
|
|
||||||
taxable_amount_value: taxableAmount.value,
|
taxable_amount_value: source.taxableAmount.value,
|
||||||
taxable_amount_scale: taxableAmount.scale,
|
taxable_amount_scale: source.taxableAmount.scale,
|
||||||
|
|
||||||
taxes_amount_value: taxesAmount.value,
|
taxes_amount_value: source.taxesAmount.value,
|
||||||
taxes_amount_scale: taxesAmount.scale,
|
taxes_amount_scale: source.taxesAmount.scale,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,13 +5,15 @@ import {
|
|||||||
SequelizeDomainMapper,
|
SequelizeDomainMapper,
|
||||||
Tax,
|
Tax,
|
||||||
} from "@erp/core/api";
|
} from "@erp/core/api";
|
||||||
import { CustomerInvoiceItem, ItemTax } from "@erp/customer-invoices/api/domain";
|
|
||||||
import {
|
import {
|
||||||
|
UniqueID,
|
||||||
ValidationErrorCollection,
|
ValidationErrorCollection,
|
||||||
ValidationErrorDetail,
|
ValidationErrorDetail,
|
||||||
extractOrPushError,
|
extractOrPushError,
|
||||||
} from "@repo/rdx-ddd";
|
} from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
import { CustomerInvoiceItem } from "../../../domain";
|
||||||
import {
|
import {
|
||||||
CustomerInvoiceItemTaxCreationAttributes,
|
CustomerInvoiceItemTaxCreationAttributes,
|
||||||
CustomerInvoiceItemTaxModel,
|
CustomerInvoiceItemTaxModel,
|
||||||
@ -21,14 +23,14 @@ export interface IItemTaxesDomainMapper
|
|||||||
extends ISequelizeDomainMapper<
|
extends ISequelizeDomainMapper<
|
||||||
CustomerInvoiceItemTaxModel,
|
CustomerInvoiceItemTaxModel,
|
||||||
CustomerInvoiceItemTaxCreationAttributes,
|
CustomerInvoiceItemTaxCreationAttributes,
|
||||||
ItemTax
|
Tax
|
||||||
> {}
|
> {}
|
||||||
|
|
||||||
export class ItemTaxesDomainMapper
|
export class ItemTaxesDomainMapper
|
||||||
extends SequelizeDomainMapper<
|
extends SequelizeDomainMapper<
|
||||||
CustomerInvoiceItemTaxModel,
|
CustomerInvoiceItemTaxModel,
|
||||||
CustomerInvoiceItemTaxCreationAttributes,
|
CustomerInvoiceItemTaxCreationAttributes,
|
||||||
ItemTax
|
Tax
|
||||||
>
|
>
|
||||||
implements IItemTaxesDomainMapper
|
implements IItemTaxesDomainMapper
|
||||||
{
|
{
|
||||||
@ -50,7 +52,7 @@ export class ItemTaxesDomainMapper
|
|||||||
public mapToDomain(
|
public mapToDomain(
|
||||||
source: CustomerInvoiceItemTaxModel,
|
source: CustomerInvoiceItemTaxModel,
|
||||||
params?: MapperParamsType
|
params?: MapperParamsType
|
||||||
): Result<ItemTax, Error> {
|
): Result<Tax, Error> {
|
||||||
const { errors, index } = params as {
|
const { errors, index } = params as {
|
||||||
index: number;
|
index: number;
|
||||||
errors: ValidationErrorDetail[];
|
errors: ValidationErrorDetail[];
|
||||||
@ -63,7 +65,7 @@ export class ItemTaxesDomainMapper
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Creación del objeto de dominio
|
// Creación del objeto de dominio
|
||||||
const createResult = ItemTax.create({ tax: tax! });
|
const createResult = Tax.create(tax!);
|
||||||
if (createResult.isFailure) {
|
if (createResult.isFailure) {
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
new ValidationErrorCollection("Invoice item tax creation failed", [
|
new ValidationErrorCollection("Invoice item tax creation failed", [
|
||||||
@ -76,7 +78,7 @@ export class ItemTaxesDomainMapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
public mapToPersistence(
|
public mapToPersistence(
|
||||||
source: ItemTax,
|
source: Tax,
|
||||||
params?: MapperParamsType
|
params?: MapperParamsType
|
||||||
): Result<CustomerInvoiceItemTaxCreationAttributes, Error> {
|
): Result<CustomerInvoiceItemTaxCreationAttributes, Error> {
|
||||||
const { errors, parent } = params as {
|
const { errors, parent } = params as {
|
||||||
@ -85,13 +87,13 @@ export class ItemTaxesDomainMapper
|
|||||||
};
|
};
|
||||||
|
|
||||||
const taxableAmount = parent.getTaxableAmount();
|
const taxableAmount = parent.getTaxableAmount();
|
||||||
const taxAmount = source.getTaxAmount(taxableAmount);
|
const taxAmount = taxableAmount.percentage(source.percentage);
|
||||||
|
|
||||||
return Result.ok({
|
return Result.ok({
|
||||||
tax_id: source.id.toPrimitive(),
|
tax_id: UniqueID.generateNewID().toPrimitive(),
|
||||||
item_id: parent.id.toPrimitive(),
|
item_id: parent.id.toPrimitive(),
|
||||||
|
|
||||||
tax_code: source.tax.code,
|
tax_code: source.code,
|
||||||
|
|
||||||
taxable_amount_value: taxableAmount.value,
|
taxable_amount_value: taxableAmount.value,
|
||||||
taxable_amount_scale: taxableAmount.scale,
|
taxable_amount_scale: taxableAmount.scale,
|
||||||
|
|||||||
@ -68,26 +68,26 @@ export default (database: Sequelize) => {
|
|||||||
|
|
||||||
taxable_amount_value: {
|
taxable_amount_value: {
|
||||||
type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
|
type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
|
||||||
allowNull: true,
|
allowNull: false,
|
||||||
defaultValue: null,
|
defaultValue: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
taxable_amount_scale: {
|
taxable_amount_scale: {
|
||||||
type: new DataTypes.SMALLINT(),
|
type: new DataTypes.SMALLINT(),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
defaultValue: 2,
|
defaultValue: 4,
|
||||||
},
|
},
|
||||||
|
|
||||||
taxes_amount_value: {
|
taxes_amount_value: {
|
||||||
type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
|
type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
|
||||||
allowNull: true,
|
allowNull: false,
|
||||||
defaultValue: null,
|
defaultValue: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
taxes_amount_scale: {
|
taxes_amount_scale: {
|
||||||
type: new DataTypes.SMALLINT(),
|
type: new DataTypes.SMALLINT(),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
defaultValue: 2,
|
defaultValue: 4,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
CreationOptional,
|
||||||
DataTypes,
|
DataTypes,
|
||||||
InferAttributes,
|
InferAttributes,
|
||||||
InferCreationAttributes,
|
InferCreationAttributes,
|
||||||
@ -28,38 +29,39 @@ export class CustomerInvoiceItemModel extends Model<
|
|||||||
|
|
||||||
declare position: number;
|
declare position: number;
|
||||||
|
|
||||||
declare description: string;
|
declare description: CreationOptional<string | null>;
|
||||||
|
|
||||||
declare quantity_value: number;
|
declare quantity_value: CreationOptional<number | null>;
|
||||||
declare quantity_scale: number;
|
declare quantity_scale: number;
|
||||||
|
|
||||||
declare unit_amount_value: number;
|
declare unit_amount_value: CreationOptional<number | null>;
|
||||||
declare unit_amount_scale: number;
|
declare unit_amount_scale: number;
|
||||||
|
|
||||||
// Subtotal
|
// Subtotal
|
||||||
declare subtotal_amount_value: number;
|
declare subtotal_amount_value: CreationOptional<number | null>;
|
||||||
declare subtotal_amount_scale: number;
|
declare subtotal_amount_scale: number;
|
||||||
|
|
||||||
// Discount percentage
|
// Discount percentage
|
||||||
declare discount_percentage_value: number;
|
declare discount_percentage_value: CreationOptional<number | null>;
|
||||||
declare discount_percentage_scale: number;
|
declare discount_percentage_scale: number;
|
||||||
|
|
||||||
// Discount amount
|
// Discount amount
|
||||||
declare discount_amount_value: number;
|
declare discount_amount_value: CreationOptional<number | null>;
|
||||||
declare discount_amount_scale: number;
|
declare discount_amount_scale: number;
|
||||||
|
|
||||||
// Taxable amount (base imponible)
|
// Taxable amount (base imponible)
|
||||||
declare taxable_amount_value: number;
|
declare taxable_amount_value: CreationOptional<number | null>;
|
||||||
declare taxable_amount_scale: number;
|
declare taxable_amount_scale: number;
|
||||||
|
|
||||||
// Total taxes amount / taxes total
|
// Total taxes amount / taxes total
|
||||||
declare taxes_amount_value: number;
|
declare taxes_amount_value: CreationOptional<number | null>;
|
||||||
declare taxes_amount_scale: number;
|
declare taxes_amount_scale: number;
|
||||||
|
|
||||||
// Total
|
// Total
|
||||||
declare total_amount_value: number;
|
declare total_amount_value: CreationOptional<number | null>;
|
||||||
declare total_amount_scale: number;
|
declare total_amount_scale: number;
|
||||||
|
|
||||||
|
// Relaciones
|
||||||
declare invoice: NonAttribute<CustomerInvoiceModel>;
|
declare invoice: NonAttribute<CustomerInvoiceModel>;
|
||||||
declare taxes: NonAttribute<CustomerInvoiceItemTaxModel[]>;
|
declare taxes: NonAttribute<CustomerInvoiceItemTaxModel[]>;
|
||||||
|
|
||||||
|
|||||||
@ -67,8 +67,8 @@ export default (database: Sequelize) => {
|
|||||||
|
|
||||||
taxable_amount_value: {
|
taxable_amount_value: {
|
||||||
type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
|
type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
|
||||||
allowNull: true,
|
allowNull: false,
|
||||||
defaultValue: null,
|
defaultValue: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
taxable_amount_scale: {
|
taxable_amount_scale: {
|
||||||
@ -79,8 +79,8 @@ export default (database: Sequelize) => {
|
|||||||
|
|
||||||
taxes_amount_value: {
|
taxes_amount_value: {
|
||||||
type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
|
type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
|
||||||
allowNull: true,
|
allowNull: false,
|
||||||
defaultValue: null,
|
defaultValue: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
taxes_amount_scale: {
|
taxes_amount_scale: {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
CreationOptional,
|
||||||
DataTypes,
|
DataTypes,
|
||||||
InferAttributes,
|
InferAttributes,
|
||||||
InferCreationAttributes,
|
InferCreationAttributes,
|
||||||
@ -34,15 +35,20 @@ export class CustomerInvoiceModel extends Model<
|
|||||||
|
|
||||||
declare is_proforma: boolean;
|
declare is_proforma: boolean;
|
||||||
declare status: string;
|
declare status: string;
|
||||||
declare series: string;
|
declare series: CreationOptional<string | null>;
|
||||||
declare invoice_number: string;
|
declare invoice_number: CreationOptional<string | null>;
|
||||||
declare invoice_date: string;
|
declare invoice_date: CreationOptional<string>;
|
||||||
declare operation_date: string;
|
declare operation_date: CreationOptional<string | null>;
|
||||||
declare language_code: string;
|
declare language_code: CreationOptional<string>;
|
||||||
declare currency_code: string;
|
declare currency_code: CreationOptional<string>;
|
||||||
//declare xxxxxx
|
|
||||||
|
|
||||||
declare notes: string;
|
declare reference: CreationOptional<string | null>;
|
||||||
|
|
||||||
|
declare notes: CreationOptional<string | null>;
|
||||||
|
|
||||||
|
// Método de pago
|
||||||
|
declare payment_method_id: CreationOptional<string | null>;
|
||||||
|
declare payment_method_description: CreationOptional<string | null>;
|
||||||
|
|
||||||
// Subtotal
|
// Subtotal
|
||||||
declare subtotal_amount_value: number;
|
declare subtotal_amount_value: number;
|
||||||
@ -70,18 +76,14 @@ export class CustomerInvoiceModel extends Model<
|
|||||||
|
|
||||||
// Customer
|
// Customer
|
||||||
declare customer_id: string;
|
declare customer_id: string;
|
||||||
declare customer_tin: string;
|
declare customer_tin: CreationOptional<string | null>;
|
||||||
declare customer_name: string;
|
declare customer_name: CreationOptional<string | null>;
|
||||||
declare customer_street: string;
|
declare customer_street: CreationOptional<string | null>;
|
||||||
declare customer_street2: string;
|
declare customer_street2: CreationOptional<string | null>;
|
||||||
declare customer_city: string;
|
declare customer_city: CreationOptional<string | null>;
|
||||||
declare customer_province: string;
|
declare customer_province: CreationOptional<string | null>;
|
||||||
declare customer_postal_code: string;
|
declare customer_postal_code: CreationOptional<string | null>;
|
||||||
declare customer_country: string;
|
declare customer_country: CreationOptional<string | null>;
|
||||||
|
|
||||||
// Método de pago
|
|
||||||
declare payment_method_id: string;
|
|
||||||
declare payment_method_description: string;
|
|
||||||
|
|
||||||
// Relaciones
|
// Relaciones
|
||||||
declare items: NonAttribute<CustomerInvoiceItemModel[]>;
|
declare items: NonAttribute<CustomerInvoiceItemModel[]>;
|
||||||
@ -163,8 +165,7 @@ export default (database: Sequelize) => {
|
|||||||
|
|
||||||
invoice_date: {
|
invoice_date: {
|
||||||
type: new DataTypes.DATEONLY(),
|
type: new DataTypes.DATEONLY(),
|
||||||
allowNull: true,
|
allowNull: false,
|
||||||
defaultValue: null,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
operation_date: {
|
operation_date: {
|
||||||
@ -182,6 +183,13 @@ export default (database: Sequelize) => {
|
|||||||
currency_code: {
|
currency_code: {
|
||||||
type: new DataTypes.STRING(3),
|
type: new DataTypes.STRING(3),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
|
defaultValue: "EUR",
|
||||||
|
},
|
||||||
|
|
||||||
|
reference: {
|
||||||
|
type: new DataTypes.STRING(),
|
||||||
|
allowNull: true,
|
||||||
|
defaultValue: null,
|
||||||
},
|
},
|
||||||
|
|
||||||
notes: {
|
notes: {
|
||||||
@ -207,6 +215,7 @@ export default (database: Sequelize) => {
|
|||||||
allowNull: false,
|
allowNull: false,
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
subtotal_amount_scale: {
|
subtotal_amount_scale: {
|
||||||
type: new DataTypes.SMALLINT(),
|
type: new DataTypes.SMALLINT(),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
@ -215,8 +224,8 @@ export default (database: Sequelize) => {
|
|||||||
|
|
||||||
discount_percentage_value: {
|
discount_percentage_value: {
|
||||||
type: new DataTypes.SMALLINT(),
|
type: new DataTypes.SMALLINT(),
|
||||||
allowNull: true,
|
allowNull: false,
|
||||||
defaultValue: null,
|
defaultValue: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
discount_percentage_scale: {
|
discount_percentage_scale: {
|
||||||
@ -227,8 +236,8 @@ export default (database: Sequelize) => {
|
|||||||
|
|
||||||
discount_amount_value: {
|
discount_amount_value: {
|
||||||
type: new DataTypes.BIGINT(),
|
type: new DataTypes.BIGINT(),
|
||||||
allowNull: true,
|
allowNull: false,
|
||||||
defaultValue: null,
|
defaultValue: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
discount_amount_scale: {
|
discount_amount_scale: {
|
||||||
@ -239,8 +248,8 @@ export default (database: Sequelize) => {
|
|||||||
|
|
||||||
taxable_amount_value: {
|
taxable_amount_value: {
|
||||||
type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
|
type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
|
||||||
allowNull: true,
|
allowNull: false,
|
||||||
defaultValue: null,
|
defaultValue: 0,
|
||||||
},
|
},
|
||||||
taxable_amount_scale: {
|
taxable_amount_scale: {
|
||||||
type: new DataTypes.SMALLINT(),
|
type: new DataTypes.SMALLINT(),
|
||||||
@ -250,8 +259,8 @@ export default (database: Sequelize) => {
|
|||||||
|
|
||||||
taxes_amount_value: {
|
taxes_amount_value: {
|
||||||
type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
|
type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
|
||||||
allowNull: true,
|
allowNull: false,
|
||||||
defaultValue: null,
|
defaultValue: 0,
|
||||||
},
|
},
|
||||||
taxes_amount_scale: {
|
taxes_amount_scale: {
|
||||||
type: new DataTypes.SMALLINT(),
|
type: new DataTypes.SMALLINT(),
|
||||||
@ -261,8 +270,8 @@ export default (database: Sequelize) => {
|
|||||||
|
|
||||||
total_amount_value: {
|
total_amount_value: {
|
||||||
type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
|
type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
|
||||||
allowNull: true,
|
allowNull: false,
|
||||||
defaultValue: null,
|
defaultValue: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
total_amount_scale: {
|
total_amount_scale: {
|
||||||
|
|||||||
@ -30,14 +30,18 @@ export interface CustomerProps {
|
|||||||
|
|
||||||
emailPrimary: Maybe<EmailAddress>;
|
emailPrimary: Maybe<EmailAddress>;
|
||||||
emailSecondary: Maybe<EmailAddress>;
|
emailSecondary: Maybe<EmailAddress>;
|
||||||
|
|
||||||
phonePrimary: Maybe<PhoneNumber>;
|
phonePrimary: Maybe<PhoneNumber>;
|
||||||
phoneSecondary: Maybe<PhoneNumber>;
|
phoneSecondary: Maybe<PhoneNumber>;
|
||||||
|
|
||||||
mobilePrimary: Maybe<PhoneNumber>;
|
mobilePrimary: Maybe<PhoneNumber>;
|
||||||
mobileSecondary: Maybe<PhoneNumber>;
|
mobileSecondary: Maybe<PhoneNumber>;
|
||||||
|
|
||||||
fax: Maybe<PhoneNumber>;
|
fax: Maybe<PhoneNumber>;
|
||||||
website: Maybe<URLAddress>;
|
website: Maybe<URLAddress>;
|
||||||
|
|
||||||
legalRecord: Maybe<TextValue>;
|
legalRecord: Maybe<TextValue>;
|
||||||
|
|
||||||
defaultTaxes: Collection<TaxCode>;
|
defaultTaxes: Collection<TaxCode>;
|
||||||
|
|
||||||
languageCode: LanguageCode;
|
languageCode: LanguageCode;
|
||||||
|
|||||||
@ -171,7 +171,7 @@ export class CustomerDomainMapper
|
|||||||
// source.default_taxes is stored as a comma-separated string
|
// source.default_taxes is stored as a comma-separated string
|
||||||
const defaultTaxes = new Collection<TaxCode>();
|
const defaultTaxes = new Collection<TaxCode>();
|
||||||
if (!isNullishOrEmpty(source.default_taxes)) {
|
if (!isNullishOrEmpty(source.default_taxes)) {
|
||||||
source.default_taxes.split(",").map((taxCode, index) => {
|
source.default_taxes!.split(",").map((taxCode, index) => {
|
||||||
const tax = extractOrPushError(TaxCode.create(taxCode), `default_taxes.${index}`, errors);
|
const tax = extractOrPushError(TaxCode.create(taxCode), `default_taxes.${index}`, errors);
|
||||||
if (tax) {
|
if (tax) {
|
||||||
defaultTaxes.add(tax!);
|
defaultTaxes.add(tax!);
|
||||||
|
|||||||
@ -1,4 +1,11 @@
|
|||||||
import { DataTypes, InferAttributes, InferCreationAttributes, Model, Sequelize } from "sequelize";
|
import {
|
||||||
|
CreationOptional,
|
||||||
|
DataTypes,
|
||||||
|
InferAttributes,
|
||||||
|
InferCreationAttributes,
|
||||||
|
Model,
|
||||||
|
Sequelize,
|
||||||
|
} from "sequelize";
|
||||||
|
|
||||||
export type CustomerCreationAttributes = InferCreationAttributes<CustomerModel, {}> & {};
|
export type CustomerCreationAttributes = InferCreationAttributes<CustomerModel, {}> & {};
|
||||||
|
|
||||||
@ -13,43 +20,43 @@ export class CustomerModel extends Model<
|
|||||||
|
|
||||||
declare id: string;
|
declare id: string;
|
||||||
declare company_id: string;
|
declare company_id: string;
|
||||||
declare reference: string;
|
declare reference: CreationOptional<string | null>;
|
||||||
|
|
||||||
declare is_company: boolean;
|
declare is_company: boolean;
|
||||||
declare name: string;
|
declare name: string;
|
||||||
declare trade_name: string;
|
declare trade_name: CreationOptional<string | null>;
|
||||||
declare tin: string;
|
declare tin: CreationOptional<string | null>;
|
||||||
|
|
||||||
declare street: string;
|
declare street: CreationOptional<string | null>;
|
||||||
declare street2: string;
|
declare street2: CreationOptional<string | null>;
|
||||||
declare city: string;
|
declare city: CreationOptional<string | null>;
|
||||||
declare province: string;
|
declare province: CreationOptional<string | null>;
|
||||||
declare postal_code: string;
|
declare postal_code: CreationOptional<string | null>;
|
||||||
declare country: string;
|
declare country: CreationOptional<string | null>;
|
||||||
|
|
||||||
// Correos electrónicos
|
// Correos electrónicos
|
||||||
declare email_primary: string;
|
declare email_primary: CreationOptional<string | null>;
|
||||||
declare email_secondary: string;
|
declare email_secondary: CreationOptional<string | null>;
|
||||||
|
|
||||||
// Teléfonos fijos
|
// Teléfonos fijos
|
||||||
declare phone_primary: string;
|
declare phone_primary: CreationOptional<string | null>;
|
||||||
declare phone_secondary: string;
|
declare phone_secondary: CreationOptional<string | null>;
|
||||||
|
|
||||||
// Móviles
|
// Móviles
|
||||||
declare mobile_primary: string;
|
declare mobile_primary: CreationOptional<string | null>;
|
||||||
declare mobile_secondary: string;
|
declare mobile_secondary: CreationOptional<string | null>;
|
||||||
|
|
||||||
declare fax: string;
|
declare fax: CreationOptional<string | null>;
|
||||||
declare website: string;
|
declare website: CreationOptional<string | null>;
|
||||||
|
|
||||||
declare legal_record: string;
|
declare legal_record: CreationOptional<string | null>;
|
||||||
|
|
||||||
declare default_taxes: string;
|
declare default_taxes: CreationOptional<string | null>;
|
||||||
declare status: string;
|
declare status: string;
|
||||||
declare language_code: string;
|
declare language_code: CreationOptional<string>;
|
||||||
declare currency_code: string;
|
declare currency_code: CreationOptional<string>;
|
||||||
|
|
||||||
declare factuges_id: string;
|
declare factuges_id: CreationOptional<string | null>;
|
||||||
|
|
||||||
static associate(database: Sequelize) {}
|
static associate(database: Sequelize) {}
|
||||||
|
|
||||||
@ -187,6 +194,12 @@ export default (database: Sequelize) => {
|
|||||||
allowNull: true,
|
allowNull: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
status: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
defaultValue: "active",
|
||||||
|
},
|
||||||
|
|
||||||
language_code: {
|
language_code: {
|
||||||
type: DataTypes.STRING(2),
|
type: DataTypes.STRING(2),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
@ -199,12 +212,6 @@ export default (database: Sequelize) => {
|
|||||||
defaultValue: "EUR",
|
defaultValue: "EUR",
|
||||||
},
|
},
|
||||||
|
|
||||||
status: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false,
|
|
||||||
defaultValue: "active",
|
|
||||||
},
|
|
||||||
|
|
||||||
factuges_id: {
|
factuges_id: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: true,
|
allowNull: true,
|
||||||
|
|||||||
@ -21,7 +21,12 @@ export function maybeFromNullableString(input?: string | null): Maybe<string> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Maybe<T> -> null para transporte */
|
/** Maybe<T> -> null para transporte */
|
||||||
export function toNullable<T>(m: Maybe<T>, map?: (t: T) => any): any | null {
|
export function toNullable<T, R>(m: Maybe<T>, map: (t: T) => R): R | null {
|
||||||
|
if (!m || m.isNone()) return null;
|
||||||
|
return map(m.unwrap() as T);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toNullable2<T>(m: Maybe<T>, map?: (t: T) => unknown): unknown | null {
|
||||||
if (!m || m.isNone()) return null;
|
if (!m || m.isNone()) return null;
|
||||||
const v = m.unwrap() as T;
|
const v = m.unwrap() as T;
|
||||||
return map ? String(map(v)) : String(v);
|
return map ? String(map(v)) : String(v);
|
||||||
|
|||||||
@ -3,8 +3,8 @@
|
|||||||
* Ofrece métodos básicos para manipular, consultar y recorrer los elementos.
|
* Ofrece métodos básicos para manipular, consultar y recorrer los elementos.
|
||||||
*/
|
*/
|
||||||
export class Collection<T> {
|
export class Collection<T> {
|
||||||
private items: T[];
|
protected items: T[];
|
||||||
private totalItems: number;
|
protected totalItems: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crea una nueva colección.
|
* Crea una nueva colección.
|
||||||
@ -46,7 +46,7 @@ export class Collection<T> {
|
|||||||
return this.removeByIndex(index);
|
return this.removeByIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeByIndex(index: number) {
|
removeByIndex(index: number) {
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
this.items.splice(index, 1);
|
this.items.splice(index, 1);
|
||||||
if (this.totalItems !== null) {
|
if (this.totalItems !== null) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user