- Add GetProformaIssuanceReadinessUseCase to check proforma issuance readiness. - Create GetProformaIssuanceReadinessController to handle requests and responses. - Introduce request and response DTOs for proforma issuance readiness. - Develop tests for the use case and controller to ensure functionality. - Implement adapter and hooks for integrating issuance readiness in the web application. - Create UI components for displaying issuance readiness alerts and help popover. - Add utility functions for translating blocker messages and details.
5.9 KiB
Proforma Create Contract
Objetivo
Definir la semantica correcta de create proforma como creacion de cabecera inicial y separarla del calculo fiscal real que depende de lineas valoradas.
Para la semántica vigente de payment_term_id, herencia desde Company o Customer y diferencia entre referencia viva y snapshot, usar como fuente principal:
Regla principal
tax_regime_code no es un impuesto aplicado.
En create:
taxRegimeCoderepresenta configuracion fiscal inicialtax_configrepresenta la configuracion fiscal persistida de cabecerataxesrepresenta impuestos realmente calculados desde lineas valoradastotalsrepresenta importes realmente calculados desde lineas valoradastax_modepor defecto essingle
Contrato funcional de create
Una proforma puede crearse sin lineas.
Si items se omite o se envia como []:
- la proforma debe crearse correctamente como borrador
- debe generarse
proforma_reference - pueden resolverse defaults comerciales y fiscales iniciales
itemsdebe devolverse como[]taxesdebe devolverse como[]- los totales monetarios deben devolverse a
0 - no deben crearse filas artificiales en
proforma_taxes
Payload minimo esperado
{
proforma_date: string;
customer_id: string;
proforma_series_code?: string | null;
target_invoice_series_code?: string | null;
currency_code?: string;
payment_method_id?: string | null;
payment_term_id?: string | null;
tax_regime_code?: string | null;
tax_config?: {
tax_mode?: "single" | "per_line";
default_iva_code?: string | null;
uses_equivalence_surcharge?: boolean;
default_rec_code?: string | null;
uses_retention?: boolean;
default_retention_code?: string | null;
};
items?: [];
}
Notas:
- el contrato actual del modulo puede seguir exigiendo otros campos tecnicos ya existentes
itemses opcional; si existe, puede ir vacio- no se usan defaults ocultos en Zod para disfrazar la intencion del request
- si no se informa
tax_config, el backend resuelve defaults iniciales y los persiste - si el cliente cambia después, la proforma conserva su
tax_configpersistido payment_term_idsigue la prioridad vigente:Customer.paymentTermIdCompany.defaultPaymentTermIdnull
payment_term_id = nullsignifica “sin plazo de pago”- una selección manual de
payment_term_id = nullno debe volver a activar un default después
Response esperada al crear sin lineas
Adaptando nombres exactos al contrato publico actual:
{
id: string;
proforma_reference: string;
proforma_date: string;
customer_id: string;
currency_code: string;
payment_method_id: string | null;
payment_term_id: string | null;
tax_regime_code: string | null;
target_invoice_series_code: string | null;
items: [];
taxes: [];
totals: {
subtotal_before_discounts: "0.00";
line_discount_total: "0.00";
taxable_base: "0.00";
tax_total: "0.00";
total: "0.00";
};
}
Punto correcto de calculo
createcrea cabecera minima, numera y resuelve defaultscreatepersiste tambien eltax_configresueltoupdatepermite anadir o editar lineas- al existir lineas valoradas,
updaterecalculataxesytotals issuegenera laissued_invoicematerializada usandotarget_invoice_series_codesi existe y, si no, la default activa deissued_invoice
Diferencia entre draft y emision
create y update no deben imponer automaticamente todas las precondiciones de emision.
Una Proforma puede existir validamente como borrador incompleto.
En concreto:
proforma_dateforma parte de la estructura base del documento y debe existir desde create;operation_dateno se exige en create ni en update general;descriptionno se exige en create ni en update general;payment_method_idpuede seguir vacio mientras el documento permanezca en draft.
La obligatoriedad de esos campos pertenece al boundary de issue.
Precondiciones funcionales de emision auditadas en backend:
descriptionobligatoria;operation_dateobligatoria;payment_method_idobligatorio y resoluble dentro de la company activa;- el
payment_methoddebe seguir activo al emitir; payment_term_idsigue siendo opcional;- la emision sigue usando
invoice_date = todaycomo fecha documental de la factura emitida.
Relacion con borrado
- una proforma creada en
draftpuede borrarse logicamente mas adelante - ese borrado no modifica
tax_config, impuestos, totales ni numeracion historica - la referencia visible consumida por create no vuelve a reutilizarse aunque la proforma se borre
Wording de UI
La UI de create debe hablar de:
- "Se preparara automaticamente"
- "valores iniciales"
- "configuracion fiscal inicial"
La UI no debe sugerir:
- que los impuestos ya quedaron aplicados al crear
- que existe desglose fiscal real sin lineas
- que los totales ya fueron calculados si todavia no hay lineas valoradas
Diagnostico SQL recomendado
SELECT
p.id,
p.proforma_reference,
COUNT(DISTINCT pi.item_id) AS item_rows,
COUNT(DISTINCT pt.tax_id) AS tax_rows
FROM proformas p
LEFT JOIN proforma_items pi
ON pi.proforma_id = p.id
LEFT JOIN proforma_taxes pt
ON pt.proforma_id = p.id
GROUP BY p.id, p.proforma_reference
HAVING COUNT(DISTINCT pi.item_id) = 0
AND COUNT(DISTINCT pt.tax_id) > 0;
Resultado esperado:
0filas
Si devuelve filas:
- documentar los ids afectados
- revisar si provienen de datos legacy o de una version intermedia del flujo
- no borrar datos sin confirmacion explicita
Pendientes conocidos
- no se introduce un motor fiscal nuevo en este ajuste
Archivado
- una proforma creada nace con
archived_at = NULL - el archivado posterior no altera
status - una proforma
draftarchivada puede borrarse sin desarchivarse antes - en listados, la visibilidad archivada se expresa mediante
Criteria filters[]sobrearchived_at, no mediante un estado de negocio nuevo