Merged in release/2023-11-17 (pull request #1060)

Release/2023 11 17
This commit is contained in:
Allan Carr
2023-11-17 21:46:20 +00:00
14 changed files with 116 additions and 49 deletions

2
.gitignore vendored
View File

@@ -118,3 +118,5 @@ logs/oAuthClient-log.log
.node-persist/** .node-persist/**
/*.env.* /*.env.*
.idea/*
.idea

View File

@@ -2,10 +2,10 @@ import { useQuery } from "@apollo/client";
import React from "react"; import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import ContractJobsComponent from "./contract-jobs.component"; import ContractJobsComponent from "./contract-jobs.component";
import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser //currentUser: selectCurrentUser
@@ -15,6 +15,7 @@ export function ContractJobsContainer({ selectedJobState, bodyshop }) {
const { loading, error, data } = useQuery(QUERY_ALL_ACTIVE_JOBS, { const { loading, error, data } = useQuery(QUERY_ALL_ACTIVE_JOBS, {
variables: { variables: {
statuses: bodyshop.md_ro_statuses.active_statuses || ["Open"], statuses: bodyshop.md_ro_statuses.active_statuses || ["Open"],
isConverted: true,
}, },
fetchPolicy: "network-only", fetchPolicy: "network-only",
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",

View File

@@ -4,14 +4,14 @@ import queryString from "query-string";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link, useHistory, useLocation } from "react-router-dom"; import { Link, useHistory, useLocation } from "react-router-dom";
import { setModalContext } from "../../redux/modals/modals.actions";
import { DateTimeFormatter } from "../../utils/DateFormatter"; import { DateTimeFormatter } from "../../utils/DateFormatter";
import { alphaSort } from "../../utils/sorters"; import { alphaSort } from "../../utils/sorters";
import ContractsFindModalContainer from "../contracts-find-modal/contracts-find-modal.container"; import ContractsFindModalContainer from "../contracts-find-modal/contracts-find-modal.container";
import { setModalContext } from "../../redux/modals/modals.actions";
import moment from "moment";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import moment from "moment";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({

View File

@@ -34,6 +34,18 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
{/* <FormFieldsChanged form={form} /> */} {/* <FormFieldsChanged form={form} /> */}
<LayoutFormRow header={t("courtesycars.labels.vehicle")}> <LayoutFormRow header={t("courtesycars.labels.vehicle")}>
<Form.Item
label={t("courtesycars.fields.year")}
name="year"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Input />
</Form.Item>
<Form.Item <Form.Item
label={t("courtesycars.fields.make")} label={t("courtesycars.fields.make")}
name="make" name="make"
@@ -58,18 +70,6 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
> >
<Input /> <Input />
</Form.Item> </Form.Item>
<Form.Item
label={t("courtesycars.fields.year")}
name="year"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Input />
</Form.Item>
<Form.Item <Form.Item
label={t("courtesycars.fields.plate")} label={t("courtesycars.fields.plate")}
name="plate" name="plate"
@@ -216,12 +216,6 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
<Form.Item <Form.Item
label={t("courtesycars.fields.nextservicekm")} label={t("courtesycars.fields.nextservicekm")}
name="nextservicekm" name="nextservicekm"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
@@ -229,12 +223,6 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
<Form.Item <Form.Item
label={t("courtesycars.fields.nextservicedate")} label={t("courtesycars.fields.nextservicedate")}
name="nextservicedate" name="nextservicedate"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
> >
<FormDatePicker /> <FormDatePicker />
</Form.Item> </Form.Item>
@@ -283,12 +271,6 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
<Form.Item <Form.Item
label={t("courtesycars.fields.registrationexpires")} label={t("courtesycars.fields.registrationexpires")}
name="registrationexpires" name="registrationexpires"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
> >
<FormDatePicker /> <FormDatePicker />
</Form.Item> </Form.Item>
@@ -330,9 +312,7 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
<FormDatePicker /> <FormDatePicker />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
shouldUpdate={(p, c) => shouldUpdate={(p, c) => p.insuranceexpires !== c.insuranceexpires}
p.insuranceexpires !== c.insuranceexpires
}
> >
{() => { {() => {
const expires = form.getFieldValue("insuranceexpires"); const expires = form.getFieldValue("insuranceexpires");

View File

@@ -174,6 +174,7 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
(c.year || "").toLowerCase().includes(searchText.toLowerCase()) || (c.year || "").toLowerCase().includes(searchText.toLowerCase()) ||
(c.make || "").toLowerCase().includes(searchText.toLowerCase()) || (c.make || "").toLowerCase().includes(searchText.toLowerCase()) ||
(c.model || "").toLowerCase().includes(searchText.toLowerCase()) || (c.model || "").toLowerCase().includes(searchText.toLowerCase()) ||
(c.plate || "").toLowerCase().includes(searchText.toLowerCase()) ||
(t(c.status) || "").toLowerCase().includes(searchText.toLowerCase()) (t(c.status) || "").toLowerCase().includes(searchText.toLowerCase())
) )
: courtesycars; : courtesycars;

View File

@@ -54,6 +54,7 @@ export default function GlobalSearchOs() {
job.v_make_desc || "" job.v_make_desc || ""
} ${job.v_model_desc || ""}`}</span> } ${job.v_model_desc || ""}`}</span>
<span>{`${job.clm_no || ""}`}</span> <span>{`${job.clm_no || ""}`}</span>
<span>{`${job.plate_no || ""}`}</span>
</Space> </Space>
</Link> </Link>
), ),

