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:
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). */
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user