@zaamx/netme-pos 0.0.14 → 0.0.15
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.
|
@@ -5,8 +5,8 @@ const icons = require("@medusajs/icons");
|
|
|
5
5
|
const ui = require("@medusajs/ui");
|
|
6
6
|
const react = require("react");
|
|
7
7
|
const reactQuery = require("@tanstack/react-query");
|
|
8
|
-
const Medusa = require("@medusajs/js-sdk");
|
|
9
8
|
const reactRouterDom = require("react-router-dom");
|
|
9
|
+
const Medusa = require("@medusajs/js-sdk");
|
|
10
10
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
11
11
|
const Medusa__default = /* @__PURE__ */ _interopDefault(Medusa);
|
|
12
12
|
const sdk = new Medusa__default.default({
|
|
@@ -18,6 +18,187 @@ const sdk = new Medusa__default.default({
|
|
|
18
18
|
type: "session"
|
|
19
19
|
}
|
|
20
20
|
});
|
|
21
|
+
const POS_ROLES = [
|
|
22
|
+
{ value: "cashier", label: "Cajero" },
|
|
23
|
+
{ value: "supervisor", label: "Supervisor" },
|
|
24
|
+
{ value: "manager", label: "Gerente" }
|
|
25
|
+
];
|
|
26
|
+
const CAPABILITY_GROUPS = [
|
|
27
|
+
{
|
|
28
|
+
title: "Venta / carrito",
|
|
29
|
+
items: [
|
|
30
|
+
{ key: "cancel_sale", label: "Cancelar venta", description: "Botón que borra el draft" },
|
|
31
|
+
{ key: "pause_sale", label: "Pausar venta", description: "Guardar para después" },
|
|
32
|
+
{ key: "remove_item", label: "Eliminar ítems del carrito" },
|
|
33
|
+
{ key: "edit_quantity", label: "Cambiar cantidades" },
|
|
34
|
+
{ key: "apply_promotion", label: "Aplicar / quitar cupón" },
|
|
35
|
+
{ key: "apply_manual_discount", label: "Descuento manual (override de precio)", description: "Acción sensible" }
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
title: "Configuración de la sesión",
|
|
40
|
+
items: [
|
|
41
|
+
{ key: "change_region", label: "Cambiar región" },
|
|
42
|
+
{ key: "change_sales_channel", label: "Cambiar canal de venta" },
|
|
43
|
+
{ key: "change_location", label: "Cambiar ubicación de surtido" }
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
title: "Pago",
|
|
48
|
+
items: [
|
|
49
|
+
{ key: "pay_cash", label: "Cobrar en caja (efectivo)" },
|
|
50
|
+
{ key: "pay_card", label: "Cobrar con tarjeta (Stripe)" },
|
|
51
|
+
{ key: "use_store_credit", label: "Pagar con Monedero (store credit)" },
|
|
52
|
+
{ key: "capture_payment", label: "Capturar pago" },
|
|
53
|
+
{ key: "capture_without_docs", label: "Capturar sin documentación", description: "Acción sensible" }
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
title: "Envío / dirección",
|
|
58
|
+
items: [
|
|
59
|
+
{ key: "edit_shipping", label: "Elegir / cambiar método de envío" },
|
|
60
|
+
{ key: "edit_customer_address", label: "Editar dirección de envío del cliente" }
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
title: "Ventas pendientes",
|
|
65
|
+
items: [
|
|
66
|
+
{ key: "view_pending_drafts", label: "Ver ventas pendientes (/pos-drafts)" },
|
|
67
|
+
{ key: "recover_draft", label: "Recuperar / cargar un draft" }
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
];
|
|
71
|
+
const CAPABILITY_KEYS = CAPABILITY_GROUPS.flatMap(
|
|
72
|
+
(g) => g.items.map((i) => i.key)
|
|
73
|
+
);
|
|
74
|
+
const allTrue = () => CAPABILITY_KEYS.reduce(
|
|
75
|
+
(acc, key) => ({ ...acc, [key]: true }),
|
|
76
|
+
{}
|
|
77
|
+
);
|
|
78
|
+
const ROLE_PRESETS = {
|
|
79
|
+
cashier: {
|
|
80
|
+
...allTrue(),
|
|
81
|
+
cancel_sale: false,
|
|
82
|
+
apply_manual_discount: false,
|
|
83
|
+
change_region: false,
|
|
84
|
+
change_sales_channel: false,
|
|
85
|
+
capture_payment: false,
|
|
86
|
+
capture_without_docs: false,
|
|
87
|
+
view_pending_drafts: false,
|
|
88
|
+
recover_draft: false
|
|
89
|
+
},
|
|
90
|
+
supervisor: {
|
|
91
|
+
...allTrue(),
|
|
92
|
+
capture_without_docs: false
|
|
93
|
+
},
|
|
94
|
+
manager: {
|
|
95
|
+
...allTrue()
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const presetForRole = (role) => {
|
|
99
|
+
if (role && ROLE_PRESETS[role]) {
|
|
100
|
+
return ROLE_PRESETS[role];
|
|
101
|
+
}
|
|
102
|
+
return allTrue();
|
|
103
|
+
};
|
|
104
|
+
const resolveCapabilities = (role, stored) => {
|
|
105
|
+
const preset = presetForRole(role);
|
|
106
|
+
return CAPABILITY_KEYS.reduce((acc, key) => {
|
|
107
|
+
const storedValue = stored && typeof stored[key] === "boolean" ? stored[key] : void 0;
|
|
108
|
+
acc[key] = storedValue ?? preset[key] ?? true;
|
|
109
|
+
return acc;
|
|
110
|
+
}, {});
|
|
111
|
+
};
|
|
112
|
+
const columnHelper$2 = ui.createDataTableColumnHelper();
|
|
113
|
+
const roleLabel = (role) => {
|
|
114
|
+
var _a;
|
|
115
|
+
return ((_a = POS_ROLES.find((r) => r.value === role)) == null ? void 0 : _a.label) || null;
|
|
116
|
+
};
|
|
117
|
+
const scopeSummary = (ids) => Array.isArray(ids) ? `${ids.length} seleccionada${ids.length === 1 ? "" : "s"}` : "Todas";
|
|
118
|
+
const useColumns$2 = () => react.useMemo(
|
|
119
|
+
() => [
|
|
120
|
+
columnHelper$2.accessor("first_name", {
|
|
121
|
+
header: "Nombre",
|
|
122
|
+
cell: ({ row }) => `${row.original.first_name ?? ""} ${row.original.last_name ?? ""}`.trim() || "—"
|
|
123
|
+
}),
|
|
124
|
+
columnHelper$2.accessor("email", {
|
|
125
|
+
header: "Email"
|
|
126
|
+
}),
|
|
127
|
+
columnHelper$2.display({
|
|
128
|
+
id: "role",
|
|
129
|
+
header: "Rol POS",
|
|
130
|
+
cell: ({ row }) => {
|
|
131
|
+
var _a;
|
|
132
|
+
const label = roleLabel((_a = row.original.metadata) == null ? void 0 : _a.pos_role);
|
|
133
|
+
return label ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "blue", children: label }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted", children: "Sin rol" });
|
|
134
|
+
}
|
|
135
|
+
}),
|
|
136
|
+
columnHelper$2.display({
|
|
137
|
+
id: "locations",
|
|
138
|
+
header: "Ubicaciones",
|
|
139
|
+
cell: ({ row }) => {
|
|
140
|
+
var _a;
|
|
141
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: scopeSummary((_a = row.original.metadata) == null ? void 0 : _a.pos_stock_location_ids) });
|
|
142
|
+
}
|
|
143
|
+
}),
|
|
144
|
+
columnHelper$2.display({
|
|
145
|
+
id: "actions",
|
|
146
|
+
cell: ({ row }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { asChild: true, size: "small", variant: "secondary", children: /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Link, { to: `/pos-permissions/${row.original.id}`, children: "Editar permisos" }) }) })
|
|
147
|
+
})
|
|
148
|
+
],
|
|
149
|
+
[]
|
|
150
|
+
);
|
|
151
|
+
const PosPermissionsPage = () => {
|
|
152
|
+
const [searchValue, setSearchValue] = react.useState("");
|
|
153
|
+
const [pagination, setPagination] = react.useState({
|
|
154
|
+
pageIndex: 0,
|
|
155
|
+
pageSize: 15
|
|
156
|
+
});
|
|
157
|
+
const limit = pagination.pageSize;
|
|
158
|
+
const offset = pagination.pageIndex * limit;
|
|
159
|
+
const { data, isLoading } = reactQuery.useQuery({
|
|
160
|
+
queryFn: () => sdk.client.fetch("/admin/operators", {
|
|
161
|
+
query: {
|
|
162
|
+
limit,
|
|
163
|
+
offset,
|
|
164
|
+
q: searchValue || void 0
|
|
165
|
+
}
|
|
166
|
+
}),
|
|
167
|
+
queryKey: ["operators", "pos-permissions", limit, offset, searchValue],
|
|
168
|
+
placeholderData: (previousData) => previousData
|
|
169
|
+
});
|
|
170
|
+
const columns = useColumns$2();
|
|
171
|
+
const table = ui.useDataTable({
|
|
172
|
+
data: (data == null ? void 0 : data.operators) || [],
|
|
173
|
+
columns,
|
|
174
|
+
getRowId: (row) => row.id,
|
|
175
|
+
rowCount: (data == null ? void 0 : data.count) || 0,
|
|
176
|
+
isLoading,
|
|
177
|
+
search: {
|
|
178
|
+
state: searchValue,
|
|
179
|
+
onSearchChange: setSearchValue
|
|
180
|
+
},
|
|
181
|
+
pagination: {
|
|
182
|
+
state: pagination,
|
|
183
|
+
onPaginationChange: setPagination
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "flex flex-col items-stretch overflow-hidden p-0", children: [
|
|
187
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between border-b border-ui-border-base px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
|
|
188
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: "Permisos POS" }),
|
|
189
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Define el alcance (ubicaciones, canales, regiones) y las capacidades de cada operador del Punto de Venta." })
|
|
190
|
+
] }) }),
|
|
191
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.DataTable, { instance: table, children: [
|
|
192
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Toolbar, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex w-full items-center justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Search, { placeholder: "Buscar operador..." }) }) }),
|
|
193
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Table, {}),
|
|
194
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Pagination, {})
|
|
195
|
+
] })
|
|
196
|
+
] });
|
|
197
|
+
};
|
|
198
|
+
const config$2 = adminSdk.defineRouteConfig({
|
|
199
|
+
label: "Permisos POS",
|
|
200
|
+
icon: icons.ShieldCheck
|
|
201
|
+
});
|
|
21
202
|
const EditOperatorDrawer = ({
|
|
22
203
|
operator,
|
|
23
204
|
open,
|
|
@@ -324,24 +505,24 @@ const CreateOperatorModal = () => {
|
|
|
324
505
|
] }) }) })
|
|
325
506
|
] });
|
|
326
507
|
};
|
|
327
|
-
const columnHelper$
|
|
328
|
-
const useColumns$
|
|
508
|
+
const columnHelper$1 = ui.createDataTableColumnHelper();
|
|
509
|
+
const useColumns$1 = () => {
|
|
329
510
|
return react.useMemo(
|
|
330
511
|
() => [
|
|
331
|
-
columnHelper$
|
|
512
|
+
columnHelper$1.accessor("first_name", {
|
|
332
513
|
header: "First Name"
|
|
333
514
|
}),
|
|
334
|
-
columnHelper$
|
|
515
|
+
columnHelper$1.accessor("last_name", {
|
|
335
516
|
header: "Last Name"
|
|
336
517
|
}),
|
|
337
|
-
columnHelper$
|
|
518
|
+
columnHelper$1.accessor("email", {
|
|
338
519
|
header: "Email"
|
|
339
520
|
}),
|
|
340
|
-
columnHelper$
|
|
521
|
+
columnHelper$1.accessor("created_at", {
|
|
341
522
|
header: "Date Added",
|
|
342
523
|
cell: ({ getValue }) => new Date(getValue()).toLocaleDateString()
|
|
343
524
|
}),
|
|
344
|
-
columnHelper$
|
|
525
|
+
columnHelper$1.display({
|
|
345
526
|
id: "actions",
|
|
346
527
|
cell: ({ row }) => /* @__PURE__ */ jsxRuntime.jsx(OperatorActions, { operator: row.original })
|
|
347
528
|
})
|
|
@@ -368,7 +549,7 @@ const OperatorTable = () => {
|
|
|
368
549
|
queryKey: ["operators", limit, offset, searchValue],
|
|
369
550
|
placeholderData: (previousData) => previousData
|
|
370
551
|
});
|
|
371
|
-
const columns = useColumns$
|
|
552
|
+
const columns = useColumns$1();
|
|
372
553
|
const table = ui.useDataTable({
|
|
373
554
|
data: (data == null ? void 0 : data.operators) || [],
|
|
374
555
|
columns,
|
|
@@ -399,7 +580,7 @@ const OperatorsPage = () => {
|
|
|
399
580
|
/* @__PURE__ */ jsxRuntime.jsx(OperatorTable, {})
|
|
400
581
|
] });
|
|
401
582
|
};
|
|
402
|
-
const config$
|
|
583
|
+
const config$1 = adminSdk.defineRouteConfig({
|
|
403
584
|
label: "Operators",
|
|
404
585
|
icon: icons.Users
|
|
405
586
|
});
|
|
@@ -735,7 +916,7 @@ const PaymentOptionActions = ({
|
|
|
735
916
|
)
|
|
736
917
|
] });
|
|
737
918
|
};
|
|
738
|
-
const columnHelper
|
|
919
|
+
const columnHelper = ui.createDataTableColumnHelper();
|
|
739
920
|
const formatAmount = (value) => {
|
|
740
921
|
const n = Number(value ?? 0);
|
|
741
922
|
return n.toLocaleString("es-MX", {
|
|
@@ -766,10 +947,10 @@ const statusColor = (status) => {
|
|
|
766
947
|
return "grey";
|
|
767
948
|
}
|
|
768
949
|
};
|
|
769
|
-
const useColumns
|
|
950
|
+
const useColumns = () => {
|
|
770
951
|
return react.useMemo(
|
|
771
952
|
() => [
|
|
772
|
-
columnHelper
|
|
953
|
+
columnHelper.accessor("order_display_id", {
|
|
773
954
|
header: "Orden",
|
|
774
955
|
cell: ({ row }) => {
|
|
775
956
|
const displayId = row.original.order_display_id;
|
|
@@ -794,19 +975,19 @@ const useColumns$1 = () => {
|
|
|
794
975
|
);
|
|
795
976
|
}
|
|
796
977
|
}),
|
|
797
|
-
columnHelper
|
|
978
|
+
columnHelper.accessor("reference_code", {
|
|
798
979
|
header: "Folio / Referencia",
|
|
799
980
|
cell: ({ getValue }) => getValue() || "—"
|
|
800
981
|
}),
|
|
801
|
-
columnHelper
|
|
982
|
+
columnHelper.accessor("payment_method", {
|
|
802
983
|
header: "Método",
|
|
803
984
|
cell: ({ getValue }) => getValue() || "—"
|
|
804
985
|
}),
|
|
805
|
-
columnHelper
|
|
986
|
+
columnHelper.accessor("amount", {
|
|
806
987
|
header: "Monto",
|
|
807
988
|
cell: ({ getValue }) => formatAmount(getValue())
|
|
808
989
|
}),
|
|
809
|
-
columnHelper
|
|
990
|
+
columnHelper.accessor("status", {
|
|
810
991
|
header: "Estatus",
|
|
811
992
|
cell: ({ getValue }) => {
|
|
812
993
|
const status = getValue();
|
|
@@ -816,15 +997,15 @@ const useColumns$1 = () => {
|
|
|
816
997
|
return /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: statusColor(status), children: status });
|
|
817
998
|
}
|
|
818
999
|
}),
|
|
819
|
-
columnHelper
|
|
1000
|
+
columnHelper.accessor("concept", {
|
|
820
1001
|
header: "Concepto",
|
|
821
1002
|
cell: ({ getValue }) => getValue() || "—"
|
|
822
1003
|
}),
|
|
823
|
-
columnHelper
|
|
1004
|
+
columnHelper.accessor("created_at", {
|
|
824
1005
|
header: "Fecha",
|
|
825
1006
|
cell: ({ getValue }) => new Date(getValue()).toLocaleString()
|
|
826
1007
|
}),
|
|
827
|
-
columnHelper
|
|
1008
|
+
columnHelper.display({
|
|
828
1009
|
id: "actions",
|
|
829
1010
|
cell: ({ row }) => /* @__PURE__ */ jsxRuntime.jsx(PaymentOptionActions, { paymentOption: row.original })
|
|
830
1011
|
})
|
|
@@ -851,7 +1032,7 @@ const PaymentOptionTable = () => {
|
|
|
851
1032
|
queryKey: ["payment-options", limit, offset, searchValue],
|
|
852
1033
|
placeholderData: (previousData) => previousData
|
|
853
1034
|
});
|
|
854
|
-
const columns = useColumns
|
|
1035
|
+
const columns = useColumns();
|
|
855
1036
|
const table = ui.useDataTable({
|
|
856
1037
|
data: (data == null ? void 0 : data.payment_options) || [],
|
|
857
1038
|
columns,
|
|
@@ -888,191 +1069,10 @@ const PaymentOptionsPage = () => {
|
|
|
888
1069
|
/* @__PURE__ */ jsxRuntime.jsx(PaymentOptionTable, {})
|
|
889
1070
|
] });
|
|
890
1071
|
};
|
|
891
|
-
const config
|
|
1072
|
+
const config = adminSdk.defineRouteConfig({
|
|
892
1073
|
label: "Notas de pago",
|
|
893
1074
|
icon: icons.CurrencyDollar
|
|
894
1075
|
});
|
|
895
|
-
const POS_ROLES = [
|
|
896
|
-
{ value: "cashier", label: "Cajero" },
|
|
897
|
-
{ value: "supervisor", label: "Supervisor" },
|
|
898
|
-
{ value: "manager", label: "Gerente" }
|
|
899
|
-
];
|
|
900
|
-
const CAPABILITY_GROUPS = [
|
|
901
|
-
{
|
|
902
|
-
title: "Venta / carrito",
|
|
903
|
-
items: [
|
|
904
|
-
{ key: "cancel_sale", label: "Cancelar venta", description: "Botón que borra el draft" },
|
|
905
|
-
{ key: "pause_sale", label: "Pausar venta", description: "Guardar para después" },
|
|
906
|
-
{ key: "remove_item", label: "Eliminar ítems del carrito" },
|
|
907
|
-
{ key: "edit_quantity", label: "Cambiar cantidades" },
|
|
908
|
-
{ key: "apply_promotion", label: "Aplicar / quitar cupón" },
|
|
909
|
-
{ key: "apply_manual_discount", label: "Descuento manual (override de precio)", description: "Acción sensible" }
|
|
910
|
-
]
|
|
911
|
-
},
|
|
912
|
-
{
|
|
913
|
-
title: "Configuración de la sesión",
|
|
914
|
-
items: [
|
|
915
|
-
{ key: "change_region", label: "Cambiar región" },
|
|
916
|
-
{ key: "change_sales_channel", label: "Cambiar canal de venta" },
|
|
917
|
-
{ key: "change_location", label: "Cambiar ubicación de surtido" }
|
|
918
|
-
]
|
|
919
|
-
},
|
|
920
|
-
{
|
|
921
|
-
title: "Pago",
|
|
922
|
-
items: [
|
|
923
|
-
{ key: "pay_cash", label: "Cobrar en caja (efectivo)" },
|
|
924
|
-
{ key: "pay_card", label: "Cobrar con tarjeta (Stripe)" },
|
|
925
|
-
{ key: "use_store_credit", label: "Pagar con Monedero (store credit)" },
|
|
926
|
-
{ key: "capture_payment", label: "Capturar pago" },
|
|
927
|
-
{ key: "capture_without_docs", label: "Capturar sin documentación", description: "Acción sensible" }
|
|
928
|
-
]
|
|
929
|
-
},
|
|
930
|
-
{
|
|
931
|
-
title: "Envío / dirección",
|
|
932
|
-
items: [
|
|
933
|
-
{ key: "edit_shipping", label: "Elegir / cambiar método de envío" },
|
|
934
|
-
{ key: "edit_customer_address", label: "Editar dirección de envío del cliente" }
|
|
935
|
-
]
|
|
936
|
-
},
|
|
937
|
-
{
|
|
938
|
-
title: "Ventas pendientes",
|
|
939
|
-
items: [
|
|
940
|
-
{ key: "view_pending_drafts", label: "Ver ventas pendientes (/pos-drafts)" },
|
|
941
|
-
{ key: "recover_draft", label: "Recuperar / cargar un draft" }
|
|
942
|
-
]
|
|
943
|
-
}
|
|
944
|
-
];
|
|
945
|
-
const CAPABILITY_KEYS = CAPABILITY_GROUPS.flatMap(
|
|
946
|
-
(g) => g.items.map((i) => i.key)
|
|
947
|
-
);
|
|
948
|
-
const allTrue = () => CAPABILITY_KEYS.reduce(
|
|
949
|
-
(acc, key) => ({ ...acc, [key]: true }),
|
|
950
|
-
{}
|
|
951
|
-
);
|
|
952
|
-
const ROLE_PRESETS = {
|
|
953
|
-
cashier: {
|
|
954
|
-
...allTrue(),
|
|
955
|
-
cancel_sale: false,
|
|
956
|
-
apply_manual_discount: false,
|
|
957
|
-
change_region: false,
|
|
958
|
-
change_sales_channel: false,
|
|
959
|
-
capture_payment: false,
|
|
960
|
-
capture_without_docs: false,
|
|
961
|
-
view_pending_drafts: false,
|
|
962
|
-
recover_draft: false
|
|
963
|
-
},
|
|
964
|
-
supervisor: {
|
|
965
|
-
...allTrue(),
|
|
966
|
-
capture_without_docs: false
|
|
967
|
-
},
|
|
968
|
-
manager: {
|
|
969
|
-
...allTrue()
|
|
970
|
-
}
|
|
971
|
-
};
|
|
972
|
-
const presetForRole = (role) => {
|
|
973
|
-
if (role && ROLE_PRESETS[role]) {
|
|
974
|
-
return ROLE_PRESETS[role];
|
|
975
|
-
}
|
|
976
|
-
return allTrue();
|
|
977
|
-
};
|
|
978
|
-
const resolveCapabilities = (role, stored) => {
|
|
979
|
-
const preset = presetForRole(role);
|
|
980
|
-
return CAPABILITY_KEYS.reduce((acc, key) => {
|
|
981
|
-
const storedValue = stored && typeof stored[key] === "boolean" ? stored[key] : void 0;
|
|
982
|
-
acc[key] = storedValue ?? preset[key] ?? true;
|
|
983
|
-
return acc;
|
|
984
|
-
}, {});
|
|
985
|
-
};
|
|
986
|
-
const columnHelper = ui.createDataTableColumnHelper();
|
|
987
|
-
const roleLabel = (role) => {
|
|
988
|
-
var _a;
|
|
989
|
-
return ((_a = POS_ROLES.find((r) => r.value === role)) == null ? void 0 : _a.label) || null;
|
|
990
|
-
};
|
|
991
|
-
const scopeSummary = (ids) => Array.isArray(ids) ? `${ids.length} seleccionada${ids.length === 1 ? "" : "s"}` : "Todas";
|
|
992
|
-
const useColumns = () => react.useMemo(
|
|
993
|
-
() => [
|
|
994
|
-
columnHelper.accessor("first_name", {
|
|
995
|
-
header: "Nombre",
|
|
996
|
-
cell: ({ row }) => `${row.original.first_name ?? ""} ${row.original.last_name ?? ""}`.trim() || "—"
|
|
997
|
-
}),
|
|
998
|
-
columnHelper.accessor("email", {
|
|
999
|
-
header: "Email"
|
|
1000
|
-
}),
|
|
1001
|
-
columnHelper.display({
|
|
1002
|
-
id: "role",
|
|
1003
|
-
header: "Rol POS",
|
|
1004
|
-
cell: ({ row }) => {
|
|
1005
|
-
var _a;
|
|
1006
|
-
const label = roleLabel((_a = row.original.metadata) == null ? void 0 : _a.pos_role);
|
|
1007
|
-
return label ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "blue", children: label }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted", children: "Sin rol" });
|
|
1008
|
-
}
|
|
1009
|
-
}),
|
|
1010
|
-
columnHelper.display({
|
|
1011
|
-
id: "locations",
|
|
1012
|
-
header: "Ubicaciones",
|
|
1013
|
-
cell: ({ row }) => {
|
|
1014
|
-
var _a;
|
|
1015
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: scopeSummary((_a = row.original.metadata) == null ? void 0 : _a.pos_stock_location_ids) });
|
|
1016
|
-
}
|
|
1017
|
-
}),
|
|
1018
|
-
columnHelper.display({
|
|
1019
|
-
id: "actions",
|
|
1020
|
-
cell: ({ row }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { asChild: true, size: "small", variant: "secondary", children: /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Link, { to: `/pos-permissions/${row.original.id}`, children: "Editar permisos" }) }) })
|
|
1021
|
-
})
|
|
1022
|
-
],
|
|
1023
|
-
[]
|
|
1024
|
-
);
|
|
1025
|
-
const PosPermissionsPage = () => {
|
|
1026
|
-
const [searchValue, setSearchValue] = react.useState("");
|
|
1027
|
-
const [pagination, setPagination] = react.useState({
|
|
1028
|
-
pageIndex: 0,
|
|
1029
|
-
pageSize: 15
|
|
1030
|
-
});
|
|
1031
|
-
const limit = pagination.pageSize;
|
|
1032
|
-
const offset = pagination.pageIndex * limit;
|
|
1033
|
-
const { data, isLoading } = reactQuery.useQuery({
|
|
1034
|
-
queryFn: () => sdk.client.fetch("/admin/operators", {
|
|
1035
|
-
query: {
|
|
1036
|
-
limit,
|
|
1037
|
-
offset,
|
|
1038
|
-
q: searchValue || void 0
|
|
1039
|
-
}
|
|
1040
|
-
}),
|
|
1041
|
-
queryKey: ["operators", "pos-permissions", limit, offset, searchValue],
|
|
1042
|
-
placeholderData: (previousData) => previousData
|
|
1043
|
-
});
|
|
1044
|
-
const columns = useColumns();
|
|
1045
|
-
const table = ui.useDataTable({
|
|
1046
|
-
data: (data == null ? void 0 : data.operators) || [],
|
|
1047
|
-
columns,
|
|
1048
|
-
getRowId: (row) => row.id,
|
|
1049
|
-
rowCount: (data == null ? void 0 : data.count) || 0,
|
|
1050
|
-
isLoading,
|
|
1051
|
-
search: {
|
|
1052
|
-
state: searchValue,
|
|
1053
|
-
onSearchChange: setSearchValue
|
|
1054
|
-
},
|
|
1055
|
-
pagination: {
|
|
1056
|
-
state: pagination,
|
|
1057
|
-
onPaginationChange: setPagination
|
|
1058
|
-
}
|
|
1059
|
-
});
|
|
1060
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "flex flex-col items-stretch overflow-hidden p-0", children: [
|
|
1061
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between border-b border-ui-border-base px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
|
|
1062
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: "Permisos POS" }),
|
|
1063
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Define el alcance (ubicaciones, canales, regiones) y las capacidades de cada operador del Punto de Venta." })
|
|
1064
|
-
] }) }),
|
|
1065
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.DataTable, { instance: table, children: [
|
|
1066
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Toolbar, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex w-full items-center justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Search, { placeholder: "Buscar operador..." }) }) }),
|
|
1067
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Table, {}),
|
|
1068
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Pagination, {})
|
|
1069
|
-
] })
|
|
1070
|
-
] });
|
|
1071
|
-
};
|
|
1072
|
-
const config = adminSdk.defineRouteConfig({
|
|
1073
|
-
label: "Permisos POS",
|
|
1074
|
-
icon: icons.ShieldCheck
|
|
1075
|
-
});
|
|
1076
1076
|
const MultiSelect = ({
|
|
1077
1077
|
options,
|
|
1078
1078
|
value,
|
|
@@ -1697,6 +1697,10 @@ const i18nTranslations0 = {};
|
|
|
1697
1697
|
const widgetModule = { widgets: [] };
|
|
1698
1698
|
const routeModule = {
|
|
1699
1699
|
routes: [
|
|
1700
|
+
{
|
|
1701
|
+
Component: PosPermissionsPage,
|
|
1702
|
+
path: "/pos-permissions"
|
|
1703
|
+
},
|
|
1700
1704
|
{
|
|
1701
1705
|
Component: OperatorsPage,
|
|
1702
1706
|
path: "/operators"
|
|
@@ -1705,10 +1709,6 @@ const routeModule = {
|
|
|
1705
1709
|
Component: PaymentOptionsPage,
|
|
1706
1710
|
path: "/payment-options"
|
|
1707
1711
|
},
|
|
1708
|
-
{
|
|
1709
|
-
Component: PosPermissionsPage,
|
|
1710
|
-
path: "/pos-permissions"
|
|
1711
|
-
},
|
|
1712
1712
|
{
|
|
1713
1713
|
Component: PosPermissionEditorPage,
|
|
1714
1714
|
path: "/pos-permissions/:id"
|
|
@@ -1718,25 +1718,25 @@ const routeModule = {
|
|
|
1718
1718
|
const menuItemModule = {
|
|
1719
1719
|
menuItems: [
|
|
1720
1720
|
{
|
|
1721
|
-
label: config
|
|
1722
|
-
icon: config
|
|
1723
|
-
path: "/
|
|
1721
|
+
label: config.label,
|
|
1722
|
+
icon: config.icon,
|
|
1723
|
+
path: "/payment-options",
|
|
1724
1724
|
nested: void 0,
|
|
1725
1725
|
rank: void 0,
|
|
1726
1726
|
translationNs: void 0
|
|
1727
1727
|
},
|
|
1728
1728
|
{
|
|
1729
|
-
label: config$
|
|
1730
|
-
icon: config$
|
|
1731
|
-
path: "/
|
|
1729
|
+
label: config$2.label,
|
|
1730
|
+
icon: config$2.icon,
|
|
1731
|
+
path: "/pos-permissions",
|
|
1732
1732
|
nested: void 0,
|
|
1733
1733
|
rank: void 0,
|
|
1734
1734
|
translationNs: void 0
|
|
1735
1735
|
},
|
|
1736
1736
|
{
|
|
1737
|
-
label: config.label,
|
|
1738
|
-
icon: config.icon,
|
|
1739
|
-
path: "/
|
|
1737
|
+
label: config$1.label,
|
|
1738
|
+
icon: config$1.icon,
|
|
1739
|
+
path: "/operators",
|
|
1740
1740
|
nested: void 0,
|
|
1741
1741
|
rank: void 0,
|
|
1742
1742
|
translationNs: void 0
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { defineRouteConfig } from "@medusajs/admin-sdk";
|
|
3
|
-
import { EllipsisHorizontal, PencilSquare,
|
|
4
|
-
import {
|
|
3
|
+
import { ShieldCheck, EllipsisHorizontal, PencilSquare, Trash, Users, CurrencyDollar, XMark, ChevronUpDown, ArrowUturnLeft, Spinner, ArrowLeft, Buildings, ChannelsSolid, Tag } from "@medusajs/icons";
|
|
4
|
+
import { createDataTableColumnHelper, useDataTable, Container, Heading, Text, DataTable, Badge, Button, toast, Drawer, Label, Input, Prompt, DropdownMenu, IconButton, FocusModal, Select, Popover, clx, Checkbox, Switch } from "@medusajs/ui";
|
|
5
5
|
import { useState, useMemo, useEffect, useRef } from "react";
|
|
6
|
-
import { useQueryClient, useMutation
|
|
6
|
+
import { useQuery, useQueryClient, useMutation } from "@tanstack/react-query";
|
|
7
|
+
import { Link, useNavigate, useParams } from "react-router-dom";
|
|
7
8
|
import Medusa from "@medusajs/js-sdk";
|
|
8
|
-
import { useNavigate, Link, useParams } from "react-router-dom";
|
|
9
9
|
const sdk = new Medusa({
|
|
10
10
|
// @ts-ignore
|
|
11
11
|
baseUrl: "/",
|
|
@@ -15,6 +15,187 @@ const sdk = new Medusa({
|
|
|
15
15
|
type: "session"
|
|
16
16
|
}
|
|
17
17
|
});
|
|
18
|
+
const POS_ROLES = [
|
|
19
|
+
{ value: "cashier", label: "Cajero" },
|
|
20
|
+
{ value: "supervisor", label: "Supervisor" },
|
|
21
|
+
{ value: "manager", label: "Gerente" }
|
|
22
|
+
];
|
|
23
|
+
const CAPABILITY_GROUPS = [
|
|
24
|
+
{
|
|
25
|
+
title: "Venta / carrito",
|
|
26
|
+
items: [
|
|
27
|
+
{ key: "cancel_sale", label: "Cancelar venta", description: "Botón que borra el draft" },
|
|
28
|
+
{ key: "pause_sale", label: "Pausar venta", description: "Guardar para después" },
|
|
29
|
+
{ key: "remove_item", label: "Eliminar ítems del carrito" },
|
|
30
|
+
{ key: "edit_quantity", label: "Cambiar cantidades" },
|
|
31
|
+
{ key: "apply_promotion", label: "Aplicar / quitar cupón" },
|
|
32
|
+
{ key: "apply_manual_discount", label: "Descuento manual (override de precio)", description: "Acción sensible" }
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
title: "Configuración de la sesión",
|
|
37
|
+
items: [
|
|
38
|
+
{ key: "change_region", label: "Cambiar región" },
|
|
39
|
+
{ key: "change_sales_channel", label: "Cambiar canal de venta" },
|
|
40
|
+
{ key: "change_location", label: "Cambiar ubicación de surtido" }
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
title: "Pago",
|
|
45
|
+
items: [
|
|
46
|
+
{ key: "pay_cash", label: "Cobrar en caja (efectivo)" },
|
|
47
|
+
{ key: "pay_card", label: "Cobrar con tarjeta (Stripe)" },
|
|
48
|
+
{ key: "use_store_credit", label: "Pagar con Monedero (store credit)" },
|
|
49
|
+
{ key: "capture_payment", label: "Capturar pago" },
|
|
50
|
+
{ key: "capture_without_docs", label: "Capturar sin documentación", description: "Acción sensible" }
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
title: "Envío / dirección",
|
|
55
|
+
items: [
|
|
56
|
+
{ key: "edit_shipping", label: "Elegir / cambiar método de envío" },
|
|
57
|
+
{ key: "edit_customer_address", label: "Editar dirección de envío del cliente" }
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
title: "Ventas pendientes",
|
|
62
|
+
items: [
|
|
63
|
+
{ key: "view_pending_drafts", label: "Ver ventas pendientes (/pos-drafts)" },
|
|
64
|
+
{ key: "recover_draft", label: "Recuperar / cargar un draft" }
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
];
|
|
68
|
+
const CAPABILITY_KEYS = CAPABILITY_GROUPS.flatMap(
|
|
69
|
+
(g) => g.items.map((i) => i.key)
|
|
70
|
+
);
|
|
71
|
+
const allTrue = () => CAPABILITY_KEYS.reduce(
|
|
72
|
+
(acc, key) => ({ ...acc, [key]: true }),
|
|
73
|
+
{}
|
|
74
|
+
);
|
|
75
|
+
const ROLE_PRESETS = {
|
|
76
|
+
cashier: {
|
|
77
|
+
...allTrue(),
|
|
78
|
+
cancel_sale: false,
|
|
79
|
+
apply_manual_discount: false,
|
|
80
|
+
change_region: false,
|
|
81
|
+
change_sales_channel: false,
|
|
82
|
+
capture_payment: false,
|
|
83
|
+
capture_without_docs: false,
|
|
84
|
+
view_pending_drafts: false,
|
|
85
|
+
recover_draft: false
|
|
86
|
+
},
|
|
87
|
+
supervisor: {
|
|
88
|
+
...allTrue(),
|
|
89
|
+
capture_without_docs: false
|
|
90
|
+
},
|
|
91
|
+
manager: {
|
|
92
|
+
...allTrue()
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const presetForRole = (role) => {
|
|
96
|
+
if (role && ROLE_PRESETS[role]) {
|
|
97
|
+
return ROLE_PRESETS[role];
|
|
98
|
+
}
|
|
99
|
+
return allTrue();
|
|
100
|
+
};
|
|
101
|
+
const resolveCapabilities = (role, stored) => {
|
|
102
|
+
const preset = presetForRole(role);
|
|
103
|
+
return CAPABILITY_KEYS.reduce((acc, key) => {
|
|
104
|
+
const storedValue = stored && typeof stored[key] === "boolean" ? stored[key] : void 0;
|
|
105
|
+
acc[key] = storedValue ?? preset[key] ?? true;
|
|
106
|
+
return acc;
|
|
107
|
+
}, {});
|
|
108
|
+
};
|
|
109
|
+
const columnHelper$2 = createDataTableColumnHelper();
|
|
110
|
+
const roleLabel = (role) => {
|
|
111
|
+
var _a;
|
|
112
|
+
return ((_a = POS_ROLES.find((r) => r.value === role)) == null ? void 0 : _a.label) || null;
|
|
113
|
+
};
|
|
114
|
+
const scopeSummary = (ids) => Array.isArray(ids) ? `${ids.length} seleccionada${ids.length === 1 ? "" : "s"}` : "Todas";
|
|
115
|
+
const useColumns$2 = () => useMemo(
|
|
116
|
+
() => [
|
|
117
|
+
columnHelper$2.accessor("first_name", {
|
|
118
|
+
header: "Nombre",
|
|
119
|
+
cell: ({ row }) => `${row.original.first_name ?? ""} ${row.original.last_name ?? ""}`.trim() || "—"
|
|
120
|
+
}),
|
|
121
|
+
columnHelper$2.accessor("email", {
|
|
122
|
+
header: "Email"
|
|
123
|
+
}),
|
|
124
|
+
columnHelper$2.display({
|
|
125
|
+
id: "role",
|
|
126
|
+
header: "Rol POS",
|
|
127
|
+
cell: ({ row }) => {
|
|
128
|
+
var _a;
|
|
129
|
+
const label = roleLabel((_a = row.original.metadata) == null ? void 0 : _a.pos_role);
|
|
130
|
+
return label ? /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: "blue", children: label }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Sin rol" });
|
|
131
|
+
}
|
|
132
|
+
}),
|
|
133
|
+
columnHelper$2.display({
|
|
134
|
+
id: "locations",
|
|
135
|
+
header: "Ubicaciones",
|
|
136
|
+
cell: ({ row }) => {
|
|
137
|
+
var _a;
|
|
138
|
+
return /* @__PURE__ */ jsx(Text, { size: "small", children: scopeSummary((_a = row.original.metadata) == null ? void 0 : _a.pos_stock_location_ids) });
|
|
139
|
+
}
|
|
140
|
+
}),
|
|
141
|
+
columnHelper$2.display({
|
|
142
|
+
id: "actions",
|
|
143
|
+
cell: ({ row }) => /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(Button, { asChild: true, size: "small", variant: "secondary", children: /* @__PURE__ */ jsx(Link, { to: `/pos-permissions/${row.original.id}`, children: "Editar permisos" }) }) })
|
|
144
|
+
})
|
|
145
|
+
],
|
|
146
|
+
[]
|
|
147
|
+
);
|
|
148
|
+
const PosPermissionsPage = () => {
|
|
149
|
+
const [searchValue, setSearchValue] = useState("");
|
|
150
|
+
const [pagination, setPagination] = useState({
|
|
151
|
+
pageIndex: 0,
|
|
152
|
+
pageSize: 15
|
|
153
|
+
});
|
|
154
|
+
const limit = pagination.pageSize;
|
|
155
|
+
const offset = pagination.pageIndex * limit;
|
|
156
|
+
const { data, isLoading } = useQuery({
|
|
157
|
+
queryFn: () => sdk.client.fetch("/admin/operators", {
|
|
158
|
+
query: {
|
|
159
|
+
limit,
|
|
160
|
+
offset,
|
|
161
|
+
q: searchValue || void 0
|
|
162
|
+
}
|
|
163
|
+
}),
|
|
164
|
+
queryKey: ["operators", "pos-permissions", limit, offset, searchValue],
|
|
165
|
+
placeholderData: (previousData) => previousData
|
|
166
|
+
});
|
|
167
|
+
const columns = useColumns$2();
|
|
168
|
+
const table = useDataTable({
|
|
169
|
+
data: (data == null ? void 0 : data.operators) || [],
|
|
170
|
+
columns,
|
|
171
|
+
getRowId: (row) => row.id,
|
|
172
|
+
rowCount: (data == null ? void 0 : data.count) || 0,
|
|
173
|
+
isLoading,
|
|
174
|
+
search: {
|
|
175
|
+
state: searchValue,
|
|
176
|
+
onSearchChange: setSearchValue
|
|
177
|
+
},
|
|
178
|
+
pagination: {
|
|
179
|
+
state: pagination,
|
|
180
|
+
onPaginationChange: setPagination
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
return /* @__PURE__ */ jsxs(Container, { className: "flex flex-col items-stretch overflow-hidden p-0", children: [
|
|
184
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-between border-b border-ui-border-base px-6 py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-1", children: [
|
|
185
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", children: "Permisos POS" }),
|
|
186
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Define el alcance (ubicaciones, canales, regiones) y las capacidades de cada operador del Punto de Venta." })
|
|
187
|
+
] }) }),
|
|
188
|
+
/* @__PURE__ */ jsxs(DataTable, { instance: table, children: [
|
|
189
|
+
/* @__PURE__ */ jsx(DataTable.Toolbar, { children: /* @__PURE__ */ jsx("div", { className: "flex w-full items-center justify-end", children: /* @__PURE__ */ jsx(DataTable.Search, { placeholder: "Buscar operador..." }) }) }),
|
|
190
|
+
/* @__PURE__ */ jsx(DataTable.Table, {}),
|
|
191
|
+
/* @__PURE__ */ jsx(DataTable.Pagination, {})
|
|
192
|
+
] })
|
|
193
|
+
] });
|
|
194
|
+
};
|
|
195
|
+
const config$2 = defineRouteConfig({
|
|
196
|
+
label: "Permisos POS",
|
|
197
|
+
icon: ShieldCheck
|
|
198
|
+
});
|
|
18
199
|
const EditOperatorDrawer = ({
|
|
19
200
|
operator,
|
|
20
201
|
open,
|
|
@@ -321,24 +502,24 @@ const CreateOperatorModal = () => {
|
|
|
321
502
|
] }) }) })
|
|
322
503
|
] });
|
|
323
504
|
};
|
|
324
|
-
const columnHelper$
|
|
325
|
-
const useColumns$
|
|
505
|
+
const columnHelper$1 = createDataTableColumnHelper();
|
|
506
|
+
const useColumns$1 = () => {
|
|
326
507
|
return useMemo(
|
|
327
508
|
() => [
|
|
328
|
-
columnHelper$
|
|
509
|
+
columnHelper$1.accessor("first_name", {
|
|
329
510
|
header: "First Name"
|
|
330
511
|
}),
|
|
331
|
-
columnHelper$
|
|
512
|
+
columnHelper$1.accessor("last_name", {
|
|
332
513
|
header: "Last Name"
|
|
333
514
|
}),
|
|
334
|
-
columnHelper$
|
|
515
|
+
columnHelper$1.accessor("email", {
|
|
335
516
|
header: "Email"
|
|
336
517
|
}),
|
|
337
|
-
columnHelper$
|
|
518
|
+
columnHelper$1.accessor("created_at", {
|
|
338
519
|
header: "Date Added",
|
|
339
520
|
cell: ({ getValue }) => new Date(getValue()).toLocaleDateString()
|
|
340
521
|
}),
|
|
341
|
-
columnHelper$
|
|
522
|
+
columnHelper$1.display({
|
|
342
523
|
id: "actions",
|
|
343
524
|
cell: ({ row }) => /* @__PURE__ */ jsx(OperatorActions, { operator: row.original })
|
|
344
525
|
})
|
|
@@ -365,7 +546,7 @@ const OperatorTable = () => {
|
|
|
365
546
|
queryKey: ["operators", limit, offset, searchValue],
|
|
366
547
|
placeholderData: (previousData) => previousData
|
|
367
548
|
});
|
|
368
|
-
const columns = useColumns$
|
|
549
|
+
const columns = useColumns$1();
|
|
369
550
|
const table = useDataTable({
|
|
370
551
|
data: (data == null ? void 0 : data.operators) || [],
|
|
371
552
|
columns,
|
|
@@ -396,7 +577,7 @@ const OperatorsPage = () => {
|
|
|
396
577
|
/* @__PURE__ */ jsx(OperatorTable, {})
|
|
397
578
|
] });
|
|
398
579
|
};
|
|
399
|
-
const config$
|
|
580
|
+
const config$1 = defineRouteConfig({
|
|
400
581
|
label: "Operators",
|
|
401
582
|
icon: Users
|
|
402
583
|
});
|
|
@@ -732,7 +913,7 @@ const PaymentOptionActions = ({
|
|
|
732
913
|
)
|
|
733
914
|
] });
|
|
734
915
|
};
|
|
735
|
-
const columnHelper
|
|
916
|
+
const columnHelper = createDataTableColumnHelper();
|
|
736
917
|
const formatAmount = (value) => {
|
|
737
918
|
const n = Number(value ?? 0);
|
|
738
919
|
return n.toLocaleString("es-MX", {
|
|
@@ -763,10 +944,10 @@ const statusColor = (status) => {
|
|
|
763
944
|
return "grey";
|
|
764
945
|
}
|
|
765
946
|
};
|
|
766
|
-
const useColumns
|
|
947
|
+
const useColumns = () => {
|
|
767
948
|
return useMemo(
|
|
768
949
|
() => [
|
|
769
|
-
columnHelper
|
|
950
|
+
columnHelper.accessor("order_display_id", {
|
|
770
951
|
header: "Orden",
|
|
771
952
|
cell: ({ row }) => {
|
|
772
953
|
const displayId = row.original.order_display_id;
|
|
@@ -791,19 +972,19 @@ const useColumns$1 = () => {
|
|
|
791
972
|
);
|
|
792
973
|
}
|
|
793
974
|
}),
|
|
794
|
-
columnHelper
|
|
975
|
+
columnHelper.accessor("reference_code", {
|
|
795
976
|
header: "Folio / Referencia",
|
|
796
977
|
cell: ({ getValue }) => getValue() || "—"
|
|
797
978
|
}),
|
|
798
|
-
columnHelper
|
|
979
|
+
columnHelper.accessor("payment_method", {
|
|
799
980
|
header: "Método",
|
|
800
981
|
cell: ({ getValue }) => getValue() || "—"
|
|
801
982
|
}),
|
|
802
|
-
columnHelper
|
|
983
|
+
columnHelper.accessor("amount", {
|
|
803
984
|
header: "Monto",
|
|
804
985
|
cell: ({ getValue }) => formatAmount(getValue())
|
|
805
986
|
}),
|
|
806
|
-
columnHelper
|
|
987
|
+
columnHelper.accessor("status", {
|
|
807
988
|
header: "Estatus",
|
|
808
989
|
cell: ({ getValue }) => {
|
|
809
990
|
const status = getValue();
|
|
@@ -813,15 +994,15 @@ const useColumns$1 = () => {
|
|
|
813
994
|
return /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: statusColor(status), children: status });
|
|
814
995
|
}
|
|
815
996
|
}),
|
|
816
|
-
columnHelper
|
|
997
|
+
columnHelper.accessor("concept", {
|
|
817
998
|
header: "Concepto",
|
|
818
999
|
cell: ({ getValue }) => getValue() || "—"
|
|
819
1000
|
}),
|
|
820
|
-
columnHelper
|
|
1001
|
+
columnHelper.accessor("created_at", {
|
|
821
1002
|
header: "Fecha",
|
|
822
1003
|
cell: ({ getValue }) => new Date(getValue()).toLocaleString()
|
|
823
1004
|
}),
|
|
824
|
-
columnHelper
|
|
1005
|
+
columnHelper.display({
|
|
825
1006
|
id: "actions",
|
|
826
1007
|
cell: ({ row }) => /* @__PURE__ */ jsx(PaymentOptionActions, { paymentOption: row.original })
|
|
827
1008
|
})
|
|
@@ -848,7 +1029,7 @@ const PaymentOptionTable = () => {
|
|
|
848
1029
|
queryKey: ["payment-options", limit, offset, searchValue],
|
|
849
1030
|
placeholderData: (previousData) => previousData
|
|
850
1031
|
});
|
|
851
|
-
const columns = useColumns
|
|
1032
|
+
const columns = useColumns();
|
|
852
1033
|
const table = useDataTable({
|
|
853
1034
|
data: (data == null ? void 0 : data.payment_options) || [],
|
|
854
1035
|
columns,
|
|
@@ -885,191 +1066,10 @@ const PaymentOptionsPage = () => {
|
|
|
885
1066
|
/* @__PURE__ */ jsx(PaymentOptionTable, {})
|
|
886
1067
|
] });
|
|
887
1068
|
};
|
|
888
|
-
const config
|
|
1069
|
+
const config = defineRouteConfig({
|
|
889
1070
|
label: "Notas de pago",
|
|
890
1071
|
icon: CurrencyDollar
|
|
891
1072
|
});
|
|
892
|
-
const POS_ROLES = [
|
|
893
|
-
{ value: "cashier", label: "Cajero" },
|
|
894
|
-
{ value: "supervisor", label: "Supervisor" },
|
|
895
|
-
{ value: "manager", label: "Gerente" }
|
|
896
|
-
];
|
|
897
|
-
const CAPABILITY_GROUPS = [
|
|
898
|
-
{
|
|
899
|
-
title: "Venta / carrito",
|
|
900
|
-
items: [
|
|
901
|
-
{ key: "cancel_sale", label: "Cancelar venta", description: "Botón que borra el draft" },
|
|
902
|
-
{ key: "pause_sale", label: "Pausar venta", description: "Guardar para después" },
|
|
903
|
-
{ key: "remove_item", label: "Eliminar ítems del carrito" },
|
|
904
|
-
{ key: "edit_quantity", label: "Cambiar cantidades" },
|
|
905
|
-
{ key: "apply_promotion", label: "Aplicar / quitar cupón" },
|
|
906
|
-
{ key: "apply_manual_discount", label: "Descuento manual (override de precio)", description: "Acción sensible" }
|
|
907
|
-
]
|
|
908
|
-
},
|
|
909
|
-
{
|
|
910
|
-
title: "Configuración de la sesión",
|
|
911
|
-
items: [
|
|
912
|
-
{ key: "change_region", label: "Cambiar región" },
|
|
913
|
-
{ key: "change_sales_channel", label: "Cambiar canal de venta" },
|
|
914
|
-
{ key: "change_location", label: "Cambiar ubicación de surtido" }
|
|
915
|
-
]
|
|
916
|
-
},
|
|
917
|
-
{
|
|
918
|
-
title: "Pago",
|
|
919
|
-
items: [
|
|
920
|
-
{ key: "pay_cash", label: "Cobrar en caja (efectivo)" },
|
|
921
|
-
{ key: "pay_card", label: "Cobrar con tarjeta (Stripe)" },
|
|
922
|
-
{ key: "use_store_credit", label: "Pagar con Monedero (store credit)" },
|
|
923
|
-
{ key: "capture_payment", label: "Capturar pago" },
|
|
924
|
-
{ key: "capture_without_docs", label: "Capturar sin documentación", description: "Acción sensible" }
|
|
925
|
-
]
|
|
926
|
-
},
|
|
927
|
-
{
|
|
928
|
-
title: "Envío / dirección",
|
|
929
|
-
items: [
|
|
930
|
-
{ key: "edit_shipping", label: "Elegir / cambiar método de envío" },
|
|
931
|
-
{ key: "edit_customer_address", label: "Editar dirección de envío del cliente" }
|
|
932
|
-
]
|
|
933
|
-
},
|
|
934
|
-
{
|
|
935
|
-
title: "Ventas pendientes",
|
|
936
|
-
items: [
|
|
937
|
-
{ key: "view_pending_drafts", label: "Ver ventas pendientes (/pos-drafts)" },
|
|
938
|
-
{ key: "recover_draft", label: "Recuperar / cargar un draft" }
|
|
939
|
-
]
|
|
940
|
-
}
|
|
941
|
-
];
|
|
942
|
-
const CAPABILITY_KEYS = CAPABILITY_GROUPS.flatMap(
|
|
943
|
-
(g) => g.items.map((i) => i.key)
|
|
944
|
-
);
|
|
945
|
-
const allTrue = () => CAPABILITY_KEYS.reduce(
|
|
946
|
-
(acc, key) => ({ ...acc, [key]: true }),
|
|
947
|
-
{}
|
|
948
|
-
);
|
|
949
|
-
const ROLE_PRESETS = {
|
|
950
|
-
cashier: {
|
|
951
|
-
...allTrue(),
|
|
952
|
-
cancel_sale: false,
|
|
953
|
-
apply_manual_discount: false,
|
|
954
|
-
change_region: false,
|
|
955
|
-
change_sales_channel: false,
|
|
956
|
-
capture_payment: false,
|
|
957
|
-
capture_without_docs: false,
|
|
958
|
-
view_pending_drafts: false,
|
|
959
|
-
recover_draft: false
|
|
960
|
-
},
|
|
961
|
-
supervisor: {
|
|
962
|
-
...allTrue(),
|
|
963
|
-
capture_without_docs: false
|
|
964
|
-
},
|
|
965
|
-
manager: {
|
|
966
|
-
...allTrue()
|
|
967
|
-
}
|
|
968
|
-
};
|
|
969
|
-
const presetForRole = (role) => {
|
|
970
|
-
if (role && ROLE_PRESETS[role]) {
|
|
971
|
-
return ROLE_PRESETS[role];
|
|
972
|
-
}
|
|
973
|
-
return allTrue();
|
|
974
|
-
};
|
|
975
|
-
const resolveCapabilities = (role, stored) => {
|
|
976
|
-
const preset = presetForRole(role);
|
|
977
|
-
return CAPABILITY_KEYS.reduce((acc, key) => {
|
|
978
|
-
const storedValue = stored && typeof stored[key] === "boolean" ? stored[key] : void 0;
|
|
979
|
-
acc[key] = storedValue ?? preset[key] ?? true;
|
|
980
|
-
return acc;
|
|
981
|
-
}, {});
|
|
982
|
-
};
|
|
983
|
-
const columnHelper = createDataTableColumnHelper();
|
|
984
|
-
const roleLabel = (role) => {
|
|
985
|
-
var _a;
|
|
986
|
-
return ((_a = POS_ROLES.find((r) => r.value === role)) == null ? void 0 : _a.label) || null;
|
|
987
|
-
};
|
|
988
|
-
const scopeSummary = (ids) => Array.isArray(ids) ? `${ids.length} seleccionada${ids.length === 1 ? "" : "s"}` : "Todas";
|
|
989
|
-
const useColumns = () => useMemo(
|
|
990
|
-
() => [
|
|
991
|
-
columnHelper.accessor("first_name", {
|
|
992
|
-
header: "Nombre",
|
|
993
|
-
cell: ({ row }) => `${row.original.first_name ?? ""} ${row.original.last_name ?? ""}`.trim() || "—"
|
|
994
|
-
}),
|
|
995
|
-
columnHelper.accessor("email", {
|
|
996
|
-
header: "Email"
|
|
997
|
-
}),
|
|
998
|
-
columnHelper.display({
|
|
999
|
-
id: "role",
|
|
1000
|
-
header: "Rol POS",
|
|
1001
|
-
cell: ({ row }) => {
|
|
1002
|
-
var _a;
|
|
1003
|
-
const label = roleLabel((_a = row.original.metadata) == null ? void 0 : _a.pos_role);
|
|
1004
|
-
return label ? /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: "blue", children: label }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: "Sin rol" });
|
|
1005
|
-
}
|
|
1006
|
-
}),
|
|
1007
|
-
columnHelper.display({
|
|
1008
|
-
id: "locations",
|
|
1009
|
-
header: "Ubicaciones",
|
|
1010
|
-
cell: ({ row }) => {
|
|
1011
|
-
var _a;
|
|
1012
|
-
return /* @__PURE__ */ jsx(Text, { size: "small", children: scopeSummary((_a = row.original.metadata) == null ? void 0 : _a.pos_stock_location_ids) });
|
|
1013
|
-
}
|
|
1014
|
-
}),
|
|
1015
|
-
columnHelper.display({
|
|
1016
|
-
id: "actions",
|
|
1017
|
-
cell: ({ row }) => /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(Button, { asChild: true, size: "small", variant: "secondary", children: /* @__PURE__ */ jsx(Link, { to: `/pos-permissions/${row.original.id}`, children: "Editar permisos" }) }) })
|
|
1018
|
-
})
|
|
1019
|
-
],
|
|
1020
|
-
[]
|
|
1021
|
-
);
|
|
1022
|
-
const PosPermissionsPage = () => {
|
|
1023
|
-
const [searchValue, setSearchValue] = useState("");
|
|
1024
|
-
const [pagination, setPagination] = useState({
|
|
1025
|
-
pageIndex: 0,
|
|
1026
|
-
pageSize: 15
|
|
1027
|
-
});
|
|
1028
|
-
const limit = pagination.pageSize;
|
|
1029
|
-
const offset = pagination.pageIndex * limit;
|
|
1030
|
-
const { data, isLoading } = useQuery({
|
|
1031
|
-
queryFn: () => sdk.client.fetch("/admin/operators", {
|
|
1032
|
-
query: {
|
|
1033
|
-
limit,
|
|
1034
|
-
offset,
|
|
1035
|
-
q: searchValue || void 0
|
|
1036
|
-
}
|
|
1037
|
-
}),
|
|
1038
|
-
queryKey: ["operators", "pos-permissions", limit, offset, searchValue],
|
|
1039
|
-
placeholderData: (previousData) => previousData
|
|
1040
|
-
});
|
|
1041
|
-
const columns = useColumns();
|
|
1042
|
-
const table = useDataTable({
|
|
1043
|
-
data: (data == null ? void 0 : data.operators) || [],
|
|
1044
|
-
columns,
|
|
1045
|
-
getRowId: (row) => row.id,
|
|
1046
|
-
rowCount: (data == null ? void 0 : data.count) || 0,
|
|
1047
|
-
isLoading,
|
|
1048
|
-
search: {
|
|
1049
|
-
state: searchValue,
|
|
1050
|
-
onSearchChange: setSearchValue
|
|
1051
|
-
},
|
|
1052
|
-
pagination: {
|
|
1053
|
-
state: pagination,
|
|
1054
|
-
onPaginationChange: setPagination
|
|
1055
|
-
}
|
|
1056
|
-
});
|
|
1057
|
-
return /* @__PURE__ */ jsxs(Container, { className: "flex flex-col items-stretch overflow-hidden p-0", children: [
|
|
1058
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-between border-b border-ui-border-base px-6 py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-1", children: [
|
|
1059
|
-
/* @__PURE__ */ jsx(Heading, { level: "h2", children: "Permisos POS" }),
|
|
1060
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Define el alcance (ubicaciones, canales, regiones) y las capacidades de cada operador del Punto de Venta." })
|
|
1061
|
-
] }) }),
|
|
1062
|
-
/* @__PURE__ */ jsxs(DataTable, { instance: table, children: [
|
|
1063
|
-
/* @__PURE__ */ jsx(DataTable.Toolbar, { children: /* @__PURE__ */ jsx("div", { className: "flex w-full items-center justify-end", children: /* @__PURE__ */ jsx(DataTable.Search, { placeholder: "Buscar operador..." }) }) }),
|
|
1064
|
-
/* @__PURE__ */ jsx(DataTable.Table, {}),
|
|
1065
|
-
/* @__PURE__ */ jsx(DataTable.Pagination, {})
|
|
1066
|
-
] })
|
|
1067
|
-
] });
|
|
1068
|
-
};
|
|
1069
|
-
const config = defineRouteConfig({
|
|
1070
|
-
label: "Permisos POS",
|
|
1071
|
-
icon: ShieldCheck
|
|
1072
|
-
});
|
|
1073
1073
|
const MultiSelect = ({
|
|
1074
1074
|
options,
|
|
1075
1075
|
value,
|
|
@@ -1694,6 +1694,10 @@ const i18nTranslations0 = {};
|
|
|
1694
1694
|
const widgetModule = { widgets: [] };
|
|
1695
1695
|
const routeModule = {
|
|
1696
1696
|
routes: [
|
|
1697
|
+
{
|
|
1698
|
+
Component: PosPermissionsPage,
|
|
1699
|
+
path: "/pos-permissions"
|
|
1700
|
+
},
|
|
1697
1701
|
{
|
|
1698
1702
|
Component: OperatorsPage,
|
|
1699
1703
|
path: "/operators"
|
|
@@ -1702,10 +1706,6 @@ const routeModule = {
|
|
|
1702
1706
|
Component: PaymentOptionsPage,
|
|
1703
1707
|
path: "/payment-options"
|
|
1704
1708
|
},
|
|
1705
|
-
{
|
|
1706
|
-
Component: PosPermissionsPage,
|
|
1707
|
-
path: "/pos-permissions"
|
|
1708
|
-
},
|
|
1709
1709
|
{
|
|
1710
1710
|
Component: PosPermissionEditorPage,
|
|
1711
1711
|
path: "/pos-permissions/:id"
|
|
@@ -1715,25 +1715,25 @@ const routeModule = {
|
|
|
1715
1715
|
const menuItemModule = {
|
|
1716
1716
|
menuItems: [
|
|
1717
1717
|
{
|
|
1718
|
-
label: config
|
|
1719
|
-
icon: config
|
|
1720
|
-
path: "/
|
|
1718
|
+
label: config.label,
|
|
1719
|
+
icon: config.icon,
|
|
1720
|
+
path: "/payment-options",
|
|
1721
1721
|
nested: void 0,
|
|
1722
1722
|
rank: void 0,
|
|
1723
1723
|
translationNs: void 0
|
|
1724
1724
|
},
|
|
1725
1725
|
{
|
|
1726
|
-
label: config$
|
|
1727
|
-
icon: config$
|
|
1728
|
-
path: "/
|
|
1726
|
+
label: config$2.label,
|
|
1727
|
+
icon: config$2.icon,
|
|
1728
|
+
path: "/pos-permissions",
|
|
1729
1729
|
nested: void 0,
|
|
1730
1730
|
rank: void 0,
|
|
1731
1731
|
translationNs: void 0
|
|
1732
1732
|
},
|
|
1733
1733
|
{
|
|
1734
|
-
label: config.label,
|
|
1735
|
-
icon: config.icon,
|
|
1736
|
-
path: "/
|
|
1734
|
+
label: config$1.label,
|
|
1735
|
+
icon: config$1.icon,
|
|
1736
|
+
path: "/operators",
|
|
1737
1737
|
nested: void 0,
|
|
1738
1738
|
rank: void 0,
|
|
1739
1739
|
translationNs: void 0
|
|
@@ -131,6 +131,12 @@ exports.wrapVariantsWithInventoryQuantity = wrapVariantsWithInventoryQuantity;
|
|
|
131
131
|
* single requested stock location.
|
|
132
132
|
*/
|
|
133
133
|
const getVariantAvailabilityForLocation = async (query, variantIds, stockLocationId) => {
|
|
134
|
+
// NEVER cache availability: inventory is the most volatile data the POS
|
|
135
|
+
// reads, and Medusa's query cache only invalidates on module EVENTS. Any
|
|
136
|
+
// write that bypasses the API (WMS SQL, reserved_quantity reconciliation
|
|
137
|
+
// jobs, restored dumps) leaves the cached entry stale forever — seen in prod
|
|
138
|
+
// (07/08-sep-2026): POS kept serving day-old availability after the levels
|
|
139
|
+
// were corrected directly in the database.
|
|
134
140
|
const { data: variantInventoryItems } = await query.graph({
|
|
135
141
|
entity: "product_variant_inventory_items",
|
|
136
142
|
fields: [
|
|
@@ -140,7 +146,7 @@ const getVariantAvailabilityForLocation = async (query, variantIds, stockLocatio
|
|
|
140
146
|
"inventory.location_levels.*",
|
|
141
147
|
],
|
|
142
148
|
filters: { variant_id: variantIds },
|
|
143
|
-
}
|
|
149
|
+
});
|
|
144
150
|
const variantInventoriesMap = new Map();
|
|
145
151
|
variantInventoryItems.forEach((link) => {
|
|
146
152
|
const arr = variantInventoriesMap.get(link.variant_id) || [];
|
|
@@ -186,4 +192,4 @@ const getInventoryScope = (req) => {
|
|
|
186
192
|
return { salesChannelId, stockLocationId };
|
|
187
193
|
};
|
|
188
194
|
exports.getInventoryScope = getInventoryScope;
|
|
189
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
195
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcGkvYWRtaW4vbmV0bWUtcG9zL3Byb2R1Y3RzL2hlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQ0EscURBTWtDO0FBZWxDOztHQUVHO0FBQ0ksTUFBTSxrQ0FBa0MsR0FBRyxDQUFDLFFBQWUsRUFBRSxFQUFFO0lBQ3BFLE9BQU8sUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLE9BQVksRUFBRSxFQUFFO1FBQ3ZDLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDeEIsT0FBTTtRQUNSLENBQUM7UUFDRCxPQUFPLENBQUMsVUFBVSxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUM1QyxDQUFDLFFBQWEsRUFBRSxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUN6QyxDQUFBO0lBQ0gsQ0FBQyxDQUFDLENBQUE7QUFDSixDQUFDLENBQUE7QUFUWSxRQUFBLGtDQUFrQyxzQ0FTOUM7QUFFRDs7Ozs7R0FLRztBQUNJLE1BQU0seUJBQXlCLEdBQUcsS0FBSyxFQUM1QyxHQUF1QixFQUN2QixRQUFlLEVBQ2YsRUFBRTtJQUNGLElBQUksQ0FBQyxHQUFHLENBQUMsVUFBVSxFQUFFLHFCQUFxQixJQUFJLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRSxjQUFjLEVBQUUsQ0FBQztRQUM5RSxPQUFNO0lBQ1IsQ0FBQztJQUVELElBQUksQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLHFCQUFxQixDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ3pELE9BQU07SUFDUixDQUFDO0lBRUQsTUFBTSxVQUFVLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsZUFBTyxDQUFDLEdBQUcsQ0FBQyxDQUFBO0lBRWpELE1BQU0sUUFBUSxHQUFHLENBQUMsTUFBTSxVQUFVLENBQUMsV0FBVyxDQUM1QyxRQUFR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
|