@asteby/metacore-runtime-react 49.1.0 → 49.2.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.
Files changed (33) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/action-modal-dispatcher.d.ts +1 -0
  3. package/dist/action-modal-dispatcher.d.ts.map +1 -1
  4. package/dist/action-modal-dispatcher.js +34 -5
  5. package/dist/business/document-editor-model.d.ts +6 -1
  6. package/dist/business/document-editor-model.d.ts.map +1 -1
  7. package/dist/business/document-editor-model.js +48 -7
  8. package/dist/business/document-editor-panels.d.ts +18 -0
  9. package/dist/business/document-editor-panels.d.ts.map +1 -1
  10. package/dist/business/document-editor-panels.js +9 -0
  11. package/dist/business/document-editor.d.ts +7 -1
  12. package/dist/business/document-editor.d.ts.map +1 -1
  13. package/dist/business/document-editor.js +69 -24
  14. package/dist/document-form-dialog.d.ts.map +1 -1
  15. package/dist/document-form-dialog.js +8 -3
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +1 -1
  19. package/dist/record-mutation-events.d.ts +12 -0
  20. package/dist/record-mutation-events.d.ts.map +1 -1
  21. package/dist/record-mutation-events.js +18 -0
  22. package/package.json +1 -1
  23. package/src/__tests__/document-editor-model.test.ts +27 -0
  24. package/src/__tests__/document-editor.test.tsx +60 -0
  25. package/src/__tests__/invoice-document-editor.test.tsx +267 -0
  26. package/src/__tests__/r5-self-label-settled.test.ts +57 -0
  27. package/src/action-modal-dispatcher.tsx +34 -5
  28. package/src/business/document-editor-model.ts +50 -7
  29. package/src/business/document-editor-panels.tsx +49 -0
  30. package/src/business/document-editor.tsx +246 -164
  31. package/src/document-form-dialog.tsx +13 -4
  32. package/src/index.ts +2 -0
  33. package/src/record-mutation-events.ts +23 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @asteby/metacore-runtime-react
2
2
 
3
+ ## 49.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 4fca0af: DocumentEditor a pantalla completa para documentos con renglones (factura, cotización, pedido, OC).
8
+
9
+ - **Pantalla completa:** DocumentFormDialog abre el editor de un tipo `layout: "editor"` con renglones de venta o compra en un diálogo que ocupa la pantalla (máx. 1440 px). En pantallas anchas va a dos columnas: captura a la izquierda; totales, revisión y vista previa a la derecha. NC y cobro/REP siguen en el diálogo de 960 px.
10
+ - **Divulgación progresiva:** lo obligatorio que el tipo declara queda a la vista aunque sea de extensión (`fiscal_data.metodo_pago`, `fiscal_data.forma_pago` de la factura); las extensiones que llegan del metadata siguen plegadas en «Opciones fiscales».
11
+ - **Tarjeta de la contraparte:** sus filas usan las etiquetas del formulario del modelo de la contraparte (`/metadata/modal/<party.model>`): «RFC», «Régimen fiscal», «Uso CFDI» en vez de `tax_id` o `regimen_receptor`.
12
+ - **«Cargar desde…»:** con varias fuentes, botones por tipo de origen (venta, OT, cotización) en lugar de un `<select>`. Un origen sin dato de impuesto (p. ej. una OT de taller) toma la tasa de la org, como un renglón nuevo.
13
+ - **Vista previa local:** un tipo con renglones y sin acción `preview` del servidor ofrece una vista previa plegada del documento (encabezado, renglones y totales) sin crear borrador.
14
+ - i18n es/en: `documentEditor.source_kind`, `documentEditor.preview`, `documentEditor.advanced`.
15
+
16
+ - 4fca0af: Retest Pitsline r5 (nota de crédito y acciones):
17
+
18
+ - «Crear desde»: un renglón de origen sin descripción propia (InvoiceItem solo
19
+ lleva el producto) se nombra con la etiqueta del producto que resuelve el
20
+ host, y un renglón con producto ya no exige texto para guardar. El fallo de
21
+ `source-lines` (404, 400/500 de un host sin la ruta) cae a la relación.
22
+ - `ActionModalDispatcher` anuncia la mutación ahora y otra vez cuando el
23
+ servidor asienta lo derivado (`emitRecordMutationSettled`,
24
+ `RECORD_MUTATION_SETTLE_DELAYS`): la lista y la pestaña REP se refrescan
25
+ tras timbrar o registrar un pago.
26
+ - Un selector sembrado con el id de la propia fila muestra su folio
27
+ («Factura a abonar: FAC-00015») y no el UUID.
28
+
3
29
  ## 49.1.0
4
30
 
5
31
  ### Minor Changes
@@ -106,6 +106,7 @@ export interface FieldDefaultContext {
106
106
  */
107
107
  export declare function resolveFieldDefault(field: ActionFieldDef, ctx?: FieldDefaultContext): unknown;
108
108
  export declare function buildFieldDefaults(fields: ActionFieldDef[], record: any, model?: string, ctx?: FieldDefaultContext): Record<string, any>;
109
+ export declare function seedOptionFromRecord(field: ActionFieldDef, value: any, record?: Record<string, any>): import('./use-options-resolver').ResolvedOption | undefined;
109
110
  /** Renders one action field (same widgets as the action modals). Shared with DocumentFormDialog. */
110
111
  export declare function renderField(field: ActionFieldDef, value: any, onChange: (value: any) => void, formValues?: Record<string, any>, record?: Record<string, any>, fieldErrors?: Record<string, string>): import("react").JSX.Element;
111
112
  //# sourceMappingURL=action-modal-dispatcher.d.ts.map
@@ -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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"}
@@ -15,7 +15,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
15
15
  //
16
16
  // The host injects its axios-like client via <ApiProvider>; we no longer
17
17
  // depend on a bundler alias to `@/lib/api`.
18
- import { emitRecordMutation } from './record-mutation-events';
18
+ import { emitRecordMutationSettled } from './record-mutation-events';
19
19
  import { Suspense, useState, useCallback, useEffect, useMemo, useRef, useSyncExternalStore } from 'react';
20
20
  import { useTranslation } from 'react-i18next';
21
21
  import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, Button, Input, Textarea, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Switch, } from '@asteby/metacore-ui/primitives';
