feature/IO-3357-Reynolds-and-Reynolds-DMS-API-Integration - Fixes to Caching of allocations summary

This commit is contained in:
Dave
2025-11-28 11:29:48 -05:00
parent d885bac7d0
commit c1e3c08652
6 changed files with 93 additions and 31 deletions

View File

@@ -24,10 +24,11 @@ export default connect(mapStateToProps, mapDispatchToProps)(DmsAllocationsSummar
* @param bodyshop
* @param jobId
* @param title
* @param onAllocationsChange
* @returns {JSX.Element}
* @constructor
*/
export function DmsAllocationsSummary({ mode, socket, bodyshop, jobId, title }) {
export function DmsAllocationsSummary({ mode, socket, bodyshop, jobId, title, onAllocationsChange }) {
const { t } = useTranslation();
const [allocationsSummary, setAllocationsSummary] = useState([]);
@@ -48,11 +49,17 @@ export function DmsAllocationsSummary({ mode, socket, bodyshop, jobId, title })
setAllocationsSummary(list);
// Preserve side-channel used by the post form for discrepancy checks
socket.allocationsSummary = list;
if (onAllocationsChange) onAllocationsChange(list);
});
} catch {
// Best-effort; leave table empty on error
setAllocationsSummary([]);
socket && (socket.allocationsSummary = []);
if (socket) {
socket.allocationsSummary = [];
}
if (onAllocationsChange) {
onAllocationsChange([]);
}
}
}, [socket, jobId, mode, allocationsEvent]);

View File

