feat(web): documentos de ventas y compras con tipo Artículo / Servicio (columnas de línea, validación, guardado y copiado)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
68d2cfe6d0
commit
2e74bccd65
11 files changed
+260
-25
No files matched your search
@@ -123,6 +123,8 @@ export interface LinesSpec {
|
||||
fields: readonly string[];
|
||||
/** Los documentos de ventas y compras referencian el origen de una línea copiada (`BaseType`…). */
|
||||
base: boolean;
|
||||
/** Líneas de un documento de servicio: cuenta contable, descripción, impuesto y total, sin artículo ni cantidad. */
|
||||
service?: boolean;
|
||||
}
|
||||
export const MARKETING_LINES: LinesSpec = { key: 'DocumentLines', fields: LINE_FIELDS, base: true };
|
||||
|
||||
@@ -130,13 +132,17 @@ export const MARKETING_LINES: LinesSpec = { key: 'DocumentLines', fields: LINE_F
|
||||
const BASE_FIELDS = ['BaseType', 'BaseEntry', 'BaseLine'] as const;
|
||||
const hasBase = (l: GridLine): boolean => hasBaseRef(l['BaseType'], l['BaseEntry']);
|
||||
|
||||
/** Una línea vacía (la fila en blanco que deja la grilla) no se envía. */
|
||||
export const isBlankLine = (line: GridLine): boolean => isEmpty(line['ItemCode']);
|
||||
/**
|
||||
* Una línea vacía (la fila en blanco que deja la grilla) no se envía. En un documento de artículos es la que no
|
||||
* tiene artículo; en uno de servicio, la que no tiene cuenta, descripción ni total.
|
||||
*/
|
||||
export const isBlankLine = (line: GridLine, service = false): boolean =>
|
||||
service ? isEmpty(line['AccountCode']) && isEmpty(line['ItemDescription']) && num(line['LineTotal']) === 0 : isEmpty(line['ItemCode']);
|
||||
|
||||
/** Líneas listas para SAP: sin filas en blanco ni campos vacíos. */
|
||||
export function linesPayload(lines: readonly GridLine[], spec: LinesSpec = MARKETING_LINES): DocRecord[] {
|
||||
return lines
|
||||
.filter((l) => !isBlankLine(l))
|
||||
.filter((l) => !isBlankLine(l, spec.service))
|
||||
.map((l) => {
|
||||
const out: DocRecord = {};
|
||||
for (const f of spec.fields) {
|
||||
@@ -171,12 +177,18 @@ export function validateLayout(
|
||||
lines: readonly GridLine[],
|
||||
requiredHeader: readonly RequiredField[],
|
||||
requiredLine: readonly RequiredField[],
|
||||
service = false,
|
||||
): string[] {
|
||||
const errors: string[] = [];
|
||||
for (const f of requiredHeader) if (isEmpty(header[f.key])) errors.push(`Indique ${f.label.toLowerCase()}.`);
|
||||
const real = lines.filter((l) => !isBlankLine(l));
|
||||
if (!real.length) errors.push('Agregue al menos una línea con artículo.');
|
||||
const real = lines.filter((l) => !isBlankLine(l, service));
|
||||
if (!real.length) errors.push(service ? 'Agregue al menos una línea con cuenta contable.' : 'Agregue al menos una línea con artículo.');
|
||||
real.forEach((l, i) => {
|
||||
if (service) {
|
||||
if (isEmpty(l['AccountCode'])) errors.push(`Línea ${i + 1}: indique la cuenta contable.`);
|
||||
if (num(l['LineTotal']) <= 0) errors.push(`Línea ${i + 1}: el total debe ser mayor que cero.`);
|
||||
return;
|
||||
}
|
||||
if (num(l['Quantity']) <= 0) errors.push(`Línea ${i + 1}: la cantidad debe ser mayor que cero.`);
|
||||
for (const f of requiredLine) if (isEmpty(l[f.key])) errors.push(`Línea ${i + 1}: indique ${f.label.toLowerCase()}.`);
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user