Compare commits

...

4 Commits

Author SHA1 Message Date
Dave
8a4679f86c feature/IO-3638-Reynolds-OpenSearch - Add Search on DMS id in Reynolds shops 2026-04-09 11:14:17 -04:00
Dave Richer
a4dbc5250e Merged in release/2026-04-03 (pull request #3179)
Release/2026-04-03 - IO-1366, IO-3356, IO-3515, IO-3587, IO-3599, IO-3609, IO-3616, IO-3622, IO-3623, IO-3627, IO-3629, IO-3637
2026-04-03 01:46:11 +00:00
Allan Carr
a1d0e2df93 Merged in feature/IO-3637-DMS-ID-Production-Board-Column (pull request #3175)
IO-3637 DMS ID Production Board Column

Approved-by: Dave Richer
Approved-by: Patrick Fic
2026-04-03 01:32:25 +00:00
Allan Carr
9a86a337bb IO-3637 DMS ID Production Board Column
Signed-off-by: Allan Carr <allan@imexsystems.ca>
2026-04-02 15:50:56 -07:00
9 changed files with 122 additions and 39 deletions

View File

@@ -58,6 +58,7 @@ export function ProductionColumnsComponent({
const columnKeys = columns.map((i) => i.key);
const cols = dataSource({
bodyshop,
technician,
data,
state: tableState,

View File

@@ -609,7 +609,19 @@ const productionListColumnsData = ({ technician, state, activeStatuses, data, bo
ellipsis: true,
render: (text, record) => <TimeFormatter>{record.date_repairstarted}</TimeFormatter>
}
},
...(bodyshop && bodyshop.rr_dealerid
? [
{
title: i18n.t("jobs.fields.dms.id"),
dataIndex: "dms_id",
key: "dms_id",
ellipsis: true,
sorter: (a, b) => alphaSort(a.dms_id, b.dms_id),
sortOrder: state.sortedInfo.columnKey === "dms_id" && state.sortedInfo.order
}
]
: []),
];
};
export default productionListColumnsData;

View File

@@ -244,6 +244,7 @@ export function ProductionListConfigManager({
nextConfig.columns.columnKeys.map((k) => {
return {
...ProductionListColumns({
bodyshop,
technician,
state: ensureDefaultState(state),
refetch,
@@ -270,6 +271,7 @@ export function ProductionListConfigManager({
activeConfig.columns.columnKeys.map((k) => {
return {
...ProductionListColumns({
bodyshop,
technician,
state: ensureDefaultState(state),
refetch,

View File

@@ -197,6 +197,7 @@ export const QUERY_EXACT_JOB_IN_PRODUCTION = gql`
employee_prep
employee_csr
date_repairstarted
dms_id
joblines_status {
part_type
status
@@ -269,6 +270,7 @@ export const QUERY_EXACT_JOBS_IN_PRODUCTION = gql`
employee_prep
employee_csr
date_repairstarted
dms_id
joblines_status {
part_type
status
@@ -2671,6 +2673,7 @@ export const QUERY_JOBS_IN_PRODUCTION = gql`
suspended
job_totals
date_repairstarted
dms_id
joblines_status {
part_type
status

View File

@@ -32,6 +32,7 @@ async function OpenSearchUpdateHandler(req, res) {
clm_no
clm_total
comment
dms_id
ins_co_nm
owner_owing
ownr_co_nm

View File

@@ -2442,6 +2442,9 @@ exports.ACTIVE_SHOP_BY_USER = `query ACTIVE_SHOP_BY_USER($user: String) {
associations(where: {active: {_eq: true}, useremail: {_eq: $user}}) {
id
shopid
bodyshop {
rr_dealerid
}
}
}`;

View File

@@ -4,6 +4,7 @@ const queries = require("../graphql-client/queries");
const client = require("../graphql-client/graphql-client").client;
const { pick, isNil } = require("lodash");
const { getClient } = require("../../libs/awsUtils");
const { JOB_DOCUMENT_FIELDS, getGlobalSearchQueryStringFields } = require("./os-search-config");
async function OpenSearchUpdateHandler(req, res) {
try {
@@ -21,27 +22,7 @@ async function OpenSearchUpdateHandler(req, res) {
switch (req.body.table.name) {
case "jobs":
document = pick(req.body.event.data.new, [
"id",
"bodyshopid",
"clm_no",
"clm_total",
"comment",
"ins_co_nm",
"owner_owing",
"ownr_co_nm",
"ownr_fn",
"ownr_ln",
"ownr_ph1",
"ownr_ph2",
"plate_no",
"ro_number",
"status",
"v_model_yr",
"v_make_desc",
"v_model_desc",
"v_vin"
]);
document = pick(req.body.event.data.new, JOB_DOCUMENT_FIELDS);
document.bodyshopid = req.body.event.data.new.shopid;
break;
case "vehicles":
@@ -197,15 +178,18 @@ async function OpenSearchSearchHandler(req, res) {
user: req.user.email
});
if (assocs.length === 0) {
if (assocs.associations.length === 0) {
res.sendStatus(401);
return;
}
const osClient = await getClient();
const activeAssociation = assocs.associations[0];
const bodyShopIdMatchOverride = isNil(process.env.BODY_SHOP_ID_MATCH_OVERRIDE)
? assocs.associations[0].shopid
? activeAssociation.shopid
: process.env.BODY_SHOP_ID_MATCH_OVERRIDE;
const isReynoldsEnabled = Boolean(activeAssociation.bodyshop?.rr_dealerid);
const { body } = await osClient.search({
...(index ? { index } : { index: ["jobs", "vehicles", "owners", "bills", "payments"] }),
@@ -241,21 +225,8 @@ async function OpenSearchSearchHandler(req, res) {
query: `*${search}*`,
// Weighted Fields
fields: [
"*ro_number^20",
"*clm_no^14",
"*v_vin^12",
"*plate_no^12",
"*ownr_ln^10",
"transactionid^10",
"paymentnum^10",
"invoice_number^10",
"*ownr_fn^8",
"*ownr_co_nm^8",
"*ownr_ph1^8",
"*ownr_ph2^8",
"*vendor.name^8",
"*comment^6"
// "*"
...getGlobalSearchQueryStringFields({ isReynoldsEnabled })
// "*"
]
}
}

View File

@@ -0,0 +1,69 @@
/**
* Fields to be included in the job document indexed in OpenSearch. These fields are used for both indexing and
* searching.
* @type {string[]}
*/
const JOB_DOCUMENT_FIELDS = [
"id",
"bodyshopid",
"clm_no",
"clm_total",
"comment",
"dms_id",
"ins_co_nm",
"owner_owing",
"ownr_co_nm",
"ownr_fn",
"ownr_ln",
"ownr_ph1",
"ownr_ph2",
"plate_no",
"ro_number",
"status",
"v_model_yr",
"v_make_desc",
"v_model_desc",
"v_vin"
];
/**
* Fields to be included in the global search query string. These fields are used for constructing the search query.
* @type {string[]}
*/
const BASE_GLOBAL_SEARCH_QUERY_STRING_FIELDS = [
"*ro_number^20",
"*clm_no^14",
"*v_vin^12",
"*plate_no^12",
"*ownr_ln^10",
"transactionid^10",
"paymentnum^10",
"invoice_number^10",
"*ownr_fn^8",
"*ownr_co_nm^8",
"*ownr_ph1^8",
"*ownr_ph2^8",
"*vendor.name^8",
"*comment^6"
];
/**
* Returns the fields to be included in the global search query string. If Reynolds is enabled, it includes the dms_id
* field with a higher boost.
* @param param0
* @param param0.isReynoldsEnabled
* @returns {string[]}
*/
const getGlobalSearchQueryStringFields = ({ isReynoldsEnabled = false } = {}) => {
if (!isReynoldsEnabled) {
return BASE_GLOBAL_SEARCH_QUERY_STRING_FIELDS;
}
return ["*dms_id^20", ...BASE_GLOBAL_SEARCH_QUERY_STRING_FIELDS];
};
module.exports = {
JOB_DOCUMENT_FIELDS,
BASE_GLOBAL_SEARCH_QUERY_STRING_FIELDS,
getGlobalSearchQueryStringFields
};

View File

@@ -0,0 +1,21 @@
import { describe, expect, it } from "vitest";
import { createRequire } from "module";
const require = createRequire(import.meta.url);
const { JOB_DOCUMENT_FIELDS, BASE_GLOBAL_SEARCH_QUERY_STRING_FIELDS, getGlobalSearchQueryStringFields } = require(
"../os-search-config"
);
describe("os-search-config", () => {
it("indexes dms_id on job documents", () => {
expect(JOB_DOCUMENT_FIELDS).toContain("dms_id");
});
it("includes dms_id in global search fields for Reynolds shops", () => {
expect(getGlobalSearchQueryStringFields({ isReynoldsEnabled: true })).toContain("*dms_id^20");
});
it("keeps the default search fields unchanged for non-Reynolds shops", () => {
expect(getGlobalSearchQueryStringFields()).toEqual(BASE_GLOBAL_SEARCH_QUERY_STRING_FIELDS);
});
});