View File

@@ -1,6 +1,6 @@
import { useMutation } from "@apollo/client";
import { notification, Select } from "antd"; import { notification, Select } from "antd";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useMutation } from "@apollo/client";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
@@ -56,8 +56,10 @@ export function JobLineLocationPopup({ bodyshop, jobline, disabled }) {
<LoadingSpinner loading={loading}> <LoadingSpinner loading={loading}>
<Select <Select
autoFocus autoFocus
allowClear
dropdownMatchSelectWidth={100} dropdownMatchSelectWidth={100}
value={location} value={location}
onClear={() => setLocation(null)}
onSelect={handleChange} onSelect={handleChange}
onBlur={handleSave} onBlur={handleSave}
> >

View File

@@ -1,8 +1,8 @@
import { import {
BranchesOutlined,
ExclamationCircleFilled, ExclamationCircleFilled,
PauseCircleOutlined, PauseCircleOutlined,
SyncOutlined, SyncOutlined,
BranchesOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import { Button, Card, Grid, Input, Space, Table, Tooltip } from "antd"; import { Button, Card, Grid, Input, Space, Table, Tooltip } from "antd";
@@ -14,8 +14,8 @@ import { Link, useHistory, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries"; import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import { onlyUnique } from "../../utils/arrayHelper";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { onlyUnique } from "../../utils/arrayHelper";
import { alphaSort } from "../../utils/sorters"; import { alphaSort } from "../../utils/sorters";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import ChatOpenButton from "../chat-open-button/chat-open-button.component"; import ChatOpenButton from "../chat-open-button/chat-open-button.component";
@@ -46,6 +46,7 @@ export function JobsReadyList({ bodyshop }) {
const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, { const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, {
variables: { variables: {
statuses: readyStatuses, statuses: readyStatuses,
isConverted: true,
}, },
fetchPolicy: "network-only", fetchPolicy: "network-only",
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",

View File

@@ -25,6 +25,7 @@ export function TechLookupJobsList({ bodyshop }) {
const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, { const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, {
variables: { variables: {
statuses: bodyshop.md_ro_statuses.active_statuses || ["Open", "Open*"], statuses: bodyshop.md_ro_statuses.active_statuses || ["Open", "Open*"],
isConverted: true,
}, },
fetchPolicy: "network-only", fetchPolicy: "network-only",
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",

View File

@@ -1,9 +1,9 @@
import { gql } from "@apollo/client"; import { gql } from "@apollo/client";
export const QUERY_ALL_ACTIVE_JOBS = gql` export const QUERY_ALL_ACTIVE_JOBS = gql`
query QUERY_ALL_ACTIVE_JOBS($statuses: [String!]!) { query QUERY_ALL_ACTIVE_JOBS($statuses: [String!]!, $isConverted: Boolean) {
jobs( jobs(
where: { status: { _in: $statuses } } where: { status: { _in: $statuses }, converted: { _eq: $isConverted } }
order_by: { created_at: desc } order_by: { created_at: desc }
) { ) {
iouparent iouparent
@@ -432,7 +432,6 @@ export const QUERY_JOB_COSTING_DETAILS = gql`
status status
ca_bc_pvrt ca_bc_pvrt
ca_customer_gst ca_customer_gst
joblines(where: { removed: { _eq: false } }) { joblines(where: { removed: { _eq: false } }) {
id id
unq_seq unq_seq
@@ -1001,7 +1000,6 @@ export const QUERY_TECH_JOB_DETAILS = gql`
actual_completion actual_completion
actual_delivery actual_delivery
actual_in actual_in
id id
ins_co_nm ins_co_nm
clm_no clm_no
@@ -1586,7 +1584,6 @@ export const QUERY_ALL_JOB_FIELDS = gql`
clm_title clm_title
clm_total clm_total
clm_zip clm_zip
cust_pr cust_pr
ded_amt ded_amt
ded_status ded_status
@@ -1669,7 +1666,6 @@ export const QUERY_ALL_JOB_FIELDS = gql`
parts_tax_rates parts_tax_rates
pay_amt pay_amt
pay_chknm pay_chknm
pay_type pay_type
payee_nms payee_nms
plate_no plate_no
@@ -2077,6 +2073,7 @@ export const QUERY_JOB_EXPORT_DMS = gql`
} }
} }
`; `;
export const QUERY_RELATED_ROS = gql` export const QUERY_RELATED_ROS = gql`
query QUERY_RELATED_ROS($jobid: uuid!) { query QUERY_RELATED_ROS($jobid: uuid!) {
relatedjobs( relatedjobs(
@@ -2098,6 +2095,7 @@ export const QUERY_RELATED_ROS = gql`
} }
} }
`; `;
export const INSERT_RELATED_ROS = gql` export const INSERT_RELATED_ROS = gql`
mutation INSERT_RELATED_ROS($relationship: relatedjobs_insert_input!) { mutation INSERT_RELATED_ROS($relationship: relatedjobs_insert_input!) {
insert_relatedjobs_one(object: $relationship) { insert_relatedjobs_one(object: $relationship) {
@@ -2115,6 +2113,7 @@ export const INSERT_RELATED_ROS = gql`
} }
} }
`; `;
export const DELETE_RELATED_RO = gql` export const DELETE_RELATED_RO = gql`
mutation DELETE_RELATED_RO($relationshipid: uuid!) { mutation DELETE_RELATED_RO($relationshipid: uuid!) {
delete_relatedjobs_by_pk(id: $relationshipid) { delete_relatedjobs_by_pk(id: $relationshipid) {
@@ -2122,6 +2121,7 @@ export const DELETE_RELATED_RO = gql`
} }
} }
`; `;
export const GET_JOB_LINE_ORDERS = gql` export const GET_JOB_LINE_ORDERS = gql`
query GET_JOB_LINE_ORDERS($joblineid: uuid!) { query GET_JOB_LINE_ORDERS($joblineid: uuid!) {
billlines(where: { joblineid: { _eq: $joblineid } }) { billlines(where: { joblineid: { _eq: $joblineid } }) {

View File

@@ -4089,6 +4089,7 @@
- name: event-secret - name: event-secret
value_from_env: EVENT_SECRET value_from_env: EVENT_SECRET
request_transform: request_transform:
method: POST
query_params: {} query_params: {}
template_engine: Kriti template_engine: Kriti
url: '{{$base_url}}/job/statustransition' url: '{{$base_url}}/job/statustransition'

View File

@@ -0,0 +1,38 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- CREATE OR REPLACE FUNCTION public.search_cccontracts(search text)
-- RETURNS SETOF cccontracts
-- LANGUAGE plpgsql
-- STABLE
-- AS $function$
-- BEGIN
-- IF search = '' THEN
-- RETURN query
-- SELECT
-- *
-- FROM
-- cccontracts c;
-- ELSE
-- RETURN query
-- SELECT
-- contracts.*
-- FROM
-- courtesycars cars,
-- jobs jobs,
-- cccontracts contracts
-- WHERE (jobs.ro_number ILIKE '%' || search || '%'
-- OR jobs.ownr_fn ILIKE '%' || search || '%'
-- OR jobs.ownr_ln ILIKE '%' || search || '%'
-- OR jobs.ownr_co_nm ILIKE '%' || search || '%'
-- OR (cast(contracts.agreementnumber as text)) ILIKE '%' || search || '%'
-- OR contracts.driver_fn ILIKE '%' || search || '%'
-- OR contracts.driver_ln ILIKE '%' || search || '%'
-- OR cars.fleetnumber ILIKE '%' || search || '%'
-- OR cars.make ILIKE '%' || search || '%'
-- OR cars.model ILIKE '%' || search || '%'
-- OR cars.plate ILIKE '%' || search || '%')
-- AND contracts.jobid = jobs.id
-- AND contracts.courtesycarid = cars.id;
-- END IF;
-- END
-- $function$;

View File

@@ -0,0 +1,36 @@
CREATE OR REPLACE FUNCTION public.search_cccontracts(search text)
RETURNS SETOF cccontracts
LANGUAGE plpgsql
STABLE
AS $function$
BEGIN
IF search = '' THEN
RETURN query
SELECT
*
FROM
cccontracts c;
ELSE
RETURN query
SELECT
contracts.*
FROM
courtesycars cars,
jobs jobs,
cccontracts contracts
WHERE (jobs.ro_number ILIKE '%' || search || '%'
OR jobs.ownr_fn ILIKE '%' || search || '%'
OR jobs.ownr_ln ILIKE '%' || search || '%'
OR jobs.ownr_co_nm ILIKE '%' || search || '%'
OR (cast(contracts.agreementnumber as text)) ILIKE '%' || search || '%'
OR contracts.driver_fn ILIKE '%' || search || '%'
OR contracts.driver_ln ILIKE '%' || search || '%'
OR cars.fleetnumber ILIKE '%' || search || '%'
OR cars.make ILIKE '%' || search || '%'
OR cars.model ILIKE '%' || search || '%'
OR cars.plate ILIKE '%' || search || '%')
AND contracts.jobid = jobs.id
AND contracts.courtesycarid = cars.id;
END IF;
END
$function$;

View File

@@ -19,6 +19,7 @@ const aws4 = require("aws4");
const { gql } = require("graphql-request"); const { gql } = require("graphql-request");
var host = process.env.OPEN_SEARCH_HOST; var host = process.env.OPEN_SEARCH_HOST;
const createAwsConnector = (credentials, region) => { const createAwsConnector = (credentials, region) => {
class AmazonConnection extends Connection { class AmazonConnection extends Connection {
buildRequestObject(params) { buildRequestObject(params) {
@@ -207,13 +208,15 @@ async function OpenSearchUpdateHandler(req, res) {
} }
} }
async function OpensearchSearchHandler(req, res) { async function OpenSearchSearchHandler(req, res) {
try { try {
const { search, bodyshopid, index } = req.body; const { search, bodyshopid, index } = req.body;
if (!req.user) { if (!req.user) {
res.sendStatus(401); res.sendStatus(401);
return; return;
} }
logger.log("os-search", "DEBUG", req.user.email, null, { logger.log("os-search", "DEBUG", req.user.email, null, {
search, search,
}); });
@@ -273,7 +276,7 @@ async function OpensearchSearchHandler(req, res) {
{ {
query_string: { query_string: {
query: `*${search}*`, query: `*${search}*`,
// Weighted Fields
fields: [ fields: [
"*ro_number^20", "*ro_number^20",
"*clm_no^14", "*clm_no^14",
@@ -320,4 +323,4 @@ async function OpensearchSearchHandler(req, res) {
} }
exports.handler = OpenSearchUpdateHandler; exports.handler = OpenSearchUpdateHandler;
exports.search = OpensearchSearchHandler; exports.search = OpenSearchSearchHandler;