@@ -288,9 +288,11 @@ export function scalarDefaultFromRecord(field, record, model) {
288
288
  export function ActionModalDispatcher({ open, onOpenChange, action, model, record, endpoint, onSuccess: onSuccessProp, }) {
289
289
  // Every successful action may have created/updated/deleted a record of
290
290
  // `model` (federated component, wizard, generic form or confirmation), so
291
- // announce it: mounted lists of the model reload on their own (#1020).
291
+ // announce it: mounted lists of the model reload on their own (#1020) —
292
+ // and again once the server's event subscribers had time to write what the
293
+ // action triggers (estado tras timbrar, REP tras un pago).
292
294
  const onSuccess = useCallback(() => {
293
- emitRecordMutation(model, 'update');
295
+ emitRecordMutationSettled(model, 'update');
294
296
  onSuccessProp?.();
295
297
  }, [model, onSuccessProp]);
296
298
  // Reactive read: a federated remote usually registers AFTER the first
@@ -1107,8 +1109,35 @@ function WizardActionModal({ open, onOpenChange, action, model, record, endpoint
1107
1109
  return (_jsxs(FieldCell, { fullWidth: fullWidth, children: [_jsx(FieldLabel, { htmlFor: field.key, required: field.required, children: tl(field.label) }), renderField(field, formData[field.key], (v) => updateField(field.key, v), formData, record)] }, field.key));
1108
1110
  }) })] }), _jsxs(DialogFooter, { className: "shrink-0", children: [stepIndex > 0 ? (_jsx(Button, { variant: "outline", onClick: goBack, disabled: executing, children: t('common.back', { defaultValue: 'Atrás' }) })) : (_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: executing, children: t('common.cancel') })), isLast ? (_jsxs(Button, { onClick: submit, disabled: executing, style: action.color ? { backgroundColor: action.color, color: 'white' } : undefined, children: [executing ? _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : _jsx(DynamicIcon, { name: action.icon, className: "mr-2 h-4 w-4" }), tl(action.label)] })) : (_jsx(Button, { onClick: goNext, disabled: executing, style: action.color ? { backgroundColor: action.color, color: 'white' } : undefined, children: t('common.next', { defaultValue: 'Siguiente' }) }))] }), reasonPrompt.dialog] }) }));
1109
1111
  }
