@argusoft/medplat-product-management 1.0.0 → 1.0.2
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-CSA3meke.js +385 -0
- package/dist/BrandsPage-CSA3meke.js.map +1 -0
- package/dist/CategoriesPage-BrspzkJL.js +340 -0
- package/dist/CategoriesPage-BrspzkJL.js.map +1 -0
- package/dist/{DashboardPage-BNKUQj46.js → DashboardPage-CqaquOs2.js} +21 -22
- package/dist/{DashboardPage-BNKUQj46.js.map → DashboardPage-CqaquOs2.js.map} +1 -1
- package/dist/{FacilityPicker-Coi8I3yE.js → FacilityPicker-Dv_H95WW.js} +13 -13
- package/dist/{FacilityPicker-Coi8I3yE.js.map → FacilityPicker-Dv_H95WW.js.map} +1 -1
- package/dist/{InventoryPage-BR6jOzg2.js → InventoryPage-CPbzfDMR.js} +12 -12
- package/dist/{InventoryPage-BR6jOzg2.js.map → InventoryPage-CPbzfDMR.js.map} +1 -1
- package/dist/{MemberProfileCard-DbHZCS5n.js → MemberProfileCard-0vjO3Gzd.js} +2 -2
- package/dist/{MemberProfileCard-DbHZCS5n.js.map → MemberProfileCard-0vjO3Gzd.js.map} +1 -1
- package/dist/{PaymentCreatePage-Ci3ERnby.js → PaymentCreatePage-BYmDZAIB.js} +9 -10
- package/dist/{PaymentCreatePage-Ci3ERnby.js.map → PaymentCreatePage-BYmDZAIB.js.map} +1 -1
- package/dist/{PaymentsPage-sdg902zX.js → PaymentsPage-BXPvKon-.js} +16 -16
- package/dist/{PaymentsPage-sdg902zX.js.map → PaymentsPage-BXPvKon-.js.map} +1 -1
- package/dist/PickupCreatePage-CMGwoAXj.js +426 -0
- package/dist/PickupCreatePage-CMGwoAXj.js.map +1 -0
- package/dist/{PickupsPage-Ci2Ll0Kn.js → PickupsPage-D66_Wta4.js} +84 -39
- package/dist/PickupsPage-D66_Wta4.js.map +1 -0
- package/dist/PmTable-B9970kPY.js +375 -0
- package/dist/PmTable-B9970kPY.js.map +1 -0
- package/dist/{ProductEditPage-DL8gy85Y.js → ProductEditPage-B8qFTCW9.js} +226 -243
- package/dist/ProductEditPage-B8qFTCW9.js.map +1 -0
- package/dist/ProductsPage-C7_r9cKn.js +254 -0
- package/dist/ProductsPage-C7_r9cKn.js.map +1 -0
- package/dist/{PurchaseCreatePage-C3KMfBxJ.js → PurchaseCreatePage-CDfNDcKG.js} +150 -149
- package/dist/PurchaseCreatePage-CDfNDcKG.js.map +1 -0
- package/dist/{PurchaseRequestDetailPage-C0GYFJDl.js → PurchaseRequestDetailPage-C7aAwEqw.js} +15 -15
- package/dist/{PurchaseRequestDetailPage-C0GYFJDl.js.map → PurchaseRequestDetailPage-C7aAwEqw.js.map} +1 -1
- package/dist/{PurchaseRequestsPage-DvFH_tWe.js → PurchaseRequestsPage-BwCkbpaX.js} +14 -14
- package/dist/{PurchaseRequestsPage-DvFH_tWe.js.map → PurchaseRequestsPage-BwCkbpaX.js.map} +1 -1
- package/dist/{PurchasesPage-BCvLvSp4.js → PurchasesPage-CvaZouVy.js} +11 -12
- package/dist/{PurchasesPage-BCvLvSp4.js.map → PurchasesPage-CvaZouVy.js.map} +1 -1
- package/dist/{SaleCreatePage-DpkQMoTq.js → SaleCreatePage-DP1Qmltu.js} +30 -31
- package/dist/{SaleCreatePage-DpkQMoTq.js.map → SaleCreatePage-DP1Qmltu.js.map} +1 -1
- package/dist/{SalesPage-DUwgkEO-.js → SalesPage-CO3cdYX5.js} +18 -19
- package/dist/{SalesPage-DUwgkEO-.js.map → SalesPage-CO3cdYX5.js.map} +1 -1
- package/dist/{SettingsPage-CusC0jqJ.js → SettingsPage-DvVRwSFw.js} +104 -103
- package/dist/SettingsPage-DvVRwSFw.js.map +1 -0
- package/dist/StorageUnitsPage-B9Hr_RkW.js +470 -0
- package/dist/StorageUnitsPage-B9Hr_RkW.js.map +1 -0
- package/dist/{TransactionsPage-DDaK4VyY.js → TransactionsPage-HKIGwEZN.js} +127 -123
- package/dist/TransactionsPage-HKIGwEZN.js.map +1 -0
- package/dist/{TransferCreatePage-BxudLfhS.js → TransferCreatePage-DMuZqQ3c.js} +9 -9
- package/dist/{TransferCreatePage-BxudLfhS.js.map → TransferCreatePage-DMuZqQ3c.js.map} +1 -1
- package/dist/{TransfersPage-zgmt7teZ.js → TransfersPage-COIyouL4.js} +16 -16
- package/dist/{TransfersPage-zgmt7teZ.js.map → TransfersPage-COIyouL4.js.map} +1 -1
- package/dist/{VialsPage-CjqPfgpV.js → VialsPage-BNPUwGCU.js} +291 -224
- package/dist/VialsPage-BNPUwGCU.js.map +1 -0
- package/dist/{constants-BrA_hfAI.js → constants-5ZCZo-Zm.js} +5 -2
- package/dist/{constants-BrA_hfAI.js.map → constants-5ZCZo-Zm.js.map} +1 -1
- package/dist/{PmGuard-CjJBisaN.js → currency-ClRLIEg2.js} +186 -9
- package/dist/currency-ClRLIEg2.js.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/BrandsPage-DCMCVvDY.js +0 -334
- package/dist/BrandsPage-DCMCVvDY.js.map +0 -1
- package/dist/CategoriesPage-BpRhwfrc.js +0 -284
- package/dist/CategoriesPage-BpRhwfrc.js.map +0 -1
- package/dist/PickupCreatePage-CieMsgWV.js +0 -310
- package/dist/PickupCreatePage-CieMsgWV.js.map +0 -1
- package/dist/PickupsPage-Ci2Ll0Kn.js.map +0 -1
- package/dist/PmGuard-CjJBisaN.js.map +0 -1
- package/dist/PmTable-BuXZQZCU.js +0 -302
- package/dist/PmTable-BuXZQZCU.js.map +0 -1
- package/dist/ProductEditPage-DL8gy85Y.js.map +0 -1
- package/dist/ProductsPage-BANTKxLb.js +0 -221
- package/dist/ProductsPage-BANTKxLb.js.map +0 -1
- package/dist/PurchaseCreatePage-C3KMfBxJ.js.map +0 -1
- package/dist/SettingsPage-CusC0jqJ.js.map +0 -1
- package/dist/StorageUnitsPage-BlC2AgrJ.js +0 -469
- package/dist/StorageUnitsPage-BlC2AgrJ.js.map +0 -1
- package/dist/TransactionsPage-DDaK4VyY.js.map +0 -1
- package/dist/VialsPage-CjqPfgpV.js.map +0 -1
- package/dist/currency-BDDCDgeE.js +0 -169
- package/dist/currency-BDDCDgeE.js.map +0 -1
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as
|
|
3
|
-
import { a as o, i as s, o as c, r as l, t as u } from "./PmTable-BuXZQZCU.js";
|
|
1
|
+
import { G as e, a as t, i as n, l as r, n as i, o as a, r as ee, t as te } from "./currency-ClRLIEg2.js";
|
|
2
|
+
import { a as o, c as s, i as c, s as l, t as u } from "./PmTable-B9970kPY.js";
|
|
4
3
|
import { t as d } from "./format-UOyOu75i.js";
|
|
5
4
|
import { useMemo as f, useState as p } from "react";
|
|
6
5
|
import { jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
@@ -15,7 +14,7 @@ import se from "@mui/icons-material/SearchRounded";
|
|
|
15
14
|
//#region src/views/PurchasesPage.jsx
|
|
16
15
|
var ce = 3;
|
|
17
16
|
function j() {
|
|
18
|
-
let j =
|
|
17
|
+
let j = t().has("update.manage.productManagement.purchase"), M = r(), N = te(M?.currencyCode), P = M?.managePurchaseAmounts !== !1, F = ae(), I = A(), [L, R] = p([]), [z, B] = p(!0), [V, H] = p(""), [U, W] = p(""), [G, K] = p(""), [q, J] = p("");
|
|
19
18
|
async function Y() {
|
|
20
19
|
B(!0), H("");
|
|
21
20
|
try {
|
|
@@ -30,7 +29,7 @@ function j() {
|
|
|
30
29
|
B(!1);
|
|
31
30
|
}
|
|
32
31
|
}
|
|
33
|
-
|
|
32
|
+
n("view.manage.productManagement.purchase", () => {
|
|
34
33
|
Y();
|
|
35
34
|
}, []);
|
|
36
35
|
let X = f(() => {
|
|
@@ -61,9 +60,9 @@ function j() {
|
|
|
61
60
|
W(""), K(""), J("");
|
|
62
61
|
}
|
|
63
62
|
let $ = P ? 7 : 5;
|
|
64
|
-
return /* @__PURE__ */ h(g, { children: [/* @__PURE__ */ m(
|
|
63
|
+
return /* @__PURE__ */ h(g, { children: [/* @__PURE__ */ m(ee, {}), /* @__PURE__ */ m(i, {
|
|
65
64
|
perm: "view.manage.productManagement.purchase",
|
|
66
|
-
children: /* @__PURE__ */ h(
|
|
65
|
+
children: /* @__PURE__ */ h(a, {
|
|
67
66
|
title: "Completed Purchases",
|
|
68
67
|
subtitle: "Completed purchases and approved requests. Each shows the items and cost.",
|
|
69
68
|
actions: /* @__PURE__ */ h(x, {
|
|
@@ -85,7 +84,7 @@ function j() {
|
|
|
85
84
|
severity: "error",
|
|
86
85
|
sx: { mb: 2 },
|
|
87
86
|
children: V
|
|
88
|
-
}) : null, /* @__PURE__ */ h(
|
|
87
|
+
}) : null, /* @__PURE__ */ h(s, {
|
|
89
88
|
eyebrow: "Procurement",
|
|
90
89
|
title: "Recent purchases",
|
|
91
90
|
subtitle: z ? "Loading…" : P ? `${X.length} ${X.length === 1 ? "purchase" : "purchases"} · total spend ${N}${le.toFixed(2)}` : `${X.length} ${X.length === 1 ? "purchase" : "purchases"}`,
|
|
@@ -134,7 +133,7 @@ function j() {
|
|
|
134
133
|
children: "Clear"
|
|
135
134
|
})
|
|
136
135
|
]
|
|
137
|
-
}), /* @__PURE__ */ h(
|
|
136
|
+
}), /* @__PURE__ */ h(l, {
|
|
138
137
|
dense: !0,
|
|
139
138
|
children: [/* @__PURE__ */ m(w, { children: /* @__PURE__ */ h(T, { children: [
|
|
140
139
|
/* @__PURE__ */ m(C, { children: "Ref" }),
|
|
@@ -169,7 +168,7 @@ function j() {
|
|
|
169
168
|
return /* @__PURE__ */ h(T, {
|
|
170
169
|
hover: !0,
|
|
171
170
|
children: [
|
|
172
|
-
/* @__PURE__ */ m(C, { children: /* @__PURE__ */ m(
|
|
171
|
+
/* @__PURE__ */ m(C, { children: /* @__PURE__ */ m(o, { id: e.serialId }) }),
|
|
173
172
|
/* @__PURE__ */ m(C, { children: /* @__PURE__ */ m(D, {
|
|
174
173
|
variant: "body2",
|
|
175
174
|
sx: { fontWeight: 700 },
|
|
@@ -261,7 +260,7 @@ function j() {
|
|
|
261
260
|
}) }) : null,
|
|
262
261
|
P ? /* @__PURE__ */ m(C, {
|
|
263
262
|
align: "right",
|
|
264
|
-
children: /* @__PURE__ */ m(
|
|
263
|
+
children: /* @__PURE__ */ m(c, { value: e.totalAmount })
|
|
265
264
|
}) : null,
|
|
266
265
|
/* @__PURE__ */ m(C, {
|
|
267
266
|
sx: { maxWidth: 320 },
|
|
@@ -292,4 +291,4 @@ function j() {
|
|
|
292
291
|
//#endregion
|
|
293
292
|
export { j as default };
|
|
294
293
|
|
|
295
|
-
//# sourceMappingURL=PurchasesPage-
|
|
294
|
+
//# sourceMappingURL=PurchasesPage-CvaZouVy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PurchasesPage-BCvLvSp4.js","names":[],"sources":["../src/views/PurchasesPage.jsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Alert,\n Box,\n Button,\n Chip,\n InputAdornment,\n Skeleton,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TextField,\n Typography,\n} from '@mui/material';\nimport { alpha, useTheme } from '@mui/material/styles';\nimport AddRoundedIcon from '@mui/icons-material/AddRounded';\nimport RefreshRoundedIcon from '@mui/icons-material/RefreshRounded';\nimport SearchRoundedIcon from '@mui/icons-material/SearchRounded';\nimport ShoppingCartRoundedIcon from '@mui/icons-material/ShoppingCartRounded';\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 PmEmptyRow,\n PmMoney,\n PmRef,\n PmTable,\n PmTableCard,\n} from '@pm/components/PmTable';\nimport { listPurchases } from '@pm/services/pmApi';\nimport { formatDate } from '@pm/utils/format';\nimport { currencySymbol } from '@pm/utils/currency';\nimport { usePmSettings } from '@pm/utils/settingsStore';\n\n// Compact one-liner of items+qty for the table. We render up to MAX_ITEMS_INLINE\n// pills inline; anything beyond gets a \"+N more\" pill so the row height stays\n// stable regardless of how many lines a purchase has.\nconst MAX_ITEMS_INLINE = 3;\n\nexport default function PurchasesPage() {\n const perms = usePmPermissions();\n const canCreate = perms.has('update.manage.productManagement.purchase');\n const settings = usePmSettings();\n const cur = currencySymbol(settings?.currencyCode);\n const manageAmounts = settings?.managePurchaseAmounts !== false;\n const navigate = useNavigate();\n const theme = useTheme();\n const [items, setItems] = useState([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState('');\n const [search, setSearch] = useState('');\n const [fromDate, setFromDate] = useState('');\n const [toDate, setToDate] = useState('');\n\n async function load() {\n setLoading(true);\n setError('');\n try {\n setItems(await listPurchases(0, 50));\n } catch (err) {\n const message = err?.response?.data?.message ?? err?.message ?? 'Failed to load purchases';\n setError(message);\n showToast({ message, type: 'error' });\n } finally {\n setLoading(false);\n }\n }\n\n usePermissionedEffect('view.manage.productManagement.purchase', () => {\n void load();\n }, []);\n\n // Search hits notes + every batch's productName + lotNumber. Date filters\n // bracket purchaseDate inclusively on either side; either bound is optional.\n const filteredItems = useMemo(() => {\n const q = search.trim().toLowerCase();\n const from = fromDate ? new Date(fromDate) : null;\n const to = toDate ? new Date(toDate) : null;\n return items.filter((p) => {\n if (q) {\n const hayItems = (p.batches ?? [])\n .map((b) => `${b.productName ?? ''} ${b.lotNumber ?? ''}`)\n .join(' ');\n const hay = `${p.notes ?? ''} ${hayItems}`.toLowerCase();\n if (!hay.includes(q)) return false;\n }\n if (from || to) {\n if (!p.purchaseDate) return false;\n const d = new Date(p.purchaseDate);\n if (from && d < from) return false;\n if (to) {\n // Date inputs give midnight; include the entire `to` day.\n const toEnd = new Date(to);\n toEnd.setHours(23, 59, 59, 999);\n if (d > toEnd) return false;\n }\n }\n return true;\n });\n }, [items, search, fromDate, toDate]);\n\n const totalSpend = useMemo(\n () => filteredItems.reduce((s, x) => s + Number(x.totalAmount || 0), 0),\n [filteredItems],\n );\n\n const hasFilter = search.trim() !== '' || fromDate !== '' || toDate !== '';\n\n function clearFilters() {\n setSearch('');\n setFromDate('');\n setToDate('');\n }\n\n // Match the table column count when manageAmounts swaps Payment + Total in\n // and out. Owner + Items columns are always present.\n const columnCount = manageAmounts ? 7 : 5;\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={'view.manage.productManagement.purchase'}>\n <PmPageShell\n title=\"Completed Purchases\"\n subtitle=\"Completed purchases and approved requests. Each shows the items and cost.\"\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button variant=\"outlined\" startIcon={<RefreshRoundedIcon />} onClick={() => void load()}>Refresh</Button>\n {canCreate ? (\n <Button variant=\"contained\" startIcon={<AddRoundedIcon />} onClick={() => navigate('/ui/medplat/manage/pm/purchases/new')}>\n New Purchase\n </Button>\n ) : null}\n </Stack>\n }\n >\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\n <PmTableCard\n eyebrow=\"Procurement\"\n title=\"Recent purchases\"\n subtitle={loading\n ? 'Loading…'\n : manageAmounts\n ? `${filteredItems.length} ${filteredItems.length === 1 ? 'purchase' : 'purchases'} · total spend ${cur}${totalSpend.toFixed(2)}`\n : `${filteredItems.length} ${filteredItems.length === 1 ? 'purchase' : 'purchases'}`}\n >\n <Stack direction={{ xs: 'column', md: 'row' }} spacing={1.5} sx={{ mb: 2 }}>\n <TextField\n size=\"small\"\n fullWidth\n placeholder=\"Search notes or items…\"\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 />\n <TextField\n size=\"small\"\n type=\"date\"\n label=\"From\"\n InputLabelProps={{ shrink: true }}\n value={fromDate}\n onChange={(e) => setFromDate(e.target.value)}\n sx={{ minWidth: 160 }}\n />\n <TextField\n size=\"small\"\n type=\"date\"\n label=\"To\"\n InputLabelProps={{ shrink: true }}\n value={toDate}\n onChange={(e) => setToDate(e.target.value)}\n sx={{ minWidth: 160 }}\n />\n <Button\n variant=\"text\"\n onClick={clearFilters}\n disabled={!hasFilter}\n sx={{ alignSelf: { md: 'center' } }}\n >\n Clear\n </Button>\n </Stack>\n\n <PmTable dense>\n <TableHead>\n <TableRow>\n <TableCell>Ref</TableCell>\n <TableCell>Date</TableCell>\n <TableCell>Owner</TableCell>\n <TableCell>Items</TableCell>\n {manageAmounts ? <TableCell>Payment</TableCell> : null}\n {manageAmounts ? <TableCell align=\"right\">Total</TableCell> : null}\n <TableCell>Notes</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {loading ? (\n Array.from({ length: 5 }).map((_, i) => (\n <TableRow key={i}>\n {Array.from({ length: columnCount }).map((__, j) => (\n <TableCell key={j}><Skeleton height={22} /></TableCell>\n ))}\n </TableRow>\n ))\n ) : filteredItems.length === 0 ? (\n <PmEmptyRow\n colSpan={columnCount}\n icon={ShoppingCartRoundedIcon}\n title={hasFilter ? 'No purchases match your filters' : 'No purchases yet'}\n hint={hasFilter\n ? 'Adjust your search or filters.'\n : 'Record a purchase to add items to your stock.'}\n action={hasFilter\n ? <Button variant=\"text\" size=\"small\" onClick={clearFilters}>Clear filters</Button>\n : !canCreate ? null : (\n <Button variant=\"contained\" size=\"small\" startIcon={<AddRoundedIcon />} onClick={() => navigate('/ui/medplat/manage/pm/purchases/new')}>\n Record first purchase\n </Button>\n )}\n />\n ) : filteredItems.map((p) => {\n const batches = p.batches ?? [];\n const visibleBatches = batches.slice(0, MAX_ITEMS_INLINE);\n const overflow = batches.length - visibleBatches.length;\n return (\n <TableRow key={p.id} hover>\n <TableCell><PmRef id={p.serialId} /></TableCell>\n <TableCell>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>{formatDate(p.purchaseDate)}</Typography>\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>\n {p.ownerName || (p.ownerType === 'USER' ? 'Personal' : 'Facility')}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {p.ownerType}\n </Typography>\n </TableCell>\n <TableCell sx={{ maxWidth: 360 }}>\n {batches.length === 0 ? (\n <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>\n ) : (\n <Stack direction=\"row\" spacing={0.5} flexWrap=\"wrap\" useFlexGap>\n {visibleBatches.map((b) => (\n <Chip\n key={b.id}\n size=\"small\"\n label={\n <Box component=\"span\" sx={{ display: 'inline-flex', alignItems: 'baseline', gap: 0.5 }}>\n <Box component=\"span\" sx={{ fontWeight: 700 }}>{b.productName ?? '—'}</Box>\n <Box component=\"span\" sx={{ fontWeight: 700, fontVariantNumeric: 'tabular-nums', color: 'text.secondary' }}>\n ×{b.qtyPurchased ?? 0}\n </Box>\n </Box>\n }\n sx={{\n height: 22,\n borderRadius: 1.5,\n bgcolor: alpha(theme.palette.primary.main, 0.06),\n color: 'text.primary',\n border: `1px solid ${alpha(theme.palette.primary.main, 0.16)}`,\n '& .MuiChip-label': { px: 0.85 },\n }}\n />\n ))}\n {overflow > 0 ? (\n <Chip\n size=\"small\"\n label={`+${overflow} more`}\n sx={{\n height: 22,\n borderRadius: 1.5,\n bgcolor: 'transparent',\n color: 'text.secondary',\n border: `1px dashed ${theme.palette.divider}`,\n '& .MuiChip-label': { px: 0.85, fontWeight: 700 },\n }}\n />\n ) : null}\n </Stack>\n )}\n </TableCell>\n {manageAmounts ? (\n <TableCell>\n {p.paymentMode ? (\n <Chip\n size=\"small\"\n label={p.paymentMode}\n sx={{\n fontWeight: 700, borderRadius: 1.5, height: 22,\n bgcolor: alpha(theme.palette.primary.main, 0.08),\n color: 'primary.dark',\n border: `1px solid ${alpha(theme.palette.primary.main, 0.18)}`,\n }}\n />\n ) : <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>}\n </TableCell>\n ) : null}\n {manageAmounts ? (\n <TableCell align=\"right\"><PmMoney value={p.totalAmount} /></TableCell>\n ) : null}\n <TableCell sx={{ maxWidth: 320 }}>\n {p.notes ? (\n <Typography variant=\"caption\" color=\"text.secondary\"\n sx={{ display: 'block', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {p.notes}\n </Typography>\n ) : <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>}\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </PmTable>\n </PmTableCard>\n </PmPageShell>\n </PmGuard>\n </Box>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PurchasesPage-CvaZouVy.js","names":[],"sources":["../src/views/PurchasesPage.jsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Alert,\n Box,\n Button,\n Chip,\n InputAdornment,\n Skeleton,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TextField,\n Typography,\n} from '@mui/material';\nimport { alpha, useTheme } from '@mui/material/styles';\nimport AddRoundedIcon from '@mui/icons-material/AddRounded';\nimport RefreshRoundedIcon from '@mui/icons-material/RefreshRounded';\nimport SearchRoundedIcon from '@mui/icons-material/SearchRounded';\nimport ShoppingCartRoundedIcon from '@mui/icons-material/ShoppingCartRounded';\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 PmEmptyRow,\n PmMoney,\n PmRef,\n PmTable,\n PmTableCard,\n} from '@pm/components/PmTable';\nimport { listPurchases } from '@pm/services/pmApi';\nimport { formatDate } from '@pm/utils/format';\nimport { currencySymbol } from '@pm/utils/currency';\nimport { usePmSettings } from '@pm/utils/settingsStore';\n\n// Compact one-liner of items+qty for the table. We render up to MAX_ITEMS_INLINE\n// pills inline; anything beyond gets a \"+N more\" pill so the row height stays\n// stable regardless of how many lines a purchase has.\nconst MAX_ITEMS_INLINE = 3;\n\nexport default function PurchasesPage() {\n const perms = usePmPermissions();\n const canCreate = perms.has('update.manage.productManagement.purchase');\n const settings = usePmSettings();\n const cur = currencySymbol(settings?.currencyCode);\n const manageAmounts = settings?.managePurchaseAmounts !== false;\n const navigate = useNavigate();\n const theme = useTheme();\n const [items, setItems] = useState([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState('');\n const [search, setSearch] = useState('');\n const [fromDate, setFromDate] = useState('');\n const [toDate, setToDate] = useState('');\n\n async function load() {\n setLoading(true);\n setError('');\n try {\n setItems(await listPurchases(0, 50));\n } catch (err) {\n const message = err?.response?.data?.message ?? err?.message ?? 'Failed to load purchases';\n setError(message);\n showToast({ message, type: 'error' });\n } finally {\n setLoading(false);\n }\n }\n\n usePermissionedEffect('view.manage.productManagement.purchase', () => {\n void load();\n }, []);\n\n // Search hits notes + every batch's productName + lotNumber. Date filters\n // bracket purchaseDate inclusively on either side; either bound is optional.\n const filteredItems = useMemo(() => {\n const q = search.trim().toLowerCase();\n const from = fromDate ? new Date(fromDate) : null;\n const to = toDate ? new Date(toDate) : null;\n return items.filter((p) => {\n if (q) {\n const hayItems = (p.batches ?? [])\n .map((b) => `${b.productName ?? ''} ${b.lotNumber ?? ''}`)\n .join(' ');\n const hay = `${p.notes ?? ''} ${hayItems}`.toLowerCase();\n if (!hay.includes(q)) return false;\n }\n if (from || to) {\n if (!p.purchaseDate) return false;\n const d = new Date(p.purchaseDate);\n if (from && d < from) return false;\n if (to) {\n // Date inputs give midnight; include the entire `to` day.\n const toEnd = new Date(to);\n toEnd.setHours(23, 59, 59, 999);\n if (d > toEnd) return false;\n }\n }\n return true;\n });\n }, [items, search, fromDate, toDate]);\n\n const totalSpend = useMemo(\n () => filteredItems.reduce((s, x) => s + Number(x.totalAmount || 0), 0),\n [filteredItems],\n );\n\n const hasFilter = search.trim() !== '' || fromDate !== '' || toDate !== '';\n\n function clearFilters() {\n setSearch('');\n setFromDate('');\n setToDate('');\n }\n\n // Match the table column count when manageAmounts swaps Payment + Total in\n // and out. Owner + Items columns are always present.\n const columnCount = manageAmounts ? 7 : 5;\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={'view.manage.productManagement.purchase'}>\n <PmPageShell\n title=\"Completed Purchases\"\n subtitle=\"Completed purchases and approved requests. Each shows the items and cost.\"\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button variant=\"outlined\" startIcon={<RefreshRoundedIcon />} onClick={() => void load()}>Refresh</Button>\n {canCreate ? (\n <Button variant=\"contained\" startIcon={<AddRoundedIcon />} onClick={() => navigate('/ui/medplat/manage/pm/purchases/new')}>\n New Purchase\n </Button>\n ) : null}\n </Stack>\n }\n >\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\n <PmTableCard\n eyebrow=\"Procurement\"\n title=\"Recent purchases\"\n subtitle={loading\n ? 'Loading…'\n : manageAmounts\n ? `${filteredItems.length} ${filteredItems.length === 1 ? 'purchase' : 'purchases'} · total spend ${cur}${totalSpend.toFixed(2)}`\n : `${filteredItems.length} ${filteredItems.length === 1 ? 'purchase' : 'purchases'}`}\n >\n <Stack direction={{ xs: 'column', md: 'row' }} spacing={1.5} sx={{ mb: 2 }}>\n <TextField\n size=\"small\"\n fullWidth\n placeholder=\"Search notes or items…\"\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 />\n <TextField\n size=\"small\"\n type=\"date\"\n label=\"From\"\n InputLabelProps={{ shrink: true }}\n value={fromDate}\n onChange={(e) => setFromDate(e.target.value)}\n sx={{ minWidth: 160 }}\n />\n <TextField\n size=\"small\"\n type=\"date\"\n label=\"To\"\n InputLabelProps={{ shrink: true }}\n value={toDate}\n onChange={(e) => setToDate(e.target.value)}\n sx={{ minWidth: 160 }}\n />\n <Button\n variant=\"text\"\n onClick={clearFilters}\n disabled={!hasFilter}\n sx={{ alignSelf: { md: 'center' } }}\n >\n Clear\n </Button>\n </Stack>\n\n <PmTable dense>\n <TableHead>\n <TableRow>\n <TableCell>Ref</TableCell>\n <TableCell>Date</TableCell>\n <TableCell>Owner</TableCell>\n <TableCell>Items</TableCell>\n {manageAmounts ? <TableCell>Payment</TableCell> : null}\n {manageAmounts ? <TableCell align=\"right\">Total</TableCell> : null}\n <TableCell>Notes</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {loading ? (\n Array.from({ length: 5 }).map((_, i) => (\n <TableRow key={i}>\n {Array.from({ length: columnCount }).map((__, j) => (\n <TableCell key={j}><Skeleton height={22} /></TableCell>\n ))}\n </TableRow>\n ))\n ) : filteredItems.length === 0 ? (\n <PmEmptyRow\n colSpan={columnCount}\n icon={ShoppingCartRoundedIcon}\n title={hasFilter ? 'No purchases match your filters' : 'No purchases yet'}\n hint={hasFilter\n ? 'Adjust your search or filters.'\n : 'Record a purchase to add items to your stock.'}\n action={hasFilter\n ? <Button variant=\"text\" size=\"small\" onClick={clearFilters}>Clear filters</Button>\n : !canCreate ? null : (\n <Button variant=\"contained\" size=\"small\" startIcon={<AddRoundedIcon />} onClick={() => navigate('/ui/medplat/manage/pm/purchases/new')}>\n Record first purchase\n </Button>\n )}\n />\n ) : filteredItems.map((p) => {\n const batches = p.batches ?? [];\n const visibleBatches = batches.slice(0, MAX_ITEMS_INLINE);\n const overflow = batches.length - visibleBatches.length;\n return (\n <TableRow key={p.id} hover>\n <TableCell><PmRef id={p.serialId} /></TableCell>\n <TableCell>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>{formatDate(p.purchaseDate)}</Typography>\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>\n {p.ownerName || (p.ownerType === 'USER' ? 'Personal' : 'Facility')}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {p.ownerType}\n </Typography>\n </TableCell>\n <TableCell sx={{ maxWidth: 360 }}>\n {batches.length === 0 ? (\n <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>\n ) : (\n <Stack direction=\"row\" spacing={0.5} flexWrap=\"wrap\" useFlexGap>\n {visibleBatches.map((b) => (\n <Chip\n key={b.id}\n size=\"small\"\n label={\n <Box component=\"span\" sx={{ display: 'inline-flex', alignItems: 'baseline', gap: 0.5 }}>\n <Box component=\"span\" sx={{ fontWeight: 700 }}>{b.productName ?? '—'}</Box>\n <Box component=\"span\" sx={{ fontWeight: 700, fontVariantNumeric: 'tabular-nums', color: 'text.secondary' }}>\n ×{b.qtyPurchased ?? 0}\n </Box>\n </Box>\n }\n sx={{\n height: 22,\n borderRadius: 1.5,\n bgcolor: alpha(theme.palette.primary.main, 0.06),\n color: 'text.primary',\n border: `1px solid ${alpha(theme.palette.primary.main, 0.16)}`,\n '& .MuiChip-label': { px: 0.85 },\n }}\n />\n ))}\n {overflow > 0 ? (\n <Chip\n size=\"small\"\n label={`+${overflow} more`}\n sx={{\n height: 22,\n borderRadius: 1.5,\n bgcolor: 'transparent',\n color: 'text.secondary',\n border: `1px dashed ${theme.palette.divider}`,\n '& .MuiChip-label': { px: 0.85, fontWeight: 700 },\n }}\n />\n ) : null}\n </Stack>\n )}\n </TableCell>\n {manageAmounts ? (\n <TableCell>\n {p.paymentMode ? (\n <Chip\n size=\"small\"\n label={p.paymentMode}\n sx={{\n fontWeight: 700, borderRadius: 1.5, height: 22,\n bgcolor: alpha(theme.palette.primary.main, 0.08),\n color: 'primary.dark',\n border: `1px solid ${alpha(theme.palette.primary.main, 0.18)}`,\n }}\n />\n ) : <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>}\n </TableCell>\n ) : null}\n {manageAmounts ? (\n <TableCell align=\"right\"><PmMoney value={p.totalAmount} /></TableCell>\n ) : null}\n <TableCell sx={{ maxWidth: 320 }}>\n {p.notes ? (\n <Typography variant=\"caption\" color=\"text.secondary\"\n sx={{ display: 'block', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {p.notes}\n </Typography>\n ) : <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>}\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </PmTable>\n </PmTableCard>\n </PmPageShell>\n </PmGuard>\n </Box>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { t as le } from "./MemberProfileCard-DbHZCS5n.js";
|
|
1
|
+
import { D as e, F as t, a as n, b as r, i, j as ee, l as te, n as ne, o as re, r as ie, t as ae } from "./currency-ClRLIEg2.js";
|
|
2
|
+
import { r as a } from "./PmTable-B9970kPY.js";
|
|
3
|
+
import { d as o, m as s, o as oe, t as c } from "./validation-Ba7puFIO.js";
|
|
4
|
+
import { t as se } from "./useFieldErrors-hDG8ox_x.js";
|
|
5
|
+
import { i as l, r as u } from "./format-UOyOu75i.js";
|
|
6
|
+
import { n as ce } from "./constants-5ZCZo-Zm.js";
|
|
7
|
+
import { t as le } from "./MemberProfileCard-0vjO3Gzd.js";
|
|
9
8
|
import { useMemo as d, useState as f } from "react";
|
|
10
9
|
import { Fragment as ue, jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
11
10
|
import { v4 as h } from "uuid";
|
|
@@ -25,7 +24,7 @@ function A() {
|
|
|
25
24
|
};
|
|
26
25
|
}
|
|
27
26
|
function j() {
|
|
28
|
-
let j = ge(), { memberId: M } = _e(), N =
|
|
27
|
+
let j = ge(), { memberId: M } = _e(), N = ae(te()?.currencyCode), [P, be] = f([]), [F, xe] = f([]), [Se, Ce] = f({}), [I, we] = f(""), [L, R] = f(""), Te = n().has("view.manage.productManagement.dues"), z = se(), Ee = (/* @__PURE__ */ new Date()).toISOString().substring(0, 10), [B, V] = f({
|
|
29
28
|
id: h(),
|
|
30
29
|
saleDate: Ee,
|
|
31
30
|
paymentMode: "CASH",
|
|
@@ -33,24 +32,24 @@ function j() {
|
|
|
33
32
|
notes: "",
|
|
34
33
|
items: [A()]
|
|
35
34
|
});
|
|
36
|
-
|
|
37
|
-
async function
|
|
35
|
+
i("update.manage.productManagement.sale", () => {
|
|
36
|
+
async function n() {
|
|
38
37
|
try {
|
|
39
|
-
let [r, i
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
Te ?
|
|
38
|
+
let [n, r, i] = await Promise.all([
|
|
39
|
+
t(),
|
|
40
|
+
ee().catch(() => []),
|
|
41
|
+
Te ? e().catch(() => []) : Promise.resolve([])
|
|
43
42
|
]);
|
|
44
|
-
be(
|
|
43
|
+
be(n), xe(r), Ce(Object.fromEntries((i ?? []).map((e) => [e.memberId, Number(e.totalDue)])));
|
|
45
44
|
} catch (e) {
|
|
46
45
|
R(e?.response?.data?.message ?? e?.message ?? "Failed to load reference data");
|
|
47
46
|
}
|
|
48
47
|
}
|
|
49
|
-
|
|
48
|
+
n();
|
|
50
49
|
}, []);
|
|
51
50
|
let H = (e) => P.find((t) => t.id === e), U = d(() => {
|
|
52
51
|
let e = new Set(F.filter((e) => e.notForSale === !0).map((e) => e.id));
|
|
53
|
-
return P.filter((t) => !(t.qtyRemaining <= 0 || t.isQuarantined || e.has(t.productId) ||
|
|
52
|
+
return P.filter((t) => !(t.qtyRemaining <= 0 || t.isQuarantined || e.has(t.productId) || l(t.expiryDate)));
|
|
54
53
|
}, [P, F]);
|
|
55
54
|
function W(e, t, n) {
|
|
56
55
|
V((r) => {
|
|
@@ -65,30 +64,30 @@ function j() {
|
|
|
65
64
|
});
|
|
66
65
|
}
|
|
67
66
|
let G = d(() => B.items.reduce((e, t) => !t.salePrice || !t.quantity ? e : e + Number(t.salePrice) * Number(t.quantity), 0), [B.items]), K = Number(M ? Se[M] ?? 0 : 0), De = Number(B.collectingNow || 0), q = Math.min(Math.max(De, 0), G), J = Math.max(G - q, 0), Y = J + K, X = {
|
|
68
|
-
saleDate:
|
|
67
|
+
saleDate: s(B.saleDate, "Sale date"),
|
|
69
68
|
member: M ? "" : "No member selected"
|
|
70
|
-
}, Z = B.collectingNow === "" ? "" :
|
|
69
|
+
}, Z = B.collectingNow === "" ? "" : o(B.collectingNow);
|
|
71
70
|
!Z && B.collectingNow !== "" && Number(B.collectingNow) > G ? X.collectingNow = `Cannot collect more than the sale amount (${u(G)}). Settle old dues via Payments.` : Z && (X.collectingNow = Z);
|
|
72
71
|
let Oe = new Set(U.map((e) => e.id)), Q = B.items.map((e) => {
|
|
73
|
-
let t = H(e.batchId), n =
|
|
72
|
+
let t = H(e.batchId), n = oe(e.quantity, "Quantity", {
|
|
74
73
|
required: !0,
|
|
75
74
|
min: 1
|
|
76
75
|
});
|
|
77
76
|
!n && t && Number(e.quantity) > t.qtyRemaining && (n = `Only ${t.qtyRemaining} available in selected batch`);
|
|
78
|
-
let r =
|
|
77
|
+
let r = s(e.batchId, "Batch");
|
|
79
78
|
return !r && e.batchId && !Oe.has(e.batchId) && (r = "Batch is not available for sale (expired, quarantined, out of stock, or not-for-sale)."), {
|
|
80
79
|
batchId: r,
|
|
81
80
|
quantity: n,
|
|
82
|
-
salePrice:
|
|
81
|
+
salePrice: o(e.salePrice) || s(e.salePrice, "Unit price")
|
|
83
82
|
};
|
|
84
|
-
}), $ =
|
|
83
|
+
}), $ = c(X) && Q.every(c) && B.items.length > 0 && G > 0;
|
|
85
84
|
async function ke() {
|
|
86
85
|
if (!$) {
|
|
87
86
|
z.markAllTouched(), R("Please fix the highlighted fields and try again.");
|
|
88
87
|
return;
|
|
89
88
|
}
|
|
90
89
|
try {
|
|
91
|
-
await
|
|
90
|
+
await r({
|
|
92
91
|
id: B.id,
|
|
93
92
|
saleDate: B.saleDate,
|
|
94
93
|
memberId: M,
|
|
@@ -114,10 +113,10 @@ function j() {
|
|
|
114
113
|
R(e?.response?.data?.message ?? e?.message ?? "Failed to record sale");
|
|
115
114
|
}
|
|
116
115
|
}
|
|
117
|
-
return /* @__PURE__ */ m(de, { children: [/* @__PURE__ */ p(
|
|
116
|
+
return /* @__PURE__ */ m(de, { children: [/* @__PURE__ */ p(ie, {}), /* @__PURE__ */ p(ne, {
|
|
118
117
|
perm: "update.manage.productManagement.sale",
|
|
119
118
|
title: "You don’t have permission to record sales",
|
|
120
|
-
children: /* @__PURE__ */ m(
|
|
119
|
+
children: /* @__PURE__ */ m(re, {
|
|
121
120
|
title: "Record Sale",
|
|
122
121
|
actions: /* @__PURE__ */ m(D, {
|
|
123
122
|
direction: "row",
|
|
@@ -150,7 +149,7 @@ function j() {
|
|
|
150
149
|
},
|
|
151
150
|
children: /* @__PURE__ */ m(y, {
|
|
152
151
|
sx: { p: 2.5 },
|
|
153
|
-
children: [/* @__PURE__ */ p(
|
|
152
|
+
children: [/* @__PURE__ */ p(a, {
|
|
154
153
|
eyebrow: "Step 1",
|
|
155
154
|
title: "Customer",
|
|
156
155
|
hint: "The customer is set from the link you opened. Their balance shows below.",
|
|
@@ -182,7 +181,7 @@ function j() {
|
|
|
182
181
|
justifyContent: "space-between",
|
|
183
182
|
alignItems: "flex-start",
|
|
184
183
|
sx: { mb: 2 },
|
|
185
|
-
children: [/* @__PURE__ */ p(
|
|
184
|
+
children: [/* @__PURE__ */ p(a, {
|
|
186
185
|
eyebrow: "Step 2",
|
|
187
186
|
title: "Line items",
|
|
188
187
|
hint: "Each item comes from a batch. Buy price is shown as a cost reference."
|
|
@@ -344,7 +343,7 @@ function j() {
|
|
|
344
343
|
children: /* @__PURE__ */ m(y, {
|
|
345
344
|
sx: { p: 2.5 },
|
|
346
345
|
children: [
|
|
347
|
-
/* @__PURE__ */ p(
|
|
346
|
+
/* @__PURE__ */ p(a, {
|
|
348
347
|
eyebrow: "Step 3",
|
|
349
348
|
title: "Bill summary",
|
|
350
349
|
hint: "Shows totals, previous balance, and what you're collecting. Any remainder becomes a note of what they owe.",
|
|
@@ -545,4 +544,4 @@ function j() {
|
|
|
545
544
|
//#endregion
|
|
546
545
|
export { j as default };
|
|
547
546
|
|
|
548
|
-
//# sourceMappingURL=SaleCreatePage-
|
|
547
|
+
//# sourceMappingURL=SaleCreatePage-DP1Qmltu.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SaleCreatePage-DpkQMoTq.js","names":[],"sources":["../src/views/SaleCreatePage.jsx"],"sourcesContent":["import { useMemo, useState } from \"react\";\nimport { useNavigate, useParams } from \"react-router-dom\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport {\n Alert,\n Box,\n Button,\n Card,\n CardContent,\n Divider,\n FormControl,\n FormHelperText,\n Grid,\n IconButton,\n InputAdornment,\n InputLabel,\n MenuItem,\n Select,\n Stack,\n TextField,\n Typography,\n} from \"@mui/material\";\nimport AddRoundedIcon from \"@mui/icons-material/AddRounded\";\nimport DeleteOutlineRoundedIcon from \"@mui/icons-material/DeleteOutlineRounded\";\nimport SaveRoundedIcon from \"@mui/icons-material/SaveRounded\";\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 createSale,\n getMemberOutstandingDues,\n getProducts,\n listBatches,\n} from \"@pm/services/pmApi\";\nimport MemberProfileCard from \"@pm/components/MemberProfileCard\";\nimport { PAYMENT_MODES } from \"@pm/utils/constants\";\nimport { formatNumber, isPastExpiry } from \"@pm/utils/format\";\nimport { currencySymbol } from \"@pm/utils/currency\";\nimport { usePmSettings } from \"@pm/utils/settingsStore\";\nimport { PmFormSection } from \"@pm/components/PmTable\";\nimport {\n isClean,\n validateInteger,\n validatePrice,\n validateRequired,\n} from \"@pm/utils/validation\";\nimport { useFieldErrors } from \"@pm/utils/useFieldErrors\";\n\nfunction emptyLine() {\n return { key: uuidv4(), batchId: \"\", quantity: 1, salePrice: \"\" };\n}\n\nexport default function SaleCreatePage() {\n const navigate = useNavigate();\n const { memberId } = useParams();\n const settings = usePmSettings();\n const cur = currencySymbol(settings?.currencyCode);\n const [batches, setBatches] = useState([]);\n const [products, setProducts] = useState([]);\n // Map of memberId -> previousDue. The dues endpoint only returns members\n // with non-zero dues so the map stays small. Looked up by route memberId.\n const [duesByMember, setDuesByMember] = useState({});\n // Cached after MemberProfileCard fetches — used by the warning Alert that\n // references the member by name when remaining dues will be recorded.\n const [memberName, setMemberName] = useState(\"\");\n const [error, setError] = useState(\"\");\n const perms = usePmPermissions();\n // When the operator can't see dues, previousDue gracefully degrades to 0\n // instead of populating duesByMember from a 403'ing call.\n const canSeeDues = perms.has(\"view.manage.productManagement.dues\");\n const fieldErrors = useFieldErrors();\n const today = new Date().toISOString().substring(0, 10);\n const [form, setForm] = useState({\n id: uuidv4(),\n saleDate: today,\n paymentMode: \"CASH\",\n collectingNow: \"\",\n notes: \"\",\n items: [emptyLine()],\n });\n\n usePermissionedEffect(\n \"update.manage.productManagement.sale\",\n () => {\n async function load() {\n try {\n // Members are picked via async search now — no upfront load. Dues\n // come from the (aggregated) backend query and get attached to a\n // picked member by id.\n const [b, p, dues] = await Promise.all([\n listBatches(),\n getProducts().catch(() => []),\n // Silent degrade when the operator lacks the dues permission —\n // previousDue will stay 0 and the sale itself still works.\n canSeeDues\n ? getMemberOutstandingDues().catch(() => [])\n : Promise.resolve([]),\n ]);\n setBatches(b);\n setProducts(p);\n setDuesByMember(\n Object.fromEntries(\n (dues ?? []).map((d) => [d.memberId, Number(d.totalDue)]),\n ),\n );\n } catch (err) {\n setError(\n err?.response?.data?.message ??\n err?.message ??\n \"Failed to load reference data\",\n );\n }\n }\n void load();\n },\n [],\n );\n\n const batchById = (id) => batches.find((b) => b.id === id);\n\n // Batches that can be sold: stock on hand, not quarantined, not past expiry, and\n // the underlying product is not flagged as not-for-sale. Computed once per render.\n const sellableBatches = useMemo(() => {\n const notForSaleProductIds = new Set(\n products.filter((p) => p.notForSale === true).map((p) => p.id),\n );\n return batches.filter((b) => {\n if (b.qtyRemaining <= 0) return false;\n if (b.isQuarantined) return false;\n if (notForSaleProductIds.has(b.productId)) return false;\n // A batch is sellable on the day of its printed expiry; only the\n // following day counts as expired (matches the unit packaging rule).\n if (isPastExpiry(b.expiryDate)) return false;\n return true;\n });\n }, [batches, products]);\n\n function patchLine(idx, k, v) {\n setForm((f) => {\n const items = f.items.slice();\n items[idx] = { ...items[idx], [k]: v };\n return { ...f, items };\n });\n }\n\n // -------- Money math --------\n const saleAmount = useMemo(\n () =>\n form.items.reduce((sum, line) => {\n if (!line.salePrice || !line.quantity) return sum;\n return sum + Number(line.salePrice) * Number(line.quantity);\n }, 0),\n [form.items],\n );\n\n const previousDue = Number(memberId ? (duesByMember[memberId] ?? 0) : 0);\n const collectedRaw = Number(form.collectingNow || 0);\n // Clip the collected amount at the current sale's total — anything more would\n // need to be applied to the member's old dues, which is a separate Payment flow.\n const collected = Math.min(Math.max(collectedRaw, 0), saleAmount);\n const saleDue = Math.max(saleAmount - collected, 0);\n const remainingDue = saleDue + previousDue;\n\n // -------- Validation --------\n const headerErrors = {\n saleDate: validateRequired(form.saleDate, \"Sale date\"),\n member: memberId ? \"\" : \"No member selected\",\n };\n // Collecting Now: optional; if filled, must be a non-negative number ≤ sale amount.\n const collectingErr =\n form.collectingNow === \"\" ? \"\" : validatePrice(form.collectingNow);\n if (\n !collectingErr &&\n form.collectingNow !== \"\" &&\n Number(form.collectingNow) > saleAmount\n ) {\n headerErrors.collectingNow = `Cannot collect more than the sale amount (${formatNumber(saleAmount)}). Settle old dues via Payments.`;\n } else if (collectingErr) {\n headerErrors.collectingNow = collectingErr;\n }\n\n const sellableBatchIds = new Set(sellableBatches.map((b) => b.id));\n const lineErrors = form.items.map((line) => {\n const batch = batchById(line.batchId);\n const qty = validateInteger(line.quantity, \"Quantity\", {\n required: true,\n min: 1,\n });\n let qtyErr = qty;\n if (!qtyErr && batch && Number(line.quantity) > batch.qtyRemaining) {\n qtyErr = `Only ${batch.qtyRemaining} available in selected batch`;\n }\n let batchErr = validateRequired(line.batchId, \"Batch\");\n if (!batchErr && line.batchId && !sellableBatchIds.has(line.batchId)) {\n batchErr =\n \"Batch is not available for sale (expired, quarantined, out of stock, or not-for-sale).\";\n }\n return {\n batchId: batchErr,\n quantity: qtyErr,\n salePrice:\n validatePrice(line.salePrice) ||\n validateRequired(line.salePrice, \"Unit price\"),\n };\n });\n const formIsValid =\n isClean(headerErrors) &&\n lineErrors.every(isClean) &&\n form.items.length > 0 &&\n saleAmount > 0;\n\n async function save() {\n if (!formIsValid) {\n fieldErrors.markAllTouched();\n setError(\"Please fix the highlighted fields and try again.\");\n return;\n }\n try {\n await createSale({\n id: form.id,\n saleDate: form.saleDate,\n memberId,\n paymentMode: form.paymentMode || null,\n totalAmount: Number(saleAmount.toFixed(2)),\n paidAmount: Number(collected.toFixed(2)),\n dueAmount: Number(saleDue.toFixed(2)),\n notes: form.notes || null,\n items: form.items.map((l) => {\n const batch = batchById(l.batchId);\n return {\n batchId: l.batchId,\n productId: batch?.productId,\n quantity: Number(l.quantity),\n salePrice: Number(l.salePrice),\n };\n }),\n });\n showToast({ message: \"Sale recorded.\", type: \"success\" });\n navigate(\"/ui/medplat/manage/pm/sales\");\n } catch (err) {\n setError(\n err?.response?.data?.message ?? err?.message ?? \"Failed to record sale\",\n );\n }\n }\n\n return (\n <Box>\n <PmNav />\n <PmGuard\n perm={\"update.manage.productManagement.sale\"}\n title=\"You don’t have permission to record sales\"\n >\n <PmPageShell\n title=\"Record Sale\"\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button\n variant=\"outlined\"\n onClick={() => navigate(\"/ui/medplat/manage/pm/sales\")}\n >\n Cancel\n </Button>\n <Button\n variant=\"contained\"\n startIcon={<SaveRoundedIcon />}\n disabled={!formIsValid}\n onClick={() => void save()}\n >\n Save\n </Button>\n </Stack>\n }\n >\n {error ? (\n <Alert severity=\"error\" sx={{ mb: 2 }}>\n {error}\n </Alert>\n ) : null}\n\n {/* ---------- Member ---------- */}\n <Card\n sx={{\n borderRadius: 4,\n mb: 2,\n border: \"1px solid\",\n borderColor: \"divider\",\n boxShadow: \"0 12px 32px rgba(15, 23, 42, 0.045)\",\n }}\n >\n <CardContent sx={{ p: 2.5 }}>\n <PmFormSection\n eyebrow=\"Step 1\"\n title=\"Customer\"\n hint=\"The customer is set from the link you opened. Their balance shows below.\"\n sx={{ mb: 2 }}\n />\n {memberId ? (\n <MemberProfileCard\n memberId={memberId}\n previousDue={previousDue}\n currencySymbol={cur}\n onLoad={(p) => setMemberName(p?.name ?? \"\")}\n />\n ) : (\n <Alert severity=\"warning\">No member selected</Alert>\n )}\n </CardContent>\n </Card>\n\n {/* ---------- Line items ---------- */}\n <Card\n sx={{\n borderRadius: 4,\n mb: 2,\n border: \"1px solid\",\n borderColor: \"divider\",\n boxShadow: \"0 12px 32px rgba(15, 23, 42, 0.045)\",\n }}\n >\n <CardContent sx={{ p: 2.5 }}>\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"flex-start\"\n sx={{ mb: 2 }}\n >\n <PmFormSection\n eyebrow=\"Step 2\"\n title=\"Line items\"\n hint=\"Each item comes from a batch. Buy price is shown as a cost reference.\"\n />\n <Button\n variant=\"outlined\"\n startIcon={<AddRoundedIcon />}\n onClick={() =>\n setForm({ ...form, items: [...form.items, emptyLine()] })\n }\n >\n Add Line\n </Button>\n </Stack>\n <Divider sx={{ mb: 2 }} />\n <Stack spacing={2}>\n {form.items.map((line, idx) => {\n const batch = batchById(line.batchId);\n const lerr = lineErrors[idx] || {};\n const subtotal =\n line.salePrice && line.quantity\n ? Number(line.salePrice) * Number(line.quantity)\n : 0;\n return (\n <Card\n key={line.key}\n variant=\"outlined\"\n sx={{ p: 2, borderRadius: 3 }}\n >\n <Grid container spacing={2} alignItems=\"center\">\n <Grid item xs={12} md={5}>\n <FormControl\n required\n fullWidth\n size=\"small\"\n error={\n fieldErrors.show(`items.${idx}.batchId`) &&\n !!lerr.batchId\n }\n >\n <InputLabel>Batch</InputLabel>\n <Select\n label=\"Batch\"\n value={line.batchId}\n onChange={(e) =>\n patchLine(idx, \"batchId\", e.target.value)\n }\n onBlur={fieldErrors.onBlur(\n `items.${idx}.batchId`,\n )}\n >\n {sellableBatches.map((b) => (\n <MenuItem key={b.id} value={b.id}>\n {b.productName} · lot {b.lotNumber || \"—\"} ·{\" \"}\n {b.qtyRemaining} left\n </MenuItem>\n ))}\n </Select>\n <FormHelperText>\n {fieldErrors.show(`items.${idx}.batchId`) &&\n lerr.batchId\n ? lerr.batchId\n : batch?.buyPrice != null\n ? `Buy price: ${cur}${formatNumber(batch.buyPrice)} / unit`\n : \" \"}\n </FormHelperText>\n </FormControl>\n </Grid>\n <Grid item xs={6} md={2}>\n <TextField\n required\n fullWidth\n size=\"small\"\n type=\"number\"\n label=\"Qty\"\n inputProps={{ min: 1, max: batch?.qtyRemaining }}\n value={line.quantity}\n onChange={(e) =>\n patchLine(idx, \"quantity\", e.target.value)\n }\n onBlur={fieldErrors.onBlur(`items.${idx}.quantity`)}\n error={\n fieldErrors.show(`items.${idx}.quantity`) &&\n !!lerr.quantity\n }\n helperText={\n fieldErrors.show(`items.${idx}.quantity`)\n ? lerr.quantity\n : \"\"\n }\n />\n </Grid>\n <Grid item xs={6} md={2}>\n <TextField\n required\n fullWidth\n size=\"small\"\n type=\"number\"\n inputProps={{ step: \"0.01\", min: 0 }}\n label=\"Unit Price\"\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">\n {cur}\n </InputAdornment>\n ),\n }}\n value={line.salePrice}\n onChange={(e) =>\n patchLine(idx, \"salePrice\", e.target.value)\n }\n onBlur={fieldErrors.onBlur(\n `items.${idx}.salePrice`,\n )}\n error={\n fieldErrors.show(`items.${idx}.salePrice`) &&\n !!lerr.salePrice\n }\n helperText={\n fieldErrors.show(`items.${idx}.salePrice`)\n ? lerr.salePrice\n : \"\"\n }\n />\n </Grid>\n <Grid item xs={6} md={2} sx={{ textAlign: \"right\" }}>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: \"block\" }}\n >\n Subtotal\n </Typography>\n <Typography\n variant=\"body1\"\n sx={{\n fontWeight: 800,\n fontVariantNumeric: \"tabular-nums\",\n }}\n >\n {cur}\n {formatNumber(subtotal)}\n </Typography>\n </Grid>\n <Grid item xs={6} md={1} sx={{ textAlign: \"right\" }}>\n <IconButton\n color=\"error\"\n onClick={() =>\n setForm({\n ...form,\n items: form.items.filter((_, i) => i !== idx),\n })\n }\n disabled={form.items.length === 1}\n >\n <DeleteOutlineRoundedIcon />\n </IconButton>\n </Grid>\n </Grid>\n </Card>\n );\n })}\n </Stack>\n </CardContent>\n </Card>\n\n {/* ---------- Bill Summary footer ---------- */}\n <Card\n sx={{\n borderRadius: 4,\n bgcolor: \"grey.50\",\n border: \"1px solid\",\n borderColor: \"divider\",\n boxShadow: \"0 12px 32px rgba(15, 23, 42, 0.045)\",\n }}\n >\n <CardContent sx={{ p: 2.5 }}>\n <PmFormSection\n eyebrow=\"Step 3\"\n title=\"Bill summary\"\n hint=\"Shows totals, previous balance, and what you're collecting. Any remainder becomes a note of what they owe.\"\n sx={{ mb: 2 }}\n />\n <Grid container spacing={2}>\n <Grid item xs={12} md={4}>\n <TextField\n required\n fullWidth\n size=\"small\"\n type=\"date\"\n label=\"Date\"\n InputLabelProps={{ shrink: true }}\n value={form.saleDate}\n onChange={(e) =>\n setForm({ ...form, saleDate: e.target.value })\n }\n onBlur={fieldErrors.onBlur(\"saleDate\")}\n error={\n fieldErrors.show(\"saleDate\") && !!headerErrors.saleDate\n }\n helperText={\n fieldErrors.show(\"saleDate\") ? headerErrors.saleDate : \"\"\n }\n />\n </Grid>\n <Grid item xs={12} md={4}>\n <FormControl fullWidth size=\"small\">\n <InputLabel>Payment Mode</InputLabel>\n <Select\n label=\"Payment Mode\"\n value={form.paymentMode || \"\"}\n onChange={(e) =>\n setForm({ ...form, paymentMode: e.target.value })\n }\n >\n <MenuItem value=\"\">\n <em>—</em>\n </MenuItem>\n {PAYMENT_MODES.map((m) => (\n <MenuItem key={m.value} value={m.value}>\n {m.label}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n </Grid>\n <Grid item xs={12} md={4}>\n <TextField\n fullWidth\n size=\"small\"\n label=\"Notes\"\n value={form.notes}\n onChange={(e) =>\n setForm({ ...form, notes: e.target.value })\n }\n />\n </Grid>\n </Grid>\n\n <Divider sx={{ my: 2 }} />\n\n <Stack spacing={1.25}>\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"baseline\"\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n Sale Amount ({form.items.length}{\" \"}\n {form.items.length === 1 ? \"line\" : \"lines\"})\n </Typography>\n <Typography\n variant=\"h5\"\n sx={{ fontWeight: 800, fontVariantNumeric: \"tabular-nums\" }}\n >\n {cur}\n {formatNumber(saleAmount)}\n </Typography>\n </Stack>\n\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"baseline\"\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n Previous Due\n </Typography>\n <Typography\n variant=\"body1\"\n sx={{\n fontWeight: 700,\n fontVariantNumeric: \"tabular-nums\",\n color: previousDue > 0 ? \"warning.dark\" : \"text.primary\",\n }}\n >\n {cur}\n {formatNumber(previousDue)}\n </Typography>\n </Stack>\n\n <Divider sx={{ my: 0.5 }} />\n\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n spacing={2}\n >\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ flexShrink: 0 }}\n >\n Amount Collecting Now\n </Typography>\n <TextField\n size=\"small\"\n type=\"number\"\n inputProps={{\n step: \"0.01\",\n min: 0,\n max: saleAmount,\n style: { textAlign: \"right\", fontWeight: 700 },\n }}\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">{cur}</InputAdornment>\n ),\n }}\n sx={{ width: 200 }}\n value={form.collectingNow}\n placeholder=\"0.00\"\n onChange={(e) =>\n setForm({ ...form, collectingNow: e.target.value })\n }\n onBlur={fieldErrors.onBlur(\"collectingNow\")}\n error={\n fieldErrors.show(\"collectingNow\") &&\n !!headerErrors.collectingNow\n }\n helperText={\n fieldErrors.show(\"collectingNow\")\n ? headerErrors.collectingNow\n : \"\"\n }\n />\n </Stack>\n\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"baseline\"\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n Remaining Due (after this sale)\n </Typography>\n <Typography\n variant=\"h5\"\n sx={{\n fontWeight: 800,\n fontVariantNumeric: \"tabular-nums\",\n color: remainingDue > 0 ? \"warning.dark\" : \"success.dark\",\n }}\n >\n {cur}\n {formatNumber(remainingDue)}\n </Typography>\n </Stack>\n </Stack>\n\n {memberId && remainingDue > 0 ? (\n <Alert severity=\"warning\" sx={{ mt: 2 }}>\n {cur}\n {formatNumber(remainingDue)} will be recorded as pending dues\n {memberName ? (\n <>\n {\" \"}\n for <strong>{memberName}</strong>\n </>\n ) : null}\n {saleDue > 0 && previousDue > 0\n ? ` (${cur}${formatNumber(saleDue)} from this sale + ${cur}${formatNumber(previousDue)} previously outstanding).`\n : saleDue > 0\n ? \" from this sale.\"\n : \" from previously outstanding dues.\"}\n </Alert>\n ) : null}\n </CardContent>\n </Card>\n </PmPageShell>\n </PmGuard>\n </Box>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkDA,SAAS,IAAY;CACnB,OAAO;EAAE,KAAK,EAAO;EAAG,SAAS;EAAI,UAAU;EAAG,WAAW;CAAG;AAClE;AAEA,SAAwB,IAAiB;CACvC,IAAM,IAAW,GAAY,GACvB,EAAE,gBAAa,GAAU,GAEzB,IAAM,GADK,EACU,GAAU,YAAY,GAC3C,CAAC,GAAS,MAAc,EAAS,CAAC,CAAC,GACnC,CAAC,GAAU,MAAe,EAAS,CAAC,CAAC,GAGrC,CAAC,IAAc,MAAmB,EAAS,CAAC,CAAC,GAG7C,CAAC,GAAY,MAAiB,EAAS,EAAE,GACzC,CAAC,GAAO,KAAY,EAAS,EAAE,GAI/B,KAHQ,EAGK,EAAM,IAAI,oCAAoC,GAC3D,IAAc,GAAe,GAC7B,sBAAQ,IAAI,KAAK,GAAE,YAAY,EAAE,UAAU,GAAG,EAAE,GAChD,CAAC,GAAM,KAAW,EAAS;EAC/B,IAAI,EAAO;EACX,UAAU;EACV,aAAa;EACb,eAAe;EACf,OAAO;EACP,OAAO,CAAC,EAAU,CAAC;CACrB,CAAC;CAED,GACE,8CACM;EACJ,eAAe,IAAO;GACpB,IAAI;IAIF,IAAM,CAAC,GAAG,GAAG,KAAQ,MAAM,QAAQ,IAAI;KACrC,EAAY;KACZ,EAAY,EAAE,YAAY,CAAC,CAAC;KAG5B,KACI,EAAyB,EAAE,YAAY,CAAC,CAAC,IACzC,QAAQ,QAAQ,CAAC,CAAC;IACxB,CAAC;IAGD,AAFA,GAAW,CAAC,GACZ,GAAY,CAAC,GACb,GACE,OAAO,aACJ,KAAQ,CAAC,GAAG,KAAK,MAAM,CAAC,EAAE,UAAU,OAAO,EAAE,QAAQ,CAAC,CAAC,CAC1D,CACF;GACF,SAAS,GAAK;IACZ,EACE,GAAK,UAAU,MAAM,WACnB,GAAK,WACL,+BACJ;GACF;EACF;EACA,EAAU;CACZ,GACA,CAAC,CACH;CAEA,IAAM,KAAa,MAAO,EAAQ,MAAM,MAAM,EAAE,OAAO,CAAE,GAInD,IAAkB,QAAc;EACpC,IAAM,IAAuB,IAAI,IAC/B,EAAS,QAAQ,MAAM,EAAE,eAAe,EAAI,EAAE,KAAK,MAAM,EAAE,EAAE,CAC/D;EACA,OAAO,EAAQ,QAAQ,MAMrB,EALI,EAAE,gBAAgB,KAClB,EAAE,iBACF,EAAqB,IAAI,EAAE,SAAS,KAGpC,GAAa,EAAE,UAAU,EAE9B;CACH,GAAG,CAAC,GAAS,CAAQ,CAAC;CAEtB,SAAS,EAAU,GAAK,GAAG,GAAG;EAC5B,GAAS,MAAM;GACb,IAAM,IAAQ,EAAE,MAAM,MAAM;GAE5B,OADA,EAAM,KAAO;IAAE,GAAG,EAAM;KAAO,IAAI;GAAE,GAC9B;IAAE,GAAG;IAAG;GAAM;EACvB,CAAC;CACH;CAGA,IAAM,IAAa,QAEf,EAAK,MAAM,QAAQ,GAAK,MAClB,CAAC,EAAK,aAAa,CAAC,EAAK,WAAiB,IACvC,IAAM,OAAO,EAAK,SAAS,IAAI,OAAO,EAAK,QAAQ,GACzD,CAAC,GACN,CAAC,EAAK,KAAK,CACb,GAEM,IAAc,OAAO,IAAY,GAAa,MAAa,IAAK,CAAC,GACjE,KAAe,OAAO,EAAK,iBAAiB,CAAC,GAG7C,IAAY,KAAK,IAAI,KAAK,IAAI,IAAc,CAAC,GAAG,CAAU,GAC1D,IAAU,KAAK,IAAI,IAAa,GAAW,CAAC,GAC5C,IAAe,IAAU,GAGzB,IAAe;EACnB,UAAU,EAAiB,EAAK,UAAU,WAAW;EACrD,QAAQ,IAAW,KAAK;CAC1B,GAEM,IACJ,EAAK,kBAAkB,KAAK,KAAK,EAAc,EAAK,aAAa;CACnE,AACE,CAAC,KACD,EAAK,kBAAkB,MACvB,OAAO,EAAK,aAAa,IAAI,IAE7B,EAAa,gBAAgB,6CAA6C,EAAa,CAAU,EAAE,oCAC1F,MACT,EAAa,gBAAgB;CAG/B,IAAM,KAAmB,IAAI,IAAI,EAAgB,KAAK,MAAM,EAAE,EAAE,CAAC,GAC3D,IAAa,EAAK,MAAM,KAAK,MAAS;EAC1C,IAAM,IAAQ,EAAU,EAAK,OAAO,GAKhC,IAJQ,GAAgB,EAAK,UAAU,YAAY;GACrD,UAAU;GACV,KAAK;EACP,CACa;EACb,AAAI,CAAC,KAAU,KAAS,OAAO,EAAK,QAAQ,IAAI,EAAM,iBACpD,IAAS,QAAQ,EAAM,aAAa;EAEtC,IAAI,IAAW,EAAiB,EAAK,SAAS,OAAO;EAKrD,OAJI,CAAC,KAAY,EAAK,WAAW,CAAC,GAAiB,IAAI,EAAK,OAAO,MACjE,IACE,2FAEG;GACL,SAAS;GACT,UAAU;GACV,WACE,EAAc,EAAK,SAAS,KAC5B,EAAiB,EAAK,WAAW,YAAY;EACjD;CACF,CAAC,GACK,IACJ,EAAQ,CAAY,KACpB,EAAW,MAAM,CAAO,KACxB,EAAK,MAAM,SAAS,KACpB,IAAa;CAEf,eAAe,KAAO;EACpB,IAAI,CAAC,GAAa;GAEhB,AADA,EAAY,eAAe,GAC3B,EAAS,kDAAkD;GAC3D;EACF;EACA,IAAI;GAqBF,AApBA,MAAM,GAAW;IACf,IAAI,EAAK;IACT,UAAU,EAAK;IACf;IACA,aAAa,EAAK,eAAe;IACjC,aAAa,OAAO,EAAW,QAAQ,CAAC,CAAC;IACzC,YAAY,OAAO,EAAU,QAAQ,CAAC,CAAC;IACvC,WAAW,OAAO,EAAQ,QAAQ,CAAC,CAAC;IACpC,OAAO,EAAK,SAAS;IACrB,OAAO,EAAK,MAAM,KAAK,MAAM;KAC3B,IAAM,IAAQ,EAAU,EAAE,OAAO;KACjC,OAAO;MACL,SAAS,EAAE;MACX,WAAW,GAAO;MAClB,UAAU,OAAO,EAAE,QAAQ;MAC3B,WAAW,OAAO,EAAE,SAAS;KAC/B;IACF,CAAC;GACH,CAAC,GACD,GAAU;IAAE,SAAS;IAAkB,MAAM;GAAU,CAAC,GACxD,EAAS,6BAA6B;EACxC,SAAS,GAAK;GACZ,EACE,GAAK,UAAU,MAAM,WAAW,GAAK,WAAW,uBAClD;EACF;CACF;CAEA,OACE,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,IAAD,CAAQ,CAAA,GACR,kBAAC,IAAD;EACE,MAAM;EACN,OAAM;YAEN,kBAAC,GAAD;GACE,OAAM;GACN,SACE,kBAAC,GAAD;IAAO,WAAU;IAAM,SAAS;cAAhC,CACE,kBAAC,GAAD;KACE,SAAQ;KACR,eAAe,EAAS,6BAA6B;eACtD;IAEO,CAAA,GACR,kBAAC,GAAD;KACE,SAAQ;KACR,WAAW,kBAAC,IAAD,CAAkB,CAAA;KAC7B,UAAU,CAAC;KACX,eAAe,KAAK,GAAK;eAC1B;IAEO,CAAA,CACH;;aAlBX;IAqBG,IACC,kBAAC,GAAD;KAAO,UAAS;KAAQ,IAAI,EAAE,IAAI,EAAE;eACjC;IACI,CAAA,IACL;IAGJ,kBAAC,GAAD;KACE,IAAI;MACF,cAAc;MACd,IAAI;MACJ,QAAQ;MACR,aAAa;MACb,WAAW;KACb;eAEA,kBAAC,GAAD;MAAa,IAAI,EAAE,GAAG,IAAI;gBAA1B,CACE,kBAAC,GAAD;OACE,SAAQ;OACR,OAAM;OACN,MAAK;OACL,IAAI,EAAE,IAAI,EAAE;MACb,CAAA,GACA,IACC,kBAAC,IAAD;OACY;OACG;OACb,gBAAgB;OAChB,SAAS,MAAM,GAAc,GAAG,QAAQ,EAAE;MAC3C,CAAA,IAED,kBAAC,GAAD;OAAO,UAAS;iBAAU;MAAyB,CAAA,CAE1C;;IACT,CAAA;IAGN,kBAAC,GAAD;KACE,IAAI;MACF,cAAc;MACd,IAAI;MACJ,QAAQ;MACR,aAAa;MACb,WAAW;KACb;eAEA,kBAAC,GAAD;MAAa,IAAI,EAAE,GAAG,IAAI;gBAA1B;OACE,kBAAC,GAAD;QACE,WAAU;QACV,gBAAe;QACf,YAAW;QACX,IAAI,EAAE,IAAI,EAAE;kBAJd,CAME,kBAAC,GAAD;SACE,SAAQ;SACR,OAAM;SACN,MAAK;QACN,CAAA,GACD,kBAAC,GAAD;SACE,SAAQ;SACR,WAAW,kBAAC,IAAD,CAAiB,CAAA;SAC5B,eACE,EAAQ;UAAE,GAAG;UAAM,OAAO,CAAC,GAAG,EAAK,OAAO,EAAU,CAAC;SAAE,CAAC;mBAE3D;QAEO,CAAA,CACH;;OACP,kBAAC,GAAD,EAAS,IAAI,EAAE,IAAI,EAAE,EAAI,CAAA;OACzB,kBAAC,GAAD;QAAO,SAAS;kBACb,EAAK,MAAM,KAAK,GAAM,MAAQ;SAC7B,IAAM,IAAQ,EAAU,EAAK,OAAO,GAC9B,IAAO,EAAW,MAAQ,CAAC,GAC3B,IACJ,EAAK,aAAa,EAAK,WACnB,OAAO,EAAK,SAAS,IAAI,OAAO,EAAK,QAAQ,IAC7C;SACN,OACE,kBAAC,GAAD;UAEE,SAAQ;UACR,IAAI;WAAE,GAAG;WAAG,cAAc;UAAE;oBAE5B,kBAAC,GAAD;WAAM,WAAA;WAAU,SAAS;WAAG,YAAW;qBAAvC;YACE,kBAAC,GAAD;aAAM,MAAA;aAAK,IAAI;aAAI,IAAI;uBACrB,kBAAC,GAAD;cACE,UAAA;cACA,WAAA;cACA,MAAK;cACL,OACE,EAAY,KAAK,SAAS,EAAI,SAAS,KACvC,CAAC,CAAC,EAAK;wBANX;eASE,kBAAC,GAAD,EAAA,UAAY,QAAiB,CAAA;eAC7B,kBAAC,GAAD;gBACE,OAAM;gBACN,OAAO,EAAK;gBACZ,WAAW,MACT,EAAU,GAAK,WAAW,EAAE,OAAO,KAAK;gBAE1C,QAAQ,EAAY,OAClB,SAAS,EAAI,SACf;0BAEC,EAAgB,KAAK,MACpB,kBAAC,GAAD;iBAAqB,OAAO,EAAE;2BAA9B;kBACG,EAAE;kBAAY;kBAAQ,EAAE,aAAa;kBAAI;kBAAG;kBAC5C,EAAE;kBAAa;iBACR;mBAHK,EAAE,EAGP,CACX;eACK,CAAA;eACR,kBAAC,IAAD,EAAA,UACG,EAAY,KAAK,SAAS,EAAI,SAAS,KACxC,EAAK,UACD,EAAK,UACL,GAAO,YAAY,OAEjB,MADA,cAAc,IAAM,EAAa,EAAM,QAAQ,EAAE,SAEzC,CAAA;cACL;;YACT,CAAA;YACN,kBAAC,GAAD;aAAM,MAAA;aAAK,IAAI;aAAG,IAAI;uBACpB,kBAAC,GAAD;cACE,UAAA;cACA,WAAA;cACA,MAAK;cACL,MAAK;cACL,OAAM;cACN,YAAY;eAAE,KAAK;eAAG,KAAK,GAAO;cAAa;cAC/C,OAAO,EAAK;cACZ,WAAW,MACT,EAAU,GAAK,YAAY,EAAE,OAAO,KAAK;cAE3C,QAAQ,EAAY,OAAO,SAAS,EAAI,UAAU;cAClD,OACE,EAAY,KAAK,SAAS,EAAI,UAAU,KACxC,CAAC,CAAC,EAAK;cAET,YACE,EAAY,KAAK,SAAS,EAAI,UAAU,IACpC,EAAK,WACL;aAEP,CAAA;YACG,CAAA;YACN,kBAAC,GAAD;aAAM,MAAA;aAAK,IAAI;aAAG,IAAI;uBACpB,kBAAC,GAAD;cACE,UAAA;cACA,WAAA;cACA,MAAK;cACL,MAAK;cACL,YAAY;eAAE,MAAM;eAAQ,KAAK;cAAE;cACnC,OAAM;cACN,YAAY,EACV,gBACE,kBAAC,GAAD;eAAgB,UAAS;yBACtB;cACa,CAAA,EAEpB;cACA,OAAO,EAAK;cACZ,WAAW,MACT,EAAU,GAAK,aAAa,EAAE,OAAO,KAAK;cAE5C,QAAQ,EAAY,OAClB,SAAS,EAAI,WACf;cACA,OACE,EAAY,KAAK,SAAS,EAAI,WAAW,KACzC,CAAC,CAAC,EAAK;cAET,YACE,EAAY,KAAK,SAAS,EAAI,WAAW,IACrC,EAAK,YACL;aAEP,CAAA;YACG,CAAA;YACN,kBAAC,GAAD;aAAM,MAAA;aAAK,IAAI;aAAG,IAAI;aAAG,IAAI,EAAE,WAAW,QAAQ;uBAAlD,CACE,kBAAC,GAAD;cACE,SAAQ;cACR,OAAM;cACN,IAAI,EAAE,SAAS,QAAQ;wBACxB;aAEW,CAAA,GACZ,kBAAC,GAAD;cACE,SAAQ;cACR,IAAI;eACF,YAAY;eACZ,oBAAoB;cACtB;wBALF,CAOG,GACA,EAAa,CAAQ,CACZ;eACR;;YACN,kBAAC,GAAD;aAAM,MAAA;aAAK,IAAI;aAAG,IAAI;aAAG,IAAI,EAAE,WAAW,QAAQ;uBAChD,kBAAC,IAAD;cACE,OAAM;cACN,eACE,EAAQ;eACN,GAAG;eACH,OAAO,EAAK,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAG;cAC9C,CAAC;cAEH,UAAU,EAAK,MAAM,WAAW;wBAEhC,kBAAC,IAAD,CAA2B,CAAA;aACjB,CAAA;YACR,CAAA;WACF;;SACF,GAtIC,EAAK,GAsIN;QAEV,CAAC;OACI,CAAA;MACI;;IACT,CAAA;IAGN,kBAAC,GAAD;KACE,IAAI;MACF,cAAc;MACd,SAAS;MACT,QAAQ;MACR,aAAa;MACb,WAAW;KACb;eAEA,kBAAC,GAAD;MAAa,IAAI,EAAE,GAAG,IAAI;gBAA1B;OACE,kBAAC,GAAD;QACE,SAAQ;QACR,OAAM;QACN,MAAK;QACL,IAAI,EAAE,IAAI,EAAE;OACb,CAAA;OACD,kBAAC,GAAD;QAAM,WAAA;QAAU,SAAS;kBAAzB;SACE,kBAAC,GAAD;UAAM,MAAA;UAAK,IAAI;UAAI,IAAI;oBACrB,kBAAC,GAAD;WACE,UAAA;WACA,WAAA;WACA,MAAK;WACL,MAAK;WACL,OAAM;WACN,iBAAiB,EAAE,QAAQ,GAAK;WAChC,OAAO,EAAK;WACZ,WAAW,MACT,EAAQ;YAAE,GAAG;YAAM,UAAU,EAAE,OAAO;WAAM,CAAC;WAE/C,QAAQ,EAAY,OAAO,UAAU;WACrC,OACE,EAAY,KAAK,UAAU,KAAK,CAAC,CAAC,EAAa;WAEjD,YACE,EAAY,KAAK,UAAU,IAAI,EAAa,WAAW;UAE1D,CAAA;SACG,CAAA;SACN,kBAAC,GAAD;UAAM,MAAA;UAAK,IAAI;UAAI,IAAI;oBACrB,kBAAC,GAAD;WAAa,WAAA;WAAU,MAAK;qBAA5B,CACE,kBAAC,GAAD,EAAA,UAAY,eAAwB,CAAA,GACpC,kBAAC,GAAD;YACE,OAAM;YACN,OAAO,EAAK,eAAe;YAC3B,WAAW,MACT,EAAQ;aAAE,GAAG;aAAM,aAAa,EAAE,OAAO;YAAM,CAAC;sBAJpD,CAOE,kBAAC,GAAD;aAAU,OAAM;uBACd,kBAAC,MAAD,EAAA,UAAI,IAAK,CAAA;YACD,CAAA,GACT,GAAc,KAAK,MAClB,kBAAC,GAAD;aAAwB,OAAO,EAAE;uBAC9B,EAAE;YACK,GAFK,EAAE,KAEP,CACX,CACK;aACG;;SACT,CAAA;SACN,kBAAC,GAAD;UAAM,MAAA;UAAK,IAAI;UAAI,IAAI;oBACrB,kBAAC,GAAD;WACE,WAAA;WACA,MAAK;WACL,OAAM;WACN,OAAO,EAAK;WACZ,WAAW,MACT,EAAQ;YAAE,GAAG;YAAM,OAAO,EAAE,OAAO;WAAM,CAAC;UAE7C,CAAA;SACG,CAAA;QACF;;OAEN,kBAAC,GAAD,EAAS,IAAI,EAAE,IAAI,EAAE,EAAI,CAAA;OAEzB,kBAAC,GAAD;QAAO,SAAS;kBAAhB;SACE,kBAAC,GAAD;UACE,WAAU;UACV,gBAAe;UACf,YAAW;oBAHb,CAKE,kBAAC,GAAD;WAAY,SAAQ;WAAQ,OAAM;qBAAlC;YAAmD;YACnC,EAAK,MAAM;YAAQ;YAChC,EAAK,MAAM,WAAW,IAAI,SAAS;YAAQ;WAClC;cACZ,kBAAC,GAAD;WACE,SAAQ;WACR,IAAI;YAAE,YAAY;YAAK,oBAAoB;WAAe;qBAF5D,CAIG,GACA,EAAa,CAAU,CACd;YACP;;SAEP,kBAAC,GAAD;UACE,WAAU;UACV,gBAAe;UACf,YAAW;oBAHb,CAKE,kBAAC,GAAD;WAAY,SAAQ;WAAQ,OAAM;qBAAiB;UAEvC,CAAA,GACZ,kBAAC,GAAD;WACE,SAAQ;WACR,IAAI;YACF,YAAY;YACZ,oBAAoB;YACpB,OAAO,IAAc,IAAI,iBAAiB;WAC5C;qBANF,CAQG,GACA,EAAa,CAAW,CACf;YACP;;SAEP,kBAAC,GAAD,EAAS,IAAI,EAAE,IAAI,GAAI,EAAI,CAAA;SAE3B,kBAAC,GAAD;UACE,WAAU;UACV,gBAAe;UACf,YAAW;UACX,SAAS;oBAJX,CAME,kBAAC,GAAD;WACE,SAAQ;WACR,OAAM;WACN,IAAI,EAAE,YAAY,EAAE;qBACrB;UAEW,CAAA,GACZ,kBAAC,GAAD;WACE,MAAK;WACL,MAAK;WACL,YAAY;YACV,MAAM;YACN,KAAK;YACL,KAAK;YACL,OAAO;aAAE,WAAW;aAAS,YAAY;YAAI;WAC/C;WACA,YAAY,EACV,gBACE,kBAAC,GAAD;YAAgB,UAAS;sBAAS;WAAoB,CAAA,EAE1D;WACA,IAAI,EAAE,OAAO,IAAI;WACjB,OAAO,EAAK;WACZ,aAAY;WACZ,WAAW,MACT,EAAQ;YAAE,GAAG;YAAM,eAAe,EAAE,OAAO;WAAM,CAAC;WAEpD,QAAQ,EAAY,OAAO,eAAe;WAC1C,OACE,EAAY,KAAK,eAAe,KAChC,CAAC,CAAC,EAAa;WAEjB,YACE,EAAY,KAAK,eAAe,IAC5B,EAAa,gBACb;UAEP,CAAA,CACI;;SAEP,kBAAC,GAAD;UACE,WAAU;UACV,gBAAe;UACf,YAAW;oBAHb,CAKE,kBAAC,GAAD;WAAY,SAAQ;WAAQ,OAAM;qBAAiB;UAEvC,CAAA,GACZ,kBAAC,GAAD;WACE,SAAQ;WACR,IAAI;YACF,YAAY;YACZ,oBAAoB;YACpB,OAAO,IAAe,IAAI,iBAAiB;WAC7C;qBANF,CAQG,GACA,EAAa,CAAY,CAChB;YACP;;QACF;;OAEN,KAAY,IAAe,IAC1B,kBAAC,GAAD;QAAO,UAAS;QAAU,IAAI,EAAE,IAAI,EAAE;kBAAtC;SACG;SACA,EAAa,CAAY;SAAE;SAC3B,IACC,kBAAA,IAAA,EAAA,UAAA;UACG;UAAI;UACD,kBAAC,UAAD,EAAA,UAAS,EAAmB,CAAA;SAChC,EAAA,CAAA,IACA;SACH,IAAU,KAAK,IAAc,IAC1B,KAAK,IAAM,EAAa,CAAO,EAAE,oBAAoB,IAAM,EAAa,CAAW,EAAE,6BACrF,IAAU,IACR,qBACA;QACD;YACL;MACO;;IACT,CAAA;GACK;;CACN,CAAA,CACN,EAAA,CAAA;AAET"}
|
|
1
|
+
{"version":3,"file":"SaleCreatePage-DP1Qmltu.js","names":[],"sources":["../src/views/SaleCreatePage.jsx"],"sourcesContent":["import { useMemo, useState } from \"react\";\nimport { useNavigate, useParams } from \"react-router-dom\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport {\n Alert,\n Box,\n Button,\n Card,\n CardContent,\n Divider,\n FormControl,\n FormHelperText,\n Grid,\n IconButton,\n InputAdornment,\n InputLabel,\n MenuItem,\n Select,\n Stack,\n TextField,\n Typography,\n} from \"@mui/material\";\nimport AddRoundedIcon from \"@mui/icons-material/AddRounded\";\nimport DeleteOutlineRoundedIcon from \"@mui/icons-material/DeleteOutlineRounded\";\nimport SaveRoundedIcon from \"@mui/icons-material/SaveRounded\";\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 createSale,\n getMemberOutstandingDues,\n getProducts,\n listBatches,\n} from \"@pm/services/pmApi\";\nimport MemberProfileCard from \"@pm/components/MemberProfileCard\";\nimport { PAYMENT_MODES } from \"@pm/utils/constants\";\nimport { formatNumber, isPastExpiry } from \"@pm/utils/format\";\nimport { currencySymbol } from \"@pm/utils/currency\";\nimport { usePmSettings } from \"@pm/utils/settingsStore\";\nimport { PmFormSection } from \"@pm/components/PmTable\";\nimport {\n isClean,\n validateInteger,\n validatePrice,\n validateRequired,\n} from \"@pm/utils/validation\";\nimport { useFieldErrors } from \"@pm/utils/useFieldErrors\";\n\nfunction emptyLine() {\n return { key: uuidv4(), batchId: \"\", quantity: 1, salePrice: \"\" };\n}\n\nexport default function SaleCreatePage() {\n const navigate = useNavigate();\n const { memberId } = useParams();\n const settings = usePmSettings();\n const cur = currencySymbol(settings?.currencyCode);\n const [batches, setBatches] = useState([]);\n const [products, setProducts] = useState([]);\n // Map of memberId -> previousDue. The dues endpoint only returns members\n // with non-zero dues so the map stays small. Looked up by route memberId.\n const [duesByMember, setDuesByMember] = useState({});\n // Cached after MemberProfileCard fetches — used by the warning Alert that\n // references the member by name when remaining dues will be recorded.\n const [memberName, setMemberName] = useState(\"\");\n const [error, setError] = useState(\"\");\n const perms = usePmPermissions();\n // When the operator can't see dues, previousDue gracefully degrades to 0\n // instead of populating duesByMember from a 403'ing call.\n const canSeeDues = perms.has(\"view.manage.productManagement.dues\");\n const fieldErrors = useFieldErrors();\n const today = new Date().toISOString().substring(0, 10);\n const [form, setForm] = useState({\n id: uuidv4(),\n saleDate: today,\n paymentMode: \"CASH\",\n collectingNow: \"\",\n notes: \"\",\n items: [emptyLine()],\n });\n\n usePermissionedEffect(\n \"update.manage.productManagement.sale\",\n () => {\n async function load() {\n try {\n // Members are picked via async search now — no upfront load. Dues\n // come from the (aggregated) backend query and get attached to a\n // picked member by id.\n const [b, p, dues] = await Promise.all([\n listBatches(),\n getProducts().catch(() => []),\n // Silent degrade when the operator lacks the dues permission —\n // previousDue will stay 0 and the sale itself still works.\n canSeeDues\n ? getMemberOutstandingDues().catch(() => [])\n : Promise.resolve([]),\n ]);\n setBatches(b);\n setProducts(p);\n setDuesByMember(\n Object.fromEntries(\n (dues ?? []).map((d) => [d.memberId, Number(d.totalDue)]),\n ),\n );\n } catch (err) {\n setError(\n err?.response?.data?.message ??\n err?.message ??\n \"Failed to load reference data\",\n );\n }\n }\n void load();\n },\n [],\n );\n\n const batchById = (id) => batches.find((b) => b.id === id);\n\n // Batches that can be sold: stock on hand, not quarantined, not past expiry, and\n // the underlying product is not flagged as not-for-sale. Computed once per render.\n const sellableBatches = useMemo(() => {\n const notForSaleProductIds = new Set(\n products.filter((p) => p.notForSale === true).map((p) => p.id),\n );\n return batches.filter((b) => {\n if (b.qtyRemaining <= 0) return false;\n if (b.isQuarantined) return false;\n if (notForSaleProductIds.has(b.productId)) return false;\n // A batch is sellable on the day of its printed expiry; only the\n // following day counts as expired (matches the unit packaging rule).\n if (isPastExpiry(b.expiryDate)) return false;\n return true;\n });\n }, [batches, products]);\n\n function patchLine(idx, k, v) {\n setForm((f) => {\n const items = f.items.slice();\n items[idx] = { ...items[idx], [k]: v };\n return { ...f, items };\n });\n }\n\n // -------- Money math --------\n const saleAmount = useMemo(\n () =>\n form.items.reduce((sum, line) => {\n if (!line.salePrice || !line.quantity) return sum;\n return sum + Number(line.salePrice) * Number(line.quantity);\n }, 0),\n [form.items],\n );\n\n const previousDue = Number(memberId ? (duesByMember[memberId] ?? 0) : 0);\n const collectedRaw = Number(form.collectingNow || 0);\n // Clip the collected amount at the current sale's total — anything more would\n // need to be applied to the member's old dues, which is a separate Payment flow.\n const collected = Math.min(Math.max(collectedRaw, 0), saleAmount);\n const saleDue = Math.max(saleAmount - collected, 0);\n const remainingDue = saleDue + previousDue;\n\n // -------- Validation --------\n const headerErrors = {\n saleDate: validateRequired(form.saleDate, \"Sale date\"),\n member: memberId ? \"\" : \"No member selected\",\n };\n // Collecting Now: optional; if filled, must be a non-negative number ≤ sale amount.\n const collectingErr =\n form.collectingNow === \"\" ? \"\" : validatePrice(form.collectingNow);\n if (\n !collectingErr &&\n form.collectingNow !== \"\" &&\n Number(form.collectingNow) > saleAmount\n ) {\n headerErrors.collectingNow = `Cannot collect more than the sale amount (${formatNumber(saleAmount)}). Settle old dues via Payments.`;\n } else if (collectingErr) {\n headerErrors.collectingNow = collectingErr;\n }\n\n const sellableBatchIds = new Set(sellableBatches.map((b) => b.id));\n const lineErrors = form.items.map((line) => {\n const batch = batchById(line.batchId);\n const qty = validateInteger(line.quantity, \"Quantity\", {\n required: true,\n min: 1,\n });\n let qtyErr = qty;\n if (!qtyErr && batch && Number(line.quantity) > batch.qtyRemaining) {\n qtyErr = `Only ${batch.qtyRemaining} available in selected batch`;\n }\n let batchErr = validateRequired(line.batchId, \"Batch\");\n if (!batchErr && line.batchId && !sellableBatchIds.has(line.batchId)) {\n batchErr =\n \"Batch is not available for sale (expired, quarantined, out of stock, or not-for-sale).\";\n }\n return {\n batchId: batchErr,\n quantity: qtyErr,\n salePrice:\n validatePrice(line.salePrice) ||\n validateRequired(line.salePrice, \"Unit price\"),\n };\n });\n const formIsValid =\n isClean(headerErrors) &&\n lineErrors.every(isClean) &&\n form.items.length > 0 &&\n saleAmount > 0;\n\n async function save() {\n if (!formIsValid) {\n fieldErrors.markAllTouched();\n setError(\"Please fix the highlighted fields and try again.\");\n return;\n }\n try {\n await createSale({\n id: form.id,\n saleDate: form.saleDate,\n memberId,\n paymentMode: form.paymentMode || null,\n totalAmount: Number(saleAmount.toFixed(2)),\n paidAmount: Number(collected.toFixed(2)),\n dueAmount: Number(saleDue.toFixed(2)),\n notes: form.notes || null,\n items: form.items.map((l) => {\n const batch = batchById(l.batchId);\n return {\n batchId: l.batchId,\n productId: batch?.productId,\n quantity: Number(l.quantity),\n salePrice: Number(l.salePrice),\n };\n }),\n });\n showToast({ message: \"Sale recorded.\", type: \"success\" });\n navigate(\"/ui/medplat/manage/pm/sales\");\n } catch (err) {\n setError(\n err?.response?.data?.message ?? err?.message ?? \"Failed to record sale\",\n );\n }\n }\n\n return (\n <Box>\n <PmNav />\n <PmGuard\n perm={\"update.manage.productManagement.sale\"}\n title=\"You don’t have permission to record sales\"\n >\n <PmPageShell\n title=\"Record Sale\"\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button\n variant=\"outlined\"\n onClick={() => navigate(\"/ui/medplat/manage/pm/sales\")}\n >\n Cancel\n </Button>\n <Button\n variant=\"contained\"\n startIcon={<SaveRoundedIcon />}\n disabled={!formIsValid}\n onClick={() => void save()}\n >\n Save\n </Button>\n </Stack>\n }\n >\n {error ? (\n <Alert severity=\"error\" sx={{ mb: 2 }}>\n {error}\n </Alert>\n ) : null}\n\n {/* ---------- Member ---------- */}\n <Card\n sx={{\n borderRadius: 4,\n mb: 2,\n border: \"1px solid\",\n borderColor: \"divider\",\n boxShadow: \"0 12px 32px rgba(15, 23, 42, 0.045)\",\n }}\n >\n <CardContent sx={{ p: 2.5 }}>\n <PmFormSection\n eyebrow=\"Step 1\"\n title=\"Customer\"\n hint=\"The customer is set from the link you opened. Their balance shows below.\"\n sx={{ mb: 2 }}\n />\n {memberId ? (\n <MemberProfileCard\n memberId={memberId}\n previousDue={previousDue}\n currencySymbol={cur}\n onLoad={(p) => setMemberName(p?.name ?? \"\")}\n />\n ) : (\n <Alert severity=\"warning\">No member selected</Alert>\n )}\n </CardContent>\n </Card>\n\n {/* ---------- Line items ---------- */}\n <Card\n sx={{\n borderRadius: 4,\n mb: 2,\n border: \"1px solid\",\n borderColor: \"divider\",\n boxShadow: \"0 12px 32px rgba(15, 23, 42, 0.045)\",\n }}\n >\n <CardContent sx={{ p: 2.5 }}>\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"flex-start\"\n sx={{ mb: 2 }}\n >\n <PmFormSection\n eyebrow=\"Step 2\"\n title=\"Line items\"\n hint=\"Each item comes from a batch. Buy price is shown as a cost reference.\"\n />\n <Button\n variant=\"outlined\"\n startIcon={<AddRoundedIcon />}\n onClick={() =>\n setForm({ ...form, items: [...form.items, emptyLine()] })\n }\n >\n Add Line\n </Button>\n </Stack>\n <Divider sx={{ mb: 2 }} />\n <Stack spacing={2}>\n {form.items.map((line, idx) => {\n const batch = batchById(line.batchId);\n const lerr = lineErrors[idx] || {};\n const subtotal =\n line.salePrice && line.quantity\n ? Number(line.salePrice) * Number(line.quantity)\n : 0;\n return (\n <Card\n key={line.key}\n variant=\"outlined\"\n sx={{ p: 2, borderRadius: 3 }}\n >\n <Grid container spacing={2} alignItems=\"center\">\n <Grid item xs={12} md={5}>\n <FormControl\n required\n fullWidth\n size=\"small\"\n error={\n fieldErrors.show(`items.${idx}.batchId`) &&\n !!lerr.batchId\n }\n >\n <InputLabel>Batch</InputLabel>\n <Select\n label=\"Batch\"\n value={line.batchId}\n onChange={(e) =>\n patchLine(idx, \"batchId\", e.target.value)\n }\n onBlur={fieldErrors.onBlur(\n `items.${idx}.batchId`,\n )}\n >\n {sellableBatches.map((b) => (\n <MenuItem key={b.id} value={b.id}>\n {b.productName} · lot {b.lotNumber || \"—\"} ·{\" \"}\n {b.qtyRemaining} left\n </MenuItem>\n ))}\n </Select>\n <FormHelperText>\n {fieldErrors.show(`items.${idx}.batchId`) &&\n lerr.batchId\n ? lerr.batchId\n : batch?.buyPrice != null\n ? `Buy price: ${cur}${formatNumber(batch.buyPrice)} / unit`\n : \" \"}\n </FormHelperText>\n </FormControl>\n </Grid>\n <Grid item xs={6} md={2}>\n <TextField\n required\n fullWidth\n size=\"small\"\n type=\"number\"\n label=\"Qty\"\n inputProps={{ min: 1, max: batch?.qtyRemaining }}\n value={line.quantity}\n onChange={(e) =>\n patchLine(idx, \"quantity\", e.target.value)\n }\n onBlur={fieldErrors.onBlur(`items.${idx}.quantity`)}\n error={\n fieldErrors.show(`items.${idx}.quantity`) &&\n !!lerr.quantity\n }\n helperText={\n fieldErrors.show(`items.${idx}.quantity`)\n ? lerr.quantity\n : \"\"\n }\n />\n </Grid>\n <Grid item xs={6} md={2}>\n <TextField\n required\n fullWidth\n size=\"small\"\n type=\"number\"\n inputProps={{ step: \"0.01\", min: 0 }}\n label=\"Unit Price\"\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">\n {cur}\n </InputAdornment>\n ),\n }}\n value={line.salePrice}\n onChange={(e) =>\n patchLine(idx, \"salePrice\", e.target.value)\n }\n onBlur={fieldErrors.onBlur(\n `items.${idx}.salePrice`,\n )}\n error={\n fieldErrors.show(`items.${idx}.salePrice`) &&\n !!lerr.salePrice\n }\n helperText={\n fieldErrors.show(`items.${idx}.salePrice`)\n ? lerr.salePrice\n : \"\"\n }\n />\n </Grid>\n <Grid item xs={6} md={2} sx={{ textAlign: \"right\" }}>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: \"block\" }}\n >\n Subtotal\n </Typography>\n <Typography\n variant=\"body1\"\n sx={{\n fontWeight: 800,\n fontVariantNumeric: \"tabular-nums\",\n }}\n >\n {cur}\n {formatNumber(subtotal)}\n </Typography>\n </Grid>\n <Grid item xs={6} md={1} sx={{ textAlign: \"right\" }}>\n <IconButton\n color=\"error\"\n onClick={() =>\n setForm({\n ...form,\n items: form.items.filter((_, i) => i !== idx),\n })\n }\n disabled={form.items.length === 1}\n >\n <DeleteOutlineRoundedIcon />\n </IconButton>\n </Grid>\n </Grid>\n </Card>\n );\n })}\n </Stack>\n </CardContent>\n </Card>\n\n {/* ---------- Bill Summary footer ---------- */}\n <Card\n sx={{\n borderRadius: 4,\n bgcolor: \"grey.50\",\n border: \"1px solid\",\n borderColor: \"divider\",\n boxShadow: \"0 12px 32px rgba(15, 23, 42, 0.045)\",\n }}\n >\n <CardContent sx={{ p: 2.5 }}>\n <PmFormSection\n eyebrow=\"Step 3\"\n title=\"Bill summary\"\n hint=\"Shows totals, previous balance, and what you're collecting. Any remainder becomes a note of what they owe.\"\n sx={{ mb: 2 }}\n />\n <Grid container spacing={2}>\n <Grid item xs={12} md={4}>\n <TextField\n required\n fullWidth\n size=\"small\"\n type=\"date\"\n label=\"Date\"\n InputLabelProps={{ shrink: true }}\n value={form.saleDate}\n onChange={(e) =>\n setForm({ ...form, saleDate: e.target.value })\n }\n onBlur={fieldErrors.onBlur(\"saleDate\")}\n error={\n fieldErrors.show(\"saleDate\") && !!headerErrors.saleDate\n }\n helperText={\n fieldErrors.show(\"saleDate\") ? headerErrors.saleDate : \"\"\n }\n />\n </Grid>\n <Grid item xs={12} md={4}>\n <FormControl fullWidth size=\"small\">\n <InputLabel>Payment Mode</InputLabel>\n <Select\n label=\"Payment Mode\"\n value={form.paymentMode || \"\"}\n onChange={(e) =>\n setForm({ ...form, paymentMode: e.target.value })\n }\n >\n <MenuItem value=\"\">\n <em>—</em>\n </MenuItem>\n {PAYMENT_MODES.map((m) => (\n <MenuItem key={m.value} value={m.value}>\n {m.label}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n </Grid>\n <Grid item xs={12} md={4}>\n <TextField\n fullWidth\n size=\"small\"\n label=\"Notes\"\n value={form.notes}\n onChange={(e) =>\n setForm({ ...form, notes: e.target.value })\n }\n />\n </Grid>\n </Grid>\n\n <Divider sx={{ my: 2 }} />\n\n <Stack spacing={1.25}>\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"baseline\"\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n Sale Amount ({form.items.length}{\" \"}\n {form.items.length === 1 ? \"line\" : \"lines\"})\n </Typography>\n <Typography\n variant=\"h5\"\n sx={{ fontWeight: 800, fontVariantNumeric: \"tabular-nums\" }}\n >\n {cur}\n {formatNumber(saleAmount)}\n </Typography>\n </Stack>\n\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"baseline\"\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n Previous Due\n </Typography>\n <Typography\n variant=\"body1\"\n sx={{\n fontWeight: 700,\n fontVariantNumeric: \"tabular-nums\",\n color: previousDue > 0 ? \"warning.dark\" : \"text.primary\",\n }}\n >\n {cur}\n {formatNumber(previousDue)}\n </Typography>\n </Stack>\n\n <Divider sx={{ my: 0.5 }} />\n\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n spacing={2}\n >\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ flexShrink: 0 }}\n >\n Amount Collecting Now\n </Typography>\n <TextField\n size=\"small\"\n type=\"number\"\n inputProps={{\n step: \"0.01\",\n min: 0,\n max: saleAmount,\n style: { textAlign: \"right\", fontWeight: 700 },\n }}\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">{cur}</InputAdornment>\n ),\n }}\n sx={{ width: 200 }}\n value={form.collectingNow}\n placeholder=\"0.00\"\n onChange={(e) =>\n setForm({ ...form, collectingNow: e.target.value })\n }\n onBlur={fieldErrors.onBlur(\"collectingNow\")}\n error={\n fieldErrors.show(\"collectingNow\") &&\n !!headerErrors.collectingNow\n }\n helperText={\n fieldErrors.show(\"collectingNow\")\n ? headerErrors.collectingNow\n : \"\"\n }\n />\n </Stack>\n\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"baseline\"\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n Remaining Due (after this sale)\n </Typography>\n <Typography\n variant=\"h5\"\n sx={{\n fontWeight: 800,\n fontVariantNumeric: \"tabular-nums\",\n color: remainingDue > 0 ? \"warning.dark\" : \"success.dark\",\n }}\n >\n {cur}\n {formatNumber(remainingDue)}\n </Typography>\n </Stack>\n </Stack>\n\n {memberId && remainingDue > 0 ? (\n <Alert severity=\"warning\" sx={{ mt: 2 }}>\n {cur}\n {formatNumber(remainingDue)} will be recorded as pending dues\n {memberName ? (\n <>\n {\" \"}\n for <strong>{memberName}</strong>\n </>\n ) : null}\n {saleDue > 0 && previousDue > 0\n ? ` (${cur}${formatNumber(saleDue)} from this sale + ${cur}${formatNumber(previousDue)} previously outstanding).`\n : saleDue > 0\n ? \" from this sale.\"\n : \" from previously outstanding dues.\"}\n </Alert>\n ) : null}\n </CardContent>\n </Card>\n </PmPageShell>\n </PmGuard>\n </Box>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { a as ee, i as c, o as l, r as u, t as d } from "./PmTable-BuXZQZCU.js";
|
|
1
|
+
import { K as e, i as t, k as n, l as r, n as i, o as a, r as o, t as s } from "./currency-ClRLIEg2.js";
|
|
2
|
+
import { a as ee, c, i as l, s as u, t as d } from "./PmTable-B9970kPY.js";
|
|
4
3
|
import { r as f, t as p } from "./format-UOyOu75i.js";
|
|
5
4
|
import { useMemo as m, useState as h } from "react";
|
|
6
5
|
import { jsx as g, jsxs as _ } from "react/jsx-runtime";
|
|
@@ -79,15 +78,15 @@ function V() {
|
|
|
79
78
|
async function Q() {
|
|
80
79
|
Y(!0), Z("");
|
|
81
80
|
try {
|
|
82
|
-
let
|
|
83
|
-
G(
|
|
84
|
-
let r = Array.from(new Set(
|
|
81
|
+
let t = await e(0, 50);
|
|
82
|
+
G(t);
|
|
83
|
+
let r = Array.from(new Set(t.map((e) => e.memberId).filter(Boolean)));
|
|
85
84
|
if (r.length === 0) q({});
|
|
86
85
|
else try {
|
|
87
|
-
let e = await
|
|
86
|
+
let e = await n(r), t = {};
|
|
88
87
|
e.forEach((e) => {
|
|
89
|
-
|
|
90
|
-
}), q(
|
|
88
|
+
t[e.id] = e.name;
|
|
89
|
+
}), q(t);
|
|
91
90
|
} catch {
|
|
92
91
|
q({});
|
|
93
92
|
}
|
|
@@ -101,7 +100,7 @@ function V() {
|
|
|
101
100
|
Y(!1);
|
|
102
101
|
}
|
|
103
102
|
}
|
|
104
|
-
|
|
103
|
+
t("view.manage.productManagement.sale", () => {
|
|
105
104
|
Q();
|
|
106
105
|
}, []);
|
|
107
106
|
let $ = m(() => ({
|
|
@@ -110,9 +109,9 @@ function V() {
|
|
|
110
109
|
openSales: W.filter((e) => Number(e.dueAmount) > 0).length,
|
|
111
110
|
count: W.length
|
|
112
111
|
}), [W]);
|
|
113
|
-
return /* @__PURE__ */ _(b, { children: [/* @__PURE__ */ g(
|
|
112
|
+
return /* @__PURE__ */ _(b, { children: [/* @__PURE__ */ g(o, {}), /* @__PURE__ */ g(i, {
|
|
114
113
|
perm: "view.manage.productManagement.sale",
|
|
115
|
-
children: /* @__PURE__ */ _(
|
|
114
|
+
children: /* @__PURE__ */ _(a, {
|
|
116
115
|
title: "Sales",
|
|
117
116
|
subtitle: "Customer sales and payments. Each sale is tracked with the batches used.",
|
|
118
117
|
actions: /* @__PURE__ */ _(w, {
|
|
@@ -169,11 +168,11 @@ function V() {
|
|
|
169
168
|
sx: { mb: 2 },
|
|
170
169
|
children: X
|
|
171
170
|
}) : null,
|
|
172
|
-
/* @__PURE__ */ g(
|
|
171
|
+
/* @__PURE__ */ g(c, {
|
|
173
172
|
eyebrow: "Recent activity",
|
|
174
173
|
title: "Sales transactions",
|
|
175
174
|
subtitle: J ? "Loading…" : `${$.count} ${$.count === 1 ? "sale" : "sales"} in the last window`,
|
|
176
|
-
children: /* @__PURE__ */ _(
|
|
175
|
+
children: /* @__PURE__ */ _(u, {
|
|
177
176
|
dense: !0,
|
|
178
177
|
children: [/* @__PURE__ */ g(te, { children: /* @__PURE__ */ _(D, { children: [
|
|
179
178
|
/* @__PURE__ */ g(E, { children: "Ref" }),
|
|
@@ -209,7 +208,7 @@ function V() {
|
|
|
209
208
|
return /* @__PURE__ */ _(D, {
|
|
210
209
|
hover: !0,
|
|
211
210
|
children: [
|
|
212
|
-
/* @__PURE__ */ g(E, { children: /* @__PURE__ */ g(
|
|
211
|
+
/* @__PURE__ */ g(E, { children: /* @__PURE__ */ g(ee, { id: e.serialId }) }),
|
|
213
212
|
/* @__PURE__ */ g(E, { children: /* @__PURE__ */ g(O, {
|
|
214
213
|
variant: "body2",
|
|
215
214
|
sx: { fontWeight: 700 },
|
|
@@ -274,11 +273,11 @@ function V() {
|
|
|
274
273
|
}) }),
|
|
275
274
|
/* @__PURE__ */ g(E, {
|
|
276
275
|
align: "right",
|
|
277
|
-
children: /* @__PURE__ */ g(
|
|
276
|
+
children: /* @__PURE__ */ g(l, { value: e.totalAmount })
|
|
278
277
|
}),
|
|
279
278
|
/* @__PURE__ */ g(E, {
|
|
280
279
|
align: "right",
|
|
281
|
-
children: /* @__PURE__ */ g(
|
|
280
|
+
children: /* @__PURE__ */ g(l, {
|
|
282
281
|
value: e.paidAmount,
|
|
283
282
|
tone: n ? "success" : "muted"
|
|
284
283
|
})
|
|
@@ -294,7 +293,7 @@ function V() {
|
|
|
294
293
|
borderRadius: 1.5,
|
|
295
294
|
height: 22
|
|
296
295
|
}
|
|
297
|
-
}) : /* @__PURE__ */ g(
|
|
296
|
+
}) : /* @__PURE__ */ g(l, {
|
|
298
297
|
value: t,
|
|
299
298
|
tone: "warning",
|
|
300
299
|
size: "big"
|
|
@@ -312,4 +311,4 @@ function V() {
|
|
|
312
311
|
//#endregion
|
|
313
312
|
export { V as default };
|
|
314
313
|
|
|
315
|
-
//# sourceMappingURL=SalesPage-
|
|
314
|
+
//# sourceMappingURL=SalesPage-CO3cdYX5.js.map
|