@asteby/metacore-runtime-react 45.0.0 → 45.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.
- package/CHANGELOG.md +17 -0
- package/dist/approval-events.d.ts +16 -0
- package/dist/approval-events.d.ts.map +1 -0
- package/dist/approval-events.js +27 -0
- package/dist/approval-gate.d.ts +39 -0
- package/dist/approval-gate.d.ts.map +1 -0
- package/dist/approval-gate.js +110 -0
- package/dist/approval-pin-dialog.d.ts +25 -0
- package/dist/approval-pin-dialog.d.ts.map +1 -0
- package/dist/approval-pin-dialog.js +66 -0
- package/dist/business/catalog.d.ts +16 -0
- package/dist/business/catalog.d.ts.map +1 -0
- package/dist/business/catalog.js +42 -0
- package/dist/business/customer-picker.d.ts +39 -0
- package/dist/business/customer-picker.d.ts.map +1 -0
- package/dist/business/customer-picker.js +51 -0
- package/dist/business/feedback.d.ts +72 -0
- package/dist/business/feedback.d.ts.map +1 -0
- package/dist/business/feedback.js +52 -0
- package/dist/business/field-errors.d.ts +26 -0
- package/dist/business/field-errors.d.ts.map +1 -0
- package/dist/business/field-errors.js +59 -0
- package/dist/business/format.d.ts +49 -0
- package/dist/business/format.d.ts.map +1 -0
- package/dist/business/format.js +128 -0
- package/dist/business/index.d.ts +14 -0
- package/dist/business/index.d.ts.map +1 -0
- package/dist/business/index.js +13 -0
- package/dist/business/line-items-editor.d.ts +25 -0
- package/dist/business/line-items-editor.d.ts.map +1 -0
- package/dist/business/line-items-editor.js +36 -0
- package/dist/business/line-items.d.ts +69 -0
- package/dist/business/line-items.d.ts.map +1 -0
- package/dist/business/line-items.js +133 -0
- package/dist/business/payment-capture.d.ts +21 -0
- package/dist/business/payment-capture.d.ts.map +1 -0
- package/dist/business/payment-capture.js +24 -0
- package/dist/business/payment.d.ts +61 -0
- package/dist/business/payment.d.ts.map +1 -0
- package/dist/business/payment.js +74 -0
- package/dist/business/product-picker.d.ts +24 -0
- package/dist/business/product-picker.d.ts.map +1 -0
- package/dist/business/product-picker.js +48 -0
- package/dist/business/product-search.d.ts +70 -0
- package/dist/business/product-search.d.ts.map +1 -0
- package/dist/business/product-search.js +51 -0
- package/dist/business/refund-destination.d.ts +19 -0
- package/dist/business/refund-destination.d.ts.map +1 -0
- package/dist/business/refund-destination.js +31 -0
- package/dist/business/refund.d.ts +29 -0
- package/dist/business/refund.d.ts.map +1 -0
- package/dist/business/refund.js +43 -0
- package/dist/business/use-async-search.d.ts +10 -0
- package/dist/business/use-async-search.d.ts.map +1 -0
- package/dist/business/use-async-search.js +38 -0
- package/dist/document/action-bar.d.ts +12 -0
- package/dist/document/action-bar.d.ts.map +1 -0
- package/dist/document/action-bar.js +39 -0
- package/dist/document/cancel-with-reason.d.ts +47 -0
- package/dist/document/cancel-with-reason.d.ts.map +1 -0
- package/dist/document/cancel-with-reason.js +52 -0
- package/dist/document/document-header.d.ts +41 -0
- package/dist/document/document-header.d.ts.map +1 -0
- package/dist/document/document-header.js +30 -0
- package/dist/document/document-page.d.ts +37 -0
- package/dist/document/document-page.d.ts.map +1 -0
- package/dist/document/document-page.js +137 -0
- package/dist/document/document-timeline.d.ts +20 -0
- package/dist/document/document-timeline.d.ts.map +1 -0
- package/dist/document/document-timeline.js +26 -0
- package/dist/document/evaluate.d.ts +31 -0
- package/dist/document/evaluate.d.ts.map +1 -0
- package/dist/document/evaluate.js +170 -0
- package/dist/document/format.d.ts +9 -0
- package/dist/document/format.d.ts.map +1 -0
- package/dist/document/format.js +52 -0
- package/dist/document/index.d.ts +13 -0
- package/dist/document/index.d.ts.map +1 -0
- package/dist/document/index.js +12 -0
- package/dist/document/registry.d.ts +20 -0
- package/dist/document/registry.d.ts.map +1 -0
- package/dist/document/registry.js +20 -0
- package/dist/document/smart-buttons.d.ts +16 -0
- package/dist/document/smart-buttons.d.ts.map +1 -0
- package/dist/document/smart-buttons.js +16 -0
- package/dist/document/status-badge.d.ts +16 -0
- package/dist/document/status-badge.d.ts.map +1 -0
- package/dist/document/status-badge.js +23 -0
- package/dist/document/types.d.ts +196 -0
- package/dist/document/types.d.ts.map +1 -0
- package/dist/document/types.js +1 -0
- package/dist/document/use-document-sources.d.ts +14 -0
- package/dist/document/use-document-sources.d.ts.map +1 -0
- package/dist/document/use-document-sources.js +72 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/server-error.d.ts.map +1 -1
- package/dist/server-error.js +19 -0
- package/package.json +1 -1
- package/src/__tests__/approval-gate.test.tsx +134 -0
- package/src/approval-events.ts +39 -0
- package/src/approval-gate.tsx +180 -0
- package/src/approval-pin-dialog.tsx +162 -0
- package/src/business/business.test.ts +164 -0
- package/src/business/catalog.ts +60 -0
- package/src/business/customer-picker.tsx +201 -0
- package/src/business/feedback.tsx +141 -0
- package/src/business/field-errors.ts +92 -0
- package/src/business/format.ts +151 -0
- package/src/business/index.ts +13 -0
- package/src/business/line-items-editor.tsx +259 -0
- package/src/business/line-items.ts +190 -0
- package/src/business/payment-capture.tsx +158 -0
- package/src/business/payment.ts +125 -0
- package/src/business/product-picker.tsx +171 -0
- package/src/business/product-search.ts +108 -0
- package/src/business/refund-destination.tsx +121 -0
- package/src/business/refund.ts +71 -0
- package/src/business/use-async-search.ts +43 -0
- package/src/document/__tests__/document-page.test.tsx +107 -0
- package/src/document/__tests__/evaluate.test.ts +140 -0
- package/src/document/action-bar.tsx +140 -0
- package/src/document/cancel-with-reason.tsx +214 -0
- package/src/document/document-header.tsx +140 -0
- package/src/document/document-page.tsx +268 -0
- package/src/document/document-timeline.tsx +66 -0
- package/src/document/evaluate.ts +180 -0
- package/src/document/format.ts +59 -0
- package/src/document/index.ts +28 -0
- package/src/document/registry.ts +39 -0
- package/src/document/smart-buttons.tsx +54 -0
- package/src/document/status-badge.tsx +44 -0
- package/src/document/types.ts +203 -0
- package/src/document/use-document-sources.ts +91 -0
- package/src/index.ts +23 -0
- package/src/server-error.ts +20 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import { useApi } from '../api-context';
|
|
3
|
+
import { buildRelationFilterParams } from '../dynamic-relation-helpers';
|
|
4
|
+
const DEFAULT_LIMIT = 50;
|
|
5
|
+
// El kernel ≥ 0.139.2 acepta listas `in:` largas; se parte para no exceder la URL.
|
|
6
|
+
const VIA_CHUNK = 40;
|
|
7
|
+
/**
|
|
8
|
+
* Carga las filas relacionadas con el documento (pagos, REP, notas de crédito…)
|
|
9
|
+
* que alimentan contadores, pestañas y derivados. Un fallo en una fuente deja
|
|
10
|
+
* esa fuente vacía: la página sigue siendo usable.
|
|
11
|
+
*/
|
|
12
|
+
export function useDocumentSources(defs, recordId) {
|
|
13
|
+
const api = useApi();
|
|
14
|
+
const [sources, setSources] = useState({});
|
|
15
|
+
const [loading, setLoading] = useState(false);
|
|
16
|
+
const [nonce, setNonce] = useState(0);
|
|
17
|
+
const reload = useCallback(() => setNonce((n) => n + 1), []);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (!defs || defs.length === 0 || recordId === undefined || recordId === null) {
|
|
20
|
+
setSources({});
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
let cancelled = false;
|
|
24
|
+
setLoading(true);
|
|
25
|
+
const fetchRows = async (d, params) => {
|
|
26
|
+
try {
|
|
27
|
+
const res = await api.get(`/data/${d.model}`, {
|
|
28
|
+
params: { ...params, page: 1, per_page: d.limit ?? DEFAULT_LIMIT },
|
|
29
|
+
});
|
|
30
|
+
const body = res.data;
|
|
31
|
+
const rows = (body?.data ?? body);
|
|
32
|
+
return Array.isArray(rows) ? rows : [];
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const direct = defs.filter((d) => !d.via);
|
|
39
|
+
const hopped = defs.filter((d) => d.via);
|
|
40
|
+
(async () => {
|
|
41
|
+
const out = {};
|
|
42
|
+
await Promise.all(direct.map(async (d) => {
|
|
43
|
+
out[d.key] = await fetchRows(d, buildRelationFilterParams(d.foreignKey, recordId, d.where));
|
|
44
|
+
}));
|
|
45
|
+
// Segundo salto: depende de las filas del primero.
|
|
46
|
+
for (const d of hopped) {
|
|
47
|
+
const ids = Array.from(new Set((out[d.via.source] ?? []).map((r) => r[d.via.field]).filter((v) => v != null && v !== '').map(String)));
|
|
48
|
+
const chunks = [];
|
|
49
|
+
for (let i = 0; i < ids.length; i += VIA_CHUNK)
|
|
50
|
+
chunks.push(ids.slice(i, i + VIA_CHUNK));
|
|
51
|
+
const parts = await Promise.all(chunks.map((c) => {
|
|
52
|
+
const params = { [`f_${d.foreignKey}`]: `in:${c.join(',')}` };
|
|
53
|
+
for (const [k, v] of Object.entries(d.where ?? {}))
|
|
54
|
+
params[`f_${k}`] = `eq:${v}`;
|
|
55
|
+
return fetchRows(d, params);
|
|
56
|
+
}));
|
|
57
|
+
out[d.key] = parts.flat();
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
})()
|
|
61
|
+
.then((out) => {
|
|
62
|
+
if (cancelled)
|
|
63
|
+
return;
|
|
64
|
+
setSources(out);
|
|
65
|
+
setLoading(false);
|
|
66
|
+
});
|
|
67
|
+
return () => {
|
|
68
|
+
cancelled = true;
|
|
69
|
+
};
|
|
70
|
+
}, [api, defs, recordId, nonce]);
|
|
71
|
+
return { sources, loading, reload };
|
|
72
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -36,6 +36,8 @@ export { AddonLayoutProvider, useAddonLayout, useAddonLayoutControl, useDeclareA
|
|
|
36
36
|
export * from './slot';
|
|
37
37
|
export * from './capability-gate';
|
|
38
38
|
export { PermissionsProvider, useCan, usePermissionsActive, makeCan, capabilityForActionKey, modelCapability, gateTableMetadata, resolveRowActions, type CanFn, type PermissionsProviderProps, } from './permissions-context';
|
|
39
|
+
export { ApprovalPinDialog, approvalErrorMessage, type ApprovalPinDialogProps, type ApprovalPinSubmit, } from './approval-pin-dialog';
|
|
40
|
+
export { ApprovalGateProvider, useApprovalGate, approvalCapability, approvalRequiredInfo, approvalGateAvailable, APPROVAL_PARKED_EVENT, APPROVAL_DECIDED_EVENT, type ApprovalGateValue, type ApprovalGrant, type ApprovalRequiredInfo, type RequestApprovalOptions, } from './approval-gate';
|
|
39
41
|
export { useDynamicRowActions, type UseDynamicRowActionsParams, type DynamicRowActions, } from './dynamic-row-actions';
|
|
40
42
|
export { resolveRequiresAddon, setAddonInstallHandler, getAddonInstallHandler, requiresAddonName, useRequiresAddonLabel, RequiresAddonLock, RequiresAddonDialog, type RequiresAddon, type RequiresAddonDialogProps, } from './requires-addon';
|
|
41
43
|
export { ColorPickerField, DEFAULT_ROLE_COLOR, normalizeHex } from './color-picker-field';
|
|
@@ -43,6 +45,7 @@ export { PermissionsManager, moduleActionCapability, moduleCapabilities, granted
|
|
|
43
45
|
export { applySidebarLayout, collectFolderKeys, folderAccessCapability, coreRefKey, addonModelRefKey, addonUrlRefKey, urlRefKey, leafRefFor, normalizeNavPath, slugifyFolderKey, isValidFolderKey, layoutTreeFromNavGroups, type CatalogLeaf, type SidebarLayoutDoc, type SidebarLayoutNode, type AppliedNavGroup, type AppliedNavItem, } from './apply-sidebar-layout';
|
|
44
46
|
export { SidebarLayoutManager, type SidebarLayoutManagerProps, } from './sidebar-layout-manager';
|
|
45
47
|
export * from './org-runtime-context';
|
|
48
|
+
export * from './business';
|
|
46
49
|
export * from './org-runtime-provider';
|
|
47
50
|
export * from './navigation-builder';
|
|
48
51
|
export * from './i18n-provider';
|
|
@@ -101,4 +104,5 @@ export { formatWidgetValue, formatAxisTick, formatDelta, accentClasses, paletteC
|
|
|
101
104
|
export { AssistInterview, AssistCardView } from './assist-interview';
|
|
102
105
|
export type { AssistSession, AssistTurn, AssistQuestion, AssistCard, AssistProgressStep } from './assist-interview';
|
|
103
106
|
export { useAttributeClasses, resolveAttributeClasses, resetAttributeClassCache, type AttributeClass, type AttributeClassSection, } from './attribute-classes';
|
|
107
|
+
export * from './document';
|
|
104
108
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -41,6 +41,8 @@ export { AddonLayoutProvider, useAddonLayout, useAddonLayoutControl, useDeclareA
|
|
|
41
41
|
export * from './slot';
|
|
42
42
|
export * from './capability-gate';
|
|
43
43
|
export { PermissionsProvider, useCan, usePermissionsActive, makeCan, capabilityForActionKey, modelCapability, gateTableMetadata, resolveRowActions, } from './permissions-context';
|
|
44
|
+
export { ApprovalPinDialog, approvalErrorMessage, } from './approval-pin-dialog';
|
|
45
|
+
export { ApprovalGateProvider, useApprovalGate, approvalCapability, approvalRequiredInfo, approvalGateAvailable, APPROVAL_PARKED_EVENT, APPROVAL_DECIDED_EVENT, } from './approval-gate';
|
|
44
46
|
export { useDynamicRowActions, } from './dynamic-row-actions';
|
|
45
47
|
export { resolveRequiresAddon, setAddonInstallHandler, getAddonInstallHandler, requiresAddonName, useRequiresAddonLabel, RequiresAddonLock, RequiresAddonDialog, } from './requires-addon';
|
|
46
48
|
export { ColorPickerField, DEFAULT_ROLE_COLOR, normalizeHex } from './color-picker-field';
|
|
@@ -48,6 +50,7 @@ export { PermissionsManager, moduleActionCapability, moduleCapabilities, granted
|
|
|
48
50
|
export { applySidebarLayout, collectFolderKeys, folderAccessCapability, coreRefKey, addonModelRefKey, addonUrlRefKey, urlRefKey, leafRefFor, normalizeNavPath, slugifyFolderKey, isValidFolderKey, layoutTreeFromNavGroups, } from './apply-sidebar-layout';
|
|
49
51
|
export { SidebarLayoutManager, } from './sidebar-layout-manager';
|
|
50
52
|
export * from './org-runtime-context';
|
|
53
|
+
export * from './business';
|
|
51
54
|
export * from './org-runtime-provider';
|
|
52
55
|
export * from './navigation-builder';
|
|
53
56
|
export * from './i18n-provider';
|
|
@@ -99,3 +102,5 @@ export { WidgetCard, DeltaChip, WidgetEmpty, WidgetError, } from './widgets/widg
|
|
|
99
102
|
export { formatWidgetValue, formatAxisTick, formatDelta, accentClasses, paletteColor, CHART_PALETTE, } from './widgets/widget-format';
|
|
100
103
|
export { AssistInterview, AssistCardView } from './assist-interview';
|
|
101
104
|
export { useAttributeClasses, resolveAttributeClasses, resetAttributeClassCache, } from './attribute-classes';
|
|
105
|
+
// Página de documento (benchmark §5/§6): cabecera, badges, acciones por estado, botones inteligentes.
|
|
106
|
+
export * from './document';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-error.d.ts","sourceRoot":"","sources":["../src/server-error.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server-error.d.ts","sourceRoot":"","sources":["../src/server-error.ts"],"names":[],"mappings":"AAeA,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC3B,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAA;IACb;;gDAE4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAA;CACvB;AA8BD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,cAAc,CAuBtF;AAED;;gFAEgF;AAChF,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,KAAK,MAAM,CAAA;AAUvG;8EAC8E;AAC9E,MAAM,WAAW,UAAU;IACvB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAA;CACnB;AA6BD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,GAAG,SAAS,CAazF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAC9B,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,MAAM,EACb,CAAC,EAAE,SAAS,EACZ,QAAQ,CAAC,EAAE,MAAM,GAClB,MAAM,CAMR;AAED;6EAC6E;AAC7E,wBAAgB,qBAAqB,CACjC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,EACjC,CAAC,EAAE,SAAS,EACZ,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9D,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOxB;AAUD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAC9B,IAAI,EAAE,OAAO,EACb,IAAI,CAAC,EAAE;IAAE,CAAC,CAAC,EAAE,SAAS,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/C,IAAI,CAUN;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC5B,GAAG,EAAE,OAAO,EACZ,IAAI,CAAC,EAAE;IAAE,CAAC,CAAC,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAChG,IAAI,CA+CN"}
|
package/dist/server-error.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
// the toast description, in ONE place so every call site behaves identically.
|
|
12
12
|
import { toast } from 'sonner';
|
|
13
13
|
import { validationCatalog, validationMessageKey } from './validation-catalog';
|
|
14
|
+
import { APPROVAL_PARKED_EVENT, approvalGateAvailable, approvalRequiredInfo } from './approval-events';
|
|
14
15
|
function formatIssueEntry(v) {
|
|
15
16
|
if (v == null)
|
|
16
17
|
return '';
|
|
@@ -187,6 +188,24 @@ export function toastServerError(err, opts) {
|
|
|
187
188
|
const t = opts?.t;
|
|
188
189
|
const lang = opts?.language;
|
|
189
190
|
const cat = validationCatalog(lang);
|
|
191
|
+
// A write parked for approval is not a failure: say so, and when an
|
|
192
|
+
// <ApprovalGateProvider> is mounted offer to approve it right now with a PIN.
|
|
193
|
+
const parked = approvalRequiredInfo(err);
|
|
194
|
+
if (parked) {
|
|
195
|
+
const title = parked.label || (t ? t('approvals.sent', { defaultValue: 'Enviado a aprobación' }) : 'Enviado a aprobación');
|
|
196
|
+
toast.info(title, {
|
|
197
|
+
description: parked.roles.length
|
|
198
|
+
? (t ? t('approvals.waiting_for', { defaultValue: 'Lo decide: {{roles}}', roles: parked.roles.join(', ') }) : parked.roles.join(', '))
|
|
199
|
+
: undefined,
|
|
200
|
+
action: parked.requestId && approvalGateAvailable()
|
|
201
|
+
? {
|
|
202
|
+
label: t ? t('approvals.approve_with_pin', { defaultValue: 'Aprobar con PIN' }) : 'Aprobar con PIN',
|
|
203
|
+
onClick: () => window.dispatchEvent(new CustomEvent(APPROVAL_PARKED_EVENT, { detail: parked })),
|
|
204
|
+
}
|
|
205
|
+
: undefined,
|
|
206
|
+
});
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
190
209
|
const map = extractFieldErrors(err);
|
|
191
210
|
if (map) {
|
|
192
211
|
const localized = t
|
package/package.json
CHANGED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
//
|
|
3
|
+
// ApprovalGate: inline PIN grants + parked-request approval, and the capability
|
|
4
|
+
// bypass that lets a supervisor skip their own prompt.
|
|
5
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
6
|
+
import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'
|
|
7
|
+
|
|
8
|
+
vi.mock('react-i18next', () => ({
|
|
9
|
+
useTranslation: () => ({
|
|
10
|
+
t: (_k: string, opts?: { defaultValue?: string }) => opts?.defaultValue ?? _k,
|
|
11
|
+
}),
|
|
12
|
+
}))
|
|
13
|
+
vi.mock('sonner', () => ({ toast: Object.assign(vi.fn(), { info: vi.fn(), success: vi.fn(), error: vi.fn() }) }))
|
|
14
|
+
|
|
15
|
+
import { ApiProvider, type ApiClient } from '../api-context'
|
|
16
|
+
import { PermissionsProvider } from '../permissions-context'
|
|
17
|
+
import {
|
|
18
|
+
ApprovalGateProvider,
|
|
19
|
+
useApprovalGate,
|
|
20
|
+
approvalRequiredInfo,
|
|
21
|
+
APPROVAL_PARKED_EVENT,
|
|
22
|
+
type ApprovalGrant,
|
|
23
|
+
} from '../approval-gate'
|
|
24
|
+
import { toastServerError } from '../server-error'
|
|
25
|
+
import { toast } from 'sonner'
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
cleanup()
|
|
29
|
+
vi.clearAllMocks()
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
function makeApi(post: ApiClient['post']): ApiClient {
|
|
33
|
+
return { get: vi.fn(), post, put: vi.fn(), delete: vi.fn() } as unknown as ApiClient
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let lastGrant: ApprovalGrant | null | undefined
|
|
37
|
+
function Probe({ policy }: { policy: string }) {
|
|
38
|
+
const gate = useApprovalGate()
|
|
39
|
+
return (
|
|
40
|
+
<button
|
|
41
|
+
onClick={async () => {
|
|
42
|
+
lastGrant = await gate.requestApproval({ policy, label: 'Venta sin existencias', context: { qty: 3 } })
|
|
43
|
+
}}
|
|
44
|
+
>
|
|
45
|
+
ask
|
|
46
|
+
</button>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function mount(post: ApiClient['post'], caps: string[] = [], isAdmin = false) {
|
|
51
|
+
lastGrant = undefined
|
|
52
|
+
return render(
|
|
53
|
+
<ApiProvider client={makeApi(post)}>
|
|
54
|
+
<PermissionsProvider permissions={caps} isAdmin={isAdmin}>
|
|
55
|
+
<ApprovalGateProvider>
|
|
56
|
+
<Probe policy="oversell" />
|
|
57
|
+
</ApprovalGateProvider>
|
|
58
|
+
</PermissionsProvider>
|
|
59
|
+
</ApiProvider>,
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function fill(reason: string, pin: string) {
|
|
64
|
+
fireEvent.change(screen.getByLabelText('Motivo'), { target: { value: reason } })
|
|
65
|
+
fireEvent.change(screen.getByLabelText('PIN del supervisor'), { target: { value: pin } })
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
describe('ApprovalGate', () => {
|
|
69
|
+
it('a holder of general.approve_<policy> passes without a prompt', async () => {
|
|
70
|
+
const post = vi.fn()
|
|
71
|
+
mount(post, ['general.approve_oversell'])
|
|
72
|
+
await act(async () => fireEvent.click(screen.getByText('ask')))
|
|
73
|
+
expect(lastGrant).toEqual({ id: null, policy: 'oversell', bypassed: true })
|
|
74
|
+
expect(post).not.toHaveBeenCalled()
|
|
75
|
+
expect(screen.queryByLabelText('PIN del supervisor')).toBeNull()
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('posts pin-grant with reason + context and resolves the audit id', async () => {
|
|
79
|
+
const post = vi.fn().mockResolvedValue({ data: { success: true, data: { id: 'audit-1' } } })
|
|
80
|
+
mount(post)
|
|
81
|
+
await act(async () => fireEvent.click(screen.getByText('ask')))
|
|
82
|
+
const submit = screen.getByText('Autorizar').closest('button')!
|
|
83
|
+
expect(submit.hasAttribute('disabled')).toBe(true) // reason + PIN required
|
|
84
|
+
fill('cliente esperando', '4321')
|
|
85
|
+
await act(async () => fireEvent.click(submit))
|
|
86
|
+
await waitFor(() => expect(lastGrant).toBeDefined())
|
|
87
|
+
expect(post).toHaveBeenCalledWith(
|
|
88
|
+
'/approvals/pin-grant',
|
|
89
|
+
expect.objectContaining({ policy: 'oversell', pin: '4321', reason: 'cliente esperando', context: { qty: 3 } }),
|
|
90
|
+
)
|
|
91
|
+
expect(lastGrant).toMatchObject({ id: 'audit-1', bypassed: false })
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('a wrong PIN keeps the dialog open with an inline message and nothing resolves', async () => {
|
|
95
|
+
const post = vi.fn().mockRejectedValue({ response: { data: { error: { code: 'approval_pin_invalid' } } } })
|
|
96
|
+
mount(post)
|
|
97
|
+
await act(async () => fireEvent.click(screen.getByText('ask')))
|
|
98
|
+
fill('r', '0000')
|
|
99
|
+
await act(async () => fireEvent.click(screen.getByText('Autorizar').closest('button')!))
|
|
100
|
+
expect(await screen.findByRole('alert')).toBeTruthy()
|
|
101
|
+
expect(lastGrant).toBeUndefined()
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('cancelling resolves null (fail closed)', async () => {
|
|
105
|
+
mount(vi.fn())
|
|
106
|
+
await act(async () => fireEvent.click(screen.getByText('ask')))
|
|
107
|
+
await act(async () => fireEvent.click(screen.getByText('Cancelar')))
|
|
108
|
+
await waitFor(() => expect(lastGrant).toBeNull())
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('a parked approval_required toast offers the PIN and approves through approve-pin', async () => {
|
|
112
|
+
const post = vi.fn().mockResolvedValue({ data: { success: true } })
|
|
113
|
+
mount(post)
|
|
114
|
+
const err = {
|
|
115
|
+
response: {
|
|
116
|
+
data: { success: false, error: { code: 'approval_required' }, meta: { approval_request_id: 'req-9', approval_label: 'Precio bajo el piso', approval_roles: ['gerente'] } },
|
|
117
|
+
},
|
|
118
|
+
}
|
|
119
|
+
expect(approvalRequiredInfo(err)).toMatchObject({ requestId: 'req-9', roles: ['gerente'] })
|
|
120
|
+
toastServerError(err)
|
|
121
|
+
const opts = (toast.info as unknown as ReturnType<typeof vi.fn>).mock.calls[0][1]
|
|
122
|
+
expect(toast.error).not.toHaveBeenCalled()
|
|
123
|
+
await act(async () => opts.action.onClick())
|
|
124
|
+
fill('autorizado', '1234')
|
|
125
|
+
await act(async () => fireEvent.click(screen.getByText('Autorizar').closest('button')!))
|
|
126
|
+
await waitFor(() => expect(post).toHaveBeenCalledWith('/approvals/req-9/approve-pin', { pin: '1234', reason: 'autorizado' }))
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
it('without a gate mounted the parked toast has no PIN action and the event is inert', () => {
|
|
130
|
+
toastServerError({ response: { data: { error: { code: 'approval_required' }, meta: { approval_request_id: 'x' } } } })
|
|
131
|
+
expect((toast.info as unknown as ReturnType<typeof vi.fn>).mock.calls[0][1].action).toBeUndefined()
|
|
132
|
+
window.dispatchEvent(new CustomEvent(APPROVAL_PARKED_EVENT, { detail: { requestId: 'x', roles: [] } }))
|
|
133
|
+
})
|
|
134
|
+
})
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// approval-events — dependency-free glue between server-error.ts (which sees a
|
|
2
|
+
// parked `approval_required` write) and <ApprovalGateProvider> (which owns the
|
|
3
|
+
// PIN dialog). Kept apart so the error toaster never imports React/UI code.
|
|
4
|
+
|
|
5
|
+
/** Window event toastServerError fires for a parked `approval_required` write. */
|
|
6
|
+
export const APPROVAL_PARKED_EVENT = 'metacore:approval-parked'
|
|
7
|
+
/** Fired after a parked request was approved (and replayed) with a PIN. */
|
|
8
|
+
export const APPROVAL_DECIDED_EVENT = 'metacore:approval-decided'
|
|
9
|
+
|
|
10
|
+
let gateMounted = 0
|
|
11
|
+
/** @internal provider bookkeeping. */
|
|
12
|
+
export function gateMountedDelta(d: number): void {
|
|
13
|
+
gateMounted += d
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** True while an <ApprovalGateProvider> is mounted (toastServerError offers the PIN action only then). */
|
|
17
|
+
export function approvalGateAvailable(): boolean {
|
|
18
|
+
return gateMounted > 0
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ApprovalRequiredInfo {
|
|
22
|
+
requestId: string
|
|
23
|
+
label?: string
|
|
24
|
+
roles: string[]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Extracts the parked-request info from an axios error / response body, or null. */
|
|
28
|
+
export function approvalRequiredInfo(err: unknown): ApprovalRequiredInfo | null {
|
|
29
|
+
const data = ((err as { response?: { data?: unknown } })?.response?.data ?? err) as
|
|
30
|
+
| { error?: { code?: string }; meta?: { approval_request_id?: string; approval_label?: string; approval_roles?: string[] } }
|
|
31
|
+
| undefined
|
|
32
|
+
if (data?.error?.code !== 'approval_required') return null
|
|
33
|
+
return {
|
|
34
|
+
requestId: data.meta?.approval_request_id ?? '',
|
|
35
|
+
label: data.meta?.approval_label,
|
|
36
|
+
roles: data.meta?.approval_roles ?? [],
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
// ApprovalGate — one place for "this needs a supervisor" in hosts that mount an
|
|
2
|
+
// ApiProvider. It answers two situations with the same PIN dialog:
|
|
3
|
+
//
|
|
4
|
+
// 1. INLINE policy (POS oversell, discount over the cap, refund…): the client
|
|
5
|
+
// calls `requestApproval({policy, …})`. A user who already holds the policy's
|
|
6
|
+
// `general.approve_<policy>` capability passes straight through (`bypassed`);
|
|
7
|
+
// everyone else gets the dialog, which posts `/approvals/pin-grant`.
|
|
8
|
+
// 2. PARKED request: a write answered 422 `approval_required`. toastServerError
|
|
9
|
+
// shows "Enviado a aprobación" with an "Aprobar con PIN" action that opens the
|
|
10
|
+
// dialog against `/approvals/:id/approve-pin` (kernel approvals_pin.go).
|
|
11
|
+
//
|
|
12
|
+
// Federated addons with their own HTTP client use <ApprovalPinDialog> directly
|
|
13
|
+
// (approval-pin-dialog.tsx) and post to the same endpoints.
|
|
14
|
+
import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'
|
|
15
|
+
import { useTranslation } from 'react-i18next'
|
|
16
|
+
import { toast } from 'sonner'
|
|
17
|
+
import { useApi } from './api-context'
|
|
18
|
+
import { useCan } from './permissions-context'
|
|
19
|
+
import { ApprovalPinDialog, type ApprovalPinSubmit } from './approval-pin-dialog'
|
|
20
|
+
import {
|
|
21
|
+
APPROVAL_DECIDED_EVENT,
|
|
22
|
+
APPROVAL_PARKED_EVENT,
|
|
23
|
+
gateMountedDelta,
|
|
24
|
+
type ApprovalRequiredInfo,
|
|
25
|
+
} from './approval-events'
|
|
26
|
+
|
|
27
|
+
export {
|
|
28
|
+
APPROVAL_DECIDED_EVENT,
|
|
29
|
+
APPROVAL_PARKED_EVENT,
|
|
30
|
+
approvalGateAvailable,
|
|
31
|
+
approvalRequiredInfo,
|
|
32
|
+
type ApprovalRequiredInfo,
|
|
33
|
+
} from './approval-events'
|
|
34
|
+
|
|
35
|
+
/** Capability that authorizes `policy` (and lets its holder skip the prompt). */
|
|
36
|
+
export function approvalCapability(policy: string): string {
|
|
37
|
+
return `general.approve_${policy}`
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface ApprovalGrant {
|
|
41
|
+
/** Audit row id (ApprovalRequest.kind=pin); null when the caller bypassed. */
|
|
42
|
+
id: string | null
|
|
43
|
+
policy: string
|
|
44
|
+
bypassed: boolean
|
|
45
|
+
reason?: string
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface RequestApprovalOptions {
|
|
49
|
+
/** Policy key: oversell | discount | price_below_min | refund | cancel_cfdi | inventory_adjust | <addon-declared>. */
|
|
50
|
+
policy: string
|
|
51
|
+
label: string
|
|
52
|
+
description?: React.ReactNode
|
|
53
|
+
/** Free-form audit data stored with the grant (product, qty, before → after…). */
|
|
54
|
+
context?: Record<string, unknown>
|
|
55
|
+
model?: string
|
|
56
|
+
recordId?: string
|
|
57
|
+
addonKey?: string
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface ApprovalGateValue {
|
|
61
|
+
/** Resolves the grant, or null when the operator cancelled. */
|
|
62
|
+
requestApproval: (opts: RequestApprovalOptions) => Promise<ApprovalGrant | null>
|
|
63
|
+
/** True when the current user may do `policy` without asking anyone. */
|
|
64
|
+
canSelfApprove: (policy: string) => boolean
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const ApprovalGateContext = createContext<ApprovalGateValue | null>(null)
|
|
68
|
+
|
|
69
|
+
type Pending =
|
|
70
|
+
| { kind: 'inline'; opts: RequestApprovalOptions; resolve: (g: ApprovalGrant | null) => void }
|
|
71
|
+
| { kind: 'parked'; info: ApprovalRequiredInfo }
|
|
72
|
+
|
|
73
|
+
export function ApprovalGateProvider({ children }: { children: React.ReactNode }) {
|
|
74
|
+
const { t } = useTranslation()
|
|
75
|
+
const api = useApi()
|
|
76
|
+
const can = useCan()
|
|
77
|
+
const [pending, setPending] = useState<Pending | null>(null)
|
|
78
|
+
const pendingRef = useRef<Pending | null>(null)
|
|
79
|
+
pendingRef.current = pending
|
|
80
|
+
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
gateMountedDelta(1)
|
|
83
|
+
const onParked = (e: Event) => {
|
|
84
|
+
const info = (e as CustomEvent<ApprovalRequiredInfo>).detail
|
|
85
|
+
if (info?.requestId) setPending({ kind: 'parked', info })
|
|
86
|
+
}
|
|
87
|
+
window.addEventListener(APPROVAL_PARKED_EVENT, onParked)
|
|
88
|
+
return () => {
|
|
89
|
+
gateMountedDelta(-1)
|
|
90
|
+
window.removeEventListener(APPROVAL_PARKED_EVENT, onParked)
|
|
91
|
+
}
|
|
92
|
+
}, [])
|
|
93
|
+
|
|
94
|
+
const canSelfApprove = useCallback((policy: string) => can(approvalCapability(policy)), [can])
|
|
95
|
+
|
|
96
|
+
const requestApproval = useCallback(
|
|
97
|
+
(opts: RequestApprovalOptions) => {
|
|
98
|
+
if (can(approvalCapability(opts.policy))) {
|
|
99
|
+
return Promise.resolve<ApprovalGrant>({ id: null, policy: opts.policy, bypassed: true })
|
|
100
|
+
}
|
|
101
|
+
return new Promise<ApprovalGrant | null>((resolve) => {
|
|
102
|
+
pendingRef.current?.kind === 'inline' && pendingRef.current.resolve(null)
|
|
103
|
+
setPending({ kind: 'inline', opts, resolve })
|
|
104
|
+
})
|
|
105
|
+
},
|
|
106
|
+
[can],
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
const close = () => {
|
|
110
|
+
const p = pendingRef.current
|
|
111
|
+
if (p?.kind === 'inline') p.resolve(null)
|
|
112
|
+
setPending(null)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const submit = async ({ pin, reason }: ApprovalPinSubmit) => {
|
|
116
|
+
const p = pendingRef.current
|
|
117
|
+
if (!p) return
|
|
118
|
+
if (p.kind === 'inline') {
|
|
119
|
+
const res = await api.post('/approvals/pin-grant', {
|
|
120
|
+
policy: p.opts.policy,
|
|
121
|
+
label: p.opts.label,
|
|
122
|
+
pin,
|
|
123
|
+
reason,
|
|
124
|
+
context: p.opts.context,
|
|
125
|
+
model: p.opts.model,
|
|
126
|
+
record_id: p.opts.recordId,
|
|
127
|
+
addon_key: p.opts.addonKey,
|
|
128
|
+
})
|
|
129
|
+
const row = res.data?.data
|
|
130
|
+
p.resolve({ id: row?.id ?? null, policy: p.opts.policy, bypassed: false, reason })
|
|
131
|
+
} else {
|
|
132
|
+
await api.post(`/approvals/${p.info.requestId}/approve-pin`, { pin, reason })
|
|
133
|
+
toast.success(t('approvals.approved_applied', { defaultValue: 'Aprobado y aplicado' }))
|
|
134
|
+
window.dispatchEvent(new CustomEvent(APPROVAL_DECIDED_EVENT, { detail: p.info }))
|
|
135
|
+
}
|
|
136
|
+
setPending(null)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const value = useMemo<ApprovalGateValue>(() => ({ requestApproval, canSelfApprove }), [requestApproval, canSelfApprove])
|
|
140
|
+
|
|
141
|
+
const title =
|
|
142
|
+
pending?.kind === 'inline'
|
|
143
|
+
? pending.opts.label
|
|
144
|
+
: pending?.kind === 'parked'
|
|
145
|
+
? pending.info.label || t('approvals.parked_title', { defaultValue: 'Requiere aprobación' })
|
|
146
|
+
: ''
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<ApprovalGateContext.Provider value={value}>
|
|
150
|
+
{children}
|
|
151
|
+
<ApprovalPinDialog
|
|
152
|
+
open={pending !== null}
|
|
153
|
+
title={title}
|
|
154
|
+
description={pending?.kind === 'inline' ? pending.opts.description : undefined}
|
|
155
|
+
onSubmit={submit}
|
|
156
|
+
onCancel={close}
|
|
157
|
+
/>
|
|
158
|
+
</ApprovalGateContext.Provider>
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Access the gate. Without a provider the gate fails CLOSED for inline requests
|
|
164
|
+
* (resolves null) — never silently authorizes — but honours the capability
|
|
165
|
+
* bypass, and `canSelfApprove` follows `useCan()` (always-true with no
|
|
166
|
+
* <PermissionsProvider>, i.e. legacy hosts keep today's behaviour).
|
|
167
|
+
*/
|
|
168
|
+
export function useApprovalGate(): ApprovalGateValue {
|
|
169
|
+
const ctx = useContext(ApprovalGateContext)
|
|
170
|
+
const can = useCan()
|
|
171
|
+
return useMemo<ApprovalGateValue>(
|
|
172
|
+
() =>
|
|
173
|
+
ctx ?? {
|
|
174
|
+
canSelfApprove: (policy) => can(approvalCapability(policy)),
|
|
175
|
+
requestApproval: async (opts) =>
|
|
176
|
+
can(approvalCapability(opts.policy)) ? { id: null, policy: opts.policy, bypassed: true } : null,
|
|
177
|
+
},
|
|
178
|
+
[ctx, can],
|
|
179
|
+
)
|
|
180
|
+
}
|