factura tiene en cuenta forma de pago
This commit is contained in:
parent
6cc728fb87
commit
0367c51a97
@ -0,0 +1,13 @@
|
||||
export function formatPaymentMethodDTO(paymentMethod: object) {
|
||||
if (!paymentMethod) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//Construir objeto paymentMethod para comprobar que existe
|
||||
//const value = PaymentMethod.create(
|
||||
// id: paymentMethod.payment_id),
|
||||
//).data;
|
||||
//return value.format(locale);
|
||||
|
||||
return paymentMethod.payment_description;
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
export * from "./format-date-dto";
|
||||
export * from "./format-money-dto";
|
||||
export * from "./format-payment_method-dto";
|
||||
export * from "./format-percentage-dto";
|
||||
export * from "./format-quantity-dto";
|
||||
export * from "./map-dto-to-customer-invoice-props";
|
||||
|
||||
@ -24,6 +24,17 @@ export class CustomerInvoiceFullPresenter extends Presenter<
|
||||
const items = itemsPresenter.toOutput(invoice.items);
|
||||
const allAmounts = invoice.getAllAmounts();
|
||||
|
||||
const payment = invoice.paymentMethod.match(
|
||||
(payment) => {
|
||||
const { id, payment_description } = payment.toObjectString();
|
||||
return {
|
||||
payment_id: id,
|
||||
payment_description,
|
||||
};
|
||||
},
|
||||
() => undefined
|
||||
);
|
||||
|
||||
return {
|
||||
id: invoice.id.toString(),
|
||||
company_id: invoice.companyId.toString(),
|
||||
@ -45,6 +56,8 @@ export class CustomerInvoiceFullPresenter extends Presenter<
|
||||
|
||||
taxes: invoice.taxes.getCodesToString(),
|
||||
|
||||
payment_method: payment,
|
||||
|
||||
subtotal_amount: allAmounts.subtotalAmount.toObjectString(),
|
||||
|
||||
discount_percentage: invoice.discountPercentage.toObjectString(),
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
formatMoneyDTO,
|
||||
formatPercentageDTO,
|
||||
} from "../../helpers";
|
||||
import { formatPaymentMethodDTO } from "../../helpers/format-payment_method-dto";
|
||||
|
||||
export class CustomerInvoiceReportPresenter extends Presenter<
|
||||
GetCustomerInvoiceByIdResponseDTO,
|
||||
@ -40,6 +41,8 @@ export class CustomerInvoiceReportPresenter extends Presenter<
|
||||
taxable_amount: formatMoneyDTO(invoiceDTO.taxable_amount, moneyOptions),
|
||||
taxes_amount: formatMoneyDTO(invoiceDTO.taxes_amount, moneyOptions),
|
||||
total_amount: formatMoneyDTO(invoiceDTO.total_amount, moneyOptions),
|
||||
|
||||
payment_method: formatPaymentMethodDTO(invoiceDTO.payment_method),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,14 +45,14 @@ export class CustomerInvoiceReportPDFPresenter extends Presenter<
|
||||
right: "10mm",
|
||||
top: "10mm",
|
||||
},
|
||||
// landscape: false,
|
||||
// preferCSSPageSize: true,
|
||||
// omitBackground: false,
|
||||
// printBackground: true,
|
||||
// displayHeaderFooter: false,
|
||||
// headerTemplate: "<div />",
|
||||
// footerTemplate:
|
||||
// '<div style="text-align: center;width: 297mm;font-size: 10px;">Página <span style="margin-right: 1cm"><span class="pageNumber"></span> de <span class="totalPages"></span></span></div>',
|
||||
landscape: false,
|
||||
preferCSSPageSize: true,
|
||||
omitBackground: false,
|
||||
printBackground: true,
|
||||
displayHeaderFooter: false,
|
||||
headerTemplate: "<div />",
|
||||
footerTemplate:
|
||||
'<div style="text-align: center;width: 297mm;font-size: 10px;">Página <span style="margin-right: 1cm"><span class="pageNumber"></span> de <span class="totalPages"></span></span></div>',
|
||||
});
|
||||
|
||||
await browser.close();
|
||||
|
||||
@ -185,17 +185,26 @@
|
||||
|
||||
<section id="resume" class="flex items-center justify-between pb-4 mb-4">
|
||||
|
||||
<div class="grow">
|
||||
<div class="pt-4">
|
||||
<p class="text-sm"><strong>Forma de pago:</strong> {{payment_method}}</p>
|
||||
<div class="grow relative pt-10 self-start">
|
||||
{{#if payment_method}}
|
||||
<div class="">
|
||||
<p class=" text-sm"><strong>Forma de pago:</strong> {{payment_method}}</p>
|
||||
</div>
|
||||
{{else}}
|
||||
<!-- Empty payment method-->
|
||||
{{/if}}
|
||||
{{#if notes}}
|
||||
<div class="pt-4">
|
||||
<p class="text-sm"><strong>Notas:</strong> {{notes}} </p>
|
||||
</div>
|
||||
{{else}}
|
||||
<!-- Empty notes-->
|
||||
{{/if}}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="relative pt-10 grow">
|
||||
<table class="table-header min-w-full bg-transparent">
|
||||
<table class=" table-header min-w-full bg-transparent">
|
||||
<tbody>
|
||||
{{#if discount_percentage}}
|
||||
<tr>
|
||||
@ -235,6 +244,7 @@
|
||||
</section>
|
||||
</main>
|
||||
|
||||
|
||||
<footer id="footer" class="mt-4">
|
||||
<aside>
|
||||
<p class="text-center">Insc. en el Reg. Merc. de Madrid, Tomo 20.073, Libro 0, Folio 141, Sección 8, Hoja M-354212
|
||||
|
||||
@ -111,18 +111,17 @@
|
||||
<body>
|
||||
|
||||
<header id="header">
|
||||
<aside class="flex items-start mb-4 w-full bg-red-600">
|
||||
<aside class="flex items-start mb-4 w-full ">
|
||||
<!-- Bloque IZQUIERDO: imagen arriba + texto abajo, alineado a la izquierda -->
|
||||
<div class="flex flex-col 70% items-start text-left bg-green-700">
|
||||
<div class="flex flex-col items-start text-left" style="flex:0 0 70%;">
|
||||
<img src="https://rodax-software.com/images/logo1.jpg" alt="Logo Rodax" class="block h-14 w-auto mb-1" />
|
||||
<div class="flex w-full">
|
||||
<div class="p-1 ">
|
||||
<h3 class="text-2xl font-normal">PROFORMA</h3>
|
||||
<p>Nº:<strong> {{invoice_number}}</strong></p>
|
||||
<p><span>Fecha:<strong> {{invoice_date}}</strong></p>
|
||||
<p>Página <span class="pageNumber"></span> de <span class="totalPages"></span></p>
|
||||
</div>
|
||||
<div class="p-1 ml-9">
|
||||
<div class="p-1 ml-28">
|
||||
<h2 class="font-semibold uppercase mb-1">{{recipient.name}}</h2>
|
||||
<p>{{recipient.tin}}</p>
|
||||
<p>{{recipient.street}}</p>
|
||||
@ -132,10 +131,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Bloque DERECHO: logo2 arriba y texto DEBAJO -->
|
||||
<div class="ml-auto flex flex-col items-end text-right">
|
||||
<div class="ml-auto flex flex-col items-end text-right h-full">
|
||||
<img src="https://rodax-software.com/images/logo2.jpg" alt="Logo secundario"
|
||||
class="block h-5 w-auto md:h-8 mb-1" />
|
||||
<div class="not-italic text-xs leading-tight">
|
||||
<div class="not-italic text-xs leading-tight h-full">
|
||||
<p>Telf: 91 785 02 47 / 686 62 10 59</p>
|
||||
<p><a href="mailto:info@rodax-software.com" class="hover:underline">info@rodax-software.com</a></p>
|
||||
<p><a href="https://www.rodax-software.com" target="_blank" rel="noopener"
|
||||
@ -146,6 +145,7 @@
|
||||
</header>
|
||||
|
||||
<main id="main">
|
||||
<h1>FACTURA PROFORMA</h1>
|
||||
<section id="details" class="border-b border-black ">
|
||||
<div class="relative pt-0 border-b border-black">
|
||||
<!-- Badge TOTAL decorado con imagen -->
|
||||
@ -186,17 +186,26 @@
|
||||
|
||||
<section id="resume" class="flex items-center justify-between pb-4 mb-4">
|
||||
|
||||
<div class="grow">
|
||||
<div class="pt-4">
|
||||
<p class="text-sm"><strong>Forma de pago:</strong> {{payment_method}}</p>
|
||||
<div class="grow relative pt-10 self-start">
|
||||
{{#if payment_method}}
|
||||
<div class="">
|
||||
<p class=" text-sm"><strong>Forma de pago:</strong> {{payment_method}}</p>
|
||||
</div>
|
||||
{{else}}
|
||||
<!-- Empty payment method-->
|
||||
{{/if}}
|
||||
{{#if notes}}
|
||||
<div class="pt-4">
|
||||
<p class="text-sm"><strong>Notas:</strong> {{notes}} </p>
|
||||
</div>
|
||||
{{else}}
|
||||
<!-- Empty notes-->
|
||||
{{/if}}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="relative pt-10 grow">
|
||||
<table class="table-header min-w-full bg-transparent">
|
||||
<table class=" table-header min-w-full bg-transparent">
|
||||
<tbody>
|
||||
{{#if discount_percentage}}
|
||||
<tr>
|
||||
@ -238,9 +247,10 @@
|
||||
|
||||
<footer id="footer" class="mt-4">
|
||||
<aside>
|
||||
<p class="text-center">Insc. en el Reg. Merc. de Madrid, Tomo 20.073, Libro 0, Folio 141, Sección 8, Hoja M-354212
|
||||
| CIF: B83999441 -
|
||||
Rodax Software S.L.</p>
|
||||
<p class="text-left"><strong>Factura Proforma.</strong>
|
||||
Este documento es de carácter informativo y no tiene validez contable ni fiscal. Contiene precios y condiciones
|
||||
de venta sujetos a confirmación del cliente. Solo adquirirá validez como factura definitiva una vez aceptados
|
||||
dichos términos.</p>
|
||||
</aside>
|
||||
</footer>
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ import {
|
||||
UtcDate,
|
||||
} from "@repo/rdx-ddd";
|
||||
import { Maybe, Result } from "@repo/rdx-utils";
|
||||
import { CustomerInvoiceItems } from "../entities";
|
||||
import { CustomerInvoiceItems, InvoicePaymentMethod } from "../entities";
|
||||
import { InvoiceTaxes } from "../entities/invoice-taxes";
|
||||
import {
|
||||
CustomerInvoiceNumber,
|
||||
@ -41,10 +41,15 @@ export interface CustomerInvoiceProps {
|
||||
taxes: InvoiceTaxes;
|
||||
items: CustomerInvoiceItems;
|
||||
|
||||
paymentMethod: Maybe<InvoicePaymentMethod>;
|
||||
|
||||
discountPercentage: Percentage;
|
||||
}
|
||||
|
||||
export interface ICustomerInvoice {
|
||||
hasRecipient: boolean;
|
||||
hasPaymentMethod: boolean;
|
||||
|
||||
getSubtotalAmount(): InvoiceAmount;
|
||||
getDiscountAmount(): InvoiceAmount;
|
||||
|
||||
@ -140,6 +145,10 @@ export class CustomerInvoice
|
||||
return this.props.recipient;
|
||||
}
|
||||
|
||||
public get paymentMethod(): Maybe<InvoicePaymentMethod> {
|
||||
return this.props.paymentMethod;
|
||||
}
|
||||
|
||||
public get languageCode(): LanguageCode {
|
||||
return this.props.languageCode;
|
||||
}
|
||||
@ -165,6 +174,10 @@ export class CustomerInvoice
|
||||
return this.recipient.isSome();
|
||||
}
|
||||
|
||||
public get hasPaymentMethod() {
|
||||
return this.paymentMethod.isSome();
|
||||
}
|
||||
|
||||
private _getDiscountAmount(subtotalAmount: InvoiceAmount): InvoiceAmount {
|
||||
return subtotalAmount.percentage(this.discountPercentage);
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
export * from "./customer-invoice-items";
|
||||
export * from "./invoice-payment-method";
|
||||
export * from "./invoice-taxes";
|
||||
export * from "./item-taxes";
|
||||
|
||||
@ -0,0 +1 @@
|
||||
export * from "./invoice-payment-method";
|
||||
@ -0,0 +1,32 @@
|
||||
import { DomainEntity, UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
|
||||
export interface InvoicePaymentMethodProps {
|
||||
paymentDescription: string;
|
||||
}
|
||||
|
||||
export class InvoicePaymentMethod extends DomainEntity<InvoicePaymentMethodProps> {
|
||||
public static create(
|
||||
props: InvoicePaymentMethodProps,
|
||||
id?: UniqueID
|
||||
): Result<InvoicePaymentMethod, Error> {
|
||||
const item = new InvoicePaymentMethod(props, id);
|
||||
|
||||
return Result.ok(item);
|
||||
}
|
||||
|
||||
get paymentDescription(): string {
|
||||
return this.props.paymentDescription;
|
||||
}
|
||||
|
||||
getProps(): InvoicePaymentMethodProps {
|
||||
return this.props;
|
||||
}
|
||||
|
||||
toObjectString() {
|
||||
return {
|
||||
id: String(this.id),
|
||||
payment_description: String(this.paymentDescription),
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -11,7 +11,7 @@ import {
|
||||
extractOrPushError,
|
||||
maybeFromNullableVO,
|
||||
} from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { Maybe, Result } from "@repo/rdx-utils";
|
||||
import {
|
||||
CustomerInvoice,
|
||||
CustomerInvoiceItems,
|
||||
@ -19,6 +19,7 @@ import {
|
||||
CustomerInvoiceProps,
|
||||
CustomerInvoiceSerie,
|
||||
CustomerInvoiceStatus,
|
||||
InvoicePaymentMethod,
|
||||
} from "../../../domain";
|
||||
import { InvoiceTaxes } from "../../../domain/entities/invoice-taxes";
|
||||
import { CustomerInvoiceCreationAttributes, CustomerInvoiceModel } from "../../sequelize";
|
||||
@ -53,7 +54,50 @@ export class CustomerInvoiceDomainMapper
|
||||
this._taxesMapper = new TaxesFullMapper(params);
|
||||
}
|
||||
|
||||
private mapAttributesToDomain(source: CustomerInvoiceModel, params?: MapperParamsType) {
|
||||
private _mapPaymentMethodToDomain(source: CustomerInvoiceModel, params?: MapperParamsType) {
|
||||
const { errors } = params as {
|
||||
errors: ValidationErrorDetail[];
|
||||
};
|
||||
|
||||
const paymentId = extractOrPushError(
|
||||
maybeFromNullableVO(source.payment_method_id, (value) => UniqueID.create(value)),
|
||||
"payment_method_id",
|
||||
errors
|
||||
);
|
||||
|
||||
const paymentDescription = extractOrPushError(
|
||||
maybeFromNullableVO(source.payment_method_description, (value) => Result.ok(String(value))),
|
||||
"payment_method_description",
|
||||
errors
|
||||
);
|
||||
|
||||
if (errors.length > 0) {
|
||||
return Result.fail(new ValidationErrorCollection("Invoice payment mapping failed", errors));
|
||||
}
|
||||
|
||||
if (paymentDescription!.isNone() || paymentId!.isNone()) {
|
||||
return Result.ok(Maybe.none<InvoicePaymentMethod>());
|
||||
}
|
||||
|
||||
const paymentResult = InvoicePaymentMethod.create(
|
||||
{
|
||||
paymentDescription: paymentDescription?.getOrUndefined()!,
|
||||
},
|
||||
paymentId?.getOrUndefined()!
|
||||
);
|
||||
|
||||
if (paymentResult.isFailure) {
|
||||
return Result.fail(
|
||||
new ValidationErrorCollection("Invoice payment method creation failed", [
|
||||
{ path: "paymentMethod", message: paymentResult.error.message },
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
return Result.ok(Maybe.some<InvoicePaymentMethod>(paymentResult.data));
|
||||
}
|
||||
|
||||
private _mapAttributesToDomain(source: CustomerInvoiceModel, params?: MapperParamsType) {
|
||||
const { errors } = params as {
|
||||
errors: ValidationErrorDetail[];
|
||||
};
|
||||
@ -151,7 +195,7 @@ export class CustomerInvoiceDomainMapper
|
||||
const errors: ValidationErrorDetail[] = [];
|
||||
|
||||
// 1) Valores escalares (atributos generales)
|
||||
const attributes = this.mapAttributesToDomain(source, { errors, ...params });
|
||||
const attributes = this._mapAttributesToDomain(source, { errors, ...params });
|
||||
|
||||
// 2) Recipient (snapshot en la factura o include)
|
||||
const recipientResult = this._recipientMapper.mapToDomain(source, {
|
||||
@ -204,6 +248,16 @@ export class CustomerInvoiceDomainMapper
|
||||
});
|
||||
}
|
||||
|
||||
// Payment method
|
||||
const paymentMethodResult = this._mapPaymentMethodToDomain(source, { errors, ...params });
|
||||
|
||||
if (paymentMethodResult.isFailure) {
|
||||
errors.push({
|
||||
path: "paymentMethod",
|
||||
message: paymentMethodResult.error.message,
|
||||
});
|
||||
}
|
||||
|
||||
// 5) Si hubo errores de mapeo, devolvemos colección de validación
|
||||
if (errors.length > 0) {
|
||||
return Result.fail(new ValidationErrorCollection("Customer mapping failed", errors));
|
||||
@ -212,6 +266,7 @@ export class CustomerInvoiceDomainMapper
|
||||
// 6) Construcción del agregado (Dominio)
|
||||
|
||||
const recipient = recipientResult.data;
|
||||
const paymentMethod = paymentMethodResult.data;
|
||||
|
||||
const taxes = InvoiceTaxes.create({
|
||||
items: taxesResults.data.getAll(),
|
||||
@ -243,6 +298,8 @@ export class CustomerInvoiceDomainMapper
|
||||
|
||||
discountPercentage: attributes.discountPercentage!,
|
||||
|
||||
paymentMethod: paymentMethod!,
|
||||
|
||||
taxes: taxes,
|
||||
items,
|
||||
};
|
||||
|
||||
@ -78,6 +78,10 @@ export class CustomerInvoiceModel extends Model<
|
||||
declare customer_postal_code: string;
|
||||
declare customer_country: string;
|
||||
|
||||
// Método de pago
|
||||
declare payment_method_id: string;
|
||||
declare payment_method_description: string;
|
||||
|
||||
// Relaciones
|
||||
declare items: NonAttribute<CustomerInvoiceItemModel[]>;
|
||||
declare taxes: NonAttribute<CustomerInvoiceTaxModel[]>;
|
||||
@ -185,6 +189,18 @@ export default (database: Sequelize) => {
|
||||
defaultValue: null,
|
||||
},
|
||||
|
||||
payment_method_id: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
},
|
||||
|
||||
payment_method_description: {
|
||||
type: new DataTypes.STRING(),
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
},
|
||||
|
||||
subtotal_amount_value: {
|
||||
type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes
|
||||
allowNull: false,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user