1110
- function seedOptionFromRecord(field, value, record) {
1111
- if (!record || !field.key.endsWith('_id'))
1112
+ /** Columnas con las que se nombra una fila cuando el selector no declara `options.label`. */
1113
+ const RECORD_LABEL_COLUMNS = ['number', 'folio', 'name', 'title', 'code', 'label'];
1114
+ /**
1115
+ * La etiqueta de la PROPIA fila cuando el campo se sembró con su id
1116
+ * («Factura a abonar» al registrar un pago desde la factura): la columna que el
1117
+ * selector usa de etiqueta (`options.label`) o la primera de nombre que tenga.
1118
+ * Sin esto el selector mostraba el UUID crudo (retest Pitsline r5).
1119
+ */
1120
+ function selfLabel(field, record) {
1121
+ const opts = field.options;
1122
+ const declared = opts && !Array.isArray(opts) && typeof opts === 'object' ? opts.label : undefined;
1123
+ const cols = typeof declared === 'string' && declared ? [declared, ...RECORD_LABEL_COLUMNS] : RECORD_LABEL_COLUMNS;
1124
+ for (const c of cols) {
1125
+ const v = unwrapRecordScalar(record[c]);
1126
+ if ((typeof v === 'string' && v.trim()) || typeof v === 'number')
1127
+ return String(v);
1128
+ }
1129
+ return '';
1130
+ }
1131
+ export function seedOptionFromRecord(field, value, record) {
1132
+ if (!record)
1133
+ return undefined;
1134
+ const selfId = unwrapRecordScalar(record.id);
1135
+ if (value != null && value !== '' && selfId != null && String(selfId) === String(value)) {
1136
+ const label = selfLabel(field, record);
1137
+ if (label)
1138
+ return { id: String(value), value: String(value), label, name: label };
1139
+ }
1140
+ if (!field.key.endsWith('_id'))
1112
1141
  return undefined;
1113
1142
  const siblingKey = field.key.replace(/_id$/, '');
1114
1143
  const sib = record[siblingKey];
@@ -11,7 +11,9 @@ export declare function isEditorLayout(type: Pick<DocumentFormType, 'layout' | '
11
11
  export declare function editorLinesConfig(type: DocumentFormType, forms: Pick<DocumentFormsManifest, 'lines_field'>): EditorLinesConfig | undefined;
12
12
  /**
13
13
  * Divulgación progresiva: ¿el campo va plegado en «Opciones fiscales»?
14
- * - campos de extensión (`fiscal_data.*`) que aportan otros addons;
14
+ * - campos de extensión (`fiscal_data.*`) que aportan otros addons (los que
15
+ * el propio tipo declara obligatorios, p. ej. método y forma de pago de la
16
+ * factura, se marcan esenciales en splitEditorFields);
15
17
  * - `section: "fiscal" | "advanced"`;
16
18
  * - catálogos opcionales que ya traen un default (método, serie, relación…):
17
19
  * el usuario no necesita tocarlos para guardar.
@@ -83,7 +85,10 @@ export declare function creditStatus(party: Record<string, any> | null, cols: {
83
85
  export declare function linesFromSource(rows: unknown, map?: Record<string, string>, opts?: {
84
86
  kind?: DocumentFormLines['kind'];
85
87
  discountMode?: DocumentFormLines['discount_mode'];
88
+ defaultTaxRate?: number;
86
89
  }): LineItem[];
90
+ /** El editor ocupa toda la pantalla: documentos comerciales con renglones (factura, cotización, pedido, OC). */
91
+ export declare function isFullscreenEditor(type: DocumentFormType, forms: Pick<DocumentFormsManifest, 'lines_field'>): boolean;
87
92
  /** Cuántos renglones del origen se cargaron y cuántos se omitieron por estar ya cubiertos. */
88
93
  export declare function sourceLoadSummary(rows: unknown): {
89
94
  loaded: number;
@@ -1 +1 @@
1
- {"version":3,"file":"document-editor-model.d.ts","sourceRoot":"","sources":["../../src/business/document-editor-model.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"document-editor-model.d.ts","sourceRoot":"","sources":["../../src/business/document-editor-model.ts"],"names":[],"mappings":"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"}
@@ -37,7 +37,9 @@ function declaredDefault(f) {
37
37
  }
38
38
  /**
39
39
  * Divulgación progresiva: ¿el campo va plegado en «Opciones fiscales»?
40
- * - campos de extensión (`fiscal_data.*`) que aportan otros addons;
40
+ * - campos de extensión (`fiscal_data.*`) que aportan otros addons (los que
41
+ * el propio tipo declara obligatorios, p. ej. método y forma de pago de la
42
+ * factura, se marcan esenciales en splitEditorFields);
41
43
  * - `section: "fiscal" | "advanced"`;
42
44
  * - catálogos opcionales que ya traen un default (método, serie, relación…):
43
45
  * el usuario no necesita tocarlos para guardar.
@@ -55,7 +57,10 @@ export function isAdvancedField(f, essentialKeys = new Set()) {
55
57
  }
56
58
  /** Reparte los campos del tipo (más los de extensión) en grupos de pantalla. */
57
59
  export function splitEditorFields(fields, opts = {}) {
58
- const essentialKeys = new Set(opts.essentialKeys ?? []);
60
+ // Lo obligatorio que el tipo declara siempre está a la vista, aunque sea de
61
+ // extensión (`fiscal_data.metodo_pago`): es lo que el usuario debe decidir.
62
+ // Las extensiones que llegan del metadata (no declaradas) siguen plegadas.
63
+ const essentialKeys = new Set([...(opts.essentialKeys ?? []), ...fields.filter((f) => f.required).map((f) => f.key)]);
59
64
  const out = { essential: [], advanced: [], notes: [] };
60
65
  const seen = new Set();
61
66
  for (const f of [...fields, ...(opts.extensionFields ?? [])]) {
@@ -168,13 +173,18 @@ export function linesFromSource(rows, map = {}, opts = {}) {
168
173
  if (!hasValue(rate)) {
169
174
  const sub = toAmount(get('subtotal'));
170
175
  const tax = toAmount(get('tax_amount'));
171
- rate = sub > 0 ? Math.round((tax / sub) * 10000) / 10000 : 0;
176
+ // Un origen sin dato de impuesto (p. ej. una OT de taller: solo
177
+ // cantidad y precio) toma la tasa de la org, como un renglón nuevo.
178
+ rate = hasValue(get('tax_amount'))
179
+ ? sub > 0 ? Math.round((tax / sub) * 10000) / 10000 : 0
180
+ : opts.defaultTaxRate ?? 0;
172
181
  }
173
182
  const r2 = toAmount(rate);
183
+ const product = get('product_id');
174
184
  const line = makeLine({
175
- product_id: get('product_id') ?? undefined,
185
+ product_id: refValue(product),
176
186
  sku: get('sku') ?? undefined,
177
- description: String(get('description') ?? get('product_name') ?? ''),
187
+ description: String(get('description') ?? get('product_name') ?? refLabel(product) ?? refLabel(r.product) ?? ''),
178
188
  quantity: qty,
179
189
  unit_price: toAmount(get('unit_price')),
180
190
  discount: toAmount(get('discount') ?? 0),
@@ -195,10 +205,38 @@ export function linesFromSource(rows, map = {}, opts = {}) {
195
205
  return line;
196
206
  });
197
207
  }
208
+ /** Id de una celda de relación (`{value,label}`, `{id,name}` o el id plano). */
209
+ function refValue(v) {
210
+ if (v == null || v === '')
211
+ return undefined;
212
+ if (typeof v === 'object') {
213
+ const o = v;
214
+ const id = o.value ?? o.id;
215
+ return id == null || id === '' ? undefined : String(id);
216
+ }
217
+ return String(v);
218
+ }
219
+ /**
220
+ * Nombre de una celda de relación ya resuelta por el host (`{label}`/`{name}`).
221
+ * Un renglón de origen sin descripción propia (InvoiceItem solo lleva el
222
+ * producto) se nombra con su producto en vez de entrar en blanco.
223
+ */
224
+ function refLabel(v) {
225
+ if (!v || typeof v !== 'object')
226
+ return undefined;
227
+ const o = v;
228
+ const l = o.label ?? o.name;
229
+ return typeof l === 'string' && l.trim() ? l : undefined;
230
+ }
198
231
  function isFullyConsumed(raw) {
199
232
  const r = (raw ?? {});
200
233
  return hasValue(r.remaining_quantity) && toAmount(r.remaining_quantity) <= 0;
201
234
  }
235
+ /** El editor ocupa toda la pantalla: documentos comerciales con renglones (factura, cotización, pedido, OC). */
236
+ export function isFullscreenEditor(type, forms) {
237
+ const kind = editorLinesConfig(type, forms)?.kind ?? 'sale';
238
+ return !!type.lines && (kind === 'sale' || kind === 'purchase');
239
+ }
202
240
  /** Cuántos renglones del origen se cargaron y cuántos se omitieron por estar ya cubiertos. */
203
241
  export function sourceLoadSummary(rows) {
204
242
  if (!Array.isArray(rows))
@@ -218,8 +256,11 @@ export function localIssues(lines, opts = {}) {
218
256
  issues.push({ field: 'lines', severity: 'error', message: 'Agrega al menos un renglón.' });
219
257
  }
220
258
  items.forEach((l, i) => {
221
- if (!l.description.trim())
222
- issues.push({ field: `lines.${i}`, severity: 'error', message: `Renglón ${i + 1}: falta la descripción.` });
259
+ // Un renglón con producto se describe con él (el servidor lo nombra
260
+ // desde el catálogo): solo un renglón libre exige texto, como en el
261
+ // editor de renglones (validateLineItems).
262
+ if (!l.description.trim() && !l.product_id)
263
+ issues.push({ field: `lines.${i}`, severity: 'error', message: `Renglón ${i + 1}: elige un producto o escribe la descripción.` });
223
264
  if (toAmount(l.unit_price) <= 0)
224
265
  issues.push({ field: `lines.${i}`, severity: 'warning', message: `Renglón ${i + 1}: precio en cero.` });
225
266
  if (l.max_quantity != null && toAmount(l.quantity) > toAmount(l.max_quantity)) {
@@ -1,6 +1,7 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import type { CreditStatus, EditorIssue } from './document-editor-model';
3
3
  import type { Formatter } from './format';
4
+ import { type LineItem } from './line-items';
4
5
  /** Bloque con título discreto y espaciado generoso (sin bordes pesados). */
5
6
  export declare function EditorSection({ title, hint, children, slot }: {
6
7
  title?: ReactNode;
@@ -61,4 +62,21 @@ export interface PreviewContent {
61
62
  export declare function PreviewPanel({ preview }: {
62
63
  preview: PreviewContent | null;
63
64
  }): import("react").JSX.Element | null;
65
+ export interface DraftPreviewProps {
66
+ title: string;
67
+ party?: string;
68
+ /** Datos del encabezado ya con su etiqueta y valor legibles. */
69
+ header: Array<{
70
+ label: string;
71
+ value: string;
72
+ }>;
73
+ lines: LineItem[];
74
+ totals: TotalsRow[];
75
+ fmt: Formatter;
76
+ }
77
+ /**
78
+ * Vista previa local del documento (sin servidor ni borrador): cómo queda con
79
+ * lo capturado. Para tipos sin acción `preview`; la del servidor (PDF/XML) gana.
80
+ */
81
+ export declare function DraftPreview({ title, party, header, lines, totals, fmt }: DraftPreviewProps): import("react").JSX.Element;
64
82
  //# sourceMappingURL=document-editor-panels.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"document-editor-panels.d.ts","sourceRoot":"","sources":["../../src/business/document-editor-panels.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAGvD,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEzC,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,SAAS,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,+BAYzI;AAED,MAAM,WAAW,uBAAuB;IACpC,KAAK,EAAE,SAAS,CAAA;IAChB,qEAAqE;IACrE,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,QAAQ,EAAE,SAAS,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,WAAmB,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,uBAAuB,+BA4BtI;AAED,MAAM,WAAW,cAAc;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC1D,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;IAC5B,GAAG,EAAE,SAAS,CAAA;IACd,QAAQ,CAAC,EAAE,SAAS,CAAA;CACvB;AAED,uFAAuF;AACvF,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,cAAc,+BA4B9E;AAED,MAAM,WAAW,SAAS;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,SAAS,EAAE,CAAA;CAAE,+BAW1D;AAED,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,EAAE,MAAM,EAAE,KAAiC,EAAE,EAAE;IAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,sCAe3H;AAED,MAAM,WAAW,cAAc;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAAA;CAAE,sCAO3E"}
1
+ {"version":3,"file":"document-editor-panels.d.ts","sourceRoot":"","sources":["../../src/business/document-editor-panels.tsx"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
6
6
  import { useId, useState } from 'react';
7
7
  import { Badge } from '@asteby/metacore-ui/primitives';
8
8
  import { AlertTriangle, ChevronDown, XCircle } from 'lucide-react';
9
+ import { computeLine } from './line-items';
9
10
  /** Bloque con título discreto y espaciado generoso (sin bordes pesados). */
10
11
  export function EditorSection({ title, hint, children, slot }) {
11
12
  return (_jsxs("section", { className: "space-y-3", "data-slot": slot, children: [(title || hint) && (_jsxs("header", { className: "flex items-baseline justify-between gap-3", children: [title && _jsx("h3", { className: "text-sm font-semibold", children: title }), hint && _jsx("span", { className: "text-xs text-muted-foreground", children: hint })] })), children] }));
@@ -56,3 +57,11 @@ export function PreviewPanel({ preview }) {
56
57
  return _jsx("pre", { className: "max-h-96 overflow-auto rounded bg-muted p-3 text-[11px] leading-tight", "data-slot": "preview-xml", children: preview.xml });
57
58
  return null;
58
59
  }
60
+ /**
61
+ * Vista previa local del documento (sin servidor ni borrador): cómo queda con
62
+ * lo capturado. Para tipos sin acción `preview`; la del servidor (PDF/XML) gana.
63
+ */
64
+ export function DraftPreview({ title, party, header, lines, totals, fmt }) {
65
+ const items = lines.filter((l) => l.kind === 'item');
66
+ return (_jsxs("article", { className: "space-y-3 rounded border bg-background p-4 text-xs", "data-slot": "preview-draft", children: [_jsxs("header", { className: "flex flex-wrap items-baseline justify-between gap-2 border-b pb-2", children: [_jsx("span", { className: "text-sm font-semibold", children: title }), party && _jsx("span", { className: "font-medium", children: party })] }), header.length > 0 && (_jsx("dl", { className: "grid grid-cols-2 gap-x-4 gap-y-1", children: header.map((h) => (_jsxs("div", { className: "min-w-0", children: [_jsx("dt", { className: "text-muted-foreground", children: h.label }), _jsx("dd", { className: "truncate", children: h.value })] }, h.label))) })), _jsx("table", { className: "w-full tabular-nums", children: _jsx("tbody", { children: items.map((l) => (_jsxs("tr", { className: "border-t align-top", children: [_jsx("td", { className: "py-1 pr-2", children: l.description }), _jsx("td", { className: "py-1 pr-2 text-right", children: l.quantity }), _jsx("td", { className: "py-1 text-right", children: fmt.money(computeLine(l).net) })] }, l.key))) }) }), _jsx(TotalsPanel, { rows: totals })] }));
67
+ }
@@ -22,6 +22,12 @@ export interface DocumentEditorProps {
22
22
  currency?: string;
23
23
  /** Hoy (días de atraso del reparto; inyectable en tests). */
24
24
  today?: Date;
25
+ /**
26
+ * Pantalla completa (DocumentFormDialog la pide para documentos con
27
+ * renglones): a dos columnas en pantallas anchas, con totales, revisión y
28
+ * vista previa a la derecha; en una sola columna en móvil.
29
+ */
30
+ fullscreen?: boolean;
25
31
  }
26
- export declare function DocumentEditor({ model, endpoint, forms, type, record, initialSource, onSaved, onCancel, searchProducts, productModel, defaultTaxRate, currency, today, }: DocumentEditorProps): import("react").JSX.Element;
32
+ export declare function DocumentEditor({ model, endpoint, forms, type, record, initialSource, onSaved, onCancel, searchProducts, productModel, defaultTaxRate, currency, today, fullscreen, }: DocumentEditorProps): import("react").JSX.Element;
27
33
  //# sourceMappingURL=document-editor.d.ts.map
@@ -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;AA0C1G,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;CACf;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,GACR,EAAE,mBAAmB,+BAgoBrB"}
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;AA4C1G,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,+BAysBrB"}
@@ -31,8 +31,8 @@ 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, withFriendlyOptions, } from './document-editor-model';
35
- import { CollapsibleSection, EditorSection, PartyCard, PreviewPanel, TotalsPanel, ValidationChecklist, } from './document-editor-panels';
34
+ import { allocationAmountField, allocationIssueMessages, allocationPayload, creditStatus, editorLinesConfig, linesFromSource, localIssues, sourceLoadSummary, sourceTracksRemaining, partyDefaults, partySummaryRows, splitEditorFields, toOpenDocuments, friendlyOptionLabel, withFriendlyOptions, } from './document-editor-model';
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';
38
38
  import { extractFieldErrors, localizeFieldErrorMap } from '../server-error';
@@ -43,7 +43,7 @@ import { evaluateVisibleWhen, getVisibleWhen } from '../dynamic-form-schema';
43
43
  import { useInstalledAddons } from '../installed-addons-context';
44
44
  import { allocatePayment, validateAllocation } from '../primitives/allocation';
45
45
  import { useDocumentContributions } from '../primitives/use-contributions';
46
- export function DocumentEditor({ model, endpoint, forms, type, record, initialSource, onSaved, onCancel, searchProducts, productModel, defaultTaxRate, currency, today, }) {
46
+ export function DocumentEditor({ model, endpoint, forms, type, record, initialSource, onSaved, onCancel, searchProducts, productModel, defaultTaxRate, currency, today, fullscreen = false, }) {
47
47
  const { t, i18n } = useTranslation();
48
48
  const lang = i18n?.language;
49
49
  const api = useApi();
@@ -64,6 +64,7 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
64
64
  const [linesFromSourceDoc, setLinesFromSourceDoc] = useState(false);
65
65
  const [extFields, setExtFields] = useState([]);
66
66
  const [party, setParty] = useState(null);
67
+ const [partyLabels, setPartyLabels] = useState({});
67
68
  const [openDocs, setOpenDocs] = useState([]);
68
69
  const [docsLoading, setDocsLoading] = useState(false);
69
70
  const [alloc, setAlloc] = useState({ strategy: 'oldest_due_first', manual: {} });
@@ -137,6 +138,28 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
137
138
  cancelled = true;
138
139
  };
139
140
  }, [api, type.party, partyId]);
141
+ // Etiquetas de la tarjeta (RFC, régimen…): las del formulario del modelo de
142
+ // la contraparte, incluidas sus extensiones; sin ellas se ve la columna cruda.
143
+ const partyModel = type.party?.model;
144
+ useEffect(() => {
145
+ if (!partyModel)
146
+ return;
147
+ let cancelled = false;
148
+ api.get(`/metadata/modal/${partyModel}`)
149
+ .then((res) => {
150
+ const fields = res?.data?.data?.fields ?? res?.data?.fields ?? [];
151
+ const out = {};
152
+ for (const f of fields)
153
+ if (typeof f?.key === 'string' && typeof f?.label === 'string' && f.label)
154
+ out[f.key] = f.label;
155
+ if (!cancelled)
156
+ setPartyLabels(out);
157
+ })
158
+ .catch(() => { });
159
+ return () => {
160
+ cancelled = true;
161
+ };
162
+ }, [api, partyModel]);
140
163
  // Cobro: documentos abiertos de la contraparte.
141
164
  const openCfg = lineCfg?.open_documents;
142
165
  const allocPartyId = openCfg ? header[openCfg.party_field] ?? partyId : undefined;
@@ -246,9 +269,11 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
246
269
  });
247
270
  return res?.data?.data ?? [];
248
271
  }
249
- catch (err) {
250
- if (err?.response?.status !== 404)
251
- throw err;
272
+ catch {
273
+ // Un host sin `source-lines` (404, o la ruta del registro
274
+ // contestando 400/500 a «source-lines» como id) o un origen que
275
+ // el host aún no sabe calcular: se precarga de la relación y el
276
+ // guardado del servidor sigue validando lo pendiente.
252
277
  }
253
278
  }
254
279
  let rels = relCache.current.get(src.model);
@@ -271,7 +296,7 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
271
296
  try {
272
297
  if (!isAllocation) {
273
298
  const rows = await fetchSourceRows(src, id);
274
- const loaded = linesFromSource(rows, src.map, { kind, discountMode: lineCfg.discount_mode });
299
+ const loaded = linesFromSource(rows, src.map, { kind, discountMode: lineCfg.discount_mode, defaultTaxRate: taxRate });
275
300
  const { covered } = sourceLoadSummary(rows);
276
301
  setLines(loaded);
277
302
  setLoadedSource(src);
@@ -311,7 +336,7 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
311
336
  finally {
312
337
  setBusy(null);
313
338
  }
314
- }, [api, lineCfg, isAllocation, kind, t, fetchSourceRows]);
339
+ }, [api, lineCfg, isAllocation, kind, t, fetchSourceRows, taxRate]);
315
340
  // Prefill al abrir desde un documento origen (acción de fila «Crear NC», «Facturar venta»…).
316
341
  const autoLoaded = useRef(false);
317
342
  useEffect(() => {
@@ -430,7 +455,10 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
430
455
  setFieldErrors((prev) => clearFieldErrorTree(prev, key));
431
456
  };
432
457
  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(field), header[field.key], (v) => updateField(field.key, v), header, undefined, fieldErrors), fieldErrors[field.key] && _jsx("p", { className: "mt-1 text-xs text-destructive", children: fieldErrors[field.key] })] }, field.key)) : null;
433
- const summaryRows = partySummaryRows(party, type.party?.summary, Object.fromEntries(allFields.map((f) => [f.key, tl(f.label)])));
458
+ const summaryRows = partySummaryRows(party, type.party?.summary, {
459
+ ...Object.fromEntries(Object.entries(partyLabels).map(([k, v]) => [k, tl(v)])),
460
+ ...Object.fromEntries(allFields.map((f) => [f.key, tl(f.label)])),
461
+ });
434
462
  const advancedSummary = groups.advanced
435
463
  .filter(visible)
436
464
  .map((f) => {
@@ -460,26 +488,43 @@ export function DocumentEditor({ model, endpoint, forms, type, record, initialSo
460
488
  })),
461
489
  { label: t('documentEditor.total', { defaultValue: 'Total' }), value: fmt.money(totals.total), emphasis: true },
462
490
  ];
463
- const activeSource = sources.find((s) => s.key === sourceKey);
491
+ const activeSource = sources.find((s) => s.key === sourceKey) ?? (sources.length === 1 ? sources[0] : undefined);
464
492
  const linesTitle = lineCfg?.title
465
493
  ? tl(lineCfg.title)
466
494
  : isAllocation
467
495
  ? t('documentEditor.allocation_title', { defaultValue: 'Documentos a pagar' })
468
496
  : t('documentEditor.lines_title', { defaultValue: 'Conceptos' });
469
- return (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col", "data-slot": "document-editor", "data-kind": kind, children: [_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 }), _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))) }))] }), 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 && (_jsxs("select", { "aria-label": t('documentEditor.source_kind', { defaultValue: 'Tipo de documento origen' }), className: "h-9 rounded-md border bg-background px-2 text-sm", value: sourceKey, onChange: (e) => {
470
- setSourceKey(e.target.value);
471
- setSourceId('');
472
- }, children: [_jsx("option", { value: "", children: t('documentEditor.choose_source', { defaultValue: 'Elige…' }) }), sources.map((s) => (_jsx("option", { value: s.key, children: tl(s.label) }, s.key)))] })), (activeSource ?? (sources.length === 1 ? sources[0] : undefined)) && (_jsx(SourcePicker, { source: (activeSource ?? sources[0]), value: sourceId, header: header, label: tl((activeSource ?? sources[0]).label), onPick: (id) => {
473
- if (!activeSource)
474
- setSourceKey(sources[0].key);
475
- setSourceId(id);
476
- const src = activeSource ?? sources[0];
477
- if (id)
478
- void loadFromSource(src, id);
479
- } }))] }) })), lineCfg && (_jsxs(EditorSection, { slot: isAllocation ? 'editor-allocation' : 'editor-lines', title: linesTitle, hint: isAllocation && openBalance > 0 && amountKey ? (_jsx("button", { type: "button", className: "underline-offset-2 hover:underline", onClick: () => updateField(amountKey, openBalance), children: t('documentEditor.pay_all', { defaultValue: 'Cobrar todo ({{amount}})', amount: fmt.money(openBalance) }) })) : undefined, children: [isAllocation ? (allocPartyId ? (_jsx(PaymentAllocator, { documents: openDocs, result: allocation, value: alloc, onChange: setAlloc, currency: currency, loading: docsLoading, today: today })) : (_jsx("p", { className: "text-sm text-muted-foreground", children: t('documentEditor.pick_party_first', { defaultValue: 'Elige el cliente para ver sus documentos con saldo.' }) }))) : (_jsx(DocumentLinesGrid, { value: lines, onChange: (next) => {
480
- setLines(next);
481
- setServerIssues([]);
482
- }, columns: lineCfg.columns ?? ['discount', 'tax'], priceSource: lineCfg.price_source ?? (kind === 'purchase' ? 'cost' : 'sale'), discountMode: lineCfg.discount_mode, mode: linesFromSourceDoc ? 'from_source' : 'free', policy: kind === 'credit' ? { allowZeroQuantity: linesFromSourceDoc } : undefined, search: search, currency: currency })), _jsx(TotalsPanel, { rows: totalsRows })] })), (groups.advanced.length > 0 || headerContribs.length > 0) && (_jsxs(CollapsibleSection, { slot: "advanced-options", title: t('documentEditor.advanced', { defaultValue: 'Opciones fiscales' }), summary: advancedSummary || t('documentEditor.advanced_defaults', { defaultValue: 'Valores sugeridos' }), open: advancedOpen, onOpenChange: setAdvancedOpen, children: [groups.advanced.length > 0 && _jsx(FieldGrid, { children: groups.advanced.map((f) => fieldCell(f)) }), headerContribs.map(({ id, component: C }) => (_jsx(C, { ...contribProps }, id)))] })), [...bodyContribs, ...sideContribs].map(({ id, component: C }) => (_jsx("section", { "data-contribution": id, children: _jsx(C, { ...contribProps }) }, id))), groups.notes.length > 0 && _jsx(FieldGrid, { children: groups.notes.map((f) => fieldCell(f, true)) }), previewEnabled && (_jsx(CollapsibleSection, { slot: "preview", title: tl(type.preview.label ?? 'Vista previa'), open: previewOpen, onOpenChange: togglePreview, children: busy === 'preview' ? (_jsxs("p", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "size-4 animate-spin", "aria-hidden": true }), t('documentEditor.preview_loading', { defaultValue: 'Generando vista previa…' })] })) : (_jsxs(_Fragment, { children: [_jsx(PreviewPanel, { preview: preview }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => void runPreview(), disabled: busy !== null, children: t('documentEditor.preview_refresh', { defaultValue: 'Actualizar vista previa' }) })] })) })), _jsx(ValidationChecklist, { issues: shownIssues, title: t('documentEditor.review', { defaultValue: 'Revisa antes de guardar' }) })] }), _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' })] })] })] }));
497
+ // Sin acción de vista previa del servidor, un documento con renglones ofrece
498
+ // la suya local (encabezado, renglones y totales): sin borrador ni red.
499
+ const localPreview = !previewEnabled && !type.preview && !!lineCfg && !isAllocation && kind !== 'credit';
500
+ 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: 'Tipo de documento 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
+ setSourceKey(s.key);
503
+ 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) => {
505
+ setSourceKey(activeSource.key);
506
+ setSourceId(id);
507
+ if (id)
508
+ void loadFromSource(activeSource, id);
509
+ } }, activeSource.key))] }) }));
510
+ const totalsPanel = _jsx(TotalsPanel, { rows: totalsRows });
511
+ const linesSection = lineCfg && (_jsxs(EditorSection, { slot: isAllocation ? 'editor-allocation' : 'editor-lines', title: linesTitle, hint: isAllocation && openBalance > 0 && amountKey ? (_jsx("button", { type: "button", className: "underline-offset-2 hover:underline", onClick: () => updateField(amountKey, openBalance), children: t('documentEditor.pay_all', { defaultValue: 'Cobrar todo ({{amount}})', amount: fmt.money(openBalance) }) })) : undefined, children: [isAllocation ? (allocPartyId ? (_jsx(PaymentAllocator, { documents: openDocs, result: allocation, value: alloc, onChange: setAlloc, currency: currency, loading: docsLoading, today: today })) : (_jsx("p", { className: "text-sm text-muted-foreground", children: t('documentEditor.pick_party_first', { defaultValue: 'Elige el cliente para ver sus documentos con saldo.' }) }))) : (_jsx(DocumentLinesGrid, { value: lines, onChange: (next) => {
512
+ setLines(next);
513
+ setServerIssues([]);
514
+ }, columns: lineCfg.columns ?? ['discount', 'tax'], priceSource: lineCfg.price_source ?? (kind === 'purchase' ? 'cost' : 'sale'), discountMode: lineCfg.discount_mode, mode: linesFromSourceDoc ? 'from_source' : 'free', policy: kind === 'credit' ? { allowZeroQuantity: linesFromSourceDoc } : undefined, search: search, currency: currency })), !fullscreen && totalsPanel] }));
515
+ const advanced = (groups.advanced.length > 0 || headerContribs.length > 0) && (_jsxs(CollapsibleSection, { slot: "advanced-options", title: t('documentEditor.advanced', { defaultValue: 'Opciones fiscales' }), summary: advancedSummary || t('documentEditor.advanced_defaults', { defaultValue: 'Valores sugeridos' }), open: advancedOpen, onOpenChange: setAdvancedOpen, children: [groups.advanced.length > 0 && _jsx(FieldGrid, { children: groups.advanced.map((f) => fieldCell(f)) }), headerContribs.map(({ id, component: C }) => (_jsx(C, { ...contribProps }, id)))] }));
516
+ const contributedSections = [...bodyContribs, ...sideContribs].map(({ id, component: C }) => (_jsx("section", { "data-contribution": id, children: _jsx(C, { ...contribProps }) }, id)));
517
+ const notes = groups.notes.length > 0 && _jsx(FieldGrid, { children: groups.notes.map((f) => fieldCell(f, true)) });
518
+ const previewSection = previewEnabled ? (_jsx(CollapsibleSection, { slot: "preview", title: tl(type.preview.label ?? 'Vista previa'), open: previewOpen, onOpenChange: togglePreview, children: busy === 'preview' ? (_jsxs("p", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "size-4 animate-spin", "aria-hidden": true }), t('documentEditor.preview_loading', { defaultValue: 'Generando vista previa…' })] })) : (_jsxs(_Fragment, { children: [_jsx(PreviewPanel, { preview: preview }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => void runPreview(), disabled: busy !== null, children: t('documentEditor.preview_refresh', { defaultValue: 'Actualizar vista previa' }) })] })) })) : localPreview ? (_jsx(CollapsibleSection, { slot: "preview", title: t('documentEditor.preview', { defaultValue: 'Vista previa' }), open: previewOpen, onOpenChange: setPreviewOpen, children: _jsx(DraftPreview, { title: tl(type.label), party: party ? String(party.name ?? party.legal_name ?? '') : undefined, header: [...groups.essential, ...groups.advanced]
519
+ .filter(visible)
520
+ .map((f) => {
521
+ const v = header[f.key];
522
+ const opt = f.options?.find((o) => String(o.value) === String(v));
523
+ return { label: tl(f.label), value: v == null || v === '' ? '' : opt ? friendlyOptionLabel(tl(String(opt.label ?? v))) : String(v) };
524
+ })
525
+ .filter((r) => r.value), lines: lines, totals: totalsRows, fmt: fmt }) })) : null;
526
+ const checklist = _jsx(ValidationChecklist, { issues: shownIssues, title: t('documentEditor.review', { defaultValue: 'Revisa antes de guardar' }) });
527
+ 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' })] })] })] }));
483
528
  }
