Característica: Mejora de los modelos de facturas proforma y emitidas con atributos de serie de documentos
- Se han añadido `document_series_id`, `invoice_series_code` e `invoice_reference` a los modelos y instantáneas de facturas emitidas. - Se han introducido `proforma_series_code` y `proforma_number`, y se han actualizado las referencias en los modelos y instantáneas de las facturas proforma. - Se han actualizado los esquemas de la base de datos y los scripts SQL para dar cabida a los nuevos campos y garantizar la integridad de los datos. - Se ha elaborado la documentación correspondiente a las nuevas series de documentos «contrato de instantánea» y «contrato de serie de facturas emitidas». - Se han implementado scripts SQL de rellenado para completar los registros existentes con los nuevos campos.
This commit is contained in:
parent
1f5bd18665
commit
ee040b8335
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
File diff suppressed because one or more lines are too long
31
docs/customer-invoices/document-series-snapshot-contract.md
Normal file
31
docs/customer-invoices/document-series-snapshot-contract.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Document Series Snapshot Contract
|
||||
|
||||
## Regla base
|
||||
|
||||
- `document-series` asigna numero y referencia.
|
||||
- `proformas` e `issued_invoices` persisten un snapshot inmutable del resultado.
|
||||
- las referencias visibles no se recalculan en lecturas normales.
|
||||
|
||||
## Snapshot persistido
|
||||
|
||||
### Proformas
|
||||
|
||||
- `document_series_id`
|
||||
- `proforma_series_code`
|
||||
- `proforma_number`
|
||||
- `proforma_reference`
|
||||
|
||||
### Issued invoices
|
||||
|
||||
- `document_series_id`
|
||||
- `invoice_series_code`
|
||||
- `invoice_number`
|
||||
- `invoice_reference`
|
||||
|
||||
## Motivo
|
||||
|
||||
- `document_series_id` conserva trazabilidad tecnica exacta.
|
||||
- `series_code` conserva un snapshot legible e historico.
|
||||
- `number` conserva el valor estructurado y consultable.
|
||||
- `reference` conserva el valor visible/legal final.
|
||||
- una factura emitida es historica e inalterable aunque luego cambie la configuracion viva de `document_series`.
|
||||
42
docs/customer-invoices/issued-invoice-series-contract.md
Normal file
42
docs/customer-invoices/issued-invoice-series-contract.md
Normal file
@ -0,0 +1,42 @@
|
||||
# Issued Invoice Series Contract
|
||||
|
||||
## Objetivo
|
||||
|
||||
Definir el contrato backend para la numeracion documental de `issued_invoices`.
|
||||
|
||||
## Snapshot persistido
|
||||
|
||||
Una factura emitida debe persistir estos cuatro datos de numeracion:
|
||||
|
||||
- `document_series_id`
|
||||
- `invoice_series_code`
|
||||
- `invoice_number`
|
||||
- `invoice_reference`
|
||||
|
||||
## Regla operativa
|
||||
|
||||
- `document-series` es la unica fuente de verdad para asignar numeracion de `document_type = issued_invoice`.
|
||||
- `customer-invoices` no recompone manualmente la referencia final si `document-series` ya la devuelve.
|
||||
- `invoice_reference` se calcula en el momento de emision.
|
||||
- `invoice_reference` se persiste como snapshot documental inmutable.
|
||||
- `invoice_reference` no se recalcula despues aunque cambie la configuracion de `document_series`.
|
||||
|
||||
## Emision desde proforma
|
||||
|
||||
- si `target_invoice_series_code` tiene valor, se usa como `seriesCode` de `issued_invoice`
|
||||
- si `target_invoice_series_code` es `NULL`, `document-series` resuelve la serie default activa
|
||||
- la respuesta de `assignNextNumber(...)` debe aportar `series_id`, `series_code`, `number` y `reference`
|
||||
- `issued_invoices` debe persistir `document_series_id`, `invoice_series_code`, `invoice_number` e `invoice_reference`
|
||||
|
||||
## Semantica de campos
|
||||
|
||||
- `document_series_id`: id tecnico de la serie exacta usada al emitir para trazabilidad y backoffice
|
||||
- `invoice_number`: numero secuencial dentro de la serie
|
||||
- `invoice_reference`: referencia final visible/legal compuesta por la serie documental
|
||||
- `reference`: referencia comercial libre del documento, si aplica; no sustituye a `invoice_reference`
|
||||
|
||||
## Regla de no contaminacion
|
||||
|
||||
- `proforma_reference` nunca se reutiliza como `invoice_reference`
|
||||
- `target_invoice_series_code` solo selecciona la serie futura y no es en si mismo la referencia final
|
||||
- no se usa `MAX(invoice_number)` para recomponer numeracion
|
||||
@ -9,6 +9,7 @@ Normalizar el contrato publico de proformas para separar definitivamente la seri
|
||||
En proformas:
|
||||
|
||||
- `document_series_id` identifica la serie documental propia de la proforma
|
||||
- `proforma_series_code` guarda el codigo snapshot de la serie propia de la proforma
|
||||
- `proforma_number` guarda el numero propio de la proforma
|
||||
- `proforma_reference` guarda la referencia visible de la proforma, por ejemplo `PF-0139`
|
||||
- `proforma_series_code` es el codigo funcional que se usa solo en create para elegir una serie de `document_type = proforma`
|
||||
@ -92,7 +93,7 @@ Si el request informa `proforma_series_code`:
|
||||
|
||||
- debe corresponder a una serie activa de `document_type = proforma`
|
||||
- solo se usa para numerar la proforma en create
|
||||
- despues queda congelado en `document_series_id`, `proforma_number` y `proforma_reference`
|
||||
- despues queda congelado en `document_series_id`, `proforma_series_code`, `proforma_number` y `proforma_reference`
|
||||
|
||||
## Retirada futura de `series`
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@ Preparar el esquema fisico para separar:
|
||||
- `target_invoice_series_code` es opcional y solo puede apuntar a una serie de `issued_invoice`.
|
||||
- una serie `PF` o cualquier otra serie de `document_type = proforma` nunca debe persistirse en `target_invoice_series_code`.
|
||||
- si `target_invoice_series_code` queda `NULL`, la emision de la factura usara la serie default activa de `issued_invoice`.
|
||||
- `issued_invoices` usa `invoice_series_code`, `invoice_number`, `invoice_date` y `source_proforma_id`.
|
||||
- `issued_invoices` usa `invoice_series_code`, `invoice_number`, `invoice_reference`, `invoice_date` y `source_proforma_id`.
|
||||
- `proformas` no guarda `issued_invoice_id`; la relacion se resuelve con `issued_invoices.source_proforma_id`.
|
||||
- Los impuestos del esquema actual son por documento, no por linea: `proforma_taxes` y `issued_invoice_taxes`.
|
||||
- `payment_method` y `payment_term` en `issued_invoices` son snapshot historico, no estado vivo de cobro.
|
||||
@ -119,6 +119,8 @@ Preparar el esquema fisico para separar:
|
||||
- al emitir una proforma, la factura definitiva se numera con `document_type = issued_invoice`
|
||||
- si la proforma trae `target_invoice_series_code`, se usa como `seriesCode`
|
||||
- si `target_invoice_series_code` es `NULL`, `document-series` resuelve la serie default activa de `issued_invoice`
|
||||
- la referencia final devuelta por `document-series` se persiste en `issued_invoices.invoice_reference`
|
||||
- `invoice_reference` es snapshot documental y no se recalcula despues
|
||||
- `proforma_series_code` es un input de create para `document_type = proforma` y no vuelve a ser editable despues
|
||||
|
||||
## Estado Fase 2B
|
||||
@ -218,6 +220,7 @@ Preparar el esquema fisico para separar:
|
||||
- `source_proforma_id`
|
||||
- `invoice_series_code`
|
||||
- `invoice_number`
|
||||
- `invoice_reference`
|
||||
- `invoice_date`
|
||||
- `operation_date`
|
||||
- `reference`
|
||||
|
||||
@ -8,6 +8,8 @@ Este directorio mezcla SQL vigentes de soporte con SQL historicos/transicionales
|
||||
|
||||
- `add-proforma-document-series-columns.sql`
|
||||
- `add-proforma-tax-config-columns.sql`
|
||||
- `add-issued-invoice-reference.sql`
|
||||
- `normalize-document-series-snapshots.sql`
|
||||
- `fix-proforma-series-semantics.sql`
|
||||
- `validate-proforma-tax-config.sql`
|
||||
- `validate-proforma-soft-delete.sql`
|
||||
@ -24,8 +26,9 @@ Estos archivos no deben tratarse como el camino normal de entornos nuevos salvo
|
||||
1. Verificar que la BD objetivo es inequívocamente de desarrollo.
|
||||
2. Hacer backup o confirmar que los datos son descartables.
|
||||
3. Ejecutar el DDL vigente que falte para `proformas`.
|
||||
4. Ejecutar las validaciones SQL vigentes.
|
||||
5. Levantar backend V2 y validar flujos funcionales.
|
||||
4. Ejecutar `normalize-document-series-snapshots.sql` para completar snapshots y validaciones de seriado.
|
||||
5. Ejecutar las validaciones SQL vigentes.
|
||||
6. Levantar backend V2 y validar flujos funcionales.
|
||||
|
||||
## Propiedades de los scripts históricos de split
|
||||
|
||||
|
||||
53
docs/customer-invoices/sql/add-issued-invoice-reference.sql
Normal file
53
docs/customer-invoices/sql/add-issued-invoice-reference.sql
Normal file
@ -0,0 +1,53 @@
|
||||
-- Estado: vigente / manual.
|
||||
-- Objetivo:
|
||||
-- 1. Anadir `issued_invoices.invoice_reference` si no existe.
|
||||
-- 2. Backfill conservador para facturas emitidas existentes.
|
||||
-- 3. Validar que no quedan filas sin snapshot documental.
|
||||
-- 4. Endurecer a NOT NULL cuando la validacion sea correcta.
|
||||
--
|
||||
-- No ejecutar automaticamente desde backend.
|
||||
-- Revisar antes el nombre real de la tabla `document_series` y sus columnas
|
||||
-- `prefix`, `padding`, `suffix` en el entorno objetivo.
|
||||
|
||||
START TRANSACTION;
|
||||
|
||||
ALTER TABLE issued_invoices
|
||||
ADD COLUMN IF NOT EXISTS invoice_reference VARCHAR(64) NULL AFTER invoice_number;
|
||||
|
||||
UPDATE issued_invoices ii
|
||||
JOIN document_series ds
|
||||
ON ds.company_id = ii.company_id
|
||||
AND ds.code = ii.invoice_series_code
|
||||
AND ds.document_type = 'issued_invoice'
|
||||
SET ii.invoice_reference = CONCAT(
|
||||
COALESCE(ds.prefix, ''),
|
||||
LPAD(CAST(ii.invoice_number AS CHAR), ds.padding, '0'),
|
||||
COALESCE(ds.suffix, '')
|
||||
)
|
||||
WHERE ii.invoice_reference IS NULL;
|
||||
|
||||
SELECT id, source_proforma_id, invoice_series_code, invoice_number, invoice_reference
|
||||
FROM issued_invoices
|
||||
WHERE invoice_reference IS NULL;
|
||||
|
||||
SELECT
|
||||
ii.id,
|
||||
ii.invoice_series_code,
|
||||
ii.invoice_number,
|
||||
ii.invoice_reference,
|
||||
ds.prefix,
|
||||
ds.padding,
|
||||
ds.suffix
|
||||
FROM issued_invoices ii
|
||||
JOIN document_series ds
|
||||
ON ds.company_id = ii.company_id
|
||||
AND ds.code = ii.invoice_series_code
|
||||
AND ds.document_type = 'issued_invoice'
|
||||
ORDER BY ii.created_at DESC
|
||||
LIMIT 20;
|
||||
|
||||
-- Ejecutar solo cuando la consulta anterior no devuelva filas.
|
||||
ALTER TABLE issued_invoices
|
||||
MODIFY COLUMN invoice_reference VARCHAR(64) NOT NULL;
|
||||
|
||||
COMMIT;
|
||||
@ -170,6 +170,7 @@ CREATE TABLE IF NOT EXISTS issued_invoices (
|
||||
source_proforma_id CHAR(36) NULL,
|
||||
invoice_series_code VARCHAR(10) NOT NULL,
|
||||
invoice_number VARCHAR(12) NOT NULL,
|
||||
invoice_reference VARCHAR(64) NOT NULL,
|
||||
invoice_date DATE NOT NULL,
|
||||
operation_date DATE NULL,
|
||||
reference VARCHAR(255) NULL,
|
||||
|
||||
@ -0,0 +1,85 @@
|
||||
-- Normaliza snapshots documentales en `proformas` e `issued_invoices`.
|
||||
-- Fases:
|
||||
-- 1. DDL conservadora.
|
||||
-- 2. Backfill de snapshots.
|
||||
-- 3. Diagnostico/validacion.
|
||||
-- 4. Endurecimiento opcional cuando no queden nulos.
|
||||
|
||||
ALTER TABLE proformas
|
||||
ADD COLUMN IF NOT EXISTS proforma_series_code VARCHAR(10) NULL AFTER document_series_id;
|
||||
|
||||
ALTER TABLE issued_invoices
|
||||
ADD COLUMN IF NOT EXISTS document_series_id CHAR(36) NULL AFTER source_proforma_id,
|
||||
ADD COLUMN IF NOT EXISTS invoice_reference VARCHAR(64) NULL AFTER invoice_number;
|
||||
|
||||
UPDATE proformas p
|
||||
JOIN document_series ds ON ds.id = p.document_series_id
|
||||
SET p.proforma_series_code = ds.code
|
||||
WHERE p.proforma_series_code IS NULL;
|
||||
|
||||
SELECT id, document_series_id, proforma_series_code, proforma_number, proforma_reference
|
||||
FROM proformas
|
||||
WHERE proforma_series_code IS NULL;
|
||||
|
||||
SELECT
|
||||
ds.company_id,
|
||||
ds.document_type,
|
||||
ds.code,
|
||||
COUNT(*) AS series_count
|
||||
FROM document_series ds
|
||||
WHERE ds.document_type = 'issued_invoice'
|
||||
GROUP BY ds.company_id, ds.document_type, ds.code
|
||||
HAVING COUNT(*) > 1;
|
||||
|
||||
UPDATE issued_invoices ii
|
||||
JOIN document_series ds
|
||||
ON ds.company_id = ii.company_id
|
||||
AND ds.document_type = 'issued_invoice'
|
||||
AND ds.code = ii.invoice_series_code
|
||||
SET ii.document_series_id = ds.id
|
||||
WHERE ii.document_series_id IS NULL;
|
||||
|
||||
SELECT id, invoice_series_code, invoice_number
|
||||
FROM issued_invoices
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 20;
|
||||
|
||||
UPDATE issued_invoices ii
|
||||
JOIN document_series ds ON ds.id = ii.document_series_id
|
||||
SET ii.invoice_reference = CONCAT(
|
||||
COALESCE(ds.prefix, ''),
|
||||
LPAD(CAST(ii.invoice_number AS UNSIGNED), ds.padding, '0'),
|
||||
COALESCE(ds.suffix, '')
|
||||
)
|
||||
WHERE ii.invoice_reference IS NULL;
|
||||
|
||||
SELECT id, source_proforma_id, document_series_id, invoice_series_code, invoice_number, invoice_reference
|
||||
FROM issued_invoices
|
||||
WHERE document_series_id IS NULL
|
||||
OR invoice_reference IS NULL;
|
||||
|
||||
SELECT company_id, proforma_series_code, proforma_number, COUNT(*) AS c
|
||||
FROM proformas
|
||||
WHERE deleted_at IS NULL
|
||||
GROUP BY company_id, proforma_series_code, proforma_number
|
||||
HAVING c > 1;
|
||||
|
||||
SELECT company_id, invoice_series_code, invoice_number, COUNT(*) AS c
|
||||
FROM issued_invoices
|
||||
WHERE deleted_at IS NULL
|
||||
GROUP BY company_id, invoice_series_code, invoice_number
|
||||
HAVING c > 1;
|
||||
|
||||
CREATE INDEX idx_proformas_document_series_id
|
||||
ON proformas (document_series_id);
|
||||
|
||||
CREATE INDEX idx_issued_invoices_document_series_id
|
||||
ON issued_invoices (document_series_id);
|
||||
|
||||
-- Ejecutar solo cuando las validaciones anteriores devuelvan 0 filas pendientes.
|
||||
-- ALTER TABLE proformas
|
||||
-- MODIFY proforma_series_code VARCHAR(10) NOT NULL;
|
||||
--
|
||||
-- ALTER TABLE issued_invoices
|
||||
-- MODIFY document_series_id CHAR(36) NOT NULL,
|
||||
-- MODIFY invoice_reference VARCHAR(64) NOT NULL;
|
||||
@ -52,8 +52,11 @@ La asignación usa transacción obligatoria y bloqueo de fila con `LOCK.UPDATE`
|
||||
En V1:
|
||||
|
||||
- `issued-invoices` delega la asignacion de numero en `document-series`
|
||||
- `document-series.assignNextNumber(...)` devuelve `series_id`, `series_code`, `number` y `reference`
|
||||
- `proformas` delega la asignacion de referencia en `document-series`
|
||||
- `proformas` persiste `document_series_id` y `proforma_number` como snapshot tecnico adicional a `proforma_reference`
|
||||
- `issued-invoices` persiste `invoice_reference` como snapshot documental inmutable adicional a `invoice_number`
|
||||
- `issued-invoices.invoice_reference` no se recalcula si luego cambia `prefix`, `suffix` o `padding` de la serie
|
||||
- `proformas.document_series_id` identifica la serie documental usada para numerar la proforma
|
||||
- `proformas.proforma_number` guarda el numero propio de la proforma
|
||||
- `proformas.proforma_reference` guarda la referencia visible de la proforma
|
||||
|
||||
@ -5,7 +5,7 @@ import type { InvoiceNumber, InvoiceSerie } from "../../../domain";
|
||||
|
||||
export interface InvoiceSeriesAssignment {
|
||||
invoiceNumber: InvoiceNumber;
|
||||
formattedNumber: string;
|
||||
invoiceReference: string;
|
||||
invoiceSeriesId: string;
|
||||
invoiceSeriesCode: InvoiceSerie;
|
||||
}
|
||||
|
||||
@ -14,7 +14,10 @@ export type IssuedInvoiceSummary = {
|
||||
id: UniqueID;
|
||||
companyId: UniqueID;
|
||||
|
||||
documentSeriesId: Maybe<string>;
|
||||
invoiceSeriesCode: Maybe<InvoiceSerie>;
|
||||
invoiceNumber: InvoiceNumber;
|
||||
invoiceReference: string;
|
||||
status: InvoiceStatus;
|
||||
series: Maybe<InvoiceSerie>;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { Maybe, Result } from "@repo/rdx-utils";
|
||||
|
||||
import { IssuedInvoice } from "../../../domain";
|
||||
import type { IInvoiceSeriesNumberAssigner } from "../../invoice-series";
|
||||
@ -45,13 +45,13 @@ export class IssuedInvoiceCreator implements IIssuedInvoiceCreator {
|
||||
return Result.fail(numberResult.error);
|
||||
}
|
||||
|
||||
const invoiceNumber = numberResult.data.invoiceNumber;
|
||||
|
||||
const invoiceResult = IssuedInvoice.create(
|
||||
{
|
||||
...props,
|
||||
documentSeriesId: Maybe.some(numberResult.data.invoiceSeriesId),
|
||||
series: numberResult.data.invoiceSeriesCode,
|
||||
invoiceNumber,
|
||||
invoiceNumber: numberResult.data.invoiceNumber,
|
||||
invoiceReference: numberResult.data.invoiceReference,
|
||||
companyId,
|
||||
},
|
||||
id
|
||||
|
||||
@ -34,8 +34,7 @@ export class IssuedInvoiceDocumentMetadataFactory
|
||||
}
|
||||
|
||||
private buildFilename(snapshot: IIssuedInvoiceReportSnapshot): string {
|
||||
// Ejemplo: factura-F2024-000123-FULANITO.pdf
|
||||
return `factura-${snapshot.series}${snapshot.invoice_number}-${snapshot.recipient.name}.pdf`;
|
||||
return `factura-${snapshot.invoice_reference}-${snapshot.recipient.name}.pdf`;
|
||||
}
|
||||
|
||||
private buildCacheKey(snapshot: IIssuedInvoiceReportSnapshot): string {
|
||||
@ -43,8 +42,7 @@ export class IssuedInvoiceDocumentMetadataFactory
|
||||
return [
|
||||
"issued-invoice",
|
||||
snapshot.company_id,
|
||||
snapshot.series,
|
||||
snapshot.invoice_number,
|
||||
snapshot.invoice_reference,
|
||||
"v1",
|
||||
].join(":");
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type { IDocumentProperties, IDocumentPropertiesFactory } from "@erp/core/api";
|
||||
|
||||
import type { IssuedInvoiceReportSnapshot } from "../models";
|
||||
import type { IIssuedInvoiceReportSnapshot } from "../snapshot-builders";
|
||||
|
||||
/**
|
||||
* Construye los metadatos del documento PDF de una factura emitida.
|
||||
@ -10,11 +10,11 @@ import type { IssuedInvoiceReportSnapshot } from "../models";
|
||||
* - Sin IO
|
||||
*/
|
||||
export class IssuedInvoiceDocumentPropertiesFactory
|
||||
implements IDocumentPropertiesFactory<IssuedInvoiceReportSnapshot>
|
||||
implements IDocumentPropertiesFactory<IIssuedInvoiceReportSnapshot>
|
||||
{
|
||||
build(snapshot: IssuedInvoiceReportSnapshot): IDocumentProperties {
|
||||
build(snapshot: IIssuedInvoiceReportSnapshot): IDocumentProperties {
|
||||
return {
|
||||
title: snapshot.reference,
|
||||
title: snapshot.invoice_reference,
|
||||
subject: "issued-invoice",
|
||||
author: snapshot.company_slug,
|
||||
creator: "FactuGES ERP",
|
||||
|
||||
@ -19,7 +19,7 @@ import type { ProformaIssueReadModel } from "../models";
|
||||
|
||||
export type ProformaToIssuedInvoiceCreateProps = Omit<
|
||||
IIssuedInvoiceCreateProps,
|
||||
"invoiceNumber" | "series"
|
||||
"documentSeriesId" | "invoiceNumber" | "invoiceReference" | "series"
|
||||
> & {
|
||||
series: Maybe<InvoiceSerie>;
|
||||
};
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import type { ISnapshotBuilder } from "@erp/core/api";
|
||||
import { maybeToNullable } from "@repo/rdx-ddd";
|
||||
import { Maybe } from "@repo/rdx-utils";
|
||||
|
||||
import type { IssuedInvoice } from "../../../../domain";
|
||||
|
||||
@ -41,7 +42,10 @@ export class IssuedInvoiceFullSnapshotBuilder implements IIssuedInvoiceFullSnaps
|
||||
company_id: invoice.companyId.toString(),
|
||||
is_proforma: false,
|
||||
|
||||
document_series_id: maybeToNullable(invoice.documentSeriesId, (value) => value),
|
||||
invoice_series_code: maybeToNullable(Maybe.some(invoice.series), (value) => value.toString()),
|
||||
invoice_number: invoice.invoiceNumber.toString(),
|
||||
invoice_reference: invoice.invoiceReference,
|
||||
status: invoice.status.toPrimitive(),
|
||||
series: invoice.series.toString(),
|
||||
|
||||
|
||||
@ -19,7 +19,10 @@ export interface IIssuedInvoiceFullSnapshot {
|
||||
company_id: string;
|
||||
is_proforma: boolean;
|
||||
|
||||
document_series_id: string | null;
|
||||
invoice_series_code: string | null;
|
||||
invoice_number: string;
|
||||
invoice_reference: string;
|
||||
status: string;
|
||||
series: string;
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ export class IssuedInvoiceReportItemSnapshotBuilder
|
||||
items: IIssuedInvoiceItemFullSnapshot[],
|
||||
params?: ISnapshotBuilderParams
|
||||
): IIssuedInvoiceReportItemSnapshot[] {
|
||||
const locale = params?.locale as string;
|
||||
const locale = (params as { locale?: string } | undefined)?.locale ?? "es";
|
||||
|
||||
const moneyOptions = {
|
||||
hideZeros: true,
|
||||
@ -23,7 +23,7 @@ export class IssuedInvoiceReportItemSnapshotBuilder
|
||||
};
|
||||
|
||||
return items.map((item) => ({
|
||||
description: item.description,
|
||||
description: item.description ?? "",
|
||||
quantity: QuantityDTOHelper.format(item.quantity, locale, { minimumFractionDigits: 0 }),
|
||||
unit_amount: MoneyDTOHelper.format(item.unit_amount, locale, moneyOptions),
|
||||
subtotal_amount: MoneyDTOHelper.format(item.subtotal_amount, locale, moneyOptions),
|
||||
|
||||
@ -21,7 +21,7 @@ export class IssuedInvoiceReportSnapshotBuilder implements IIssuedInvoiceReportS
|
||||
snapshot: IIssuedInvoiceFullSnapshot,
|
||||
params?: ISnapshotBuilderParams
|
||||
): IIssuedInvoiceReportSnapshot {
|
||||
const locale = params?.locale as string;
|
||||
const locale = (params as { locale?: string } | undefined)?.locale ?? "es";
|
||||
|
||||
const moneyOptions = {
|
||||
hideZeros: true,
|
||||
@ -33,6 +33,7 @@ export class IssuedInvoiceReportSnapshotBuilder implements IIssuedInvoiceReportS
|
||||
company_id: snapshot.company_id,
|
||||
company_slug: "rodax",
|
||||
invoice_number: snapshot.invoice_number,
|
||||
invoice_reference: snapshot.invoice_reference,
|
||||
series: snapshot.series,
|
||||
status: snapshot.status,
|
||||
reference: snapshot.reference,
|
||||
@ -43,7 +44,7 @@ export class IssuedInvoiceReportSnapshotBuilder implements IIssuedInvoiceReportS
|
||||
invoice_date: DateHelper.format(snapshot.invoice_date, locale),
|
||||
|
||||
payment_method: snapshot.payment_method?.payment_description ?? "",
|
||||
notes: snapshot.notes,
|
||||
notes: snapshot.notes ?? "",
|
||||
|
||||
recipient: {
|
||||
name: snapshot.recipient.name,
|
||||
@ -65,7 +66,8 @@ export class IssuedInvoiceReportSnapshotBuilder implements IIssuedInvoiceReportS
|
||||
|
||||
verifactu: {
|
||||
...snapshot.verifactu,
|
||||
qr_code: snapshot.verifactu.qr_code.replace("data:image/png;base64,", ""),
|
||||
url: snapshot.verifactu.url ?? "",
|
||||
qr_code: (snapshot.verifactu.qr_code ?? "").replace("data:image/png;base64,", ""),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -6,9 +6,10 @@ export interface IIssuedInvoiceReportSnapshot {
|
||||
company_id: string;
|
||||
company_slug: string;
|
||||
invoice_number: string;
|
||||
invoice_reference: string;
|
||||
series: string;
|
||||
status: string;
|
||||
reference: string;
|
||||
reference: string | null;
|
||||
|
||||
language_code: string;
|
||||
currency_code: string;
|
||||
|
||||
@ -15,7 +15,7 @@ export class IssuedInvoiceReportTaxSnapshotBuilder
|
||||
taxes: IIssuedInvoiceTaxFullSnapshot[],
|
||||
params?: ISnapshotBuilderParams
|
||||
): IIssuedInvoiceReportTaxSnapshot[] {
|
||||
const locale = params?.locale as string;
|
||||
const locale = (params as { locale?: string } | undefined)?.locale ?? "es";
|
||||
|
||||
const moneyOptions = {
|
||||
hideZeros: true,
|
||||
@ -29,11 +29,11 @@ export class IssuedInvoiceReportTaxSnapshotBuilder
|
||||
iva_percentage: PercentageDTOHelper.format(tax.iva_percentage, locale),
|
||||
iva_amount: MoneyDTOHelper.format(tax.iva_amount, locale, moneyOptions),
|
||||
|
||||
rec_code: tax.rec_code,
|
||||
rec_code: tax.rec_code ?? "",
|
||||
rec_percentage: PercentageDTOHelper.format(tax.rec_percentage, locale),
|
||||
rec_amount: MoneyDTOHelper.format(tax.rec_amount, locale, moneyOptions),
|
||||
|
||||
retention_code: tax.retention_code,
|
||||
retention_code: tax.retention_code ?? "",
|
||||
retention_percentage: PercentageDTOHelper.format(tax.retention_percentage, locale),
|
||||
retention_amount: MoneyDTOHelper.format(tax.retention_amount, locale, moneyOptions),
|
||||
|
||||
|
||||
@ -32,7 +32,10 @@ export class IssuedInvoiceSummarySnapshotBuilder implements IIssuedInvoiceSummar
|
||||
id: invoice.id.toString(),
|
||||
company_id: invoice.companyId.toString(),
|
||||
|
||||
document_series_id: maybeToNullable(invoice.documentSeriesId, (value) => value),
|
||||
invoice_series_code: maybeToNullable(invoice.invoiceSeriesCode, (value) => value.toString()),
|
||||
invoice_number: invoice.invoiceNumber.toString(),
|
||||
invoice_reference: invoice.invoiceReference,
|
||||
status: invoice.status.toPrimitive(),
|
||||
series: maybeToEmptyString(invoice.series, (v) => v.toString()),
|
||||
|
||||
|
||||
@ -5,7 +5,10 @@ export interface IIssuedInvoiceSummarySnapshot {
|
||||
id: string;
|
||||
company_id: string;
|
||||
|
||||
document_series_id: string | null;
|
||||
invoice_series_code: string | null;
|
||||
invoice_number: string;
|
||||
invoice_reference: string;
|
||||
status: string;
|
||||
series: string;
|
||||
|
||||
|
||||
@ -13,6 +13,9 @@ export type ProformaSummary = {
|
||||
id: UniqueID;
|
||||
companyId: UniqueID;
|
||||
|
||||
documentSeriesId: Maybe<string>;
|
||||
proformaSeriesCode: Maybe<InvoiceSerie>;
|
||||
proformaNumber: Maybe<InvoiceNumber>;
|
||||
proformaReference: InvoiceNumber;
|
||||
status: InvoiceStatus;
|
||||
archivedAt: Maybe<UtcDate>;
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
type IProformaCreateProps,
|
||||
type IProformaItemCreateProps,
|
||||
InvoiceNumber,
|
||||
InvoiceSerie,
|
||||
Proforma,
|
||||
ProformaTaxConfig,
|
||||
} from "../../../domain";
|
||||
@ -98,6 +99,12 @@ export class ProformaCreator implements IProformaCreator {
|
||||
return Result.fail(proformaNumberResult.error);
|
||||
}
|
||||
|
||||
const proformaSeriesCodeResult = InvoiceSerie.create(numberResult.data.documentSeriesCode);
|
||||
|
||||
if (proformaSeriesCodeResult.isFailure) {
|
||||
return Result.fail(proformaSeriesCodeResult.error);
|
||||
}
|
||||
|
||||
const proformaReference = proformaReferenceResult.data;
|
||||
|
||||
// 2. Crear agregado
|
||||
@ -107,6 +114,7 @@ export class ProformaCreator implements IProformaCreator {
|
||||
companyId,
|
||||
archivedAt: Maybe.none(),
|
||||
documentSeriesId: Maybe.some(numberResult.data.documentSeriesId),
|
||||
proformaSeriesCode: Maybe.some(proformaSeriesCodeResult.data),
|
||||
proformaNumber: Maybe.some(proformaNumberResult.data),
|
||||
proformaReference,
|
||||
targetInvoiceSeriesCode: resolvedPropsResult.data.targetInvoiceSeriesCode,
|
||||
@ -142,7 +150,10 @@ export class ProformaCreator implements IProformaCreator {
|
||||
transaction?: unknown
|
||||
): Promise<
|
||||
Result<
|
||||
Omit<IProformaCreateProps, "proformaReference" | "proformaNumber" | "documentSeriesId">,
|
||||
Omit<
|
||||
IProformaCreateProps,
|
||||
"proformaReference" | "proformaNumber" | "documentSeriesId" | "proformaSeriesCode"
|
||||
>,
|
||||
Error
|
||||
>
|
||||
> {
|
||||
|
||||
@ -14,7 +14,7 @@ export class ProformaDocumentPropertiesFactory
|
||||
{
|
||||
build(snapshot: ProformaReportSnapshot): IDocumentProperties {
|
||||
return {
|
||||
title: snapshot.reference ?? `Proforma ${snapshot.series}${snapshot.invoice_number}`,
|
||||
title: snapshot.reference ?? snapshot.proforma_reference,
|
||||
subject: "proforma",
|
||||
author: snapshot.company.legalName,
|
||||
creator: "FactuGES ERP",
|
||||
|
||||
@ -40,6 +40,11 @@ export class ProformaFullSnapshotBuilder implements IProformaFullSnapshotBuilder
|
||||
id: proforma.id.toString(),
|
||||
company_id: proforma.companyId.toString(),
|
||||
|
||||
document_series_id: maybeToNullable(proforma.documentSeriesId, (value) => value),
|
||||
proforma_series_code: maybeToNullable(proforma.proformaSeriesCode, (value) =>
|
||||
value.toString()
|
||||
),
|
||||
proforma_number: maybeToNullable(proforma.proformaNumber, (value) => value.toString()),
|
||||
proforma_reference: proforma.proformaReference.toString(),
|
||||
status: proforma.status.toPrimitive() as ProformaFullSnapshot["status"],
|
||||
archived_at: maybeToNullable(proforma.archivedAt, (value) => value.toISOString()),
|
||||
|
||||
@ -12,8 +12,11 @@ export class IssueProformaResponseSnapshotBuilder implements IIssueProformaRespo
|
||||
issued_invoice: {
|
||||
id: invoice.id.toString(),
|
||||
proforma_id: invoice.linkedProformaId.toString(),
|
||||
document_series_id: invoice.documentSeriesId.getOrUndefined() ?? null,
|
||||
invoice_series_code: invoice.series.toString(),
|
||||
series: invoice.series.toString(),
|
||||
invoice_number: invoice.invoiceNumber.toString(),
|
||||
invoice_reference: invoice.invoiceReference,
|
||||
invoice_date: invoice.invoiceDate.toDateString(),
|
||||
status: "issued",
|
||||
recipient: {
|
||||
|
||||
@ -53,6 +53,7 @@ export class ProformaReportSnapshotBuilder implements IProformaReportSnapshotBui
|
||||
return {
|
||||
id: snapshot.id,
|
||||
company_id: snapshot.company_id,
|
||||
proforma_reference: snapshot.proforma_reference,
|
||||
invoice_number: snapshot.invoice_number,
|
||||
series: snapshot.series,
|
||||
status: snapshot.status,
|
||||
|
||||
@ -5,6 +5,7 @@ import type { ProformaReportTaxSnapshot } from "./proforma-report-tax-snapshot.i
|
||||
export interface ProformaReportSnapshot {
|
||||
id: string;
|
||||
company_id: string;
|
||||
proforma_reference: string;
|
||||
invoice_number: string;
|
||||
series: string | null;
|
||||
status: string;
|
||||
|
||||
@ -15,11 +15,18 @@ export class ProformaSummarySnapshotBuilder implements IProformaSummarySnapshotB
|
||||
id: proforma.id.toString(),
|
||||
company_id: proforma.companyId.toString(),
|
||||
|
||||
document_series_id: maybeToNullable(proforma.documentSeriesId, (value) => value),
|
||||
proforma_series_code: maybeToNullable(proforma.proformaSeriesCode, (value) =>
|
||||
value.toString()
|
||||
),
|
||||
proforma_number: maybeToNullable(proforma.proformaNumber, (value) => value.toString()),
|
||||
proforma_reference: proforma.proformaReference.toString(),
|
||||
status: proforma.status.toPrimitive() as ProformaSummaryDTO["status"],
|
||||
archived_at: maybeToNullable(proforma.archivedAt, (value) => value.toISOString()),
|
||||
target_invoice_series_code: maybeToNullable(proforma.series, (value) => value.toString()),
|
||||
series: maybeToNullable(proforma.series, (value) => value.toString()),
|
||||
target_invoice_series_code: maybeToNullable(proforma.targetInvoiceSeriesCode, (value) =>
|
||||
value.toString()
|
||||
),
|
||||
series: maybeToNullable(proforma.targetInvoiceSeriesCode, (value) => value.toString()),
|
||||
|
||||
proforma_date: proforma.proformaDate.toDateString(),
|
||||
operation_date: maybeToNullable(proforma.operationDate, (value) => value.toDateString()),
|
||||
|
||||
@ -35,8 +35,10 @@ export interface IIssuedInvoiceCreateProps {
|
||||
|
||||
linkedProformaId: UniqueID; // <- id de la proforma padre en caso de issue
|
||||
|
||||
documentSeriesId: Maybe<string>;
|
||||
series: InvoiceSerie;
|
||||
invoiceNumber: InvoiceNumber;
|
||||
invoiceReference: string;
|
||||
|
||||
invoiceDate: UtcDate;
|
||||
operationDate: Maybe<UtcDate>;
|
||||
@ -151,6 +153,16 @@ export class IssuedInvoice
|
||||
);
|
||||
}
|
||||
|
||||
if (!props.invoiceReference.trim()) {
|
||||
return Result.fail(
|
||||
new DomainValidationError(
|
||||
"MISSING_INVOICE_REFERENCE",
|
||||
"invoiceReference",
|
||||
"Issued invoice requires invoice reference"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@ -194,6 +206,10 @@ export class IssuedInvoice
|
||||
return this.props.linkedProformaId;
|
||||
}
|
||||
|
||||
public get documentSeriesId(): Maybe<string> {
|
||||
return this.props.documentSeriesId;
|
||||
}
|
||||
|
||||
public get status(): InvoiceStatus {
|
||||
return this.props.status;
|
||||
}
|
||||
@ -206,6 +222,10 @@ export class IssuedInvoice
|
||||
return this.props.invoiceNumber;
|
||||
}
|
||||
|
||||
public get invoiceReference(): string {
|
||||
return this.props.invoiceReference;
|
||||
}
|
||||
|
||||
public get invoiceDate(): UtcDate {
|
||||
return this.props.invoiceDate;
|
||||
}
|
||||
|
||||
@ -51,6 +51,7 @@ export interface IProformaCreateProps {
|
||||
archivedAt: Maybe<UtcDate>;
|
||||
|
||||
documentSeriesId: Maybe<string>;
|
||||
proformaSeriesCode: Maybe<InvoiceSerie>;
|
||||
proformaNumber: Maybe<InvoiceNumber>;
|
||||
proformaReference: InvoiceNumber;
|
||||
targetInvoiceSeriesCode: Maybe<InvoiceSerie>;
|
||||
@ -105,6 +106,7 @@ export interface IProforma {
|
||||
archivedAt: Maybe<UtcDate>;
|
||||
|
||||
documentSeriesId: Maybe<string>;
|
||||
proformaSeriesCode: Maybe<InvoiceSerie>;
|
||||
proformaNumber: Maybe<InvoiceNumber>;
|
||||
targetInvoiceSeriesCode: Maybe<InvoiceSerie>;
|
||||
proformaReference: InvoiceNumber;
|
||||
@ -266,6 +268,10 @@ export class Proforma extends AggregateRoot<ProformaInternalProps> implements IP
|
||||
return this.props.documentSeriesId;
|
||||
}
|
||||
|
||||
public get proformaSeriesCode(): Maybe<InvoiceSerie> {
|
||||
return this.props.proformaSeriesCode;
|
||||
}
|
||||
|
||||
public get proformaNumber(): Maybe<InvoiceNumber> {
|
||||
return this.props.proformaNumber;
|
||||
}
|
||||
|
||||
@ -44,8 +44,10 @@ export class IssuedInvoiceModel extends Model<
|
||||
declare status: string;
|
||||
|
||||
declare source_proforma_id: CreationOptional<string | null>;
|
||||
declare document_series_id: CreationOptional<string | null>;
|
||||
declare invoice_series_code: string;
|
||||
declare invoice_number: string;
|
||||
declare invoice_reference: string;
|
||||
declare invoice_date: string;
|
||||
declare operation_date: CreationOptional<string | null>;
|
||||
|
||||
@ -231,6 +233,13 @@ export default (database: Sequelize) => {
|
||||
charset: "utf8mb4",
|
||||
collate: "utf8mb4_bin",
|
||||
} as any,
|
||||
document_series_id: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
charset: "utf8mb4",
|
||||
collate: "utf8mb4_bin",
|
||||
} as any,
|
||||
|
||||
invoice_series_code: {
|
||||
type: new DataTypes.STRING(10),
|
||||
@ -240,6 +249,10 @@ export default (database: Sequelize) => {
|
||||
type: new DataTypes.STRING(12),
|
||||
allowNull: false,
|
||||
},
|
||||
invoice_reference: {
|
||||
type: new DataTypes.STRING(64),
|
||||
allowNull: false,
|
||||
},
|
||||
invoice_date: {
|
||||
type: new DataTypes.DATEONLY(),
|
||||
allowNull: false,
|
||||
@ -502,6 +515,10 @@ export default (database: Sequelize) => {
|
||||
name: "idx_issued_invoices_company",
|
||||
fields: ["company_id"],
|
||||
},
|
||||
{
|
||||
name: "idx_issued_invoices_document_series_id",
|
||||
fields: ["document_series_id"],
|
||||
},
|
||||
{
|
||||
name: "uq_issued_invoice_company_series_number",
|
||||
fields: ["company_id", "invoice_series_code", "invoice_number"],
|
||||
|
||||
@ -37,6 +37,7 @@ export class ProformaModel extends Model<
|
||||
declare archived_at: CreationOptional<string | null>;
|
||||
|
||||
declare document_series_id: CreationOptional<string | null>;
|
||||
declare proforma_series_code: CreationOptional<string | null>;
|
||||
declare proforma_number: CreationOptional<string | null>;
|
||||
declare proforma_reference: string;
|
||||
declare proforma_date: string;
|
||||
@ -192,6 +193,11 @@ export default (database: Sequelize) => {
|
||||
charset: "utf8mb4",
|
||||
collate: "utf8mb4_bin",
|
||||
} as any,
|
||||
proforma_series_code: {
|
||||
type: new DataTypes.STRING(10),
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
},
|
||||
proforma_number: {
|
||||
type: new DataTypes.STRING(32),
|
||||
allowNull: true,
|
||||
@ -479,6 +485,15 @@ export default (database: Sequelize) => {
|
||||
name: "idx_proformas_company_document_series",
|
||||
fields: ["company_id", "document_series_id"],
|
||||
},
|
||||
{
|
||||
name: "idx_proformas_document_series_id",
|
||||
fields: ["document_series_id"],
|
||||
},
|
||||
{
|
||||
name: "uq_proformas_company_series_number",
|
||||
fields: ["company_id", "proforma_series_code", "proforma_number"],
|
||||
unique: true,
|
||||
},
|
||||
{
|
||||
name: "uq_proformas_company_reference",
|
||||
fields: ["company_id", "proforma_reference"],
|
||||
|
||||
@ -60,7 +60,7 @@ export function buildIssuedInvoicePublicServices(
|
||||
|
||||
return Result.ok({
|
||||
invoiceNumber: invoiceNumberResult.data,
|
||||
formattedNumber: assignResult.data.reference,
|
||||
invoiceReference: assignResult.data.reference,
|
||||
invoiceSeriesId: assignResult.data.series_id,
|
||||
invoiceSeriesCode: assignedSeriesResult.data,
|
||||
});
|
||||
|
||||
@ -83,6 +83,11 @@ export class SequelizeIssuedInvoiceDomainMapper extends SequelizeDomainMapper<
|
||||
"invoice_number",
|
||||
errors
|
||||
);
|
||||
const invoiceReference = extractOrPushError(
|
||||
Result.ok(`${String(raw.series ?? "")}${String(raw.invoice_number ?? "")}`),
|
||||
"invoice_reference",
|
||||
errors
|
||||
);
|
||||
|
||||
// Fechas
|
||||
const invoiceDate = extractOrPushError(
|
||||
@ -281,6 +286,7 @@ export class SequelizeIssuedInvoiceDomainMapper extends SequelizeDomainMapper<
|
||||
status,
|
||||
series,
|
||||
invoiceNumber,
|
||||
invoiceReference,
|
||||
invoiceDate,
|
||||
operationDate,
|
||||
reference,
|
||||
@ -375,6 +381,7 @@ export class SequelizeIssuedInvoiceDomainMapper extends SequelizeDomainMapper<
|
||||
status: attributes.status!,
|
||||
series: attributes.series!,
|
||||
invoiceNumber: attributes.invoiceNumber!,
|
||||
invoiceReference: attributes.invoiceReference!,
|
||||
invoiceDate: attributes.invoiceDate!,
|
||||
operationDate: attributes.operationDate!,
|
||||
|
||||
|
||||
@ -62,6 +62,11 @@ export class SequelizeIssuedInvoiceV2DomainMapper extends SequelizeDomainMapper<
|
||||
"source_proforma_id",
|
||||
errors
|
||||
);
|
||||
const documentSeriesId = extractOrPushError(
|
||||
maybeFromNullableResult(raw.document_series_id, (value) => Result.ok(String(value))),
|
||||
"document_series_id",
|
||||
errors
|
||||
);
|
||||
const status = extractOrPushError(InvoiceStatus.create(raw.status), "status", errors);
|
||||
const series = extractOrPushError(
|
||||
InvoiceSerie.create(raw.invoice_series_code ?? ""),
|
||||
@ -73,6 +78,11 @@ export class SequelizeIssuedInvoiceV2DomainMapper extends SequelizeDomainMapper<
|
||||
"invoice_number",
|
||||
errors
|
||||
);
|
||||
const invoiceReference = extractOrPushError(
|
||||
Result.ok(String(raw.invoice_reference ?? "")),
|
||||
"invoice_reference",
|
||||
errors
|
||||
);
|
||||
const invoiceDate = extractOrPushError(
|
||||
UtcDate.createFromISO(raw.invoice_date),
|
||||
"invoice_date",
|
||||
@ -217,9 +227,11 @@ export class SequelizeIssuedInvoiceV2DomainMapper extends SequelizeDomainMapper<
|
||||
companyId,
|
||||
customerId,
|
||||
linkedProformaId,
|
||||
documentSeriesId,
|
||||
status,
|
||||
series,
|
||||
invoiceNumber,
|
||||
invoiceReference,
|
||||
invoiceDate,
|
||||
operationDate,
|
||||
reference,
|
||||
@ -294,8 +306,10 @@ export class SequelizeIssuedInvoiceV2DomainMapper extends SequelizeDomainMapper<
|
||||
const invoiceProps: InternalIssuedInvoiceProps = {
|
||||
companyId: attributes.companyId!,
|
||||
status: attributes.status!,
|
||||
documentSeriesId: attributes.documentSeriesId!,
|
||||
series: attributes.series!,
|
||||
invoiceNumber: attributes.invoiceNumber!,
|
||||
invoiceReference: attributes.invoiceReference!,
|
||||
invoiceDate: attributes.invoiceDate!,
|
||||
operationDate: attributes.operationDate!,
|
||||
customerId: attributes.customerId!,
|
||||
@ -372,8 +386,10 @@ export class SequelizeIssuedInvoiceV2DomainMapper extends SequelizeDomainMapper<
|
||||
company_id: source.companyId.toPrimitive(),
|
||||
status: source.status.toPrimitive(),
|
||||
source_proforma_id: source.linkedProformaId.toPrimitive(),
|
||||
document_series_id: maybeToNullable(source.documentSeriesId, (value) => value),
|
||||
invoice_series_code: source.series.toPrimitive(),
|
||||
invoice_number: source.invoiceNumber.toPrimitive(),
|
||||
invoice_reference: source.invoiceReference,
|
||||
invoice_date: source.invoiceDate.toPrimitive(),
|
||||
operation_date: maybeToNullable(source.operationDate, (v) => v.toPrimitive()),
|
||||
language_code: source.languageCode.toPrimitive(),
|
||||
|
||||
@ -92,6 +92,7 @@ export class SequelizeIssuedInvoiceSummaryMapper extends SequelizeQueryMapper<
|
||||
status: attributes.status!,
|
||||
series: attributes.series!,
|
||||
invoiceNumber: attributes.invoiceNumber!,
|
||||
invoiceReference: attributes.invoiceReference!,
|
||||
invoiceDate: attributes.invoiceDate!,
|
||||
operationDate: attributes.operationDate!,
|
||||
|
||||
@ -141,6 +142,11 @@ export class SequelizeIssuedInvoiceSummaryMapper extends SequelizeQueryMapper<
|
||||
"invoice_number",
|
||||
errors
|
||||
);
|
||||
const invoiceReference = extractOrPushError(
|
||||
Result.ok(`${String(raw.series ?? "")}${String(raw.invoice_number ?? "")}`),
|
||||
"invoice_reference",
|
||||
errors
|
||||
);
|
||||
|
||||
const invoiceDate = extractOrPushError(
|
||||
UtcDate.createFromISO(raw.invoice_date),
|
||||
@ -237,6 +243,7 @@ export class SequelizeIssuedInvoiceSummaryMapper extends SequelizeQueryMapper<
|
||||
status,
|
||||
series,
|
||||
invoiceNumber,
|
||||
invoiceReference,
|
||||
invoiceDate,
|
||||
operationDate,
|
||||
reference,
|
||||
|
||||
@ -75,9 +75,12 @@ export class SequelizeIssuedInvoiceV2SummaryMapper extends SequelizeQueryMapper<
|
||||
id: attributes.invoiceId!,
|
||||
companyId: attributes.companyId!,
|
||||
isProforma: false,
|
||||
documentSeriesId: attributes.documentSeriesId!,
|
||||
invoiceSeriesCode: attributes.series!,
|
||||
status: attributes.status!,
|
||||
series: attributes.series!,
|
||||
invoiceNumber: attributes.invoiceNumber!,
|
||||
invoiceReference: attributes.invoiceReference!,
|
||||
invoiceDate: attributes.invoiceDate!,
|
||||
operationDate: attributes.operationDate!,
|
||||
description: attributes.description!,
|
||||
@ -102,6 +105,11 @@ export class SequelizeIssuedInvoiceV2SummaryMapper extends SequelizeQueryMapper<
|
||||
const invoiceId = extractOrPushError(UniqueID.create(raw.id), "id", errors);
|
||||
const companyId = extractOrPushError(UniqueID.create(raw.company_id), "company_id", errors);
|
||||
const customerId = extractOrPushError(UniqueID.create(raw.customer_id), "customer_id", errors);
|
||||
const documentSeriesId = extractOrPushError(
|
||||
maybeFromNullableResult(raw.document_series_id, (value) => Result.ok(String(value))),
|
||||
"document_series_id",
|
||||
errors
|
||||
);
|
||||
const status = extractOrPushError(InvoiceStatus.create(raw.status), "status", errors);
|
||||
const series = extractOrPushError(
|
||||
maybeFromNullableResult(raw.invoice_series_code, (value) => InvoiceSerie.create(value)),
|
||||
@ -113,6 +121,11 @@ export class SequelizeIssuedInvoiceV2SummaryMapper extends SequelizeQueryMapper<
|
||||
"invoice_number",
|
||||
errors
|
||||
);
|
||||
const invoiceReference = extractOrPushError(
|
||||
Result.ok(String(raw.invoice_reference ?? "")),
|
||||
"invoice_reference",
|
||||
errors
|
||||
);
|
||||
const invoiceDate = extractOrPushError(
|
||||
UtcDate.createFromISO(raw.invoice_date),
|
||||
"invoice_date",
|
||||
@ -182,9 +195,11 @@ export class SequelizeIssuedInvoiceV2SummaryMapper extends SequelizeQueryMapper<
|
||||
invoiceId,
|
||||
companyId,
|
||||
customerId,
|
||||
documentSeriesId,
|
||||
status,
|
||||
series,
|
||||
invoiceNumber,
|
||||
invoiceReference,
|
||||
invoiceDate,
|
||||
operationDate,
|
||||
reference,
|
||||
|
||||
@ -175,10 +175,11 @@ export class SequelizeIssuedInvoiceRepositoryV2
|
||||
try {
|
||||
const criteriaConverter = new CriteriaToSequelizeConverter();
|
||||
const criteriaQuery = criteriaConverter.convert(criteria, {
|
||||
searchableFields: ["invoice_number", "reference", "description"],
|
||||
searchableFields: ["invoice_number", "invoice_reference", "reference", "description"],
|
||||
mappings: {
|
||||
invoice_date: { type: "root", column: "invoice_date" },
|
||||
invoice_number: { type: "root", column: "invoice_number" },
|
||||
invoice_reference: { type: "root", column: "invoice_reference" },
|
||||
reference: { type: "root", column: "reference" },
|
||||
description: { type: "root", column: "description" },
|
||||
recipient_name: { type: "root", column: "customer_name" },
|
||||
|
||||
@ -13,7 +13,7 @@ export class ProformaHtmlPreviewDocumentMetadataFactory
|
||||
companySlug: snapshot.company.slug,
|
||||
format: "HTML",
|
||||
languageCode: snapshot.localization.languageCode,
|
||||
filename: `proforma-${snapshot.series}${snapshot.invoice_number}.html`,
|
||||
filename: `proforma-${snapshot.proforma_reference}.html`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ export class ProformaPdfDocumentMetadataFactory
|
||||
companySlug: snapshot.company.slug,
|
||||
format: "PDF",
|
||||
languageCode: snapshot.localization.languageCode,
|
||||
filename: `proforma-${snapshot.series}${snapshot.invoice_number}.pdf`,
|
||||
filename: `proforma-${snapshot.proforma_reference}.pdf`,
|
||||
storageKey: this.buildStorageKey(snapshot),
|
||||
};
|
||||
}
|
||||
|
||||
@ -61,6 +61,11 @@ export class SequelizeProformaV2DomainMapper extends SequelizeDomainMapper<
|
||||
"document_series_id",
|
||||
errors
|
||||
);
|
||||
const proformaSeriesCode = extractOrPushError(
|
||||
maybeFromNullableResult(raw.proforma_series_code, (value) => InvoiceSerie.create(value)),
|
||||
"proforma_series_code",
|
||||
errors
|
||||
);
|
||||
const targetInvoiceSeriesCode = extractOrPushError(
|
||||
maybeFromNullableResult(raw.target_invoice_series_code, (value) =>
|
||||
InvoiceSerie.create(value)
|
||||
@ -167,6 +172,7 @@ export class SequelizeProformaV2DomainMapper extends SequelizeDomainMapper<
|
||||
status,
|
||||
archivedAt,
|
||||
documentSeriesId,
|
||||
proformaSeriesCode,
|
||||
proformaNumber,
|
||||
targetInvoiceSeriesCode,
|
||||
proformaReference,
|
||||
@ -220,6 +226,7 @@ export class SequelizeProformaV2DomainMapper extends SequelizeDomainMapper<
|
||||
status: attributes.status!,
|
||||
archivedAt: attributes.archivedAt!,
|
||||
documentSeriesId: attributes.documentSeriesId!,
|
||||
proformaSeriesCode: attributes.proformaSeriesCode!,
|
||||
proformaNumber: attributes.proformaNumber!,
|
||||
targetInvoiceSeriesCode: attributes.targetInvoiceSeriesCode!,
|
||||
proformaReference: attributes.proformaReference!,
|
||||
@ -286,6 +293,9 @@ export class SequelizeProformaV2DomainMapper extends SequelizeDomainMapper<
|
||||
status: source.status.toPrimitive(),
|
||||
archived_at: maybeToNullable(source.archivedAt, (value) => value.toPrimitive()),
|
||||
document_series_id: maybeToNullable(source.documentSeriesId, (value) => value),
|
||||
proforma_series_code: maybeToNullable(source.proformaSeriesCode, (value) =>
|
||||
value.toPrimitive()
|
||||
),
|
||||
proforma_number: maybeToNullable(source.proformaNumber, (value) => value.toPrimitive()),
|
||||
proforma_reference: source.proformaReference.toPrimitive(),
|
||||
proforma_date: source.proformaDate.toPrimitive(),
|
||||
|
||||
@ -59,6 +59,9 @@ export class SequelizeProformaV2SummaryMapper extends SequelizeQueryMapper<
|
||||
return Result.ok({
|
||||
id: attributes.invoiceId!,
|
||||
companyId: attributes.companyId!,
|
||||
documentSeriesId: attributes.documentSeriesId!,
|
||||
proformaSeriesCode: attributes.proformaSeriesCode!,
|
||||
proformaNumber: attributes.proformaNumber!,
|
||||
status: attributes.status!,
|
||||
archivedAt: attributes.archivedAt!,
|
||||
targetInvoiceSeriesCode: attributes.targetInvoiceSeriesCode!,
|
||||
@ -92,6 +95,21 @@ export class SequelizeProformaV2SummaryMapper extends SequelizeQueryMapper<
|
||||
"archived_at",
|
||||
errors
|
||||
);
|
||||
const documentSeriesId = extractOrPushError(
|
||||
maybeFromNullableResult(raw.document_series_id, (value) => Result.ok(String(value))),
|
||||
"document_series_id",
|
||||
errors
|
||||
);
|
||||
const proformaSeriesCode = extractOrPushError(
|
||||
maybeFromNullableResult(raw.proforma_series_code, (value) => InvoiceSerie.create(value)),
|
||||
"proforma_series_code",
|
||||
errors
|
||||
);
|
||||
const proformaNumber = extractOrPushError(
|
||||
maybeFromNullableResult(raw.proforma_number, (value) => InvoiceNumber.create(value)),
|
||||
"proforma_number",
|
||||
errors
|
||||
);
|
||||
const targetInvoiceSeriesCode = extractOrPushError(
|
||||
maybeFromNullableResult(raw.target_invoice_series_code, (value) =>
|
||||
InvoiceSerie.create(value)
|
||||
@ -172,6 +190,9 @@ export class SequelizeProformaV2SummaryMapper extends SequelizeQueryMapper<
|
||||
invoiceId,
|
||||
companyId,
|
||||
customerId,
|
||||
documentSeriesId,
|
||||
proformaSeriesCode,
|
||||
proformaNumber,
|
||||
status,
|
||||
archivedAt,
|
||||
targetInvoiceSeriesCode,
|
||||
|
||||
@ -22,7 +22,10 @@ export const GetIssuedInvoiceByIdResponseSchema = z.object({
|
||||
id: z.uuid(),
|
||||
company_id: z.uuid(),
|
||||
|
||||
document_series_id: z.uuid().nullable(),
|
||||
invoice_series_code: z.string().nullable(),
|
||||
invoice_number: z.string(),
|
||||
invoice_reference: z.string(),
|
||||
status: IssuedInvoiceStatusSchema,
|
||||
series: z.string(),
|
||||
|
||||
|
||||
@ -25,6 +25,9 @@ export const GetProformaByIdResponseSchema = z.object({
|
||||
id: z.uuid(),
|
||||
company_id: z.uuid(),
|
||||
|
||||
document_series_id: z.uuid().nullable(),
|
||||
proforma_series_code: z.string().nullable(),
|
||||
proforma_number: z.string().nullable(),
|
||||
proforma_reference: z.string(),
|
||||
status: ProformaStatusSchema,
|
||||
archived_at: z.iso.datetime().nullable(),
|
||||
|
||||
@ -19,8 +19,11 @@ export const IssueProformaIssuedInvoiceTotalsSchema = z.object({
|
||||
export const IssueProformaIssuedInvoiceSchema = z.object({
|
||||
id: z.uuid(),
|
||||
proforma_id: z.uuid().nullable(),
|
||||
document_series_id: z.uuid().nullable(),
|
||||
invoice_series_code: z.string(),
|
||||
series: z.string(),
|
||||
invoice_number: z.string(),
|
||||
invoice_reference: z.string(),
|
||||
invoice_date: IsoDateSchema,
|
||||
status: IssuedInvoiceStatusSchema,
|
||||
recipient: IssueProformaIssuedInvoiceRecipientSchema,
|
||||
|
||||
@ -9,7 +9,10 @@ export const IssuedInvoiceSummarySchema = z.object({
|
||||
id: z.uuid(),
|
||||
company_id: z.uuid(),
|
||||
|
||||
document_series_id: z.uuid().nullable(),
|
||||
invoice_series_code: z.string().nullable(),
|
||||
invoice_number: z.string(),
|
||||
invoice_reference: z.string(),
|
||||
status: IssuedInvoiceStatusSchema,
|
||||
series: z.string(),
|
||||
|
||||
|
||||
@ -8,6 +8,9 @@ export const ProformaSummarySchema = z.object({
|
||||
id: z.uuid(),
|
||||
company_id: z.uuid(),
|
||||
|
||||
document_series_id: z.uuid().nullable(),
|
||||
proforma_series_code: z.string().nullable(),
|
||||
proforma_number: z.string().nullable(),
|
||||
proforma_reference: z.string(),
|
||||
status: ProformaStatusSchema,
|
||||
archived_at: z.iso.datetime().nullable(),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user