@asteby/metacore-runtime-react 49.2.0 → 49.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/dist/action-modal-dispatcher.d.ts.map +1 -1
- package/dist/action-modal-dispatcher.js +12 -3
- package/dist/business/document-editor-model.d.ts +33 -1
- package/dist/business/document-editor-model.d.ts.map +1 -1
- package/dist/business/document-editor-model.js +105 -3
- package/dist/business/document-editor.d.ts.map +1 -1
- package/dist/business/document-editor.js +54 -25
- package/dist/dynamic-form-schema.d.ts +3 -26
- package/dist/dynamic-form-schema.d.ts.map +1 -1
- package/dist/dynamic-form-schema.js +4 -56
- package/dist/dynamic-row-actions.d.ts +6 -0
- package/dist/dynamic-row-actions.d.ts.map +1 -1
- package/dist/dynamic-row-actions.js +9 -4
- package/dist/option-when.d.ts +27 -0
- package/dist/option-when.d.ts.map +1 -0
- package/dist/option-when.js +56 -0
- package/dist/validator.d.ts.map +1 -1
- package/dist/validator.js +17 -7
- package/package.json +1 -1
- package/src/__tests__/document-editor-model.test.ts +14 -1
- package/src/__tests__/document-editor.test.tsx +23 -1
- package/src/__tests__/invoice-document-editor.test.tsx +4 -3
- package/src/__tests__/option-when-validation.test.tsx +87 -0
- package/src/__tests__/r6-editor-option-when.test.tsx +104 -0
- package/src/__tests__/r6-editor-source-seeds.test.tsx +137 -0
- package/src/__tests__/row-action-link-navigation.test.ts +10 -6
- package/src/action-modal-dispatcher.tsx +14 -5
- package/src/business/document-editor-model.ts +116 -3
- package/src/business/document-editor.tsx +59 -19
- package/src/dynamic-form-schema.ts +5 -55
- package/src/dynamic-row-actions.tsx +12 -4
- package/src/option-when.ts +61 -0
- package/src/validator.ts +17 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# @asteby/metacore-runtime-react
|
|
2
2
|
|
|
3
|
+
## 49.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 12b6d10: DocumentEditor «Cargar desde…»: al precargar solo lo pendiente de un renglón, el descuento en importe (`discount_mode: amount`) se prorratea a esa cantidad (cotización de 6 piezas con $1,200 de descuento y 4 pendientes → $800), en vez de arrastrar el importe completo y chocar con «El descuento no puede superar el importe». Un descuento en porcentaje no cambia. Avisos de carga en español más claro («con lo que falta · ya completos (omitidos)», «Documento de origen»).
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 0a64839: DocumentEditor: los selects con opciones condicionadas (`options[].when`) solo ofrecen las que aplican y ajustan solos un valor que dejó de aplicar.
|
|
12
|
+
|
|
13
|
+
Con método de pago PPD, la forma de pago pasa sola a «99 · Por definir» (la única que aplica) y el alta de la factura lleva los dos valores; al volver a PUE regresa al default del campo. Vale igual si el cambio viene de la contraparte o de «Cargar desde…».
|
|
14
|
+
|
|
15
|
+
- 0a64839: DocumentEditor: «Cargar desde» venta, OT o cotización deja el cliente elegido y los selectores muestran nombre o folio, no el UUID.
|
|
16
|
+
|
|
17
|
+
- La cabecera del origen (`sources[].header`, p. ej. `customer_id`, y `link_field`) se carga antes que los renglones, así que el cliente y su tarjeta llegan aunque los renglones del origen fallen.
|
|
18
|
+
- Los selectores que el editor llena por código (cliente, documento origen, «Factura a abonar» de la NC) se siembran con la etiqueta que ya conoce: el objeto hermano `{value,label}` que sirve el host, el nombre de la contraparte cargada o el folio del origen. El selector «Cargar desde…» también muestra el folio.
|
|
19
|
+
- La vista previa local muestra esas etiquetas, y un campo con `options` en objeto ya no rompe el resumen.
|
|
20
|
+
|
|
21
|
+
## 49.2.2
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- 4915386: `options[].when` también valida, no solo filtra el formulario genérico. El validador del cliente (`validateValues`) marca como `invalid_option` una opción que su `when` descarta con el valor actual del campo hermano (forma de pago «99» con método PUE, o PPD con una forma distinta de «99»), igual que el kernel al guardar. Las celdas de renglón se evalúan contra su renglón y el encabezado. `renderField` —el render compartido del DocumentEditor, del diálogo de document_forms y de los modales de acción— solo ofrece las opciones que aplican y marca en el acto un valor ya elegido que dejó de aplicar. `applyOptionWhen` y `getDependsOn` pasan a `option-when.ts` (se siguen exportando desde `dynamic-form-schema`).
|
|
26
|
+
|
|
27
|
+
## 49.2.1
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- c4a7056: «Nota de crédito» / crear-desde: navega con /m/$model + search (abre el editor con la factura, no solo la lista).
|
|
32
|
+
- c4a7056: DocumentEditor: «Cargar desde» venta, OT o cotización deja el cliente elegido y los selectores muestran nombre o folio, no el UUID.
|
|
33
|
+
|
|
34
|
+
- La cabecera del origen (`sources[].header`, p. ej. `customer_id`, y `link_field`) se carga antes que los renglones, así que el cliente y su tarjeta llegan aunque los renglones del origen fallen.
|
|
35
|
+
- Los selectores que el editor llena por código (cliente, documento origen, «Factura a abonar» de la NC) se siembran con la etiqueta que ya conoce: el objeto hermano `{value,label}` que sirve el host, el nombre de la contraparte cargada o el folio del origen. El selector «Cargar desde…» también muestra el folio.
|
|
36
|
+
- La vista previa local muestra esas etiquetas, y un campo con `options` en objeto ya no rompe el resumen.
|
|
37
|
+
|
|
3
38
|
## 49.2.0
|
|
4
39
|
|
|
5
40
|
### Minor Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-modal-dispatcher.d.ts","sourceRoot":"","sources":["../src/action-modal-dispatcher.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"action-modal-dispatcher.d.ts","sourceRoot":"","sources":["../src/action-modal-dispatcher.tsx"],"names":[],"mappings":"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"}
|
|
@@ -39,7 +39,7 @@ import { DynamicRelations } from './dynamic-relations';
|
|
|
39
39
|
import { DynamicSelectField } from './dynamic-select-field';
|
|
40
40
|
import { DynamicDateField } from './dynamic-date-field';
|
|
41
41
|
import { UploadField } from './upload-field';
|
|
42
|
-
import { isLineItemsField, resolveWidget, resolveDependsValue, getDependsOn, getFieldRef } from './dynamic-form-schema';
|
|
42
|
+
import { isLineItemsField, resolveWidget, resolveDependsValue, getDependsOn, getFieldRef, applyOptionWhen } from './dynamic-form-schema';
|
|
43
43
|
import { FieldGrid, FieldCell, FieldLabel } from './field-grid';
|
|
44
44
|
import { useMetadataCache } from './metadata-cache';
|
|
45
45
|
import { ViewValue, objectLabel, relationSiblingValue, isLineItemsField as isRecordLineItemsField, } from './dialogs/dynamic-record';
|
|
@@ -1194,8 +1194,17 @@ formValues, record, fieldErrors) {
|
|
|
1194
1194
|
switch (widget) {
|
|
1195
1195
|
case 'textarea':
|
|
1196
1196
|
return _jsx(Textarea, { id: field.key, value: value || '', onChange: (e) => onChange(e.target.value), placeholder: field.placeholder, "aria-invalid": invalid || undefined, className: invalidCls || undefined });
|
|
1197
|
-
case 'select':
|
|
1198
|
-
|
|
1197
|
+
case 'select': {
|
|
1198
|
+
// Opciones condicionadas por un campo hermano (`options[].when`, p. ej.
|
|
1199
|
+
// forma de pago «99» solo con método PPD): solo se ofrecen las que
|
|
1200
|
+
// aplican, y un valor ya elegido que dejó de aplicar se marca en el
|
|
1201
|
+
// acto (el validador y el kernel lo rechazan como invalid_option).
|
|
1202
|
+
const options = formValues ? applyOptionWhen(field.options, formValues, getDependsOn(field)) : field.options ?? [];
|
|
1203
|
+
const stale = !!value && !options.some((o) => String(o.value) === String(value));
|
|
1204
|
+
const selectInvalid = invalid || stale;
|
|
1205
|
+
const selectCls = selectInvalid ? 'border-destructive ring-1 ring-destructive/30 focus-visible:ring-destructive' : '';
|
|
1206
|
+
return (_jsxs(Select, { value: stale ? '' : value || '', onValueChange: onChange, children: [_jsx(SelectTrigger, { className: 'w-full' + (selectCls ? ` ${selectCls}` : ''), "aria-invalid": selectInvalid || undefined, "data-stale-option": stale || undefined, children: _jsx(SelectValue, { placeholder: field.placeholder || 'Seleccionar...' }) }), _jsx(SelectContent, { children: options.map((opt) => _jsx(SelectItem, { value: opt.value, children: opt.label }, opt.value)) })] }));
|
|
1207
|
+
}
|
|
1199
1208
|
case 'switch':
|
|
1200
1209
|
return _jsx(Switch, { id: field.key, checked: !!value, onCheckedChange: onChange });
|
|
1201
1210
|
case 'number':
|
|
@@ -44,6 +44,16 @@ export declare function splitEditorFields(fields: readonly ActionFieldDef[], opt
|
|
|
44
44
|
export declare function friendlyOptionLabel(label: string): string;
|
|
45
45
|
/** El mismo campo con sus opciones en formato «texto · código». */
|
|
46
46
|
export declare function withFriendlyOptions(f: ActionFieldDef): ActionFieldDef;
|
|
47
|
+
/** Opciones del select que aplican con los valores actuales (`options[].when`). */
|
|
48
|
+
export declare function gatedOptions(f: ActionFieldDef, values: Record<string, unknown>): ActionFieldDef;
|
|
49
|
+
/**
|
|
50
|
+
* Selects con opciones condicionadas (`options[].when`, p. ej. forma de pago
|
|
51
|
+
* «99» solo con método PPD): cuando el valor actual deja de aplicar —o está
|
|
52
|
+
* vacío y solo queda una opción— devuelve el que toca. Una sola opción
|
|
53
|
+
* permitida se elige sola; si hay varias, el default del campo si aplica; si
|
|
54
|
+
* no, vacío. Sin cambios devuelve `{}`, así que aplicarlo converge.
|
|
55
|
+
*/
|
|
56
|
+
export declare function gatedOptionFixes(fields: readonly ActionFieldDef[], values: Record<string, unknown>): Record<string, unknown>;
|
|
47
57
|
/**
|
|
48
58
|
* Defaults del encabezado que salen de la contraparte: los campos de extensión
|
|
49
59
|
* con la MISMA clave en ambos modelos (p. ej. `fiscal_data.uso_cfdi` de Customer
|
|
@@ -80,7 +90,8 @@ export declare function creditStatus(party: Record<string, any> | null, cols: {
|
|
|
80
90
|
*
|
|
81
91
|
* Con `remaining_quantity` (lo sirve el host: cantidad − lo ya facturado o
|
|
82
92
|
* devuelto) la cantidad sugerida y el tope son lo pendiente y los renglones ya
|
|
83
|
-
* cubiertos se omiten
|
|
93
|
+
* cubiertos se omiten; un descuento en importe se prorratea a lo pendiente (un
|
|
94
|
+
* porcentaje no cambia). Cada línea guarda `source_line_id` para el vínculo.
|
|
84
95
|
*/
|
|
85
96
|
export declare function linesFromSource(rows: unknown, map?: Record<string, string>, opts?: {
|
|
86
97
|
kind?: DocumentFormLines['kind'];
|
|
@@ -96,6 +107,27 @@ export declare function sourceLoadSummary(rows: unknown): {
|
|
|
96
107
|
};
|
|
97
108
|
/** Fuente que precarga desde lo pendiente servido por el host (no desde la relación cruda). */
|
|
98
109
|
export declare function sourceTracksRemaining(src: Pick<DocumentFormSource, 'line_link_field' | 'remaining_qty_field' | 'remaining_endpoint'>): boolean;
|
|
110
|
+
/** Opción ya resuelta de un selector de la cabecera que el editor llenó por código. */
|
|
111
|
+
export interface SeedLabel {
|
|
112
|
+
value: string;
|
|
113
|
+
label: string;
|
|
114
|
+
}
|
|
115
|
+
/** Nombre visible de un registro: la columna declarada por el campo, luego folio/nombre. */
|
|
116
|
+
export declare function recordLabel(rec: Record<string, any> | null | undefined, preferred?: string): string | undefined;
|
|
117
|
+
/**
|
|
118
|
+
* Etiquetas de lo que «Cargar desde…» escribe en la cabecera, para que el
|
|
119
|
+
* selector muestre el nombre y no el UUID sin abrirse:
|
|
120
|
+
* - `header` (`customer_id ← customer_id`): el objeto hermano `{value,label}`
|
|
121
|
+
* que el host sirve junto a la FK (`customer`);
|
|
122
|
+
* - `link_field`: el propio documento origen, con su folio.
|
|
123
|
+
*/
|
|
124
|
+
export declare function sourceHeaderSeeds(src: Pick<DocumentFormSource, 'header' | 'link_field'>, rec: Record<string, any>, id: string, fields?: readonly ActionFieldDef[]): Record<string, SeedLabel>;
|
|
125
|
+
/**
|
|
126
|
+
* Registro para `renderField` con las etiquetas sembradas como objeto hermano
|
|
127
|
+
* (`customer_id` → `customer: {value,label}`), el mismo contrato que sirve el
|
|
128
|
+
* host en una fila. Conserva el registro desde el que se abrió.
|
|
129
|
+
*/
|
|
130
|
+
export declare function seedRecord(seeds: Record<string, SeedLabel>, record?: Record<string, any>): Record<string, any> | undefined;
|
|
99
131
|
export interface EditorIssue {
|
|
100
132
|
field?: string;
|
|
101
133
|
severity: 'error' | 'warning';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-editor-model.d.ts","sourceRoot":"","sources":["../../src/business/document-editor-model.ts"],"names":[],"mappings":"AAMA,OAAO,EAA2B,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"document-editor-model.d.ts","sourceRoot":"","sources":["../../src/business/document-editor-model.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { roundMoney, toAmount } from './format';
|
|
7
7
|
import { computeTotals, makeLine } from './line-items';
|
|
8
8
|
import { optionPassesRule, getOptionFilter } from '../option-filter';
|
|
9
|
+
import { applyOptionWhen, getDependsOn } from '../dynamic-form-schema';
|
|
9
10
|
export const EXTENSION_PREFIX = 'fiscal_data.';
|
|
10
11
|
/** Secciones de campo que el editor pliega en «Opciones fiscales». */
|
|
11
12
|
const ADVANCED_SECTIONS = new Set(['fiscal', 'advanced']);
|
|
@@ -93,6 +94,42 @@ export function withFriendlyOptions(f) {
|
|
|
93
94
|
return f;
|
|
94
95
|
return { ...f, options: f.options.map((o) => ({ ...o, label: friendlyOptionLabel(String(o.label ?? o.value)) })) };
|
|
95
96
|
}
|
|
97
|
+
/** Select estático con alguna opción condicionada por otro campo (`options[].when`). */
|
|
98
|
+
function isGatedSelect(f) {
|
|
99
|
+
return Array.isArray(f.options) && f.options.some((o) => !!o?.when);
|
|
100
|
+
}
|
|
101
|
+
/** Opciones del select que aplican con los valores actuales (`options[].when`). */
|
|
102
|
+
export function gatedOptions(f, values) {
|
|
103
|
+
if (!isGatedSelect(f))
|
|
104
|
+
return f;
|
|
105
|
+
return { ...f, options: applyOptionWhen(f.options, values, getDependsOn(f)) };
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Selects con opciones condicionadas (`options[].when`, p. ej. forma de pago
|
|
109
|
+
* «99» solo con método PPD): cuando el valor actual deja de aplicar —o está
|
|
110
|
+
* vacío y solo queda una opción— devuelve el que toca. Una sola opción
|
|
111
|
+
* permitida se elige sola; si hay varias, el default del campo si aplica; si
|
|
112
|
+
* no, vacío. Sin cambios devuelve `{}`, así que aplicarlo converge.
|
|
113
|
+
*/
|
|
114
|
+
export function gatedOptionFixes(fields, values) {
|
|
115
|
+
const out = {};
|
|
116
|
+
for (const f of fields) {
|
|
117
|
+
if (!isGatedSelect(f))
|
|
118
|
+
continue;
|
|
119
|
+
const allowed = applyOptionWhen(f.options, values, getDependsOn(f));
|
|
120
|
+
const cur = values[f.key];
|
|
121
|
+
const ok = (v) => hasValue(v) && allowed.some((o) => String(o.value) === String(v));
|
|
122
|
+
if (ok(cur))
|
|
123
|
+
continue;
|
|
124
|
+
if (!hasValue(cur) && allowed.length !== 1)
|
|
125
|
+
continue;
|
|
126
|
+
const def = declaredDefault(f);
|
|
127
|
+
const next = allowed.length === 1 ? allowed[0].value : ok(def) ? def : '';
|
|
128
|
+
if (String(next ?? '') !== String(cur ?? ''))
|
|
129
|
+
out[f.key] = next;
|
|
130
|
+
}
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
96
133
|
/**
|
|
97
134
|
* Defaults del encabezado que salen de la contraparte: los campos de extensión
|
|
98
135
|
* con la MISMA clave en ambos modelos (p. ej. `fiscal_data.uso_cfdi` de Customer
|
|
@@ -159,7 +196,8 @@ export function creditStatus(party, cols, documentTotal) {
|
|
|
159
196
|
*
|
|
160
197
|
* Con `remaining_quantity` (lo sirve el host: cantidad − lo ya facturado o
|
|
161
198
|
* devuelto) la cantidad sugerida y el tope son lo pendiente y los renglones ya
|
|
162
|
-
* cubiertos se omiten
|
|
199
|
+
* cubiertos se omiten; un descuento en importe se prorratea a lo pendiente (un
|
|
200
|
+
* porcentaje no cambia). Cada línea guarda `source_line_id` para el vínculo.
|
|
163
201
|
*/
|
|
164
202
|
export function linesFromSource(rows, map = {}, opts = {}) {
|
|
165
203
|
if (!Array.isArray(rows))
|
|
@@ -193,8 +231,16 @@ export function linesFromSource(rows, map = {}, opts = {}) {
|
|
|
193
231
|
});
|
|
194
232
|
// El descuento del origen se lee en la unidad del documento (importe en
|
|
195
233
|
// modelos cuyo subtotal resta un monto).
|
|
196
|
-
if (opts.discountMode === 'amount')
|
|
234
|
+
if (opts.discountMode === 'amount') {
|
|
197
235
|
line.discount_kind = 'amount';
|
|
236
|
+
// Un importe es de TODO el renglón de origen: al cargar solo lo
|
|
237
|
+
// pendiente se prorratea a esa cantidad (4 llantas con $400 de
|
|
238
|
+
// descuento, 1 pendiente → $100), si no superaría el importe.
|
|
239
|
+
const sourceQty = toAmount(r.source_quantity ?? get('quantity'));
|
|
240
|
+
if (pending != null && sourceQty > 0 && pending < sourceQty) {
|
|
241
|
+
line.discount = roundMoney((toAmount(line.discount) * pending) / sourceQty);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
198
244
|
if (pending != null)
|
|
199
245
|
line.max_quantity = pending;
|
|
200
246
|
else if (opts.kind === 'credit')
|
|
@@ -248,6 +294,62 @@ export function sourceLoadSummary(rows) {
|
|
|
248
294
|
export function sourceTracksRemaining(src) {
|
|
249
295
|
return !!(src.line_link_field || src.remaining_qty_field || src.remaining_endpoint);
|
|
250
296
|
}
|
|
297
|
+
/** Columnas con las que se nombra un documento (folio antes que nombre). */
|
|
298
|
+
const DOCUMENT_LABEL_COLUMNS = ['number', 'folio', 'order_number', 'name', 'title', 'code'];
|
|
299
|
+
function declaredOptionLabel(f) {
|
|
300
|
+
const opts = f?.options;
|
|
301
|
+
const l = opts && !Array.isArray(opts) && typeof opts === 'object' ? opts.label : undefined;
|
|
302
|
+
return typeof l === 'string' && l ? l : undefined;
|
|
303
|
+
}
|
|
304
|
+
/** Nombre visible de un registro: la columna declarada por el campo, luego folio/nombre. */
|
|
305
|
+
export function recordLabel(rec, preferred) {
|
|
306
|
+
if (!rec)
|
|
307
|
+
return undefined;
|
|
308
|
+
for (const c of preferred ? [preferred, ...DOCUMENT_LABEL_COLUMNS] : DOCUMENT_LABEL_COLUMNS) {
|
|
309
|
+
const v = rec[c];
|
|
310
|
+
if ((typeof v === 'string' && v.trim()) || typeof v === 'number')
|
|
311
|
+
return String(v);
|
|
312
|
+
}
|
|
313
|
+
return undefined;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Etiquetas de lo que «Cargar desde…» escribe en la cabecera, para que el
|
|
317
|
+
* selector muestre el nombre y no el UUID sin abrirse:
|
|
318
|
+
* - `header` (`customer_id ← customer_id`): el objeto hermano `{value,label}`
|
|
319
|
+
* que el host sirve junto a la FK (`customer`);
|
|
320
|
+
* - `link_field`: el propio documento origen, con su folio.
|
|
321
|
+
*/
|
|
322
|
+
export function sourceHeaderSeeds(src, rec, id, fields = []) {
|
|
323
|
+
const out = {};
|
|
324
|
+
for (const [to, from] of Object.entries(src.header ?? {})) {
|
|
325
|
+
if (!from.endsWith('_id'))
|
|
326
|
+
continue;
|
|
327
|
+
const v = refValue(rec[from]);
|
|
328
|
+
const label = refLabel(rec[from]) ?? refLabel(rec[from.slice(0, -3)]);
|
|
329
|
+
if (v && label)
|
|
330
|
+
out[to] = { value: v, label };
|
|
331
|
+
}
|
|
332
|
+
if (src.link_field) {
|
|
333
|
+
const label = recordLabel(rec, declaredOptionLabel(fields.find((f) => f.key === src.link_field)));
|
|
334
|
+
if (label)
|
|
335
|
+
out[src.link_field] = { value: id, label };
|
|
336
|
+
}
|
|
337
|
+
return out;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Registro para `renderField` con las etiquetas sembradas como objeto hermano
|
|
341
|
+
* (`customer_id` → `customer: {value,label}`), el mismo contrato que sirve el
|
|
342
|
+
* host en una fila. Conserva el registro desde el que se abrió.
|
|
343
|
+
*/
|
|
344
|
+
export function seedRecord(seeds, record) {
|
|
345
|
+
const keys = Object.keys(seeds).filter((k) => k.endsWith('_id'));
|
|
346
|
+
if (keys.length === 0)
|
|
347
|
+
return record;
|
|
348
|
+
const out = { ...(record ?? {}) };
|
|
349
|
+
for (const k of keys)
|
|
350
|
+
out[k.slice(0, -3)] = seeds[k];
|
|
351
|
+
return out;
|
|
352
|
+
}
|
|
251
353
|
/** Revisión local (instantánea) de los renglones. Sin ruido: solo lo que hay que mirar. */
|
|
252
354
|
export function localIssues(lines, opts = {}) {
|
|
253
355
|
const issues = [];
|
|
@@ -267,7 +369,7 @@ export function localIssues(lines, opts = {}) {
|
|
|
267
369
|
issues.push({
|
|
268
370
|
field: `lines.${i}`,
|
|
269
371
|
severity: 'error',
|
|
270
|
-
message: `Renglón ${i + 1}: la cantidad excede lo pendiente del documento origen (${l.max_quantity}).`,
|
|
372
|
+
message: `Renglón ${i + 1}: la cantidad excede lo pendiente del documento origen (quedan ${l.max_quantity}).`,
|
|
271
373
|
});
|
|
272
374
|
}
|
|
273
375
|
if (opts.requireTax && toAmount(l.tax_rate) === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-editor.d.ts","sourceRoot":"","sources":["../../src/business/document-editor.tsx"],"names":[],"mappings":"AA4BA,OAAO,EAAqB,KAAK,sBAAsB,EAAwB,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"document-editor.d.ts","sourceRoot":"","sources":["../../src/business/document-editor.tsx"],"names":[],"mappings":"AA4BA,OAAO,EAAqB,KAAK,sBAAsB,EAAwB,MAAM,qBAAqB,CAAA;AAkD1G,OAAO,KAAK,EAAsC,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AAE3G,MAAM,WAAW,mBAAmB;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,qBAAqB,CAAA;IAC5B,IAAI,EAAE,gBAAgB,CAAA;IACtB,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC5B,oEAAoE;IACpE,aAAa,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAA;IAC3C,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACpC,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,cAAc,CAAC,EAAE,sBAAsB,CAAC,QAAQ,CAAC,CAAA;IACjD,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,IAAI,CAAA;IACZ;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;CACvB;AAID,wBAAgB,cAAc,CAAC,EAC3B,KAAK,EACL,QAAQ,EACR,KAAK,EACL,IAAI,EACJ,MAAM,EACN,aAAa,EACb,OAAO,EACP,QAAQ,EACR,cAAc,EACd,YAAY,EACZ,cAAc,EACd,QAAQ,EACR,KAAK,EACL,UAAkB,GACrB,EAAE,mBAAmB,+BAwuBrB"}
|
|
@@ -31,7 +31,7 @@ import { DocumentLinesGrid } from './line-items-editor';
|
|
|
31
31
|
import { computeTotals, serializeLineItems, taxBreakdown } from './line-items';
|
|
32
32
|
import { roundMoney, toAmount, useFormatter } from './format';
|
|
33
33
|
import { createCatalogProductSearch } from './catalog-product-search';
|
|
34
|
-
import { allocationAmountField, allocationIssueMessages, allocationPayload, creditStatus, editorLinesConfig, linesFromSource, localIssues, sourceLoadSummary, sourceTracksRemaining, partyDefaults, partySummaryRows, splitEditorFields, toOpenDocuments, friendlyOptionLabel, withFriendlyOptions, } from './document-editor-model';
|
|
34
|
+
import { allocationAmountField, allocationIssueMessages, allocationPayload, creditStatus, editorLinesConfig, linesFromSource, localIssues, sourceLoadSummary, sourceTracksRemaining, partyDefaults, partySummaryRows, recordLabel, seedRecord, sourceHeaderSeeds, splitEditorFields, toOpenDocuments, friendlyOptionLabel, gatedOptionFixes, gatedOptions, withFriendlyOptions, } from './document-editor-model';
|
|
35
35
|
import { CollapsibleSection, DraftPreview, EditorSection, PartyCard, PreviewPanel, TotalsPanel, ValidationChecklist, } from './document-editor-panels';
|
|
36
36
|
import { PaymentAllocator } from './payment-allocator';
|
|
37
37
|
import { actionErrorBannerMessage, buildFieldDefaults, prefillFromFieldRelationRequest, renderField } from '../action-modal-dispatcher';
|
|
@@ -65,6 +65,9 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
|
|
|
65
65
|
const [extFields, setExtFields] = useState([]);
|
|
66
66
|
const [party, setParty] = useState(null);
|
|
67
67
|
const [partyLabels, setPartyLabels] = useState({});
|
|
68
|
+
// Etiquetas de los selectores que el editor llena por código (contraparte y
|
|
69
|
+
// documento origen de «Cargar desde…»): sin ellas el selector cerrado pinta el UUID.
|
|
70
|
+
const [seeds, setSeeds] = useState({});
|
|
68
71
|
const [openDocs, setOpenDocs] = useState([]);
|
|
69
72
|
const [docsLoading, setDocsLoading] = useState(false);
|
|
70
73
|
const [alloc, setAlloc] = useState({ strategy: 'oldest_due_first', manual: {} });
|
|
@@ -84,6 +87,7 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
|
|
|
84
87
|
// renglón para que el servidor descuente lo ya facturado/devuelto y valide.
|
|
85
88
|
const [loadedSource, setLoadedSource] = useState(null);
|
|
86
89
|
const [sourceNote, setSourceNote] = useState();
|
|
90
|
+
const [sourceSeed, setSourceSeed] = useState(null);
|
|
87
91
|
const relCache = useRef(new Map());
|
|
88
92
|
const taxRate = defaultTaxRate ?? orgTaxRate;
|
|
89
93
|
const search = useMemo(() => searchProducts ?? createCatalogProductSearch(api, { model: productModel, defaultTaxRate: taxRate }), [searchProducts, api, productModel, taxRate]);
|
|
@@ -115,6 +119,15 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
|
|
|
115
119
|
const allFields = useMemo(() => [...(groups.party ? [groups.party] : []), ...groups.essential, ...groups.advanced, ...groups.notes], [groups]);
|
|
116
120
|
const fieldKeys = useRef([]);
|
|
117
121
|
fieldKeys.current = allFields.map((f) => f.key);
|
|
122
|
+
// Opciones condicionadas (`options[].when`): al cambiar el campo del que
|
|
123
|
+
// dependen —a mano, por la contraparte o por «Cargar desde…»— el valor que
|
|
124
|
+
// dejó de aplicar se ajusta solo (método PPD → forma de pago 99) y viaja así
|
|
125
|
+
// en el alta, no solo en el diálogo de timbrado.
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
const fixes = gatedOptionFixes(allFields, header);
|
|
128
|
+
if (Object.keys(fixes).length > 0)
|
|
129
|
+
setHeader((h) => ({ ...h, ...gatedOptionFixes(allFields, h) }));
|
|
130
|
+
}, [allFields, header]);
|
|
118
131
|
// Contraparte: tarjeta + defaults de las extensiones con la misma clave.
|
|
119
132
|
const partyId = type.party ? header[type.party.field] : undefined;
|
|
120
133
|
useEffect(() => {
|
|
@@ -132,6 +145,11 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
|
|
|
132
145
|
return;
|
|
133
146
|
setParty(rec);
|
|
134
147
|
setHeader((h) => ({ ...h, ...partyDefaults(rec, fieldKeys.current, h) }));
|
|
148
|
+
const label = recordLabel(rec, 'name') ?? recordLabel(rec, 'legal_name');
|
|
149
|
+
if (label && type.party) {
|
|
150
|
+
const key = type.party.field;
|
|
151
|
+
setSeeds((s) => ({ ...s, [key]: { value: String(partyId), label } }));
|
|
152
|
+
}
|
|
135
153
|
})
|
|
136
154
|
.catch(() => !cancelled && setParty(null));
|
|
137
155
|
return () => {
|
|
@@ -294,6 +312,28 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
|
|
|
294
312
|
return;
|
|
295
313
|
setBusy('source');
|
|
296
314
|
try {
|
|
315
|
+
// Cabecera primero (cliente, moneda, vínculo): llega aunque los
|
|
316
|
+
// renglones del origen fallen, y la tarjeta del cliente se carga.
|
|
317
|
+
if (src.header || src.link_field) {
|
|
318
|
+
const h = await api.get(`/data/${src.model}`, { params: { f_id: `eq:${id}`, per_page: 1 } });
|
|
319
|
+
const rec = ((h?.data?.data ?? [])[0] ?? {});
|
|
320
|
+
setHeader((prev) => {
|
|
321
|
+
const next = { ...prev };
|
|
322
|
+
for (const [to, from] of Object.entries(src.header ?? {})) {
|
|
323
|
+
const v = rec[from];
|
|
324
|
+
if (v == null || v === '')
|
|
325
|
+
continue;
|
|
326
|
+
next[to] = typeof v === 'object' && !Array.isArray(v) ? v.value ?? v.id ?? v : v;
|
|
327
|
+
}
|
|
328
|
+
if (src.link_field)
|
|
329
|
+
next[src.link_field] = id;
|
|
330
|
+
return next;
|
|
331
|
+
});
|
|
332
|
+
const seeded = sourceHeaderSeeds(src, rec, id, type.fields);
|
|
333
|
+
setSeeds((s) => ({ ...s, ...seeded }));
|
|
334
|
+
const label = src.link_field ? seeded[src.link_field]?.label : recordLabel(rec);
|
|
335
|
+
setSourceSeed(label ? { value: id, label } : null);
|
|
336
|
+
}
|
|
297
337
|
if (!isAllocation) {
|
|
298
338
|
const rows = await fetchSourceRows(src, id);
|
|
299
339
|
const loaded = linesFromSource(rows, src.map, { kind, discountMode: lineCfg.discount_mode, defaultTaxRate: taxRate });
|
|
@@ -303,29 +343,16 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
|
|
|
303
343
|
setLinesFromSourceDoc(kind === 'credit');
|
|
304
344
|
setSourceNote(loaded.length === 0 && covered > 0
|
|
305
345
|
? t('documentEditor.source_all_covered', {
|
|
306
|
-
defaultValue: '
|
|
346
|
+
defaultValue: 'Ese documento ya se registró completo; no queda nada pendiente.',
|
|
307
347
|
})
|
|
308
348
|
: covered > 0
|
|
309
349
|
? t('documentEditor.source_loaded_partial', {
|
|
310
|
-
defaultValue: '{{count}} renglones con lo
|
|
350
|
+
defaultValue: '{{count}} renglones con lo que falta · {{covered}} ya completos (omitidos)',
|
|
311
351
|
count: loaded.length,
|
|
312
352
|
covered,
|
|
313
353
|
})
|
|
314
354
|
: t('documentEditor.source_loaded', { defaultValue: '{{count}} renglones cargados', count: loaded.length }));
|
|
315
355
|
}
|
|
316
|
-
if (src.header || src.link_field) {
|
|
317
|
-
const h = await api.get(`/data/${src.model}`, { params: { f_id: `eq:${id}`, per_page: 1 } });
|
|
318
|
-
const rec = ((h?.data?.data ?? [])[0] ?? {});
|
|
319
|
-
setHeader((prev) => {
|
|
320
|
-
const next = { ...prev };
|
|
321
|
-
for (const [to, from] of Object.entries(src.header ?? {}))
|
|
322
|
-
if (rec[from] != null)
|
|
323
|
-
next[to] = rec[from];
|
|
324
|
-
if (src.link_field)
|
|
325
|
-
next[src.link_field] = id;
|
|
326
|
-
return next;
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
356
|
setServerIssues([]);
|
|
330
357
|
}
|
|
331
358
|
catch (err) {
|
|
@@ -336,7 +363,7 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
|
|
|
336
363
|
finally {
|
|
337
364
|
setBusy(null);
|
|
338
365
|
}
|
|
339
|
-
}, [api, lineCfg, isAllocation, kind, t, fetchSourceRows, taxRate]);
|
|
366
|
+
}, [api, lineCfg, isAllocation, kind, t, fetchSourceRows, taxRate, type.fields]);
|
|
340
367
|
// Prefill al abrir desde un documento origen (acción de fila «Crear NC», «Facturar venta»…).
|
|
341
368
|
const autoLoaded = useRef(false);
|
|
342
369
|
useEffect(() => {
|
|
@@ -454,7 +481,8 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
|
|
|
454
481
|
setHeader((h) => ({ ...h, [key]: value }));
|
|
455
482
|
setFieldErrors((prev) => clearFieldErrorTree(prev, key));
|
|
456
483
|
};
|
|
457
|
-
const
|
|
484
|
+
const fieldRecord = useMemo(() => seedRecord(seeds, record), [seeds, record]);
|
|
485
|
+
const fieldCell = (field, fullWidth = false) => visible(field) ? (_jsxs(FieldCell, { fullWidth: fullWidth, children: [_jsx(FieldLabel, { htmlFor: field.key, required: field.required, children: tl(field.label) }), renderField(withFriendlyOptions(gatedOptions(field, header)), header[field.key], (v) => updateField(field.key, v), header, fieldRecord, fieldErrors), fieldErrors[field.key] && _jsx("p", { className: "mt-1 text-xs text-destructive", children: fieldErrors[field.key] })] }, field.key)) : null;
|
|
458
486
|
const summaryRows = partySummaryRows(party, type.party?.summary, {
|
|
459
487
|
...Object.fromEntries(Object.entries(partyLabels).map(([k, v]) => [k, tl(v)])),
|
|
460
488
|
...Object.fromEntries(allFields.map((f) => [f.key, tl(f.label)])),
|
|
@@ -465,7 +493,7 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
|
|
|
465
493
|
const v = header[f.key];
|
|
466
494
|
if (v == null || v === '')
|
|
467
495
|
return null;
|
|
468
|
-
const opt = f.options
|
|
496
|
+
const opt = Array.isArray(f.options) ? f.options.find((o) => String(o.value) === String(v)) : undefined;
|
|
469
497
|
return opt ? String(opt.value) : String(v);
|
|
470
498
|
})
|
|
471
499
|
.filter(Boolean)
|
|
@@ -498,10 +526,10 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
|
|
|
498
526
|
// la suya local (encabezado, renglones y totales): sin borrador ni red.
|
|
499
527
|
const localPreview = !previewEnabled && !type.preview && !!lineCfg && !isAllocation && kind !== 'credit';
|
|
500
528
|
const essentials = (_jsxs(EditorSection, { slot: "editor-essentials", children: [_jsxs(FieldGrid, { children: [groups.party && fieldCell(groups.party), groups.essential.map((f) => fieldCell(f))] }), party && (_jsx(PartyCard, { name: party.name ?? party.legal_name, rows: summaryRows, credit: credit, fmt: fmt, children: partyContribs.map(({ id, component: C }) => (_jsx(C, { ...contribProps }, id))) }))] }));
|
|
501
|
-
const loadFrom = sources.length > 0 && !isAllocation && (_jsx(EditorSection, { slot: "load-from-source", title: t('documentEditor.load_from', { defaultValue: 'Cargar desde…' }), hint: busy === 'source' ? t('documentEditor.loading_source', { defaultValue: 'Cargando…' }) : sourceNote, children: _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [sources.length > 1 && (_jsx("div", { role: "radiogroup", "aria-label": t('documentEditor.source_kind', { defaultValue: '
|
|
529
|
+
const loadFrom = sources.length > 0 && !isAllocation && (_jsx(EditorSection, { slot: "load-from-source", title: t('documentEditor.load_from', { defaultValue: 'Cargar desde…' }), hint: busy === 'source' ? t('documentEditor.loading_source', { defaultValue: 'Cargando…' }) : sourceNote, children: _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [sources.length > 1 && (_jsx("div", { role: "radiogroup", "aria-label": t('documentEditor.source_kind', { defaultValue: 'Documento de origen' }), className: "inline-flex flex-wrap gap-1 rounded-md border p-1", children: sources.map((s) => (_jsx("button", { type: "button", role: "radio", "aria-checked": s.key === sourceKey, "data-source-kind": s.key, onClick: () => {
|
|
502
530
|
setSourceKey(s.key);
|
|
503
531
|
setSourceId('');
|
|
504
|
-
}, className: `rounded px-3 py-1.5 text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ${s.key === sourceKey ? 'bg-primary/10 font-medium text-primary' : 'text-muted-foreground hover:bg-accent'}`, children: tl(s.label) }, s.key))) })), activeSource && (_jsx(SourcePicker, { source: activeSource, value: sourceId, header: header, label: tl(activeSource.label), onPick: (id) => {
|
|
532
|
+
}, className: `rounded px-3 py-1.5 text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ${s.key === sourceKey ? 'bg-primary/10 font-medium text-primary' : 'text-muted-foreground hover:bg-accent'}`, children: tl(s.label) }, s.key))) })), activeSource && (_jsx(SourcePicker, { source: activeSource, value: sourceId, seed: sourceSeed, header: header, label: tl(activeSource.label), onPick: (id) => {
|
|
505
533
|
setSourceKey(activeSource.key);
|
|
506
534
|
setSourceId(id);
|
|
507
535
|
if (id)
|
|
@@ -519,15 +547,16 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
|
|
|
519
547
|
.filter(visible)
|
|
520
548
|
.map((f) => {
|
|
521
549
|
const v = header[f.key];
|
|
522
|
-
const opt = f.options
|
|
523
|
-
|
|
550
|
+
const opt = Array.isArray(f.options) ? f.options.find((o) => String(o.value) === String(v)) : undefined;
|
|
551
|
+
const seeded = seeds[f.key] && String(seeds[f.key].value) === String(v) ? seeds[f.key].label : undefined;
|
|
552
|
+
return { label: tl(f.label), value: v == null || v === '' ? '' : opt ? friendlyOptionLabel(tl(String(opt.label ?? v))) : seeded ?? String(v) };
|
|
524
553
|
})
|
|
525
554
|
.filter((r) => r.value), lines: lines, totals: totalsRows, fmt: fmt }) })) : null;
|
|
526
555
|
const checklist = _jsx(ValidationChecklist, { issues: shownIssues, title: t('documentEditor.review', { defaultValue: 'Revisa antes de guardar' }) });
|
|
527
556
|
return (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col", "data-slot": "document-editor", "data-kind": kind, "data-layout": fullscreen ? 'fullscreen' : 'dialog', children: [fullscreen ? (_jsxs("div", { className: "-mx-1 min-h-0 flex-1 overflow-y-auto px-1 py-2 lg:grid lg:grid-cols-[minmax(0,1fr)_340px] lg:gap-8", children: [_jsxs("div", { className: "min-w-0 space-y-8", "data-slot": "editor-main", children: [_jsx(FormErrorBanner, { message: formError }), essentials, loadFrom, linesSection, advanced, contributedSections, notes] }), _jsxs("aside", { className: "mt-8 space-y-6 lg:sticky lg:top-0 lg:mt-0 lg:self-start", "data-slot": "editor-aside", children: [_jsx("div", { className: "rounded-lg border p-4", children: totalsPanel }), checklist, previewSection] })] })) : (_jsxs("div", { className: "-mx-1 min-h-0 flex-1 space-y-8 overflow-y-auto px-1 py-2", children: [_jsx(FormErrorBanner, { message: formError }), essentials, loadFrom, linesSection, advanced, contributedSections, notes, previewSection, checklist] })), _jsxs("footer", { className: "flex shrink-0 flex-wrap items-center justify-end gap-2 border-t pt-4", "data-slot": "editor-actions", children: [footerContribs.map(({ id, component: C }) => (_jsx(C, { ...contribProps }, id))), _jsx(Button, { type: "button", variant: "ghost", onClick: onCancel, disabled: busy === 'save', children: t('common.cancel', { defaultValue: 'Cancelar' }) }), _jsxs(Button, { type: "button", "data-primary": "true", onClick: () => void submit(), disabled: busy !== null, children: [busy === 'save' && _jsx(Loader2, { className: "mr-2 size-4 animate-spin", "aria-hidden": true }), type.submit_label ? tl(type.submit_label) : t('common.save', { defaultValue: 'Guardar' })] })] })] }));
|
|
528
557
|
}
|
|
529
558
|
/** Selector del documento origen (mismo widget de relación que el resto de formularios). */
|
|
530
|
-
function SourcePicker({ source, value, header, label, onPick, }) {
|
|
559
|
+
function SourcePicker({ source, value, seed, header, label, onPick, }) {
|
|
531
560
|
const field = useMemo(() => ({
|
|
532
561
|
key: `__source_${source.key}`,
|
|
533
562
|
label,
|
|
@@ -535,5 +564,5 @@ function SourcePicker({ source, value, header, label, onPick, }) {
|
|
|
535
564
|
ref: source.model,
|
|
536
565
|
option_filter: source.option_filter,
|
|
537
566
|
}), [source, label]);
|
|
538
|
-
return (_jsx("div", { className: "min-w-[240px] flex-1", "data-source": source.key, children: renderField(field, value, (v) => onPick(v == null || v === '' ? '' : String(v)), header) }));
|
|
567
|
+
return (_jsx("div", { className: "min-w-[240px] flex-1", "data-source": source.key, children: renderField(field, value, (v) => onPick(v == null || v === '' ? '' : String(v)), header, seed ? { id: seed.value, label: seed.label } : undefined) }));
|
|
539
568
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import type { ActionFieldDef, FieldOptionsConfig,
|
|
2
|
+
import type { ActionFieldDef, FieldOptionsConfig, VisibleWhen } from './types';
|
|
3
|
+
import { applyOptionWhen, getDependsOn } from './option-when';
|
|
4
|
+
export { applyOptionWhen, getDependsOn };
|
|
3
5
|
/**
|
|
4
6
|
* Apps register validator implementations by slug. The slug is the value
|
|
5
7
|
* `OrgConfig.validators[<key>]` returns for a $org.<key> reference.
|
|
@@ -81,14 +83,6 @@ export declare function resolveWidget(field: ActionFieldDef): string;
|
|
|
81
83
|
export declare function getFieldRef(field: ActionFieldDef): string | undefined;
|
|
82
84
|
/** True when a field declares an FK target the SDK can resolve options against. */
|
|
83
85
|
export declare function fieldHasRef(field: ActionFieldDef): boolean;
|
|
84
|
-
/**
|
|
85
|
-
* Resolves a field's cascade dependency — the key of another form field whose
|
|
86
|
-
* current value scopes this picker's options (`filter_value`). Tolerates the
|
|
87
|
-
* camelCase `dependsOn` (authored SDK shape) and the snake_case `depends_on`
|
|
88
|
-
* the kernel manifest serves. Returns the trimmed field key, or `undefined`
|
|
89
|
-
* when the field declares no dependency.
|
|
90
|
-
*/
|
|
91
|
-
export declare function getDependsOn(field: ActionFieldDef): string | undefined;
|
|
92
86
|
/**
|
|
93
87
|
* Resolves the cascade `filter_value` for a field from the surrounding form
|
|
94
88
|
* context. The depended-on key is matched against the current row first (a
|
|
@@ -98,23 +92,6 @@ export declare function getDependsOn(field: ActionFieldDef): string | undefined;
|
|
|
98
92
|
* field has no dependency or the depended-on value is empty/unset.
|
|
99
93
|
*/
|
|
100
94
|
export declare function resolveDependsValue(field: ActionFieldDef, formValues?: Record<string, any> | null, rowValues?: Record<string, any> | null): string;
|
|
101
|
-
/**
|
|
102
|
-
* Filters a STATIC enum's `options[]` by each option's `when` gate against the
|
|
103
|
-
* current form values. Pure — no React, no side effects.
|
|
104
|
-
*
|
|
105
|
-
* Rule per option:
|
|
106
|
-
* - No `when` → always included (retrocompat; existing enums untouched).
|
|
107
|
-
* - With `when`: the gating field is `when.field ?? dependsOn`. If neither is
|
|
108
|
-
* present the option is included (nothing to gate on). Otherwise the form's
|
|
109
|
-
* value for that field is compared AS STRING: included when (no `in`, or
|
|
110
|
-
* value ∈ `in`) AND (no `not_in`, or value ∉ `not_in`). Tolerates the
|
|
111
|
-
* snake_case `not_in` the kernel serves alongside camelCase `notIn`.
|
|
112
|
-
*
|
|
113
|
-
* `formValues` is the flat map of the surrounding form/row values the gating
|
|
114
|
-
* field is read from; `dependsOn` is the containing field's declared dependency
|
|
115
|
-
* used as the default gating field.
|
|
116
|
-
*/
|
|
117
|
-
export declare function applyOptionWhen(options: OptionDef[] | undefined, formValues: Record<string, any> | null | undefined, dependsOn?: string): OptionDef[];
|
|
118
95
|
/**
|
|
119
96
|
* Reads a field's `visible_when` predicate, tolerating the camelCase alias
|
|
120
97
|
* (`visibleWhen`) an app may author and the snake_case (`visible_when`) the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-form-schema.d.ts","sourceRoot":"","sources":["../src/dynamic-form-schema.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAmB,MAAM,KAAK,CAAA;AACxC,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"dynamic-form-schema.d.ts","sourceRoot":"","sources":["../src/dynamic-form-schema.ts"],"names":[],"mappings":"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"}
|