diff --git a/client/src/pages/dms/dms.container.jsx b/client/src/pages/dms/dms.container.jsx
index a5144c0f2..fbd8154a5 100644
--- a/client/src/pages/dms/dms.container.jsx
+++ b/client/src/pages/dms/dms.container.jsx
@@ -142,6 +142,41 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
isConnected ? "Connected" : "Disconnected"
}`;
+ const resetKey = useMemo(() => `${mode || "none"}-${jobId || "none"}`, [mode, jobId]);
+
+ // 🔄 Hard reset of local + server-side DMS context when the page/job loads
+ useEffect(() => {
+ // Clear any local ephemeral state that might be stale
+ setLogs([]);
+ setRrOpenRoLimit(false);
+ setrrValidationPending(false);
+
+ if (!activeSocket) return;
+
+ const emitReset = () => {
+ // Generic reset; server can branch on `mode` if needed
+ activeSocket.emit("dms-reset-context", { jobId, mode });
+ };
+
+ if (activeSocket.connected) {
+ // WSS usually lands here
+ emitReset();
+ return;
+ }
+
+ // Legacy WS: wait for the connect before emitting reset
+ const handleConnectOnce = () => {
+ emitReset();
+ activeSocket.off("connect", handleConnectOnce);
+ };
+
+ activeSocket.on("connect", handleConnectOnce);
+
+ return () => {
+ activeSocket.off("connect", handleConnectOnce);
+ };
+ }, [jobId, mode, activeSocket]);
+
const handleExportFailed = (payload = {}) => {
const { title, friendlyMessage, error: errText, severity, errorCode, vendorStatusCode } = payload;
@@ -355,6 +390,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
{!isRrMode ? (
) : (
@@ -388,7 +425,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
-
+
{
const rate = rateMap[key];
if (!rate || !rate.adjustment) return;
- const adjMoney = Dinero(rate.adjustment);
- if (adjMoney.isZero()) return;
+ const checkMoney = Dinero(rate.adjustment);
+ if (checkMoney.isZero()) return;
const accountName = selectedDmsAllocationConfig.profits[key.toUpperCase()];
const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === accountName);
if (otherAccount) {
const bucket = ensureCenterBucket(profitCenterHash, accountName);
+
+ // Note: we intentionally use `rate.adjustments` here to mirror CDK behaviour
+ const adjMoney = Dinero(rate.adjustments);
bucket.extrasSale = bucket.extrasSale.add(adjMoney);
debugLog("Added rate adjustment", {
diff --git a/server/web-sockets/redisSocketEvents.js b/server/web-sockets/redisSocketEvents.js
index c2db293c0..c4af2fb55 100644
--- a/server/web-sockets/redisSocketEvents.js
+++ b/server/web-sockets/redisSocketEvents.js
@@ -67,6 +67,34 @@ const redisSocketEvents = ({ io, redisHelpers, ioHelpers, logger }) => {
// Register Socket Events
const registerSocketEvents = (socket) => {
+ // DMS reset events (clear per-socket DMS transactional cache)
+ const registerDmsResetEvents = (socket) => {
+ socket.on("dms-reset-context", async ({ jobId, mode } = {}, ack) => {
+ try {
+ // This clears all transactional session data for this socket
+ // (RR txEnvelope/JobData/SelectedCustomer/PendingRO/etc, Fortellis, etc.)
+ await clearSessionTransactionData(socket.id);
+
+ createLogEvent(
+ socket,
+ "debug",
+ `DMS reset-context: cleared transactional session data` +
+ (jobId ? ` (jobId=${jobId})` : "") +
+ (mode ? ` (mode=${mode})` : "")
+ );
+
+ if (typeof ack === "function") {
+ ack({ ok: true });
+ }
+ } catch (error) {
+ createLogEvent(socket, "error", `DMS reset-context failed: ${error.message}`);
+ if (typeof ack === "function") {
+ ack({ ok: false, error: error.message });
+ }
+ }
+ });
+ };
+
// Token Update Events
const registerUpdateEvents = (socket) => {
let latestTokenTimestamp = 0;
@@ -164,7 +192,9 @@ const redisSocketEvents = ({ io, redisHelpers, ioHelpers, logger }) => {
// Optional: clear transactional session
try {
await clearSessionTransactionData(socket.id);
- } catch {}
+ } catch {
+ //
+ }
// Leave all rooms except the default room (socket.id)
const rooms = Array.from(socket.rooms).filter((room) => room !== socket.id);
for (const room of rooms) {
@@ -363,6 +393,7 @@ const redisSocketEvents = ({ io, redisHelpers, ioHelpers, logger }) => {
};
// Call Handlers
+ registerDmsResetEvents(socket);
registerRoomAndBroadcastEvents(socket);
registerUpdateEvents(socket);
registerMessagingEvents(socket);
diff --git a/server/web-sockets/web-socket.js b/server/web-sockets/web-socket.js
index fbef1cf65..0abcf91bd 100644
--- a/server/web-sockets/web-socket.js
+++ b/server/web-sockets/web-socket.js
@@ -115,6 +115,33 @@ function SetLegacyWebsocketHandlers(io) {
socket.on("disconnect", () => {
createLogEvent(socket, "DEBUG", `User disconnected.`);
});
+
+ // DMS reset for legacy WS (CDK / PBS)
+ socket.on("dms-reset-context", ({ jobId, mode } = {}, ack) => {
+ try {
+ // Clear any per-socket DMS state that can leak across jobs
+ socket.selectedCustomerId = null; // CDK / PBS AR
+ socket.txEnvelope = null; // PBS AP export
+ socket.apAllocations = null; // PBS AP allocations
+
+ createLogEvent(
+ socket,
+ "DEBUG",
+ `DMS reset-context (legacy WS): cleared per-socket state` +
+ (jobId ? ` (jobId=${jobId})` : "") +
+ (mode ? ` (mode=${mode})` : "")
+ );
+
+ if (typeof ack === "function") {
+ ack({ ok: true });
+ }
+ } catch (error) {
+ createLogEvent(socket, "ERROR", `DMS reset-context (legacy WS) failed: ${error.message}`);
+ if (typeof ack === "function") {
+ ack({ ok: false, error: error.message });
+ }
+ }
+ });
});
}