diff --git a/client/src/components/chat-affix/registerMessagingSocketHandlers.js b/client/src/components/chat-affix/registerMessagingSocketHandlers.js
index a6c7cc33a..41d65427d 100644
--- a/client/src/components/chat-affix/registerMessagingSocketHandlers.js
+++ b/client/src/components/chat-affix/registerMessagingSocketHandlers.js
@@ -334,12 +334,47 @@ export const registerMessagingHandlers = ({ socket, client }) => {
break;
case "tag-added":
+ // Ensure `job_conversations` is properly formatted
+ const formattedJobConversations = job_conversations.map((jc) => ({
+ __typename: "job_conversations",
+ jobid: jc.jobid || jc.job?.id,
+ conversationid: conversationId,
+ job: jc.job || {
+ __typename: "jobs",
+ id: data.selectedJob.id,
+ ro_number: data.selectedJob.ro_number,
+ ownr_co_nm: data.selectedJob.ownr_co_nm,
+ ownr_fn: data.selectedJob.ownr_fn,
+ ownr_ln: data.selectedJob.ownr_ln
+ }
+ }));
+
client.cache.modify({
id: client.cache.identify({ __typename: "conversations", id: conversationId }),
fields: {
- job_conversations: (existing = []) => [...existing, ...job_conversations]
+ job_conversations: (existing = []) => {
+ // Ensure no duplicates based on `jobid`
+ const existingIds = new Set(
+ existing.map(
+ (jc) =>
+ client.cache.readFragment({
+ id: client.cache.identify(jc),
+ fragment: gql`
+ fragment JobConversationId on job_conversations {
+ jobid
+ }
+ `
+ })?.jobid
+ )
+ );
+
+ const newItems = formattedJobConversations.filter((jc) => !existingIds.has(jc.jobid));
+
+ return [...existing, ...newItems];
+ }
}
});
+
break;
case "tag-removed":
diff --git a/client/src/components/chat-messages-list/chat-message-list.component.jsx b/client/src/components/chat-messages-list/chat-message-list.component.jsx
index f045cae8c..3f2bba2f0 100644
--- a/client/src/components/chat-messages-list/chat-message-list.component.jsx
+++ b/client/src/components/chat-messages-list/chat-message-list.component.jsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useRef, useState } from "react";
+import React, { useCallback, useEffect, useRef, useState } from "react";
import { Virtuoso } from "react-virtuoso";
import { renderMessage } from "./renderMessage";
import "./chat-message-list.styles.scss";
@@ -16,7 +16,7 @@ export default function ChatMessageListComponent({ messages }) {
loadedImagesRef.current = 0;
};
- const preloadImages = (imagePaths, onComplete) => {
+ const preloadImages = useCallback((imagePaths, onComplete) => {
resetImageLoadState();
if (imagePaths.length === 0) {
@@ -34,7 +34,7 @@ export default function ChatMessageListComponent({ messages }) {
}
};
});
- };
+ }, []);
// Ensure all images are loaded on initial render
useEffect(() => {
@@ -51,7 +51,7 @@ export default function ChatMessageListComponent({ messages }) {
});
}
});
- }, [messages]);
+ }, [messages, preloadImages]);
// Handle scrolling when new messages are added
useEffect(() => {
@@ -69,7 +69,7 @@ export default function ChatMessageListComponent({ messages }) {
});
}
});
- }, [messages, atBottom]);
+ }, [messages, atBottom, preloadImages]);
return (
diff --git a/client/src/components/chat-tag-ro/chat-tag-ro.container.jsx b/client/src/components/chat-tag-ro/chat-tag-ro.container.jsx
index 1bb791b00..63839b263 100644
--- a/client/src/components/chat-tag-ro/chat-tag-ro.container.jsx
+++ b/client/src/components/chat-tag-ro/chat-tag-ro.container.jsx
@@ -52,20 +52,26 @@ export function ChatTagRoContainer({ conversation, bodyshop }) {
// Find the job details from the search data
const selectedJob = data?.search_jobs.find((job) => job.id === option.key);
if (!selectedJob) return;
- const newJobConversation = {
- __typename: "job_conversations",
- jobid: selectedJob.id,
- conversationid: conversation.id,
- job: {
- __typename: "jobs",
- ...selectedJob
- }
- };
socket.emit("conversation-modified", {
conversationId: conversation.id,
bodyshopId: bodyshop.id,
type: "tag-added",
- job_conversations: [newJobConversation]
+ selectedJob,
+ job_conversations: [
+ {
+ __typename: "job_conversations",
+ jobid: selectedJob.id,
+ conversationid: conversation.id,
+ job: {
+ __typename: "jobs",
+ id: selectedJob.id,
+ ro_number: selectedJob.ro_number,
+ ownr_co_nm: selectedJob.ownr_co_nm,
+ ownr_fn: selectedJob.ownr_fn,
+ ownr_ln: selectedJob.ownr_ln
+ }
+ }
+ ]
});
}
diff --git a/client/src/components/owner-detail-form/owner-detail-form.component.jsx b/client/src/components/owner-detail-form/owner-detail-form.component.jsx
index 419de25fa..5de4231f7 100644
--- a/client/src/components/owner-detail-form/owner-detail-form.component.jsx
+++ b/client/src/components/owner-detail-form/owner-detail-form.component.jsx
@@ -25,6 +25,9 @@ export default function OwnerDetailFormComponent({ form, loading }) {
+
+
+
diff --git a/client/src/graphql/owners.queries.js b/client/src/graphql/owners.queries.js
index e28fc8aa2..d169263f4 100644
--- a/client/src/graphql/owners.queries.js
+++ b/client/src/graphql/owners.queries.js
@@ -48,6 +48,7 @@ export const QUERY_OWNER_BY_ID = gql`
query QUERY_OWNER_BY_ID($id: uuid!) {
owners_by_pk(id: $id) {
id
+ accountingid
allow_text_message
ownr_addr1
ownr_addr2
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json
index e86e9936e..95254cb3d 100644
--- a/client/src/translations/en_us/common.json
+++ b/client/src/translations/en_us/common.json
@@ -2394,6 +2394,7 @@
"selectexistingornew": "Select an existing owner record or create a new one. "
},
"fields": {
+ "accountingid": "Accounting ID",
"address": "Address",
"allow_text_message": "Permission to Text?",
"name": "Name",
@@ -3057,6 +3058,7 @@
"production_not_production_status": "Production not in Production Status",
"production_over_time": "Production Level over Time",
"psr_by_make": "Percent of Sales by Vehicle Make",
+ "purchase_return_ratio_excel": "Purchase & Return Ratio - Excel",
"purchase_return_ratio_grouped_by_vendor_detail": "Purchase & Return Ratio by Vendor (Detail)",
"purchase_return_ratio_grouped_by_vendor_summary": "Purchase & Return Ratio by Vendor (Summary)",
"purchases_by_cost_center_detail": "Purchases by Cost Center (Detail)",
diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json
index 8b9026489..9b4c00b4b 100644
--- a/client/src/translations/es/common.json
+++ b/client/src/translations/es/common.json
@@ -2394,6 +2394,7 @@
"selectexistingornew": ""
},
"fields": {
+ "accountingid": "",
"address": "Dirección",
"allow_text_message": "Permiso de texto?",
"name": "Nombre",
@@ -3057,6 +3058,7 @@
"production_not_production_status": "",
"production_over_time": "",
"psr_by_make": "",
+ "purchase_return_ratio_excel": "",
"purchase_return_ratio_grouped_by_vendor_detail": "",
"purchase_return_ratio_grouped_by_vendor_summary": "",
"purchases_by_cost_center_detail": "",
diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json
index 8f9330ea0..1362054a4 100644
--- a/client/src/translations/fr/common.json
+++ b/client/src/translations/fr/common.json
@@ -2394,6 +2394,7 @@
"selectexistingornew": ""
},
"fields": {
+ "accountingid": "",
"address": "Adresse",
"allow_text_message": "Autorisation de texte?",
"name": "Prénom",
@@ -3057,6 +3058,7 @@
"production_not_production_status": "",
"production_over_time": "",
"psr_by_make": "",
+ "purchase_return_ratio_excel": "",
"purchase_return_ratio_grouped_by_vendor_detail": "",
"purchase_return_ratio_grouped_by_vendor_summary": "",
"purchases_by_cost_center_detail": "",
diff --git a/client/src/utils/GraphQLClient.js b/client/src/utils/GraphQLClient.js
index c60545f02..689083139 100644
--- a/client/src/utils/GraphQLClient.js
+++ b/client/src/utils/GraphQLClient.js
@@ -3,7 +3,7 @@ import { setContext } from "@apollo/client/link/context";
import { HttpLink } from "@apollo/client/link/http"; //"apollo-link-http";
import { RetryLink } from "@apollo/client/link/retry";
import { WebSocketLink } from "@apollo/client/link/ws";
-import { getMainDefinition, offsetLimitPagination } from "@apollo/client/utilities";
+import { getMainDefinition } from "@apollo/client/utilities";
//import { split } from "apollo-link";
import apolloLogger from "apollo-link-logger";
//import axios from "axios";
@@ -143,36 +143,7 @@ middlewares.push(
new SentryLink().concat(roundTripLink.concat(retryLink.concat(errorLink.concat(authLink.concat(link)))))
);
-const cache = new InMemoryCache({
- typePolicies: {
- conversations: {
- fields: {
- job_conversations: {
- merge(existing = [], incoming = [], { readField }) {
- const merged = new Map();
-
- // Add existing data to the map
- existing.forEach((jobConversation) => {
- // Use `readField` to get the unique `jobid`, fallback to `__ref`
- const jobId = readField("jobid", jobConversation) || jobConversation.__ref;
- if (jobId) merged.set(jobId, jobConversation);
- });
-
- // Add or replace with incoming data
- incoming.forEach((jobConversation) => {
- // Use `readField` to get the unique `jobid`, fallback to `__ref`
- const jobId = readField("jobid", jobConversation) || jobConversation.__ref;
- if (jobId) merged.set(jobId, jobConversation);
- });
-
- // Return the merged data as an array
- return Array.from(merged.values());
- }
- }
- }
- }
- }
-});
+const cache = new InMemoryCache({});
const client = new ApolloClient({
link: ApolloLink.from(middlewares),
cache,
diff --git a/client/src/utils/TemplateConstants.js b/client/src/utils/TemplateConstants.js
index 9f80986d2..c193dbb49 100644
--- a/client/src/utils/TemplateConstants.js
+++ b/client/src/utils/TemplateConstants.js
@@ -2184,6 +2184,19 @@ export const TemplateList = (type, context) => {
},
group: "payroll",
adp_payroll: true
+ },
+ purchase_return_ratio_excel: {
+ title: i18n.t("reportcenter.templates.purchase_return_ratio_excel"),
+ subject: i18n.t("reportcenter.templates.purchase_return_ratio_excel"),
+ key: "purchase_return_ratio_excel",
+ //idtype: "vendor",
+ reporttype: "excel",
+ disabled: false,
+ rangeFilter: {
+ object: i18n.t("reportcenter.labels.objects.bills"),
+ field: i18n.t("bills.fields.date")
+ },
+ group: "purchases"
}
}
: {}),