@@ -51,7 +51,7 @@ function normalizeJobAllocations(ack) {
* is now done on the backend via buildRogogFromAllocations/buildRolaborFromRogog.
* This component just renders the preview from `ack.rogg` / `ack.rolabor`.
*/
export function RrAllocationsSummary({ socket, bodyshop, jobId, title }) {
export function RrAllocationsSummary({ socket, bodyshop, jobId, title, onAllocationsChange }) {
const { t } = useTranslation();
const [roggPreview, setRoggPreview] = useState(null);
const [rolaborPreview, setRolaborPreview] = useState(null);
@@ -70,6 +70,9 @@ export function RrAllocationsSummary({ socket, bodyshop, jobId, title }) {
socket.allocationsSummary = [];
socket.rrAllocationsRaw = ack;
}
if (onAllocationsChange) {
onAllocationsChange([]);
}
return;
}
@@ -83,6 +86,9 @@ export function RrAllocationsSummary({ socket, bodyshop, jobId, title }) {
socket.allocationsSummary = jobAllocRows;
socket.rrAllocationsRaw = ack;
}
if (onAllocationsChange) {
onAllocationsChange(jobAllocRows);
}
});
} catch {
setRoggPreview(null);
@@ -91,8 +97,11 @@ export function RrAllocationsSummary({ socket, bodyshop, jobId, title }) {
if (socket) {
socket.allocationsSummary = [];
}
if (onAllocationsChange) {
onAllocationsChange([]);
}
}
}, [socket, jobId, t]);
}, [socket, jobId, t, onAllocationsChange]);
useEffect(() => {
fetchAllocations();

View File

@@ -39,10 +39,11 @@ import { useSplitTreatments } from "@splitsoftware/splitio-react";
* @param job
* @param logsRef
* @param mode
* @param allocationsSummary
* @returns {JSX.Element}
* @constructor
*/
export default function CdkLikePostForm({ bodyshop, socket, job, logsRef, mode }) {
export default function CdkLikePostForm({ bodyshop, socket, job, logsRef, mode, allocationsSummary }) {
const [form] = Form.useForm();
const { t } = useTranslation();
const [, /*unused*/ setTick] = useState(0); // handy if you need a forceUpdate later
@@ -120,15 +121,19 @@ export default function CdkLikePostForm({ bodyshop, socket, job, logsRef, mode }
};
// Totals & discrepancy
const totals = socket?.allocationsSummary
? socket.allocationsSummary.reduce(
(acc, val) => ({
totalSale: acc.totalSale.add(Dinero(val.sale)),
totalCost: acc.totalCost.add(Dinero(val.cost))
}),
{ totalSale: Dinero(), totalCost: Dinero() }
)
: { totalSale: Dinero(), totalCost: Dinero() };
const totals = useMemo(() => {
if (!allocationsSummary || allocationsSummary.length === 0) {
return { totalSale: Dinero(), totalCost: Dinero() };
}
return allocationsSummary.reduce(
(acc, val) => ({
totalSale: acc.totalSale.add(Dinero(val.sale)),
totalCost: acc.totalCost.add(Dinero(val.cost))
}),
{ totalSale: Dinero(), totalCost: Dinero() }
);
}, [allocationsSummary]);
return (
<Card title={t("jobs.labels.dms.postingform")}>
@@ -214,7 +219,7 @@ export default function CdkLikePostForm({ bodyshop, socket, job, logsRef, mode }
<Row gutter={[16, 12]}>
<Col span={24}>
<Form.Item name="story" label={t("jobs.fields.dms.story")} rules={[{ required: true }]}>
<Input.TextArea maxLength={Fortellis.treatment === "on" ? 40 : 240} showCount/>
<Input.TextArea maxLength={Fortellis.treatment === "on" ? 40 : 240} showCount />
</Form.Item>
</Col>
</Row>
@@ -382,7 +387,10 @@ export default function CdkLikePostForm({ bodyshop, socket, job, logsRef, mode }
const payersOk =
payers.length > 0 &&
payers.every((p) => p?.name && p.dms_acctnumber && (p.amount ?? "") !== "" && p.controlnumber);
const nonRrDiscrepancyGate = socket?.allocationsSummary ? discrep.getAmount() !== 0 : true;
const hasAllocations = allocationsSummary && allocationsSummary.length > 0;
const nonRrDiscrepancyGate = hasAllocations ? discrep.getAmount() !== 0 : true;
const disablePost = !payersOk || nonRrDiscrepancyGate;
return (

View File

@@ -19,20 +19,41 @@ export default connect(mapStateToProps, mapDispatchToProps)(DmsPostForm);
* @param socket
* @param job
* @param logsRef
* @param key
* @param allocationsSummary
* @returns {JSX.Element|null}
* @constructor
*/
export function DmsPostForm({ mode, bodyshop, socket, job, logsRef }) {
export function DmsPostForm({ mode, bodyshop, socket, job, logsRef, key, allocationsSummary }) {
switch (mode) {
case DMS_MAP.reynolds:
return <RRPostForm bodyshop={bodyshop} socket={socket} job={job} logsRef={logsRef} />;
return (
<RRPostForm
bodyshop={bodyshop}
socket={socket}
job={job}
logsRef={logsRef}
key={key}
allocationsSummary={allocationsSummary}
/>
);
// CDK (legacy /ws), Fortellis (CDK-over-WSS), and PBS share the same UI;
// we pass mode down so the child can choose the correct event name.
case DMS_MAP.fortellis:
case DMS_MAP.cdk:
case DMS_MAP.pbs:
return <CdkLikePostForm mode={mode} bodyshop={bodyshop} socket={socket} job={job} logsRef={logsRef} />;
return (
<CdkLikePostForm
mode={mode}
bodyshop={bodyshop}
socket={socket}
job={job}
logsRef={logsRef}
key={key}
allocationsSummary={allocationsSummary}
/>
);
default:
return null;

View File

@@ -26,10 +26,11 @@ import dayjs from "../../utils/day";
* @param socket
* @param job
* @param logsRef
* @param allocationsSummary
* @returns {JSX.Element}
* @constructor
*/
export default function RRPostForm({ bodyshop, socket, job, logsRef }) {
export default function RRPostForm({ bodyshop, socket, job, logsRef, allocationsSummary }) {
const [form] = Form.useForm();
const { t } = useTranslation();
@@ -113,16 +114,21 @@ export default function RRPostForm({ bodyshop, socket, job, logsRef }) {
logsRef?.current?.scrollIntoView({ behavior: "smooth" });
};
// Discrepancy is ignored for RR; we still show totals for operator context
const totals = socket?.allocationsSummary
? socket.allocationsSummary.reduce(
(acc, val) => ({
totalSale: acc.totalSale.add(Dinero(val.sale)),
totalCost: acc.totalCost.add(Dinero(val.cost))
}),
{ totalSale: Dinero(), totalCost: Dinero() }
)
: { totalSale: Dinero(), totalCost: Dinero() };
// Discrepancy is ignored for RR; we still show totals for operator context.
// Use the lifted allocationsSummary from the container instead of reading from the socket.
const totals = useMemo(() => {
if (!allocationsSummary || allocationsSummary.length === 0) {
return { totalSale: Dinero(), totalCost: Dinero() };
}
return allocationsSummary.reduce(
(acc, val) => ({
totalSale: acc.totalSale.add(Dinero(val.sale)),
totalCost: acc.totalCost.add(Dinero(val.cost))
}),
{ totalSale: Dinero(), totalCost: Dinero() }
);
}, [allocationsSummary]);
return (
<Card title={t("jobs.labels.dms.postingform")}>

View File

@@ -68,6 +68,7 @@ const DMS_SOCKET_EVENTS = {
export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, insertAuditTrail }) {
const { t } = useTranslation();
const [resetAfterReconnect, setResetAfterReconnect] = useState(false);
const [allocationsSummary, setAllocationsSummary] = useState(null);
const history = useNavigate();
const search = queryString.parse(useLocation().search);
@@ -152,6 +153,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
setLogs([]);
setRrOpenRoLimit(false);
setrrValidationPending(false);
setAllocationsSummary(null);
if (!activeSocket) return;
@@ -398,6 +400,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
{!isRrMode ? (
<DmsAllocationsSummary
key={resetKey}
onAllocationsChange={setAllocationsSummary}
title={
<span>
<Link
@@ -415,6 +418,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
) : (
<RrAllocationsSummary
key={resetKey}
onAllocationsChange={setAllocationsSummary}
title={
<span>
<Link to={`/manage/jobs/${data && data.jobs_by_pk.id}`}>
@@ -432,7 +436,14 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
</Col>
<Col md={24} lg={14} className="dms-equal-height-col">
<DmsPostForm key={resetKey} socket={activeSocket} job={data?.jobs_by_pk} logsRef={logsRef} mode={mode} />
<DmsPostForm
key={resetKey}
socket={activeSocket}
job={data?.jobs_by_pk}
logsRef={logsRef}
mode={mode}
allocationsSummary={allocationsSummary}
/>
</Col>
<DmsCustomerSelector