484
529
  /** Selector del documento origen (mismo widget de relación que el resto de formularios). */
485
530
  function SourcePicker({ source, value, header, label, onPick, }) {
@@ -1 +1 @@
1
- {"version":3,"file":"document-form-dialog.d.ts","sourceRoot":"","sources":["../src/document-form-dialog.tsx"],"names":[],"mappings":"AA6BA,OAAO,EAEH,KAAK,sBAAsB,EAE9B,MAAM,8BAA8B,CAAA;AAerC,OAAO,KAAK,EAER,gBAAgB,EAChB,qBAAqB,EACrB,aAAa,EAChB,MAAM,SAAS,CAAA;AAEhB,MAAM,WAAW,uBAAuB;IACpC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAA;IACb,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,qBAAqB,CAAA;IAC5B,mDAAmD;IACnD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uCAAuC;IACvC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACpC;;;OAGG;IACH,cAAc,CAAC,EAAE,sBAAsB,CAAC,QAAQ,CAAC,CAAA;IACjD,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,0GAA0G;IAC1G,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC5B,gFAAgF;IAChF,aAAa,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAA;IAC3C;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAA;CACvD;AAED,2EAA2E;AAC3E,MAAM,WAAW,eAAe;IAC5B,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAA;IACb,2BAA2B;IAC3B,IAAI,EAAE,gBAAgB,CAAA;CACzB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,qBAAqB,GAAG,SAAS,GAAG,eAAe,GAAG,SAAS,CAIrG;AAED,8EAA8E;AAC9E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,GAAG,SAAS,GAAG,qBAAqB,GAAG,SAAS,CAKjH;AAED,uFAAuF;AACvF,wBAAgB,oBAAoB,CAChC,QAAQ,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,IAAI,EACvD,QAAQ,CAAC,EAAE,qBAAqB,GAAG,IAAI,GACxC,qBAAqB,GAAG,SAAS,CAGnC;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACtC,KAAK,EAAE,qBAAqB,GAAG,SAAS,EACxC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GACxC;IAAE,KAAK,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAQnE;AAID,wBAAgB,kBAAkB,CAAC,EAC/B,IAAI,EACJ,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,KAAK,EACL,WAAW,EACX,OAAO,EACP,cAAc,EACd,YAAY,EACZ,cAAc,EACd,QAAQ,EACR,MAAM,EACN,aAAa,EACb,gBAAgB,GACnB,EAAE,uBAAuB,sCAwUzB"}
1
+ {"version":3,"file":"document-form-dialog.d.ts","sourceRoot":"","sources":["../src/document-form-dialog.tsx"],"names":[],"mappings":"AA6BA,OAAO,EAEH,KAAK,sBAAsB,EAE9B,MAAM,8BAA8B,CAAA;AAerC,OAAO,KAAK,EAER,gBAAgB,EAChB,qBAAqB,EACrB,aAAa,EAChB,MAAM,SAAS,CAAA;AAEhB,MAAM,WAAW,uBAAuB;IACpC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAA;IACb,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,qBAAqB,CAAA;IAC5B,mDAAmD;IACnD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uCAAuC;IACvC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACpC;;;OAGG;IACH,cAAc,CAAC,EAAE,sBAAsB,CAAC,QAAQ,CAAC,CAAA;IACjD,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,0GAA0G;IAC1G,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC5B,gFAAgF;IAChF,aAAa,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAA;IAC3C;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAA;CACvD;AAED,2EAA2E;AAC3E,MAAM,WAAW,eAAe;IAC5B,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAA;IACb,2BAA2B;IAC3B,IAAI,EAAE,gBAAgB,CAAA;CACzB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,qBAAqB,GAAG,SAAS,GAAG,eAAe,GAAG,SAAS,CAIrG;AAED,8EAA8E;AAC9E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,GAAG,SAAS,GAAG,qBAAqB,GAAG,SAAS,CAKjH;AAED,uFAAuF;AACvF,wBAAgB,oBAAoB,CAChC,QAAQ,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,IAAI,EACvD,QAAQ,CAAC,EAAE,qBAAqB,GAAG,IAAI,GACxC,qBAAqB,GAAG,SAAS,CAGnC;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACtC,KAAK,EAAE,qBAAqB,GAAG,SAAS,EACxC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GACxC;IAAE,KAAK,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAQnE;AAID,wBAAgB,kBAAkB,CAAC,EAC/B,IAAI,EACJ,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,KAAK,EACL,WAAW,EACX,OAAO,EACP,cAAc,EACd,YAAY,EACZ,cAAc,EACd,QAAQ,EACR,MAAM,EACN,aAAa,EACb,gBAAgB,GACnB,EAAE,uBAAuB,sCAiVzB"}
@@ -30,7 +30,7 @@ import { emitRecordMutation } from './record-mutation-events';
30
30
  import { isLineItemsField, resolveWidget, scopeValueFromFilterToken } from './dynamic-form-schema';
31
31
  import { createCatalogProductSearch, withDefaultTaxRate } from './business/catalog-product-search';
32
32
  import { DocumentEditor } from './business/document-editor';
33
- import { editorLinesConfig, isEditorLayout } from './business/document-editor-model';
33
+ import { editorLinesConfig, isEditorLayout, isFullscreenEditor } from './business/document-editor-model';
34
34
  /**
35
35
  * Si «Crear» de estos formularios es un alta delegada: un único tipo (p. ej.
36
36
  * ya acotado por el filtro de la vista) con `create_model`. Con varios tipos el
@@ -239,9 +239,14 @@ export function DocumentFormDialog({ open, onOpenChange, model, endpoint, forms,
239
239
  if (open && type && delegatedModel)
240
240
  return null;
241
241
  // layout "editor": una sola pantalla por secciones (DocumentEditor). Sin él
242
- // sigue el wizard de siempre (retrocompatible).
242
+ // sigue el wizard de siempre (retrocompatible). Un documento con renglones
243
+ // (factura, cotización, pedido, OC) ocupa toda la pantalla; NC y cobro
244
+ // siguen en el diálogo grande.
243
245
  if (open && type && step !== 'type' && (isEditorLayout(type) || !!initialSource)) {
244
- return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "flex max-h-[92dvh] flex-col overflow-hidden", style: { maxHeight: '92dvh', maxWidth: '960px', width: '95vw' }, "data-slot": "document-editor-dialog", children: [_jsxs(DialogHeader, { className: "shrink-0", children: [_jsx(DialogTitle, { children: tl(type.label) }), type.description && _jsx(DialogDescription, { children: tl(type.description) })] }), _jsx(DocumentEditor, { model: model, endpoint: endpoint, forms: forms, type: type, record: record, initialSource: initialSource, searchProducts: lineSearch, currency: currency, onCancel: () => (canGoBackToTypes ? setStep('type') : onOpenChange(false)), onSaved: (rec) => {
246
+ const fullscreen = isFullscreenEditor(type, forms);
247
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: fullscreen ? 'flex flex-col overflow-hidden sm:max-w-none' : 'flex max-h-[92dvh] flex-col overflow-hidden', style: fullscreen
248
+ ? { width: 'calc(100vw - 2rem)', maxWidth: '1440px', height: 'calc(100dvh - 2rem)', maxHeight: 'calc(100dvh - 2rem)' }
249
+ : { maxHeight: '92dvh', maxWidth: '960px', width: '95vw' }, "data-slot": "document-editor-dialog", "data-fullscreen": fullscreen ? 'true' : undefined, children: [_jsxs(DialogHeader, { className: "shrink-0", children: [_jsx(DialogTitle, { children: tl(type.label) }), type.description && _jsx(DialogDescription, { children: tl(type.description) })] }), _jsx(DocumentEditor, { model: model, endpoint: endpoint, forms: forms, type: type, record: record, initialSource: initialSource, searchProducts: lineSearch, currency: currency, fullscreen: fullscreen, onCancel: () => (canGoBackToTypes ? setStep('type') : onOpenChange(false)), onSaved: (rec) => {
245
250
  onSaved?.(rec);
246
251
  onOpenChange(false);
247
252
  } }, type.key)] }) }));
package/dist/index.d.ts CHANGED
@@ -32,7 +32,7 @@ export { todayInZone, isTodayToken } from './calendar-date';
32
32
  export { setFederatedActionLoader, type FederatedActionLoader } from './federated-action-loader';
33
33
  export { ModelActionToolbar, useModelActions, type ModelActionToolbarProps, type ActionPlacement, } from './model-action-toolbar';
34
34
  export { resolveListPrimaryAction, actionReplacesCreate, type ListPrimaryActionInput, type ListPrimaryActionResult, type ListActionRef, type CreateMode, } from './list-primary-action';
35
- export { emitRecordMutation, subscribeRecordMutations, RECORD_MUTATION_EVENT, type RecordMutationKind, type RecordMutationDetail, } from './record-mutation-events';
35
+ export { emitRecordMutation, emitRecordMutationSettled, subscribeRecordMutations, RECORD_MUTATION_EVENT, RECORD_MUTATION_SETTLE_DELAYS, type RecordMutationKind, type RecordMutationDetail, } from './record-mutation-events';
36
36
  export { DocumentFormDialog, resolveDocumentForms, scopeDocumentFormsToFilter, delegatedCreate, withoutDelegatedTypes, type DelegatedCreate, type DocumentFormDialogProps, } from './document-form-dialog';
37
37
  export { modelFromNavUrl, capabilityForNavItem, isNavItemAllowed, useNavItemVisible, type NavLeafLike, } from './nav-permissions';
38
38
  export { CfdiStampPanel, CfdiStampResultDialog, extractStampResult, type CfdiStampResult, type CfdiStampPanelProps, type CfdiStampResultDialogProps, } from './cfdi-stamp-panel';