feat(web): el stock por almacén oculta los almacenes sin cantidades (casilla marcada por defecto; el total sigue sumando todos)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GeorgeandClaude Sonnet 5.5 committed 2026-10-19 19:08:17 -05:00
1 parent a659276d9a
commit aa520d574f
4 files changed
+25 -2

No files matched your search

@@ -148,6 +148,8 @@ export const ARTICULOS_SCREENS: readonly MasterScreen[] = [
key: 'ItemWarehouseInfoCollection',
mode: 'replace',
readonly: true,
hideEmptyBy: ['InStock', 'Committed', 'Ordered'],
hideEmptyLabel: 'Solo almacenes con stock, comprometido o pedido',
identity: ['WarehouseCode'],
columns: [
{ key: 'WarehouseCode', title: 'Almacén', type: 'text', width: '110px' },
@@ -45,6 +45,8 @@
[rows]="rowsOf(c)"
(rowsChange)="setRows(c, $event)"
[readonly]="!!c.readonly"
[hideEmptyBy]="c.readonly ? (c.hideEmptyBy ?? null) : null"
[hideEmptyLabel]="c.hideEmptyLabel ?? 'Ocultar las filas en 0'"
[removable]="growable(c)"
[emptyText]="c.readonly ? 'Sin datos.' : 'Sin filas.'"
/>
@@ -20,6 +20,9 @@ export interface MasterCollection {
mode: 'replace' | 'merge';
/** Campo que identifica una fila en `merge` (`PriceList`). */
rowKey?: string;
/** Columnas numéricas por las que se ocultan las filas en 0, con una casilla marcada por defecto (solo con `readonly`). */
hideEmptyBy?: readonly string[];
hideEmptyLabel?: string;
/** Solo se muestra (el stock por almacén). */
readonly?: boolean;
/** Se pueden añadir y quitar filas (por defecto sí; no en `merge` ni en solo lectura). */
+18 -2
View File
@@ -22,6 +22,9 @@ const dateOnly = (v: unknown): string => (typeof v === 'string' ? v.slice(0, 10)
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ValueHelp],
template: `
@if (hideEmptyBy()) {
<label class="only"><input type="checkbox" [checked]="onlyFilled()" (change)="onlyFilled.set($any($event.target).checked)" /> {{ hideEmptyLabel() }}</label>
}
<div class="wrap">
<table>
<thead>
@@ -47,7 +50,7 @@ const dateOnly = (v: unknown): string => (typeof v === 'string' ? v.slice(0, 10)
}
</thead>
<tbody>
@for (row of rows(); track $index; let i = $index) {
@for (row of shown(); track $index; let i = $index) {
<tr>
<td class="rn">{{ i + 1 }}</td>
@for (c of columns(); track c.key) {
@@ -99,7 +102,7 @@ const dateOnly = (v: unknown): string => (typeof v === 'string' ? v.slice(0, 10)
</tr>
} @empty {
<tr class="none">
<td [attr.colspan]="columns().length + 2">{{ emptyText() }}</td>
<td [attr.colspan]="columns().length + 2">{{ rows().length ? 'Ninguna fila cumple el filtro.' : emptyText() }}</td>
</tr>
}
</tbody>
@@ -130,6 +133,8 @@ const dateOnly = (v: unknown): string => (typeof v === 'string' ? v.slice(0, 10)
`,
styles: `
:host { display: block; }
.only { display: inline-flex; align-items: center; gap: 6px; margin-bottom: 6px; cursor: pointer; }
.only input { width: auto; height: auto; margin: 0; }
.pick { display: grid; grid-template-columns: minmax(0, 1fr) 22px; }
.pick button { padding: 0; background: var(--btn); border: 1px solid var(--field-b); border-radius: var(--radius); cursor: pointer; }
.pick button:hover { background: var(--btn-h); }
@@ -164,6 +169,17 @@ export class RowsTable {
/** Se pueden quitar filas (por defecto, si la tabla es editable). */
readonly removable = input(true);
readonly emptyText = input('Sin filas.');
/** Columnas numéricas por las que se puede ocultar las filas en 0 (solo lectura): aparece una casilla encima de la tabla, marcada. */
readonly hideEmptyBy = input<readonly string[] | null>(null);
readonly hideEmptyLabel = input('Ocultar las filas en 0');
protected readonly onlyFilled = signal(true);
/** Las filas que se ven; los totales siguen sumando todas. */
protected readonly shown = computed(() => {
const keys = this.hideEmptyBy();
const rows = this.rows();
if (!keys || !this.onlyFilled()) return rows;
return rows.filter((r) => keys.some((k) => Number(r[k]) !== 0 && Number.isFinite(Number(r[k]))));
});
private readonly lookupApi = inject(SlLookupApi);
private readonly http = inject(HttpClient);