feat(web): pestañas Contenido, Logística y Finanzas en los documentos de ventas y compras, con datos del socio (contacto, direcciones, condiciones y forma de pago)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GeorgeandClaude Sonnet 5.5 committed 2026-10-19 14:50:33 -05:00
1 parent c002c2cf3e
commit a3bd976bbd
7 files changed
+328 -32

No files matched your search

@@ -3,7 +3,7 @@ import type { GridColumn, GridDetail, GridLine } from '../../shared/grid/grid.ty
import type { ListColumn } from '../../shared/list/list.types';
import type { VhLookup } from '../../shared/value-help/value-help.types';
import type { DocRecord, LinesSpec } from './document-model';
import { INDICATOR_LOOKUP, PROJECT_LOOKUP } from './dimension-lookups';
import { ACCOUNT_LOOKUP, INDICATOR_LOOKUP, PROJECT_LOOKUP } from './dimension-lookups';
import { SERIES_SUBTYPE } from './document-objects';
import { ANALYTIC_COLUMNS, DOCUMENT_LINE_COLUMNS, lineColumnsFor, lineFieldsOf, newDocumentLine, newServiceLine, recalcLine, serviceLineColumns, uomEntryOf } from './line-columns';
@@ -118,6 +118,8 @@ export interface DocumentLayout {
* cabecera la lista «Tipo» (`FIELDS.docType`).
*/
service?: { columns: readonly GridColumn[]; lines: LinesSpec; newLine: () => GridLine };
/** Pestañas «Logística» y «Finanzas» de los documentos de ventas y compras (la primera, «Contenido», son las líneas). */
tabs?: { logistics: FieldColumns; finance: FieldColumns };
}
/** Un documento de servicio (no de artículos): `DocType` de SAP. */
@@ -154,7 +156,72 @@ export const SALES_PERSON_LOOKUP: VhLookup = {
],
};
/** Formas de envío (`TransportationCode`). */
export const SHIPPING_TYPE_LOOKUP: VhLookup = {
title: 'Formas de envío',
resource: 'ShippingTypes',
orderby: 'Code',
valueType: 'number',
columns: [
{ key: 'Code', title: 'Código', width: '90px', mono: true },
{ key: 'Name', title: 'Nombre' },
],
};
/** Condiciones de pago (`PaymentGroupCode`). */
export const PAYMENT_TERMS_LOOKUP: VhLookup = {
title: 'Condiciones de pago',
resource: 'PaymentTermsTypes',
orderby: 'GroupNumber',
valueType: 'number',
columns: [
{ key: 'GroupNumber', title: 'Código', width: '90px', mono: true },
{ key: 'PaymentTermsGroupName', title: 'Nombre' },
],
};
/** Formas de pago (`PaymentMethod`): las de cobro en ventas y las de pago en compras. */
export const paymentMethodLookup = (type: 'boptIncoming' | 'boptOutgoing'): VhLookup => ({
title: 'Formas de pago',
resource: 'WizardPaymentMethods',
orderby: 'PaymentMethodCode',
baseFilter: `Type eq '${type}' and Active eq 'tYES'`,
columns: [
{ key: 'PaymentMethodCode', title: 'Código', width: '170px', mono: true },
{ key: 'Description', title: 'Descripción' },
],
});
/** Cuentas asociadas (las de control de los socios): la cuenta de control de un documento sale de ellas. */
export const CONTROL_ACCOUNT_LOOKUP: VhLookup = {
...ACCOUNT_LOOKUP,
title: 'Cuentas asociadas',
baseFilter: `ActiveAccount eq 'tYES' and LockManualTransaction eq 'tYES'`,
};
export const FIELDS = {
shippingType: { type: 'lookup', key: 'TransportationCode', label: 'Forma de envío', lookup: SHIPPING_TYPE_LOOKUP },
trackingNumber: { type: 'text', key: 'TrackingNumber', label: 'Número de seguimiento' },
blockDunning: { type: 'checkbox', key: 'BlockDunning', label: 'Bloquear reclamaciones' },
paymentTerms: { type: 'lookup', key: 'PaymentGroupCode', label: 'Condiciones de pago', lookup: PAYMENT_TERMS_LOOKUP },
controlAccount: { type: 'lookup', key: 'ControlAccount', label: 'Cuenta asociada', lookup: CONTROL_ACCOUNT_LOOKUP },
paymentBlock: { type: 'checkbox', key: 'PaymentBlock', label: 'Bloqueo de pago' },
centralBankIndicator: { type: 'text', key: 'CentralBankIndicator', label: 'Indicador banco central' },
installments: { type: 'number', key: 'NumberOfInstallments', label: 'Plazos', decimals: 0 },
/** Desde qué fecha se calcula el vencimiento (`StartFrom`) y los meses y días que se suman. */
startFrom: {
type: 'select',
key: 'StartFrom',
label: 'Volver a calcular desde',
options: [
{ value: 'pdt_None', label: 'Ninguno' },
{ value: 'pdt_MonthEnd', label: 'Fin de mes' },
{ value: 'pdt_HalfMonth', label: 'Mitad de mes' },
{ value: 'pdt_MonthStart', label: 'Inicio de mes' },
],
},
extraMonth: { type: 'number', key: 'ExtraMonth', label: 'Meses +', decimals: 0 },
extraDays: { type: 'number', key: 'ExtraDays', label: 'Días +', decimals: 0 },
/** Persona de contacto del socio. */
contact: { type: 'contact', key: 'ContactPerson', label: 'Persona de contacto' },
/** Dirección de destino (envío) del socio. */
@@ -320,11 +387,11 @@ export function marketingLayout(opts: {
FIELDS.docType,
{ type: 'partner', key: 'CardCode', label: opts.partnerLabel, required: true, missing: `el ${opts.partnerLabel.toLowerCase()}` },
{ type: 'computed', label: 'Nombre', source: 'partnerName' },
FIELDS.contact,
{ type: 'computed', label: 'RUT', source: 'partnerTaxId' },
FIELDS.numAtCard,
{ type: 'currency', label: 'Moneda / Tipo de cambio' },
...(opts.identity ? [] : [FIELDS.indicator]),
FIELDS.project,
...(opts.left ?? []),
],
// las tres fechas juntas, una debajo de la otra: contabilización, vencimiento y del documento
@@ -355,6 +422,28 @@ export function marketingLayout(opts: {
lines: { key: 'DocumentLines', fields: lineFieldsOf(serviceLineColumns(opts.taxResource)), base: true, service: true },
newLine: newServiceLine,
},
// pestañas como en SAP: Logística (destino, facturación, envío) y Finanzas (pago, cuenta asociada, proyecto)
tabs: {
logistics: {
left: [FIELDS.shipTo, { ...FIELDS.payTo, label: opts.uom === 'sales' ? 'Destinatario de factura' : 'Dirección de facturación' }, FIELDS.shippingType],
right: [FIELDS.trackingNumber, FIELDS.blockDunning],
},
finance: {
left: [
{ ...FIELDS.journalMemo, label: 'Entrada en el diario' },
FIELDS.controlAccount,
FIELDS.paymentBlock,
FIELDS.paymentTerms,
{ type: 'lookup', key: 'PaymentMethod', label: 'Forma de pago', lookup: paymentMethodLookup(opts.uom === 'sales' ? 'boptIncoming' : 'boptOutgoing') },
FIELDS.centralBankIndicator,
FIELDS.installments,
FIELDS.startFrom,
FIELDS.extraMonth,
FIELDS.extraDays,
],
right: [FIELDS.project],
},
},
seriesSubType: SERIES_SUBTYPE[String(opts.fixed?.['DocumentSubType'] ?? 'bod_None')] ?? '--',
...(opts.fixed ? { beforeCreate: (h: DocRecord) => ({ ...h, ...opts.fixed }) } : {}),
requiredLine: [],
@@ -367,6 +456,7 @@ export function marketingLayout(opts: {
const allFields = (layout: DocumentLayout): HeaderField[] => [
...layout.header.left,
...layout.header.right,
...(layout.tabs ? [...layout.tabs.logistics.left, ...layout.tabs.logistics.right, ...layout.tabs.finance.left, ...layout.tabs.finance.right] : []),
...layout.footer.left,
...layout.footer.right,
];