@argusoft/medplat-product-management 1.0.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/dist/BrandsPage-DCMCVvDY.js +334 -0
- package/dist/BrandsPage-DCMCVvDY.js.map +1 -0
- package/dist/CategoriesPage-BpRhwfrc.js +284 -0
- package/dist/CategoriesPage-BpRhwfrc.js.map +1 -0
- package/dist/DashboardPage-BNKUQj46.js +436 -0
- package/dist/DashboardPage-BNKUQj46.js.map +1 -0
- package/dist/FacilityPicker-Coi8I3yE.js +79 -0
- package/dist/FacilityPicker-Coi8I3yE.js.map +1 -0
- package/dist/InventoryPage-BR6jOzg2.js +517 -0
- package/dist/InventoryPage-BR6jOzg2.js.map +1 -0
- package/dist/MemberProfileCard-DbHZCS5n.js +272 -0
- package/dist/MemberProfileCard-DbHZCS5n.js.map +1 -0
- package/dist/PaymentCreatePage-Ci3ERnby.js +487 -0
- package/dist/PaymentCreatePage-Ci3ERnby.js.map +1 -0
- package/dist/PaymentsPage-sdg902zX.js +157 -0
- package/dist/PaymentsPage-sdg902zX.js.map +1 -0
- package/dist/PickupCreatePage-CieMsgWV.js +310 -0
- package/dist/PickupCreatePage-CieMsgWV.js.map +1 -0
- package/dist/PickupsPage-Ci2Ll0Kn.js +566 -0
- package/dist/PickupsPage-Ci2Ll0Kn.js.map +1 -0
- package/dist/PmGuard-CjJBisaN.js +1195 -0
- package/dist/PmGuard-CjJBisaN.js.map +1 -0
- package/dist/PmTable-BuXZQZCU.js +302 -0
- package/dist/PmTable-BuXZQZCU.js.map +1 -0
- package/dist/ProductEditPage-DL8gy85Y.js +666 -0
- package/dist/ProductEditPage-DL8gy85Y.js.map +1 -0
- package/dist/ProductsPage-BANTKxLb.js +221 -0
- package/dist/ProductsPage-BANTKxLb.js.map +1 -0
- package/dist/PurchaseCreatePage-C3KMfBxJ.js +626 -0
- package/dist/PurchaseCreatePage-C3KMfBxJ.js.map +1 -0
- package/dist/PurchaseRequestDetailPage-C0GYFJDl.js +586 -0
- package/dist/PurchaseRequestDetailPage-C0GYFJDl.js.map +1 -0
- package/dist/PurchaseRequestsPage-DvFH_tWe.js +265 -0
- package/dist/PurchaseRequestsPage-DvFH_tWe.js.map +1 -0
- package/dist/PurchasesPage-BCvLvSp4.js +295 -0
- package/dist/PurchasesPage-BCvLvSp4.js.map +1 -0
- package/dist/SaleCreatePage-DpkQMoTq.js +548 -0
- package/dist/SaleCreatePage-DpkQMoTq.js.map +1 -0
- package/dist/SalesPage-DUwgkEO-.js +315 -0
- package/dist/SalesPage-DUwgkEO-.js.map +1 -0
- package/dist/SettingsPage-CusC0jqJ.js +710 -0
- package/dist/SettingsPage-CusC0jqJ.js.map +1 -0
- package/dist/StorageUnitsPage-BlC2AgrJ.js +469 -0
- package/dist/StorageUnitsPage-BlC2AgrJ.js.map +1 -0
- package/dist/TransactionsPage-DDaK4VyY.js +714 -0
- package/dist/TransactionsPage-DDaK4VyY.js.map +1 -0
- package/dist/TransferCreatePage-BxudLfhS.js +363 -0
- package/dist/TransferCreatePage-BxudLfhS.js.map +1 -0
- package/dist/TransfersPage-zgmt7teZ.js +480 -0
- package/dist/TransfersPage-zgmt7teZ.js.map +1 -0
- package/dist/VialsPage-CjqPfgpV.js +855 -0
- package/dist/VialsPage-CjqPfgpV.js.map +1 -0
- package/dist/constants-BrA_hfAI.js +254 -0
- package/dist/constants-BrA_hfAI.js.map +1 -0
- package/dist/currency-BDDCDgeE.js +169 -0
- package/dist/currency-BDDCDgeE.js.map +1 -0
- package/dist/format-UOyOu75i.js +52 -0
- package/dist/format-UOyOu75i.js.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/useFieldErrors-hDG8ox_x.js +29 -0
- package/dist/useFieldErrors-hDG8ox_x.js.map +1 -0
- package/dist/validation-Ba7puFIO.js +109 -0
- package/dist/validation-Ba7puFIO.js.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
import { P as e, Z as t, a as n, i as ee, it as te, n as ne, r as re, t as ie } from "./PmGuard-CjJBisaN.js";
|
|
2
|
+
import { a as ae, i as r, o as i, t as oe } from "./PmTable-BuXZQZCU.js";
|
|
3
|
+
import { m as a } from "./validation-Ba7puFIO.js";
|
|
4
|
+
import { a as se, i as o, t as ce } from "./format-UOyOu75i.js";
|
|
5
|
+
import { a as s, p as c, t as l } from "./constants-BrA_hfAI.js";
|
|
6
|
+
import { useMemo as u, useState as d } from "react";
|
|
7
|
+
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
8
|
+
import { v4 as m } from "uuid";
|
|
9
|
+
import { Alert as le, Box as h, Button as g, Chip as _, Dialog as ue, DialogActions as de, DialogContent as fe, DialogTitle as pe, FormControl as v, FormHelperText as me, InputAdornment as he, InputLabel as y, LinearProgress as ge, MenuItem as b, Select as x, Skeleton as _e, Stack as S, TableBody as ve, TableCell as C, TableHead as ye, TableRow as w, TextField as T, Tooltip as be, Typography as E } from "@mui/material";
|
|
10
|
+
import D from "@mui/icons-material/RefreshRounded";
|
|
11
|
+
import { showToast as O } from "@/common/toaster/toaster";
|
|
12
|
+
import { alpha as k, useTheme as A } from "@mui/material/styles";
|
|
13
|
+
import j from "@mui/icons-material/WidgetsRounded";
|
|
14
|
+
import M from "@mui/icons-material/LockRounded";
|
|
15
|
+
import N from "@mui/icons-material/LockOpenRounded";
|
|
16
|
+
import xe from "@mui/icons-material/SearchRounded";
|
|
17
|
+
//#region src/views/InventoryPage.jsx
|
|
18
|
+
function P(e) {
|
|
19
|
+
return e ? e.status === "EXPIRED" ? !0 : o(e.expiryDate) : !1;
|
|
20
|
+
}
|
|
21
|
+
function F() {
|
|
22
|
+
let o = ee().has("update.manage.productManagement.inventory"), [F, Se] = d([]), [I, L] = d(!1), [R, z] = d(""), [B, V] = d({
|
|
23
|
+
open: !1,
|
|
24
|
+
batch: null,
|
|
25
|
+
reason: "OTHER",
|
|
26
|
+
notes: ""
|
|
27
|
+
}), Ce = A(), [H, U] = d(""), [W, G] = d("ALL"), [K, q] = d(!1), [J, Y] = d(!1);
|
|
28
|
+
async function X() {
|
|
29
|
+
L(!0), z("");
|
|
30
|
+
try {
|
|
31
|
+
Se(await e());
|
|
32
|
+
} catch (e) {
|
|
33
|
+
let t = e?.response?.data?.message ?? e?.message ?? "Failed to load inventory";
|
|
34
|
+
z(t), O({
|
|
35
|
+
message: t,
|
|
36
|
+
type: "error"
|
|
37
|
+
});
|
|
38
|
+
} finally {
|
|
39
|
+
L(!1);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
re("view.manage.productManagement.inventory", () => {
|
|
43
|
+
X();
|
|
44
|
+
}, []);
|
|
45
|
+
let Z = u(() => {
|
|
46
|
+
let e = H.trim().toLowerCase();
|
|
47
|
+
return F.filter((t) => !(e && !`${t.productName ?? ""} ${t.lotNumber ?? ""}`.toLowerCase().includes(e) || W !== "ALL" && t.status !== W || K && P(t) || J && !(Number(t.qtyRemaining ?? 0) > 0)));
|
|
48
|
+
}, [
|
|
49
|
+
F,
|
|
50
|
+
H,
|
|
51
|
+
W,
|
|
52
|
+
K,
|
|
53
|
+
J
|
|
54
|
+
]), Q = H.trim() !== "" || W !== "ALL" || K || J;
|
|
55
|
+
function $() {
|
|
56
|
+
U(""), G("ALL"), q(!1), Y(!1);
|
|
57
|
+
}
|
|
58
|
+
async function we() {
|
|
59
|
+
try {
|
|
60
|
+
await t({
|
|
61
|
+
id: m(),
|
|
62
|
+
batchId: B.batch.id,
|
|
63
|
+
reason: B.reason,
|
|
64
|
+
notes: B.notes || null
|
|
65
|
+
}), O({
|
|
66
|
+
message: "Batch quarantined.",
|
|
67
|
+
type: "success"
|
|
68
|
+
}), V({
|
|
69
|
+
open: !1,
|
|
70
|
+
batch: null,
|
|
71
|
+
reason: "OTHER",
|
|
72
|
+
notes: ""
|
|
73
|
+
}), await X();
|
|
74
|
+
} catch (e) {
|
|
75
|
+
O({
|
|
76
|
+
message: e?.response?.data?.message ?? e?.message ?? "Failed to quarantine",
|
|
77
|
+
type: "error"
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async function Te(e) {
|
|
82
|
+
try {
|
|
83
|
+
await te({
|
|
84
|
+
id: m(),
|
|
85
|
+
batchId: e.id
|
|
86
|
+
}), O({
|
|
87
|
+
message: "Quarantine lifted.",
|
|
88
|
+
type: "success"
|
|
89
|
+
}), await X();
|
|
90
|
+
} catch (e) {
|
|
91
|
+
O({
|
|
92
|
+
message: e?.response?.data?.message ?? e?.message ?? "Failed to unquarantine",
|
|
93
|
+
type: "error"
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return /* @__PURE__ */ p(h, { children: [/* @__PURE__ */ f(ne, {}), /* @__PURE__ */ p(ie, {
|
|
98
|
+
perm: "view.manage.productManagement.inventory",
|
|
99
|
+
children: [/* @__PURE__ */ p(n, {
|
|
100
|
+
title: "Inventory",
|
|
101
|
+
subtitle: "Your stock batches. Click to see history or quarantine items if there's a problem.",
|
|
102
|
+
chips: ["Stock"],
|
|
103
|
+
actions: /* @__PURE__ */ f(S, {
|
|
104
|
+
direction: "row",
|
|
105
|
+
spacing: 1,
|
|
106
|
+
children: /* @__PURE__ */ f(g, {
|
|
107
|
+
variant: "outlined",
|
|
108
|
+
startIcon: /* @__PURE__ */ f(D, {}),
|
|
109
|
+
onClick: () => void X(),
|
|
110
|
+
children: "Refresh"
|
|
111
|
+
})
|
|
112
|
+
}),
|
|
113
|
+
children: [R ? /* @__PURE__ */ f(le, {
|
|
114
|
+
severity: "error",
|
|
115
|
+
sx: { mb: 2 },
|
|
116
|
+
children: R
|
|
117
|
+
}) : null, /* @__PURE__ */ p(i, {
|
|
118
|
+
eyebrow: "Stock on hand",
|
|
119
|
+
title: "Inventory batches",
|
|
120
|
+
subtitle: I ? "Loading…" : Q ? `${Z.length} of ${F.length} ${F.length === 1 ? "batch" : "batches"} match` : `${F.length} ${F.length === 1 ? "batch" : "batches"} visible`,
|
|
121
|
+
children: [/* @__PURE__ */ p(S, {
|
|
122
|
+
direction: {
|
|
123
|
+
xs: "column",
|
|
124
|
+
md: "row"
|
|
125
|
+
},
|
|
126
|
+
spacing: 1.5,
|
|
127
|
+
sx: { mb: 2 },
|
|
128
|
+
alignItems: { md: "center" },
|
|
129
|
+
children: [
|
|
130
|
+
/* @__PURE__ */ f(T, {
|
|
131
|
+
size: "small",
|
|
132
|
+
fullWidth: !0,
|
|
133
|
+
placeholder: "Search product or lot…",
|
|
134
|
+
value: H,
|
|
135
|
+
onChange: (e) => U(e.target.value),
|
|
136
|
+
InputProps: { startAdornment: /* @__PURE__ */ f(he, {
|
|
137
|
+
position: "start",
|
|
138
|
+
children: /* @__PURE__ */ f(xe, { fontSize: "small" })
|
|
139
|
+
}) },
|
|
140
|
+
sx: { maxWidth: { md: 360 } }
|
|
141
|
+
}),
|
|
142
|
+
/* @__PURE__ */ p(v, {
|
|
143
|
+
size: "small",
|
|
144
|
+
sx: { minWidth: 160 },
|
|
145
|
+
children: [/* @__PURE__ */ f(y, { children: "Status" }), /* @__PURE__ */ p(x, {
|
|
146
|
+
label: "Status",
|
|
147
|
+
value: W,
|
|
148
|
+
onChange: (e) => {
|
|
149
|
+
let t = e.target.value;
|
|
150
|
+
G(t), t === "EXPIRED" && q(!1), t === "EXHAUSTED" && Y(!1);
|
|
151
|
+
},
|
|
152
|
+
children: [/* @__PURE__ */ f(b, {
|
|
153
|
+
value: "ALL",
|
|
154
|
+
children: "All statuses"
|
|
155
|
+
}), l.map((e) => {
|
|
156
|
+
let t = e.value === "EXPIRED" && K || e.value === "EXHAUSTED" && J;
|
|
157
|
+
return /* @__PURE__ */ p(b, {
|
|
158
|
+
value: e.value,
|
|
159
|
+
disabled: t,
|
|
160
|
+
children: [e.label, t ? /* @__PURE__ */ f(E, {
|
|
161
|
+
component: "span",
|
|
162
|
+
variant: "caption",
|
|
163
|
+
color: "text.disabled",
|
|
164
|
+
sx: { ml: 1 },
|
|
165
|
+
children: "(clear chip first)"
|
|
166
|
+
}) : null]
|
|
167
|
+
}, e.value);
|
|
168
|
+
})]
|
|
169
|
+
})]
|
|
170
|
+
}),
|
|
171
|
+
/* @__PURE__ */ p(S, {
|
|
172
|
+
direction: "row",
|
|
173
|
+
spacing: 1,
|
|
174
|
+
useFlexGap: !0,
|
|
175
|
+
flexWrap: "wrap",
|
|
176
|
+
children: [/* @__PURE__ */ f(_, {
|
|
177
|
+
label: "Not yet expired",
|
|
178
|
+
size: "small",
|
|
179
|
+
disabled: W === "EXPIRED",
|
|
180
|
+
onClick: () => {
|
|
181
|
+
q((e) => {
|
|
182
|
+
let t = !e;
|
|
183
|
+
return t && W === "EXPIRED" && G("ALL"), t;
|
|
184
|
+
});
|
|
185
|
+
},
|
|
186
|
+
color: K ? "primary" : "default",
|
|
187
|
+
variant: K ? "filled" : "outlined",
|
|
188
|
+
sx: {
|
|
189
|
+
fontWeight: 700,
|
|
190
|
+
borderRadius: 1.5
|
|
191
|
+
}
|
|
192
|
+
}), /* @__PURE__ */ f(_, {
|
|
193
|
+
label: "Stock still left",
|
|
194
|
+
size: "small",
|
|
195
|
+
disabled: W === "EXHAUSTED",
|
|
196
|
+
onClick: () => {
|
|
197
|
+
Y((e) => {
|
|
198
|
+
let t = !e;
|
|
199
|
+
return t && W === "EXHAUSTED" && G("ALL"), t;
|
|
200
|
+
});
|
|
201
|
+
},
|
|
202
|
+
color: J ? "primary" : "default",
|
|
203
|
+
variant: J ? "filled" : "outlined",
|
|
204
|
+
sx: {
|
|
205
|
+
fontWeight: 700,
|
|
206
|
+
borderRadius: 1.5
|
|
207
|
+
}
|
|
208
|
+
})]
|
|
209
|
+
}),
|
|
210
|
+
/* @__PURE__ */ f(h, { sx: { flexGrow: 1 } }),
|
|
211
|
+
/* @__PURE__ */ f(g, {
|
|
212
|
+
variant: "text",
|
|
213
|
+
onClick: $,
|
|
214
|
+
disabled: !Q,
|
|
215
|
+
children: "Clear"
|
|
216
|
+
})
|
|
217
|
+
]
|
|
218
|
+
}), /* @__PURE__ */ p(ae, {
|
|
219
|
+
dense: !0,
|
|
220
|
+
children: [/* @__PURE__ */ f(ye, { children: /* @__PURE__ */ p(w, { children: [
|
|
221
|
+
/* @__PURE__ */ f(C, { children: "Product" }),
|
|
222
|
+
/* @__PURE__ */ f(C, { children: "Lot" }),
|
|
223
|
+
/* @__PURE__ */ f(C, { children: "Owner" }),
|
|
224
|
+
/* @__PURE__ */ f(C, { children: "Expiry" }),
|
|
225
|
+
/* @__PURE__ */ f(C, {
|
|
226
|
+
align: "right",
|
|
227
|
+
children: "Stock"
|
|
228
|
+
}),
|
|
229
|
+
/* @__PURE__ */ f(C, { children: "Storage" }),
|
|
230
|
+
/* @__PURE__ */ f(C, { children: "Status" }),
|
|
231
|
+
/* @__PURE__ */ f(C, {
|
|
232
|
+
align: "right",
|
|
233
|
+
children: "Action"
|
|
234
|
+
})
|
|
235
|
+
] }) }), /* @__PURE__ */ f(ve, { children: I ? Array.from({ length: 5 }).map((e, t) => /* @__PURE__ */ f(w, { children: Array.from({ length: 8 }).map((e, t) => /* @__PURE__ */ f(C, { children: /* @__PURE__ */ f(_e, { height: 22 }) }, t)) }, t)) : Z.length === 0 ? /* @__PURE__ */ f(oe, {
|
|
236
|
+
colSpan: 8,
|
|
237
|
+
icon: j,
|
|
238
|
+
title: Q ? "No batches match your filters" : "No batches in stock",
|
|
239
|
+
hint: Q ? "Adjust your search or filters." : "Record a purchase to add stock.",
|
|
240
|
+
action: Q ? /* @__PURE__ */ f(g, {
|
|
241
|
+
variant: "text",
|
|
242
|
+
size: "small",
|
|
243
|
+
onClick: $,
|
|
244
|
+
children: "Clear filters"
|
|
245
|
+
}) : null
|
|
246
|
+
}) : Z.map((e) => {
|
|
247
|
+
let t = P(e), n = e.qtyPurchased > 0 ? e.qtyRemaining / e.qtyPurchased : 0;
|
|
248
|
+
return /* @__PURE__ */ p(w, {
|
|
249
|
+
hover: !0,
|
|
250
|
+
children: [
|
|
251
|
+
/* @__PURE__ */ f(C, { children: /* @__PURE__ */ p(S, {
|
|
252
|
+
direction: "row",
|
|
253
|
+
alignItems: "baseline",
|
|
254
|
+
spacing: 1,
|
|
255
|
+
sx: { minWidth: 0 },
|
|
256
|
+
children: [/* @__PURE__ */ f(E, {
|
|
257
|
+
variant: "body2",
|
|
258
|
+
sx: {
|
|
259
|
+
fontWeight: 700,
|
|
260
|
+
lineHeight: 1.2
|
|
261
|
+
},
|
|
262
|
+
children: e.productName
|
|
263
|
+
}), /* @__PURE__ */ f(r, { id: e.serialId })]
|
|
264
|
+
}) }),
|
|
265
|
+
/* @__PURE__ */ f(C, { children: e.lotNumber ? /* @__PURE__ */ f(h, {
|
|
266
|
+
component: "span",
|
|
267
|
+
sx: {
|
|
268
|
+
display: "inline-flex",
|
|
269
|
+
px: .7,
|
|
270
|
+
py: .1,
|
|
271
|
+
borderRadius: 1,
|
|
272
|
+
bgcolor: k(Ce.palette.primary.main, .06),
|
|
273
|
+
color: "primary.dark",
|
|
274
|
+
fontFamily: "monospace",
|
|
275
|
+
fontSize: "0.72rem",
|
|
276
|
+
fontWeight: 700
|
|
277
|
+
},
|
|
278
|
+
children: e.lotNumber
|
|
279
|
+
}) : /* @__PURE__ */ f(E, {
|
|
280
|
+
variant: "caption",
|
|
281
|
+
color: "text.disabled",
|
|
282
|
+
children: "—"
|
|
283
|
+
}) }),
|
|
284
|
+
/* @__PURE__ */ p(C, { children: [/* @__PURE__ */ f(E, {
|
|
285
|
+
variant: "body2",
|
|
286
|
+
sx: { fontWeight: 700 },
|
|
287
|
+
children: e.ownerName || (e.ownerType === "USER" ? "Personal" : "Facility")
|
|
288
|
+
}), /* @__PURE__ */ f(E, {
|
|
289
|
+
variant: "caption",
|
|
290
|
+
color: "text.secondary",
|
|
291
|
+
children: e.ownerType
|
|
292
|
+
})] }),
|
|
293
|
+
/* @__PURE__ */ f(C, { children: e.expiryDate ? /* @__PURE__ */ f(be, {
|
|
294
|
+
title: t ? "Past printed expiry" : "",
|
|
295
|
+
children: /* @__PURE__ */ f(E, {
|
|
296
|
+
variant: "body2",
|
|
297
|
+
sx: {
|
|
298
|
+
fontWeight: 700,
|
|
299
|
+
fontVariantNumeric: "tabular-nums",
|
|
300
|
+
color: t ? "error.dark" : "text.primary"
|
|
301
|
+
},
|
|
302
|
+
children: ce(e.expiryDate)
|
|
303
|
+
})
|
|
304
|
+
}) : /* @__PURE__ */ f(E, {
|
|
305
|
+
variant: "caption",
|
|
306
|
+
color: "text.disabled",
|
|
307
|
+
children: "—"
|
|
308
|
+
}) }),
|
|
309
|
+
/* @__PURE__ */ f(C, {
|
|
310
|
+
align: "right",
|
|
311
|
+
sx: { minWidth: 150 },
|
|
312
|
+
children: /* @__PURE__ */ p(S, {
|
|
313
|
+
alignItems: "flex-end",
|
|
314
|
+
spacing: .5,
|
|
315
|
+
children: [/* @__PURE__ */ p(E, {
|
|
316
|
+
variant: "body2",
|
|
317
|
+
sx: {
|
|
318
|
+
fontWeight: 800,
|
|
319
|
+
fontVariantNumeric: "tabular-nums"
|
|
320
|
+
},
|
|
321
|
+
children: [e.qtyRemaining, /* @__PURE__ */ p(E, {
|
|
322
|
+
component: "span",
|
|
323
|
+
variant: "caption",
|
|
324
|
+
color: "text.secondary",
|
|
325
|
+
sx: {
|
|
326
|
+
ml: .5,
|
|
327
|
+
fontVariantNumeric: "tabular-nums"
|
|
328
|
+
},
|
|
329
|
+
children: ["/ ", e.qtyPurchased]
|
|
330
|
+
})]
|
|
331
|
+
}), /* @__PURE__ */ f(h, {
|
|
332
|
+
sx: { width: 80 },
|
|
333
|
+
children: /* @__PURE__ */ f(ge, {
|
|
334
|
+
variant: "determinate",
|
|
335
|
+
value: Math.min(100, Math.max(0, n * 100)),
|
|
336
|
+
sx: {
|
|
337
|
+
height: 4,
|
|
338
|
+
borderRadius: 2
|
|
339
|
+
},
|
|
340
|
+
color: n < .25 ? "warning" : "primary"
|
|
341
|
+
})
|
|
342
|
+
})]
|
|
343
|
+
})
|
|
344
|
+
}),
|
|
345
|
+
/* @__PURE__ */ f(C, { children: e.storageUnitName ? /* @__PURE__ */ f(E, {
|
|
346
|
+
variant: "caption",
|
|
347
|
+
sx: { fontWeight: 700 },
|
|
348
|
+
children: e.storageUnitName
|
|
349
|
+
}) : /* @__PURE__ */ f(E, {
|
|
350
|
+
variant: "caption",
|
|
351
|
+
color: "text.disabled",
|
|
352
|
+
children: "—"
|
|
353
|
+
}) }),
|
|
354
|
+
/* @__PURE__ */ f(C, { children: /* @__PURE__ */ p(S, {
|
|
355
|
+
direction: "row",
|
|
356
|
+
spacing: .5,
|
|
357
|
+
flexWrap: "wrap",
|
|
358
|
+
useFlexGap: !0,
|
|
359
|
+
children: [
|
|
360
|
+
/* @__PURE__ */ f(_, {
|
|
361
|
+
size: "small",
|
|
362
|
+
color: se(e.status),
|
|
363
|
+
label: c(l, e.status),
|
|
364
|
+
sx: {
|
|
365
|
+
fontWeight: 700,
|
|
366
|
+
borderRadius: 1.5,
|
|
367
|
+
height: 22
|
|
368
|
+
}
|
|
369
|
+
}),
|
|
370
|
+
e.isQuarantined ? /* @__PURE__ */ f(_, {
|
|
371
|
+
size: "small",
|
|
372
|
+
color: "error",
|
|
373
|
+
label: c(s, e.quarantineReason) || "Quarantined",
|
|
374
|
+
sx: {
|
|
375
|
+
fontWeight: 700,
|
|
376
|
+
borderRadius: 1.5,
|
|
377
|
+
height: 22
|
|
378
|
+
}
|
|
379
|
+
}) : null,
|
|
380
|
+
t && e.status !== "EXPIRED" ? /* @__PURE__ */ f(_, {
|
|
381
|
+
size: "small",
|
|
382
|
+
color: "warning",
|
|
383
|
+
label: "Expired",
|
|
384
|
+
sx: {
|
|
385
|
+
fontWeight: 700,
|
|
386
|
+
borderRadius: 1.5,
|
|
387
|
+
height: 22
|
|
388
|
+
}
|
|
389
|
+
}) : null,
|
|
390
|
+
e.sourceType ? /* @__PURE__ */ f(_, {
|
|
391
|
+
size: "small",
|
|
392
|
+
variant: "outlined",
|
|
393
|
+
color: e.sourceType === "PICKUP" ? "info" : e.sourceType === "TRANSFER_IN" ? "primary" : "default",
|
|
394
|
+
label: e.sourceType === "TRANSFER_IN" ? "Transfer" : e.sourceType === "PICKUP" ? "Pickup" : e.sourceType === "PURCHASE" ? "Purchase" : e.sourceType,
|
|
395
|
+
sx: {
|
|
396
|
+
fontWeight: 700,
|
|
397
|
+
borderRadius: 1.5,
|
|
398
|
+
height: 22
|
|
399
|
+
}
|
|
400
|
+
}) : null
|
|
401
|
+
]
|
|
402
|
+
}) }),
|
|
403
|
+
/* @__PURE__ */ f(C, {
|
|
404
|
+
align: "right",
|
|
405
|
+
children: o ? e.isQuarantined ? /* @__PURE__ */ f(g, {
|
|
406
|
+
size: "small",
|
|
407
|
+
variant: "outlined",
|
|
408
|
+
color: "success",
|
|
409
|
+
startIcon: /* @__PURE__ */ f(N, {}),
|
|
410
|
+
onClick: () => void Te(e),
|
|
411
|
+
children: "Unquarantine"
|
|
412
|
+
}) : t || e.status === "EXHAUSTED" || e.status === "IN_USE" ? null : /* @__PURE__ */ f(g, {
|
|
413
|
+
size: "small",
|
|
414
|
+
variant: "outlined",
|
|
415
|
+
color: "error",
|
|
416
|
+
startIcon: /* @__PURE__ */ f(M, {}),
|
|
417
|
+
onClick: () => V({
|
|
418
|
+
open: !0,
|
|
419
|
+
batch: e,
|
|
420
|
+
reason: "OTHER",
|
|
421
|
+
notes: ""
|
|
422
|
+
}),
|
|
423
|
+
children: "Quarantine"
|
|
424
|
+
}) : null
|
|
425
|
+
})
|
|
426
|
+
]
|
|
427
|
+
}, e.id);
|
|
428
|
+
}) })]
|
|
429
|
+
})]
|
|
430
|
+
})]
|
|
431
|
+
}), /* @__PURE__ */ p(ue, {
|
|
432
|
+
open: B.open,
|
|
433
|
+
onClose: () => V({
|
|
434
|
+
...B,
|
|
435
|
+
open: !1
|
|
436
|
+
}),
|
|
437
|
+
fullWidth: !0,
|
|
438
|
+
maxWidth: "sm",
|
|
439
|
+
children: [
|
|
440
|
+
/* @__PURE__ */ f(pe, { children: "Quarantine Batch" }),
|
|
441
|
+
/* @__PURE__ */ f(fe, {
|
|
442
|
+
dividers: !0,
|
|
443
|
+
children: /* @__PURE__ */ p(S, {
|
|
444
|
+
spacing: 2,
|
|
445
|
+
sx: { pt: 1 },
|
|
446
|
+
children: [
|
|
447
|
+
/* @__PURE__ */ p(E, {
|
|
448
|
+
variant: "body2",
|
|
449
|
+
children: [
|
|
450
|
+
"Product: ",
|
|
451
|
+
/* @__PURE__ */ f("strong", { children: B.batch?.productName }),
|
|
452
|
+
/* @__PURE__ */ f("br", {}),
|
|
453
|
+
"Lot: ",
|
|
454
|
+
/* @__PURE__ */ f("strong", { children: B.batch?.lotNumber || "—" }),
|
|
455
|
+
/* @__PURE__ */ f("br", {}),
|
|
456
|
+
"Remaining: ",
|
|
457
|
+
/* @__PURE__ */ f("strong", { children: B.batch?.qtyRemaining })
|
|
458
|
+
]
|
|
459
|
+
}),
|
|
460
|
+
/* @__PURE__ */ p(v, {
|
|
461
|
+
required: !0,
|
|
462
|
+
fullWidth: !0,
|
|
463
|
+
size: "small",
|
|
464
|
+
error: !!a(B.reason, "Reason"),
|
|
465
|
+
children: [
|
|
466
|
+
/* @__PURE__ */ f(y, { children: "Reason" }),
|
|
467
|
+
/* @__PURE__ */ f(x, {
|
|
468
|
+
label: "Reason",
|
|
469
|
+
value: B.reason,
|
|
470
|
+
onChange: (e) => V({
|
|
471
|
+
...B,
|
|
472
|
+
reason: e.target.value
|
|
473
|
+
}),
|
|
474
|
+
children: s.map((e) => /* @__PURE__ */ f(b, {
|
|
475
|
+
value: e.value,
|
|
476
|
+
children: e.label
|
|
477
|
+
}, e.value))
|
|
478
|
+
}),
|
|
479
|
+
a(B.reason, "Reason") ? /* @__PURE__ */ f(me, { children: a(B.reason, "Reason") }) : null
|
|
480
|
+
]
|
|
481
|
+
}),
|
|
482
|
+
/* @__PURE__ */ f(T, {
|
|
483
|
+
label: "Notes",
|
|
484
|
+
size: "small",
|
|
485
|
+
multiline: !0,
|
|
486
|
+
minRows: 2,
|
|
487
|
+
fullWidth: !0,
|
|
488
|
+
value: B.notes,
|
|
489
|
+
onChange: (e) => V({
|
|
490
|
+
...B,
|
|
491
|
+
notes: e.target.value
|
|
492
|
+
})
|
|
493
|
+
})
|
|
494
|
+
]
|
|
495
|
+
})
|
|
496
|
+
}),
|
|
497
|
+
/* @__PURE__ */ p(de, { children: [/* @__PURE__ */ f(g, {
|
|
498
|
+
onClick: () => V({
|
|
499
|
+
...B,
|
|
500
|
+
open: !1
|
|
501
|
+
}),
|
|
502
|
+
children: "Cancel"
|
|
503
|
+
}), /* @__PURE__ */ f(g, {
|
|
504
|
+
variant: "contained",
|
|
505
|
+
color: "error",
|
|
506
|
+
disabled: !!a(B.reason, "Reason"),
|
|
507
|
+
onClick: () => void we(),
|
|
508
|
+
children: "Quarantine"
|
|
509
|
+
})] })
|
|
510
|
+
]
|
|
511
|
+
})]
|
|
512
|
+
})] });
|
|
513
|
+
}
|
|
514
|
+
//#endregion
|
|
515
|
+
export { F as default };
|
|
516
|
+
|
|
517
|
+
//# sourceMappingURL=InventoryPage-BR6jOzg2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InventoryPage-BR6jOzg2.js","names":[],"sources":["../src/views/InventoryPage.jsx"],"sourcesContent":["import { useMemo, useState } from \"react\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport {\n Alert,\n Box,\n Button,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n FormControl,\n FormHelperText,\n InputAdornment,\n InputLabel,\n LinearProgress,\n MenuItem,\n Select,\n Skeleton,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TextField,\n Tooltip,\n Typography,\n} from \"@mui/material\";\nimport { alpha, useTheme } from \"@mui/material/styles\";\nimport WidgetsRoundedIcon from \"@mui/icons-material/WidgetsRounded\";\nimport { PmEmptyRow, PmRef, PmTable, PmTableCard } from \"@pm/components/PmTable\";\nimport RefreshRoundedIcon from \"@mui/icons-material/RefreshRounded\";\nimport LockRoundedIcon from \"@mui/icons-material/LockRounded\";\nimport LockOpenRoundedIcon from \"@mui/icons-material/LockOpenRounded\";\nimport SearchRoundedIcon from \"@mui/icons-material/SearchRounded\";\nimport { showToast } from \"@/common/toaster/toaster\";\nimport PmPageShell from \"@pm/components/PmPageShell\";\nimport PmNav from \"@pm/components/PmNav\";\nimport PmGuard from \"@pm/components/PmGuard\";\nimport { usePermissionedEffect, usePmPermissions } from \"@pm/utils/permissions\";\nimport {\n listBatches,\n quarantineBatch,\n unquarantineBatch,\n} from \"@pm/services/pmApi\";\nimport { BATCH_STATUSES, QUARANTINE_REASONS, labelOf } from \"@pm/utils/constants\";\nimport { formatDate, isPastExpiry, statusColor } from \"@pm/utils/format\";\nimport { validateRequired } from \"@pm/utils/validation\";\n\n// Shared \"is this batch past its printed expiry?\" check. Used for both the\n// per-row pill and the \"Not yet expired\" filter so they can never disagree.\n// A batch whose expiryDate equals today is still valid — only the day AFTER\n// the printed expiry counts as expired (matches the unit packaging rule).\nfunction isBatchExpired(b) {\n if (!b) return false;\n if (b.status === 'EXPIRED') return true;\n return isPastExpiry(b.expiryDate);\n}\n\nexport default function InventoryPage() {\n const perms = usePmPermissions();\n const canWrite = perms.has('update.manage.productManagement.inventory');\n const [items, setItems] = useState([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(\"\");\n const [quarantineDialog, setQuarantineDialog] = useState({\n open: false,\n batch: null,\n reason: \"OTHER\",\n notes: \"\",\n });\n const theme = useTheme();\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState('ALL');\n // Filter chips. notYetExpired excludes anything past its printed expiry\n // (regardless of status). inStock keeps rows with qtyRemaining > 0.\n const [notYetExpired, setNotYetExpired] = useState(false);\n const [inStock, setInStock] = useState(false);\n\n async function load() {\n setLoading(true);\n setError(\"\");\n try {\n setItems(await listBatches());\n } catch (err) {\n const message =\n err?.response?.data?.message ??\n err?.message ??\n \"Failed to load inventory\";\n setError(message);\n showToast({ message, type: \"error\" });\n } finally {\n setLoading(false);\n }\n }\n\n usePermissionedEffect('view.manage.productManagement.inventory', () => {\n void load();\n }, []);\n\n // Filters apply in-memory over whatever the list endpoint returned. Search\n // matches product name + lot (case-insensitive); chips + status narrow the\n // remaining set with AND semantics.\n const filteredItems = useMemo(() => {\n const q = search.trim().toLowerCase();\n return items.filter((b) => {\n if (q) {\n const hay = `${b.productName ?? ''} ${b.lotNumber ?? ''}`.toLowerCase();\n if (!hay.includes(q)) return false;\n }\n if (statusFilter !== 'ALL' && b.status !== statusFilter) return false;\n if (notYetExpired && isBatchExpired(b)) return false;\n if (inStock && !(Number(b.qtyRemaining ?? 0) > 0)) return false;\n return true;\n });\n }, [items, search, statusFilter, notYetExpired, inStock]);\n\n const hasFilter = search.trim() !== '' || statusFilter !== 'ALL' || notYetExpired || inStock;\n\n function clearFilters() {\n setSearch('');\n setStatusFilter('ALL');\n setNotYetExpired(false);\n setInStock(false);\n }\n\n async function doQuarantine() {\n try {\n await quarantineBatch({\n id: uuidv4(),\n batchId: quarantineDialog.batch.id,\n reason: quarantineDialog.reason,\n notes: quarantineDialog.notes || null,\n });\n showToast({ message: \"Batch quarantined.\", type: \"success\" });\n setQuarantineDialog({\n open: false,\n batch: null,\n reason: \"OTHER\",\n notes: \"\",\n });\n await load();\n } catch (err) {\n const message =\n err?.response?.data?.message ?? err?.message ?? \"Failed to quarantine\";\n showToast({ message, type: \"error\" });\n }\n }\n\n async function doUnquarantine(batch) {\n try {\n await unquarantineBatch({ id: uuidv4(), batchId: batch.id });\n showToast({ message: \"Quarantine lifted.\", type: \"success\" });\n await load();\n } catch (err) {\n const message =\n err?.response?.data?.message ??\n err?.message ??\n \"Failed to unquarantine\";\n showToast({ message, type: \"error\" });\n }\n }\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={'view.manage.productManagement.inventory'}>\n <PmPageShell\n title=\"Inventory\"\n subtitle=\"Your stock batches. Click to see history or quarantine items if there's a problem.\"\n chips={[\"Stock\"]}\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button\n variant=\"outlined\"\n startIcon={<RefreshRoundedIcon />}\n onClick={() => void load()}\n >\n Refresh\n </Button>\n </Stack>\n }\n >\n {error ? (\n <Alert severity=\"error\" sx={{ mb: 2 }}>\n {error}\n </Alert>\n ) : null}\n\n <PmTableCard\n eyebrow=\"Stock on hand\"\n title=\"Inventory batches\"\n subtitle={\n loading\n ? \"Loading…\"\n : hasFilter\n ? `${filteredItems.length} of ${items.length} ${items.length === 1 ? 'batch' : 'batches'} match`\n : `${items.length} ${items.length === 1 ? 'batch' : 'batches'} visible`\n }\n >\n <Stack direction={{ xs: 'column', md: 'row' }} spacing={1.5} sx={{ mb: 2 }} alignItems={{ md: 'center' }}>\n <TextField\n size=\"small\"\n fullWidth\n placeholder=\"Search product or lot…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">\n <SearchRoundedIcon fontSize=\"small\" />\n </InputAdornment>\n ),\n }}\n sx={{ maxWidth: { md: 360 } }}\n />\n <FormControl size=\"small\" sx={{ minWidth: 160 }}>\n <InputLabel>Status</InputLabel>\n <Select\n label=\"Status\"\n value={statusFilter}\n onChange={(e) => {\n const next = e.target.value;\n setStatusFilter(next);\n // Picking a terminal status from the dropdown auto-clears the\n // opposing chip, so the filter pair can never resolve to an\n // empty set by construction.\n if (next === 'EXPIRED') setNotYetExpired(false);\n if (next === 'EXHAUSTED') setInStock(false);\n }}\n >\n <MenuItem value=\"ALL\">All statuses</MenuItem>\n {BATCH_STATUSES.map((s) => {\n const blocked = (s.value === 'EXPIRED' && notYetExpired) || (s.value === 'EXHAUSTED' && inStock);\n return (\n <MenuItem key={s.value} value={s.value} disabled={blocked}>\n {s.label}\n {blocked ? (\n <Typography component=\"span\" variant=\"caption\" color=\"text.disabled\" sx={{ ml: 1 }}>\n (clear chip first)\n </Typography>\n ) : null}\n </MenuItem>\n );\n })}\n </Select>\n </FormControl>\n <Stack direction=\"row\" spacing={1} useFlexGap flexWrap=\"wrap\">\n <Chip\n label=\"Not yet expired\"\n size=\"small\"\n disabled={statusFilter === 'EXPIRED'}\n onClick={() => {\n // Auto-reset the conflicting dropdown value so the two\n // controls never produce an impossible combination.\n setNotYetExpired((prev) => {\n const next = !prev;\n if (next && statusFilter === 'EXPIRED') setStatusFilter('ALL');\n return next;\n });\n }}\n color={notYetExpired ? 'primary' : 'default'}\n variant={notYetExpired ? 'filled' : 'outlined'}\n sx={{ fontWeight: 700, borderRadius: 1.5 }}\n />\n <Chip\n label=\"Stock still left\"\n size=\"small\"\n disabled={statusFilter === 'EXHAUSTED'}\n onClick={() => {\n setInStock((prev) => {\n const next = !prev;\n if (next && statusFilter === 'EXHAUSTED') setStatusFilter('ALL');\n return next;\n });\n }}\n color={inStock ? 'primary' : 'default'}\n variant={inStock ? 'filled' : 'outlined'}\n sx={{ fontWeight: 700, borderRadius: 1.5 }}\n />\n </Stack>\n <Box sx={{ flexGrow: 1 }} />\n <Button variant=\"text\" onClick={clearFilters} disabled={!hasFilter}>Clear</Button>\n </Stack>\n\n <PmTable dense>\n <TableHead>\n <TableRow>\n <TableCell>Product</TableCell>\n <TableCell>Lot</TableCell>\n <TableCell>Owner</TableCell>\n <TableCell>Expiry</TableCell>\n <TableCell align=\"right\">Stock</TableCell>\n <TableCell>Storage</TableCell>\n <TableCell>Status</TableCell>\n <TableCell align=\"right\">Action</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {loading ? (\n Array.from({ length: 5 }).map((_, i) => (\n <TableRow key={i}>\n {Array.from({ length: 8 }).map((__, j) => (\n <TableCell key={j}>\n <Skeleton height={22} />\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : filteredItems.length === 0 ? (\n <PmEmptyRow\n colSpan={8}\n icon={WidgetsRoundedIcon}\n title={hasFilter ? 'No batches match your filters' : 'No batches in stock'}\n hint={hasFilter\n ? 'Adjust your search or filters.'\n : 'Record a purchase to add stock.'}\n action={hasFilter ? (\n <Button variant=\"text\" size=\"small\" onClick={clearFilters}>Clear filters</Button>\n ) : null}\n />\n ) : (\n filteredItems.map((b) => {\n const isExpired = isBatchExpired(b);\n const remainingRatio =\n b.qtyPurchased > 0 ? b.qtyRemaining / b.qtyPurchased : 0;\n return (\n <TableRow key={b.id} hover>\n <TableCell>\n <Stack\n direction=\"row\"\n alignItems=\"baseline\"\n spacing={1}\n sx={{ minWidth: 0 }}\n >\n <Typography\n variant=\"body2\"\n sx={{ fontWeight: 700, lineHeight: 1.2 }}\n >\n {b.productName}\n </Typography>\n <PmRef id={b.serialId} />\n </Stack>\n </TableCell>\n <TableCell>\n {b.lotNumber ? (\n <Box\n component=\"span\"\n sx={{\n display: \"inline-flex\",\n px: 0.7,\n py: 0.1,\n borderRadius: 1,\n bgcolor: alpha(theme.palette.primary.main, 0.06),\n color: \"primary.dark\",\n fontFamily: \"monospace\",\n fontSize: \"0.72rem\",\n fontWeight: 700,\n }}\n >\n {b.lotNumber}\n </Box>\n ) : (\n <Typography variant=\"caption\" color=\"text.disabled\">\n —\n </Typography>\n )}\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>\n {b.ownerName || (b.ownerType === 'USER' ? 'Personal' : 'Facility')}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {b.ownerType}\n </Typography>\n </TableCell>\n <TableCell>\n {b.expiryDate ? (\n <Tooltip\n title={isExpired ? \"Past printed expiry\" : \"\"}\n >\n <Typography\n variant=\"body2\"\n sx={{\n fontWeight: 700,\n fontVariantNumeric: \"tabular-nums\",\n color: isExpired\n ? \"error.dark\"\n : \"text.primary\",\n }}\n >\n {formatDate(b.expiryDate)}\n </Typography>\n </Tooltip>\n ) : (\n <Typography variant=\"caption\" color=\"text.disabled\">\n —\n </Typography>\n )}\n </TableCell>\n <TableCell align=\"right\" sx={{ minWidth: 150 }}>\n <Stack alignItems=\"flex-end\" spacing={0.5}>\n <Typography\n variant=\"body2\"\n sx={{\n fontWeight: 800,\n fontVariantNumeric: \"tabular-nums\",\n }}\n >\n {b.qtyRemaining}\n <Typography\n component=\"span\"\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{\n ml: 0.5,\n fontVariantNumeric: \"tabular-nums\",\n }}\n >\n / {b.qtyPurchased}\n </Typography>\n </Typography>\n <Box sx={{ width: 80 }}>\n <LinearProgress\n variant=\"determinate\"\n value={Math.min(\n 100,\n Math.max(0, remainingRatio * 100),\n )}\n sx={{ height: 4, borderRadius: 2 }}\n color={\n remainingRatio < 0.25 ? \"warning\" : \"primary\"\n }\n />\n </Box>\n </Stack>\n </TableCell>\n <TableCell>\n {b.storageUnitName ? (\n <Typography\n variant=\"caption\"\n sx={{ fontWeight: 700 }}\n >\n {b.storageUnitName}\n </Typography>\n ) : (\n <Typography variant=\"caption\" color=\"text.disabled\">\n —\n </Typography>\n )}\n </TableCell>\n <TableCell>\n <Stack\n direction=\"row\"\n spacing={0.5}\n flexWrap=\"wrap\"\n useFlexGap\n >\n <Chip\n size=\"small\"\n color={statusColor(b.status)}\n label={labelOf(BATCH_STATUSES, b.status)}\n sx={{\n fontWeight: 700,\n borderRadius: 1.5,\n height: 22,\n }}\n />\n {b.isQuarantined ? (\n <Chip\n size=\"small\"\n color=\"error\"\n label={labelOf(QUARANTINE_REASONS, b.quarantineReason) || \"Quarantined\"}\n sx={{\n fontWeight: 700,\n borderRadius: 1.5,\n height: 22,\n }}\n />\n ) : null}\n {isExpired && b.status !== \"EXPIRED\" ? (\n <Chip\n size=\"small\"\n color=\"warning\"\n label=\"Expired\"\n sx={{\n fontWeight: 700,\n borderRadius: 1.5,\n height: 22,\n }}\n />\n ) : null}\n {b.sourceType ? (\n <Chip\n size=\"small\"\n variant=\"outlined\"\n color={\n b.sourceType === 'PICKUP' ? 'info'\n : b.sourceType === 'TRANSFER_IN' ? 'primary'\n : 'default'\n }\n label={b.sourceType === 'TRANSFER_IN' ? 'Transfer' : b.sourceType === 'PICKUP' ? 'Pickup' : b.sourceType === 'PURCHASE' ? 'Purchase' : b.sourceType}\n sx={{\n fontWeight: 700,\n borderRadius: 1.5,\n height: 22,\n }}\n />\n ) : null}\n </Stack>\n </TableCell>\n <TableCell align=\"right\">\n {!canWrite ? null : b.isQuarantined ? (\n <Button\n size=\"small\"\n variant=\"outlined\"\n color=\"success\"\n startIcon={<LockOpenRoundedIcon />}\n onClick={() => void doUnquarantine(b)}\n >\n Unquarantine\n </Button>\n ) : isExpired ||\n b.status === \"EXHAUSTED\" ||\n b.status === \"IN_USE\" ? null : (\n <Button\n size=\"small\"\n variant=\"outlined\"\n color=\"error\"\n startIcon={<LockRoundedIcon />}\n onClick={() =>\n setQuarantineDialog({\n open: true,\n batch: b,\n reason: \"OTHER\",\n notes: \"\",\n })\n }\n >\n Quarantine\n </Button>\n )}\n </TableCell>\n </TableRow>\n );\n })\n )}\n </TableBody>\n </PmTable>\n </PmTableCard>\n </PmPageShell>\n\n <Dialog\n open={quarantineDialog.open}\n onClose={() =>\n setQuarantineDialog({ ...quarantineDialog, open: false })\n }\n fullWidth\n maxWidth=\"sm\"\n >\n <DialogTitle>Quarantine Batch</DialogTitle>\n <DialogContent dividers>\n <Stack spacing={2} sx={{ pt: 1 }}>\n <Typography variant=\"body2\">\n Product: <strong>{quarantineDialog.batch?.productName}</strong>\n <br />\n Lot: <strong>{quarantineDialog.batch?.lotNumber || \"—\"}</strong>\n <br />\n Remaining: <strong>{quarantineDialog.batch?.qtyRemaining}</strong>\n </Typography>\n <FormControl\n required\n fullWidth\n size=\"small\"\n error={!!validateRequired(quarantineDialog.reason, \"Reason\")}\n >\n <InputLabel>Reason</InputLabel>\n <Select\n label=\"Reason\"\n value={quarantineDialog.reason}\n onChange={(e) =>\n setQuarantineDialog({\n ...quarantineDialog,\n reason: e.target.value,\n })\n }\n >\n {QUARANTINE_REASONS.map((r) => (\n <MenuItem key={r.value} value={r.value}>\n {r.label}\n </MenuItem>\n ))}\n </Select>\n {validateRequired(quarantineDialog.reason, \"Reason\") ? (\n <FormHelperText>\n {validateRequired(quarantineDialog.reason, \"Reason\")}\n </FormHelperText>\n ) : null}\n </FormControl>\n <TextField\n label=\"Notes\"\n size=\"small\"\n multiline\n minRows={2}\n fullWidth\n value={quarantineDialog.notes}\n onChange={(e) =>\n setQuarantineDialog({\n ...quarantineDialog,\n notes: e.target.value,\n })\n }\n />\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button\n onClick={() =>\n setQuarantineDialog({ ...quarantineDialog, open: false })\n }\n >\n Cancel\n </Button>\n <Button\n variant=\"contained\"\n color=\"error\"\n disabled={!!validateRequired(quarantineDialog.reason, \"Reason\")}\n onClick={() => void doQuarantine()}\n >\n Quarantine\n </Button>\n </DialogActions>\n </Dialog>\n </PmGuard>\n </Box>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAqDA,SAAS,EAAe,GAAG;CAGzB,OAFK,IACD,EAAE,WAAW,YAAkB,KAC5B,EAAa,EAAE,UAAU,IAFjB;AAGjB;AAEA,SAAwB,IAAgB;CAEtC,IAAM,IADQ,GACG,EAAM,IAAI,2CAA2C,GAChE,CAAC,GAAO,MAAY,EAAS,CAAC,CAAC,GAC/B,CAAC,GAAS,KAAc,EAAS,EAAK,GACtC,CAAC,GAAO,KAAY,EAAS,EAAE,GAC/B,CAAC,GAAkB,KAAuB,EAAS;EACvD,MAAM;EACN,OAAO;EACP,QAAQ;EACR,OAAO;CACT,CAAC,GACK,KAAQ,EAAS,GACjB,CAAC,GAAQ,KAAa,EAAS,EAAE,GACjC,CAAC,GAAc,KAAmB,EAAS,KAAK,GAGhD,CAAC,GAAe,KAAoB,EAAS,EAAK,GAClD,CAAC,GAAS,KAAc,EAAS,EAAK;CAE5C,eAAe,IAAO;EAEpB,AADA,EAAW,EAAI,GACf,EAAS,EAAE;EACX,IAAI;GACF,GAAS,MAAM,EAAY,CAAC;EAC9B,SAAS,GAAK;GACZ,IAAM,IACJ,GAAK,UAAU,MAAM,WACrB,GAAK,WACL;GAEF,AADA,EAAS,CAAO,GAChB,EAAU;IAAE;IAAS,MAAM;GAAQ,CAAC;EACtC,UAAU;GACR,EAAW,EAAK;EAClB;CACF;CAEA,GAAsB,iDAAiD;EACrE,EAAU;CACZ,GAAG,CAAC,CAAC;CAKL,IAAM,IAAgB,QAAc;EAClC,IAAM,IAAI,EAAO,KAAK,EAAE,YAAY;EACpC,OAAO,EAAM,QAAQ,MAOnB,EANI,KAEE,CADQ,GAAG,EAAE,eAAe,GAAG,GAAG,EAAE,aAAa,KAAK,YACrD,EAAI,SAAS,CAAC,KAEjB,MAAiB,SAAS,EAAE,WAAW,KACvC,KAAiB,EAAe,CAAC,KACjC,KAAW,EAAE,OAAO,EAAE,gBAAgB,CAAC,IAAI,GAEhD;CACH,GAAG;EAAC;EAAO;EAAQ;EAAc;EAAe;CAAO,CAAC,GAElD,IAAY,EAAO,KAAK,MAAM,MAAM,MAAiB,SAAS,KAAiB;CAErF,SAAS,IAAe;EAItB,AAHA,EAAU,EAAE,GACZ,EAAgB,KAAK,GACrB,EAAiB,EAAK,GACtB,EAAW,EAAK;CAClB;CAEA,eAAe,KAAe;EAC5B,IAAI;GAcF,AAbA,MAAM,EAAgB;IACpB,IAAI,EAAO;IACX,SAAS,EAAiB,MAAM;IAChC,QAAQ,EAAiB;IACzB,OAAO,EAAiB,SAAS;GACnC,CAAC,GACD,EAAU;IAAE,SAAS;IAAsB,MAAM;GAAU,CAAC,GAC5D,EAAoB;IAClB,MAAM;IACN,OAAO;IACP,QAAQ;IACR,OAAO;GACT,CAAC,GACD,MAAM,EAAK;EACb,SAAS,GAAK;GAGZ,EAAU;IAAE,SADV,GAAK,UAAU,MAAM,WAAW,GAAK,WAAW;IAC7B,MAAM;GAAQ,CAAC;EACtC;CACF;CAEA,eAAe,GAAe,GAAO;EACnC,IAAI;GAGF,AAFA,MAAM,GAAkB;IAAE,IAAI,EAAO;IAAG,SAAS,EAAM;GAAG,CAAC,GAC3D,EAAU;IAAE,SAAS;IAAsB,MAAM;GAAU,CAAC,GAC5D,MAAM,EAAK;EACb,SAAS,GAAK;GAKZ,EAAU;IAAE,SAHV,GAAK,UAAU,MAAM,WACrB,GAAK,WACL;IACmB,MAAM;GAAQ,CAAC;EACtC;CACF;CAEA,OACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,IAAD,CAAQ,CAAA,GACR,kBAAC,IAAD;EAAS,MAAM;YAAf,CACA,kBAAC,GAAD;GACE,OAAM;GACN,UAAS;GACT,OAAO,CAAC,OAAO;GACf,SACE,kBAAC,GAAD;IAAO,WAAU;IAAM,SAAS;cAC9B,kBAAC,GAAD;KACE,SAAQ;KACR,WAAW,kBAAC,GAAD,CAAqB,CAAA;KAChC,eAAe,KAAK,EAAK;eAC1B;IAEO,CAAA;GACH,CAAA;aAbX,CAgBG,IACC,kBAAC,IAAD;IAAO,UAAS;IAAQ,IAAI,EAAE,IAAI,EAAE;cACjC;GACI,CAAA,IACL,MAEJ,kBAAC,GAAD;IACE,SAAQ;IACR,OAAM;IACN,UACE,IACI,aACA,IACE,GAAG,EAAc,OAAO,MAAM,EAAM,OAAO,GAAG,EAAM,WAAW,IAAI,UAAU,UAAU,UACvF,GAAG,EAAM,OAAO,GAAG,EAAM,WAAW,IAAI,UAAU,UAAU;cARtE,CAWE,kBAAC,GAAD;KAAO,WAAW;MAAE,IAAI;MAAU,IAAI;KAAM;KAAG,SAAS;KAAK,IAAI,EAAE,IAAI,EAAE;KAAG,YAAY,EAAE,IAAI,SAAS;eAAvG;MACE,kBAAC,GAAD;OACE,MAAK;OACL,WAAA;OACA,aAAY;OACZ,OAAO;OACP,WAAW,MAAM,EAAU,EAAE,OAAO,KAAK;OACzC,YAAY,EACV,gBACE,kBAAC,IAAD;QAAgB,UAAS;kBACvB,kBAAC,IAAD,EAAmB,UAAS,QAAS,CAAA;OACvB,CAAA,EAEpB;OACA,IAAI,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE;MAC7B,CAAA;MACD,kBAAC,GAAD;OAAa,MAAK;OAAQ,IAAI,EAAE,UAAU,IAAI;iBAA9C,CACE,kBAAC,GAAD,EAAA,UAAY,SAAkB,CAAA,GAC9B,kBAAC,GAAD;QACE,OAAM;QACN,OAAO;QACP,WAAW,MAAM;SACf,IAAM,IAAO,EAAE,OAAO;SAMtB,AALA,EAAgB,CAAI,GAIhB,MAAS,aAAW,EAAiB,EAAK,GAC1C,MAAS,eAAa,EAAW,EAAK;QAC5C;kBAXF,CAaE,kBAAC,GAAD;SAAU,OAAM;mBAAM;QAAsB,CAAA,GAC3C,EAAe,KAAK,MAAM;SACzB,IAAM,IAAW,EAAE,UAAU,aAAa,KAAmB,EAAE,UAAU,eAAe;SACxF,OACE,kBAAC,GAAD;UAAwB,OAAO,EAAE;UAAO,UAAU;oBAAlD,CACG,EAAE,OACF,IACC,kBAAC,GAAD;WAAY,WAAU;WAAO,SAAQ;WAAU,OAAM;WAAgB,IAAI,EAAE,IAAI,EAAE;qBAAG;UAExE,CAAA,IACV,IACI;YAPK,EAAE,KAOP;QAEd,CAAC,CACK;SACG;;MACb,kBAAC,GAAD;OAAO,WAAU;OAAM,SAAS;OAAG,YAAA;OAAW,UAAS;iBAAvD,CACE,kBAAC,GAAD;QACE,OAAM;QACN,MAAK;QACL,UAAU,MAAiB;QAC3B,eAAe;SAGb,GAAkB,MAAS;UACzB,IAAM,IAAO,CAAC;UAEd,OADI,KAAQ,MAAiB,aAAW,EAAgB,KAAK,GACtD;SACT,CAAC;QACH;QACA,OAAO,IAAgB,YAAY;QACnC,SAAS,IAAgB,WAAW;QACpC,IAAI;SAAE,YAAY;SAAK,cAAc;QAAI;OAC1C,CAAA,GACD,kBAAC,GAAD;QACE,OAAM;QACN,MAAK;QACL,UAAU,MAAiB;QAC3B,eAAe;SACb,GAAY,MAAS;UACnB,IAAM,IAAO,CAAC;UAEd,OADI,KAAQ,MAAiB,eAAa,EAAgB,KAAK,GACxD;SACT,CAAC;QACH;QACA,OAAO,IAAU,YAAY;QAC7B,SAAS,IAAU,WAAW;QAC9B,IAAI;SAAE,YAAY;SAAK,cAAc;QAAI;OAC1C,CAAA,CACI;;MACP,kBAAC,GAAD,EAAK,IAAI,EAAE,UAAU,EAAE,EAAI,CAAA;MAC3B,kBAAC,GAAD;OAAQ,SAAQ;OAAO,SAAS;OAAc,UAAU,CAAC;iBAAW;MAAa,CAAA;KAC5E;QAEP,kBAAC,IAAD;KAAS,OAAA;eAAT,CACE,kBAAC,IAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAA;MACE,kBAAC,GAAD,EAAA,UAAW,UAAkB,CAAA;MAC7B,kBAAC,GAAD,EAAA,UAAW,MAAc,CAAA;MACzB,kBAAC,GAAD,EAAA,UAAW,QAAgB,CAAA;MAC3B,kBAAC,GAAD,EAAA,UAAW,SAAiB,CAAA;MAC5B,kBAAC,GAAD;OAAW,OAAM;iBAAQ;MAAgB,CAAA;MACzC,kBAAC,GAAD,EAAA,UAAW,UAAkB,CAAA;MAC7B,kBAAC,GAAD,EAAA,UAAW,SAAiB,CAAA;MAC5B,kBAAC,GAAD;OAAW,OAAM;iBAAQ;MAAiB,CAAA;KAClC,EAAA,CAAA,EACD,CAAA,GACX,kBAAC,IAAD,EAAA,UACG,IACC,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,GAAG,MAChC,kBAAC,GAAD,EAAA,UACG,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,GAAI,MAClC,kBAAC,GAAD,EAAA,UACE,kBAAC,IAAD,EAAU,QAAQ,GAAK,CAAA,EACd,GAFK,CAEL,CACZ,EACO,GANK,CAML,CACX,IACC,EAAc,WAAW,IAC3B,kBAAC,IAAD;MACE,SAAS;MACT,MAAM;MACN,OAAO,IAAY,kCAAkC;MACrD,MAAM,IACF,mCACA;MACJ,QAAQ,IACN,kBAAC,GAAD;OAAQ,SAAQ;OAAO,MAAK;OAAQ,SAAS;iBAAc;MAAqB,CAAA,IAC9E;KACL,CAAA,IAED,EAAc,KAAK,MAAM;MACvB,IAAM,IAAY,EAAe,CAAC,GAC5B,IACJ,EAAE,eAAe,IAAI,EAAE,eAAe,EAAE,eAAe;MACzD,OACE,kBAAC,GAAD;OAAqB,OAAA;iBAArB;QACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;SACE,WAAU;SACV,YAAW;SACX,SAAS;SACT,IAAI,EAAE,UAAU,EAAE;mBAJpB,CAME,kBAAC,GAAD;UACE,SAAQ;UACR,IAAI;WAAE,YAAY;WAAK,YAAY;UAAI;oBAEtC,EAAE;SACO,CAAA,GACZ,kBAAC,GAAD,EAAO,IAAI,EAAE,SAAW,CAAA,CACnB;WACE,CAAA;QACX,kBAAC,GAAD,EAAA,UACG,EAAE,YACD,kBAAC,GAAD;SACE,WAAU;SACV,IAAI;UACF,SAAS;UACT,IAAI;UACJ,IAAI;UACJ,cAAc;UACd,SAAS,EAAM,GAAM,QAAQ,QAAQ,MAAM,GAAI;UAC/C,OAAO;UACP,YAAY;UACZ,UAAU;UACV,YAAY;SACd;mBAEC,EAAE;QACA,CAAA,IAEL,kBAAC,GAAD;SAAY,SAAQ;SAAU,OAAM;mBAAgB;QAExC,CAAA,EAEL,CAAA;QACX,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;SAAY,SAAQ;SAAQ,IAAI,EAAE,YAAY,IAAI;mBAC/C,EAAE,cAAc,EAAE,cAAc,SAAS,aAAa;QAC7C,CAAA,GACZ,kBAAC,GAAD;SAAY,SAAQ;SAAU,OAAM;mBACjC,EAAE;QACO,CAAA,CACH,EAAA,CAAA;QACX,kBAAC,GAAD,EAAA,UACG,EAAE,aACD,kBAAC,IAAD;SACE,OAAO,IAAY,wBAAwB;mBAE3C,kBAAC,GAAD;UACE,SAAQ;UACR,IAAI;WACF,YAAY;WACZ,oBAAoB;WACpB,OAAO,IACH,eACA;UACN;oBAEC,GAAW,EAAE,UAAU;SACd,CAAA;QACL,CAAA,IAET,kBAAC,GAAD;SAAY,SAAQ;SAAU,OAAM;mBAAgB;QAExC,CAAA,EAEL,CAAA;QACX,kBAAC,GAAD;SAAW,OAAM;SAAQ,IAAI,EAAE,UAAU,IAAI;mBAC3C,kBAAC,GAAD;UAAO,YAAW;UAAW,SAAS;oBAAtC,CACE,kBAAC,GAAD;WACE,SAAQ;WACR,IAAI;YACF,YAAY;YACZ,oBAAoB;WACtB;qBALF,CAOG,EAAE,cACH,kBAAC,GAAD;YACE,WAAU;YACV,SAAQ;YACR,OAAM;YACN,IAAI;aACF,IAAI;aACJ,oBAAoB;YACtB;sBAPF,CAQC,MACI,EAAE,YACK;aACF;cACZ,kBAAC,GAAD;WAAK,IAAI,EAAE,OAAO,GAAG;qBACnB,kBAAC,IAAD;YACE,SAAQ;YACR,OAAO,KAAK,IACV,KACA,KAAK,IAAI,GAAG,IAAiB,GAAG,CAClC;YACA,IAAI;aAAE,QAAQ;aAAG,cAAc;YAAE;YACjC,OACE,IAAiB,MAAO,YAAY;WAEvC,CAAA;UACE,CAAA,CACA;;QACE,CAAA;QACX,kBAAC,GAAD,EAAA,UACG,EAAE,kBACD,kBAAC,GAAD;SACE,SAAQ;SACR,IAAI,EAAE,YAAY,IAAI;mBAErB,EAAE;QACO,CAAA,IAEZ,kBAAC,GAAD;SAAY,SAAQ;SAAU,OAAM;mBAAgB;QAExC,CAAA,EAEL,CAAA;QACX,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;SACE,WAAU;SACV,SAAS;SACT,UAAS;SACT,YAAA;mBAJF;UAME,kBAAC,GAAD;WACE,MAAK;WACL,OAAO,GAAY,EAAE,MAAM;WAC3B,OAAO,EAAQ,GAAgB,EAAE,MAAM;WACvC,IAAI;YACF,YAAY;YACZ,cAAc;YACd,QAAQ;WACV;UACD,CAAA;UACA,EAAE,gBACD,kBAAC,GAAD;WACE,MAAK;WACL,OAAM;WACN,OAAO,EAAQ,GAAoB,EAAE,gBAAgB,KAAK;WAC1D,IAAI;YACF,YAAY;YACZ,cAAc;YACd,QAAQ;WACV;UACD,CAAA,IACC;UACH,KAAa,EAAE,WAAW,YACzB,kBAAC,GAAD;WACE,MAAK;WACL,OAAM;WACN,OAAM;WACN,IAAI;YACF,YAAY;YACZ,cAAc;YACd,QAAQ;WACV;UACD,CAAA,IACC;UACH,EAAE,aACD,kBAAC,GAAD;WACE,MAAK;WACL,SAAQ;WACR,OACE,EAAE,eAAe,WAAW,SAC1B,EAAE,eAAe,gBAAgB,YACjC;WAEJ,OAAO,EAAE,eAAe,gBAAgB,aAAa,EAAE,eAAe,WAAW,WAAW,EAAE,eAAe,aAAa,aAAa,EAAE;WACzI,IAAI;YACF,YAAY;YACZ,cAAc;YACd,QAAQ;WACV;UACD,CAAA,IACC;SACC;WACE,CAAA;QACX,kBAAC,GAAD;SAAW,OAAM;mBACb,IAAkB,EAAE,gBACpB,kBAAC,GAAD;UACE,MAAK;UACL,SAAQ;UACR,OAAM;UACN,WAAW,kBAAC,GAAD,CAAsB,CAAA;UACjC,eAAe,KAAK,GAAe,CAAC;oBACrC;SAEO,CAAA,IACN,KACF,EAAE,WAAW,eACb,EAAE,WAAW,WAAW,OACxB,kBAAC,GAAD;UACE,MAAK;UACL,SAAQ;UACR,OAAM;UACN,WAAW,kBAAC,GAAD,CAAkB,CAAA;UAC7B,eACE,EAAoB;WAClB,MAAM;WACN,OAAO;WACP,QAAQ;WACR,OAAO;UACT,CAAC;oBAEJ;SAEO,CAAA,IA5BG;QA8BJ,CAAA;OACH;SAxNK,EAAE,EAwNP;KAEd,CAAC,EAEM,CAAA,CACJ;MACE;KACF;MAEb,kBAAC,IAAD;GACE,MAAM,EAAiB;GACvB,eACE,EAAoB;IAAE,GAAG;IAAkB,MAAM;GAAM,CAAC;GAE1D,WAAA;GACA,UAAS;aANX;IAQE,kBAAC,IAAD,EAAA,UAAa,mBAA6B,CAAA;IAC1C,kBAAC,IAAD;KAAe,UAAA;eACb,kBAAC,GAAD;MAAO,SAAS;MAAG,IAAI,EAAE,IAAI,EAAE;gBAA/B;OACE,kBAAC,GAAD;QAAY,SAAQ;kBAApB;SAA4B;SACjB,kBAAC,UAAD,EAAA,UAAS,EAAiB,OAAO,YAAoB,CAAA;SAC9D,kBAAC,MAAD,CAAK,CAAA;SAAC;SACD,kBAAC,UAAD,EAAA,UAAS,EAAiB,OAAO,aAAa,IAAY,CAAA;SAC/D,kBAAC,MAAD,CAAK,CAAA;SAAC;SACK,kBAAC,UAAD,EAAA,UAAS,EAAiB,OAAO,aAAqB,CAAA;QACvD;;OACZ,kBAAC,GAAD;QACE,UAAA;QACA,WAAA;QACA,MAAK;QACL,OAAO,CAAC,CAAC,EAAiB,EAAiB,QAAQ,QAAQ;kBAJ7D;SAME,kBAAC,GAAD,EAAA,UAAY,SAAkB,CAAA;SAC9B,kBAAC,GAAD;UACE,OAAM;UACN,OAAO,EAAiB;UACxB,WAAW,MACT,EAAoB;WAClB,GAAG;WACH,QAAQ,EAAE,OAAO;UACnB,CAAC;oBAGF,EAAmB,KAAK,MACvB,kBAAC,GAAD;WAAwB,OAAO,EAAE;qBAC9B,EAAE;UACK,GAFK,EAAE,KAEP,CACX;SACK,CAAA;SACP,EAAiB,EAAiB,QAAQ,QAAQ,IACjD,kBAAC,IAAD,EAAA,UACG,EAAiB,EAAiB,QAAQ,QAAQ,EACrC,CAAA,IACd;QACO;;OACb,kBAAC,GAAD;QACE,OAAM;QACN,MAAK;QACL,WAAA;QACA,SAAS;QACT,WAAA;QACA,OAAO,EAAiB;QACxB,WAAW,MACT,EAAoB;SAClB,GAAG;SACH,OAAO,EAAE,OAAO;QAClB,CAAC;OAEJ,CAAA;MACI;;IACM,CAAA;IACf,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,GAAD;KACE,eACE,EAAoB;MAAE,GAAG;MAAkB,MAAM;KAAM,CAAC;eAE3D;IAEO,CAAA,GACR,kBAAC,GAAD;KACE,SAAQ;KACR,OAAM;KACN,UAAU,CAAC,CAAC,EAAiB,EAAiB,QAAQ,QAAQ;KAC9D,eAAe,KAAK,GAAa;eAClC;IAEO,CAAA,CACK,EAAA,CAAA;GACT;IACC;GACN,EAAA,CAAA;AAET"}
|