Files
basic-erp/apps/web/src/app/features/masters/master-field.ts
T

127 lines
4.6 KiB
TypeScript
Raw Normal View History

import { ChangeDetectionStrategy, Component, computed, input, output } from '@angular/core';
import { CheckboxField, DateField, LookupField, NumberField, SelectField, TextField, TextareaField } from '../../shared/form';
import { WAREHOUSE_LOOKUP } from '../documents/document-layouts';
import type { HeaderField } from '../documents/document-layouts';
const text = (v: unknown): string => (v === null || v === undefined ? '' : String(v));
/**
* Dibuja un campo de un formulario de maestro según su tipo. Recibe el valor tal como está en SAP
* (las casillas son `tYES` / `tNO`) y emite el nuevo valor en esa misma forma.
*/
@Component({
selector: 'sbo-master-field',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CheckboxField, DateField, LookupField, NumberField, SelectField, TextField, TextareaField],
template: `
@switch (field().type) {
@case ('checkbox') {
<sbo-checkbox-field
[label]="field().label"
[readonly]="readOnly() || !!ro()"
[value]="value() === 'tYES'"
(valueChange)="changed.emit($event ? 'tYES' : 'tNO')"
/>
}
@case ('lookup') {
<sbo-lookup-field
[label]="field().label"
[required]="required()"
[readonly]="readOnly()"
[value]="str()"
(valueChange)="changed.emit(typed($event))"
[lookup]="lookup()"
resolveOnLeave
/>
}
@case ('warehouse') {
<sbo-lookup-field
[label]="field().label"
[required]="required()"
[readonly]="readOnly()"
[value]="str()"
(valueChange)="changed.emit($event)"
[lookup]="warehouse"
resolveOnLeave
/>
}
@case ('select') {
<sbo-select-field
[label]="field().label"
[required]="required()"
[readonly]="readOnly()"
[options]="options()"
placeholder=""
[value]="str() || null"
(valueChange)="changed.emit($event ?? '')"
/>
}
@case ('number') {
<sbo-number-field
[label]="field().label"
[decimals]="decimals()"
[readonly]="readOnly() || !!ro()"
[value]="num()"
(valueChange)="changed.emit($event ?? 0)"
/>
}
@case ('date') {
<sbo-date-field [label]="field().label" [required]="required()" [readonly]="readOnly()" [value]="str()" (valueChange)="changed.emit($event)" />
}
@case ('textarea') {
<sbo-textarea-field [label]="field().label" [readonly]="readOnly()" [value]="str()" (valueChange)="changed.emit($event)" />
}
@default {
<sbo-text-field
[label]="field().label"
[required]="required()"
[readonly]="readOnly() || !!ro()"
[value]="str()"
(valueChange)="changed.emit($event)"
/>
}
}
`,
styles: ':host { display: block; }',
})
export class MasterField {
readonly field = input.required<HeaderField>();
readonly value = input<unknown>('');
/** Todo el formulario en solo lectura. */
readonly readOnly = input(false);
/** El registro ya existe: los campos `immutable` (el código) no se pueden cambiar. */
readonly saved = input(false);
readonly changed = output<string | number>();
protected readonly warehouse = WAREHOUSE_LOOKUP;
/** Un código numérico de SAP (grupo, lista de precios) se guarda como número. */
protected typed(code: string): string | number {
const f = this.field();
return f.type === 'lookup' && f.lookup.valueType === 'number' && /^\d+$/.test(code.trim()) ? Number(code) : code;
}
protected readonly str = computed(() => text(this.value()));
protected readonly num = computed(() => (this.value() === '' || this.value() === null || this.value() === undefined ? null : Number(this.value())));
protected readonly required = computed(() => {
const f = this.field();
return 'required' in f && f.required === true;
});
protected readonly ro = computed(() => {
const f = this.field();
if ('immutable' in f && f.immutable && this.saved()) return true;
return 'readonly' in f ? !!f.readonly : false;
});
protected readonly lookup = computed(() => {
const f = this.field();
if (f.type !== 'lookup') throw new Error('campo sin lista de valores');
return f.lookup;
});
protected readonly options = computed(() => {
const f = this.field();
return f.type === 'select' ? f.options : [];
});
protected readonly decimals = computed(() => {
const f = this.field();
return f.type === 'number' ? f.decimals : undefined;
});
}