feat(web): columnas de las listas de valores (cliente, artículo, almacén, impuesto) configurables por documento

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GeorgeandClaude Sonnet 5.5 committed 2026-10-14 15:39:53 -05:00
1 parent b3b47c34a3
commit 0d5a3074c8
6 files changed
+141 -12

No files matched your search

@@ -81,6 +81,7 @@ describe('formulario con campos de cliente', () => {
],
headerRight: [{ type: 'text', key: 'U_Obra', label: 'Obra' }],
lineColumns: [{ key: 'U_Lote', title: 'Lote' }],
lookupColumns: { partner: [{ key: 'U_Zona', title: 'Zona' }], item: [{ key: 'U_Marca', title: 'Marca' }] },
},
}),
'/ventas/ordenes',
@@ -127,6 +128,19 @@ describe('formulario con campos de cliente', () => {
expect([...el().querySelectorAll<HTMLInputElement>('input')].map((i) => i.value)).toEqual(expect.arrayContaining(['Torre 3', 'L-77']));
});
it('la ventana de artículos de una línea muestra las columnas del documento', async () => {
await open(order);
const itemBtn = el().querySelector('.pick button') as HTMLButtonElement;
itemBtn.click();
await tick();
const req = ctrl.expectOne((r) => r.url === '/api/sl/Items');
expect(req.request.params.get('$select')).toContain('U_Marca');
req.flush({ value: [{ ItemCode: 'A1', ItemName: 'Pieza', U_Marca: 'Acme' }], 'odata.count': '1' });
await tick();
expect([...el().querySelectorAll('.dlg thead th')].map((t) => t.textContent?.trim())).toEqual(expect.arrayContaining(['Código', 'Descripción', 'Marca']));
expect(el().querySelector('.dlg tbody')!.textContent).toContain('Acme');
});
it('al modificar envía solo el campo de usuario que cambió', async () => {
await open(order);
page().setHeader('U_Canal', 'T');
@@ -154,3 +168,57 @@ describe('formulario con campos de cliente', () => {
ctrl.expectOne('/api/sl/Orders/5').flush(order);
});
});
describe('columnas de las listas de valores por documento', () => {
const find = (screens: readonly { path: string }[], path: string) => by(screens, path).layout;
const itemCols = (path: string, screens = BASE_SCREENS) =>
find(screens, path).columns.find((c) => c.key === 'ItemCode')!.lookup!.config.columns.map((c) => c.key);
it('por defecto todos los documentos muestran código y descripción del artículo', () => {
expect(itemCols('/ventas/ordenes')).toEqual(['ItemCode', 'ItemName']);
expect(find(BASE_SCREENS, '/ventas/ordenes').lookups).toBeUndefined();
});
it('una pantalla del base cambia las columnas de su lista sin afectar a las demás', async () => {
const { marketingLayout } = await import('./document-layouts');
const layout = marketingLayout({
partnerLabel: 'Cliente',
taxResource: 'SalesTaxCodes',
lookups: {
item: [{ key: 'ItemCode', title: 'Código' }, { key: 'ItemName', title: 'Descripción' }, { key: 'QuantityOnStock', title: 'Stock', type: 'number' }],
partner: [{ key: 'CardCode', title: 'Código' }, { key: 'CardName', title: 'Nombre' }, { key: 'Phone1', title: 'Teléfono' }],
},
});
expect(layout.columns.find((c) => c.key === 'ItemCode')!.lookup!.config.columns.map((c) => c.key)).toEqual(['ItemCode', 'ItemName', 'QuantityOnStock']);
expect(layout.lookups!.partner!.map((c) => c.key)).toEqual(['CardCode', 'CardName', 'Phone1']);
// el recurso, el filtro y los campos extra de la lista no cambian
const cfg = layout.columns.find((c) => c.key === 'ItemCode')!.lookup!.config;
expect(cfg.resource).toBe('Items');
expect(cfg.extraFields).toEqual(expect.arrayContaining(['UoMGroupEntry']));
expect(itemCols('/ventas/facturas')).toEqual(['ItemCode', 'ItemName']);
});
it('una extensión de cliente suma columnas al final de las del base', () => {
const out = applyExtensions(BASE_SCREENS, {
'/ventas/ordenes': {
lookupColumns: {
item: [{ key: 'U_Marca', title: 'Marca' }],
partner: [{ key: 'U_Zona', title: 'Zona' }],
warehouse: [{ key: 'U_Sucursal', title: 'Sucursal' }],
},
},
});
expect(itemCols('/ventas/ordenes', out)).toEqual(['ItemCode', 'ItemName', 'U_Marca']);
const l = find(out, '/ventas/ordenes');
expect(l.lookups!.partner!.map((c) => c.key)).toEqual(['CardCode', 'CardName', 'U_Zona']);
expect(l.columns.find((c) => c.key === 'WarehouseCode')!.lookup!.config.columns.map((c) => c.key)).toEqual(['WarehouseCode', 'WarehouseName', 'U_Sucursal']);
expect(itemCols('/ventas/facturas', out)).toEqual(['ItemCode', 'ItemName']);
});
it('la lista de almacenes se aplica a las dos columnas de almacén de una transferencia', () => {
const out = applyExtensions(BASE_SCREENS, { '/inventario/transferencias': { lookupColumns: { warehouse: [{ key: 'U_Sucursal', title: 'Sucursal' }] } } });
const cols = find(out, '/inventario/transferencias').columns.filter((c) => c.lookup && /Warehouse/.test(c.key));
expect(cols).toHaveLength(2);
for (const c of cols) expect(c.lookup!.config.columns.at(-1)!.key).toBe('U_Sucursal');
});
});