From 9bd86126da2a613598844b994e196fc79b945069 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 19 Jan 2024 16:27:44 -0500 Subject: [PATCH 01/35] Update generic error message --- app/client/src/config.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/client/src/config.tsx b/app/client/src/config.tsx index d439f5d8..3437fa1f 100644 --- a/app/client/src/config.tsx +++ b/app/client/src/config.tsx @@ -32,7 +32,7 @@ const formioProjectName = VITE_FORMIO_PROJECT_NAME; export const formioProjectUrl = `${formioBaseUrl}/${formioProjectName}`; export const messages = { - genericError: "Something went wrong.", + genericError: "The application has encountered an unknown error.", authError: "Authentication error. Please log in again or contact support.", samlError: "Error logging in. Please try again or contact support.", bapSamFetchError: "Error loading SAM.gov data. Please contact support.", From 7b6fb344434a3081a3018064780a4f13fff16341 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 19 Jan 2024 16:34:22 -0500 Subject: [PATCH 02/35] Rename Submission component's ButtonLink to FormButtonLink --- app/client/src/routes/submissions.tsx | 28 +++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/app/client/src/routes/submissions.tsx b/app/client/src/routes/submissions.tsx index 6c024466..bd4a206f 100644 --- a/app/client/src/routes/submissions.tsx +++ b/app/client/src/routes/submissions.tsx @@ -37,7 +37,7 @@ import type { const defaultTableRowClassNames = "bg-gray-5"; const highlightedTableRowClassNames = "bg-primary-lighter"; -function ButtonLink(props: { type: "edit" | "view"; to: LinkProps["to"] }) { +function FormButtonLink(props: { type: "edit" | "view"; to: LinkProps["to"] }) { const icon = props.type === "edit" ? "edit" : "visibility"; const text = props.type === "edit" ? "Edit" : "View"; const linkClassNames = @@ -241,11 +241,11 @@ function FRF2022Submission(props: { rebate: Rebate }) { > {frfNeedsEdits ? ( - + ) : frf.formio.state === "submitted" || !frfSubmissionPeriodOpen ? ( - + ) : frf.formio.state === "draft" ? ( - + ) : null} @@ -566,13 +566,13 @@ function PRF2022Submission(props: { rebate: Rebate }) { > {frfNeedsEdits ? ( - + ) : prfNeedsEdits ? ( - + ) : prf.formio.state === "submitted" || !prfSubmissionPeriodOpen ? ( - + ) : prf.formio.state === "draft" ? ( - + ) : null} @@ -790,11 +790,11 @@ function CRF2022Submission(props: { rebate: Rebate }) { > {crfNeedsEdits ? ( - + ) : crf.formio.state === "submitted" || !crfSubmissionPeriodOpen ? ( - + ) : crf.formio.state === "draft" ? ( - + ) : null} @@ -948,11 +948,11 @@ function FRF2023Submission(props: { rebate: Rebate }) { > {frfNeedsEdits ? ( - + ) : frf.formio.state === "submitted" || !frfSubmissionPeriodOpen ? ( - + ) : frf.formio.state === "draft" ? ( - + ) : null} From d03ea688e57411c1f1c841d65aae59c8bd27dda4 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 19 Jan 2024 17:05:03 -0500 Subject: [PATCH 03/35] Update Submissions component with new PRF2023Submission component --- app/client/src/routes/submissions.tsx | 244 +++++++++++++++++++++++++- 1 file changed, 243 insertions(+), 1 deletion(-) diff --git a/app/client/src/routes/submissions.tsx b/app/client/src/routes/submissions.tsx index bd4a206f..d39c4d80 100644 --- a/app/client/src/routes/submissions.tsx +++ b/app/client/src/routes/submissions.tsx @@ -29,7 +29,7 @@ import type { FormioPRF2022Submission, FormioCRF2022Submission, FormioFRF2023Submission, - // FormioPRF2023Submission, + FormioPRF2023Submission, // FormioCRF2023Submission, Rebate, } from "@/utilities"; @@ -1048,6 +1048,246 @@ function FRF2023Submission(props: { rebate: Rebate }) { ); } +function PRF2023Submission(props: { rebate: Rebate }) { + const { rebate } = props; + const { frf, prf, crf } = rebate; + + const navigate = useNavigate(); + const { email } = useOutletContext<{ email: string }>(); + + const configData = useConfigData(); + const bapSamData = useBapSamData(); + const { displayErrorNotification } = useNotificationsActions(); + + /** + * Stores when data is being posted to the server, so a loading indicator can + * be rendered inside the "New Payment Request" button, and we can prevent + * double submits/creations of new PRF submissions. + */ + const [dataIsPosting, setDataIsPosting] = useState(false); + + if (!configData || !bapSamData) return null; + + const prfSubmissionPeriodOpen = configData.submissionPeriodOpen["2023"].prf; + + const frfSelected = frf.bap?.status === "Accepted"; + + const frfSelectedButNoPRF = frfSelected && !Boolean(prf.formio); + + /** matched SAM.gov entity for the FRF submission */ + const entity = bapSamData.entities.find((entity) => { + const { ENTITY_STATUS__c, ENTITY_COMBO_KEY__c } = entity; + const comboKey = (frf.formio as FormioFRF2023Submission).data + ._bap_entity_combo_key; + return ENTITY_STATUS__c === "Active" && ENTITY_COMBO_KEY__c === comboKey; + }); + + if (frfSelectedButNoPRF) { + return ( + + + + + + ); + } + + // return if a Payment Request submission has not been created for this rebate + if (!prf.formio) return null; + + const { + _user_email, + _bap_rebate_id, // + } = (prf.formio as FormioPRF2023Submission).data; + + const date = new Date(prf.formio.modified).toLocaleDateString(); + const time = new Date(prf.formio.modified).toLocaleTimeString(); + + const frfNeedsEdits = submissionNeedsEdits({ + formio: frf.formio, + bap: frf.bap, + }); + + const prfNeedsEdits = submissionNeedsEdits({ + formio: prf.formio, + bap: prf.bap, + }); + + // TODO: review statuses for 2023 PRF + const prfNeedsClarification = prf.bap?.status === "Needs Clarification"; + + const prfHasBeenWithdrawn = prf.bap?.status === "Withdrawn"; + + const prfFundingNotApproved = prf.bap?.status === "Coordinator Denied"; + + const prfFundingApproved = prf.bap?.status === "Accepted"; + + const prfFundingApprovedButNoCRF = prfFundingApproved && !Boolean(crf.formio); + + const statusTableCellClassNames = + prf.formio.state === "submitted" || !prfSubmissionPeriodOpen + ? "text-italic" + : ""; + + const statusIconClassNames = prfFundingApproved + ? "usa-icon text-primary" // blue + : "usa-icon"; + + const statusIcon = prfNeedsEdits + ? `${icons}#priority_high` // ! + : prfHasBeenWithdrawn + ? `${icons}#close` // ✕ + : prfFundingNotApproved + ? `${icons}#cancel` // ✕ inside a circle + : prfFundingApproved + ? `${icons}#check_circle` // check inside a circle + : prf.formio.state === "draft" + ? `${icons}#more_horiz` // three horizontal dots + : prf.formio.state === "submitted" + ? `${icons}#check` // check + : `${icons}#remove`; // — (fallback, not used) + + const statusText = prfNeedsEdits + ? "Edits Requested" + : prfHasBeenWithdrawn + ? "Withdrawn" + : prfFundingNotApproved + ? "Funding Not Approved" + : prfFundingApproved + ? "Funding Approved" + : prf.formio.state === "draft" + ? "Draft" + : prf.formio.state === "submitted" + ? "Submitted" + : ""; // fallback, not used + + const prfUrl = `/prf/2023/${_bap_rebate_id}`; + + return ( + + + {frfNeedsEdits ? ( + + ) : prfNeedsEdits ? ( + + ) : prf.formio.state === "submitted" || !prfSubmissionPeriodOpen ? ( + + ) : prf.formio.state === "draft" ? ( + + ) : null} + + +   + + + Payment Request +
+ + {prfNeedsClarification ? ( + + ) : ( + <> + + {statusText} + + )} + + + +   + +   + + + {_user_email} +
+ {date} + + + ); +} + +function CRF2023Submission(props: { rebate: Rebate }) { + // +} + function Submissions2022() { const content = useContentData(); const submissionsQueries = useSubmissionsQueries("2022"); @@ -1150,6 +1390,8 @@ function Submissions2023() { return rebate.rebateYear === "2023" ? ( + + {/* */} {/* blank row after all submissions but the last one */} {index !== submissions.length - 1 && ( From 0e626cb3a310514885475292974bd985ac1a9a06 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Mon, 22 Jan 2024 09:08:51 -0500 Subject: [PATCH 04/35] Add initial prf2023 route component --- app/client/src/components/app.tsx | 4 + app/client/src/routes/prf2023.tsx | 468 ++++++++++++++++++++++++++++++ 2 files changed, 472 insertions(+) create mode 100644 app/client/src/routes/prf2023.tsx diff --git a/app/client/src/components/app.tsx b/app/client/src/components/app.tsx index 98945305..43639c79 100644 --- a/app/client/src/components/app.tsx +++ b/app/client/src/components/app.tsx @@ -40,6 +40,8 @@ import { FRF2022 } from "@/routes/frf2022"; import { PRF2022 } from "@/routes/prf2022"; import { CRF2022 } from "@/routes/crf2022"; import { FRF2023 } from "@/routes/frf2023"; +import { PRF2023 } from "@/routes/prf2023"; +// import { CRF2023 } from "@/routes/crf2023"; import { useDialogState, useDialogActions } from "@/contexts/dialog"; /** Custom hook to display a site-wide alert banner */ @@ -249,6 +251,8 @@ export function App() { } /> } /> + } /> + {/* } /> */} } /> diff --git a/app/client/src/routes/prf2023.tsx b/app/client/src/routes/prf2023.tsx new file mode 100644 index 00000000..dc1f9ad6 --- /dev/null +++ b/app/client/src/routes/prf2023.tsx @@ -0,0 +1,468 @@ +import { useEffect, useMemo, useRef } from "react"; +import { useNavigate, useOutletContext, useParams } from "react-router-dom"; +import { useQueryClient, useQuery, useMutation } from "@tanstack/react-query"; +import { Dialog } from "@headlessui/react"; +import { Formio, Form } from "@formio/react"; +import s3 from "formiojs/providers/storage/s3"; +import { cloneDeep, isEqual } from "lodash"; +import icons from "uswds/img/sprite.svg"; +// --- +import { serverUrl, messages } from "@/config"; +import { + getData, + postData, + useContentData, + useConfigData, + useBapSamData, + useSubmissionsQueries, + useSubmissions, + submissionNeedsEdits, + getUserInfo, +} from "@/utilities"; +import { Loading } from "@/components/loading"; +import { Message } from "@/components/message"; +import { MarkdownContent } from "@/components/markdownContent"; +import { useNotificationsActions } from "@/contexts/notifications"; +import { useRebateYearState } from "@/contexts/rebateYear"; +import type { FormioPRF2023Submission } from "@/utilities"; + +type ServerResponse = + | { + userAccess: false; + formSchema: null; + submission: null; + } + | { + userAccess: true; + formSchema: { url: string; json: object }; + submission: FormioPRF2023Submission; + }; + +/** Custom hook to fetch Formio submission data */ +function useFormioSubmissionQueryAndMutation(rebateId: string | undefined) { + const queryClient = useQueryClient(); + + useEffect(() => { + queryClient.resetQueries({ queryKey: ["formio/2023/prf-submission"] }); + }, [queryClient]); + + const url = `${serverUrl}/api/formio/2023/prf-submission/${rebateId}`; + + const query = useQuery({ + queryKey: ["formio/2023/prf-submission", { id: rebateId }], + queryFn: () => { + return getData(url).then((res) => { + const mongoId = res.submission?._id; + const comboKey = res.submission?.data._bap_entity_combo_key; + + /** + * Change the formUrl the File component's `uploadFile` uses, so the s3 + * upload PUT request is routed through the server app. + * + * https://github.com/formio/formio.js/blob/master/src/components/file/File.js#L760 + * https://github.com/formio/formio.js/blob/master/src/providers/storage/s3.js#L5 + * https://github.com/formio/formio.js/blob/master/src/providers/storage/xhr.js#L90 + */ + Formio.Providers.providers.storage.s3 = function (formio: { + formUrl: string; + [field: string]: unknown; + }) { + const s3Formio = cloneDeep(formio); + s3Formio.formUrl = `${serverUrl}/api/formio/2023/s3/prf/${mongoId}/${comboKey}`; + return s3(s3Formio); + }; + + return Promise.resolve(res); + }); + }, + refetchOnWindowFocus: false, + }); + + const mutation = useMutation({ + mutationFn: (updatedSubmission: { + mongoId: string; + submission: { + data: { [field: string]: unknown }; + metadata: { [field: string]: unknown }; + state: "submitted" | "draft"; + }; + }) => { + return postData(url, updatedSubmission); + }, + onSuccess: (res) => { + return queryClient.setQueryData( + ["formio/2023/prf-submission", { id: rebateId }], + (prevData) => { + return prevData?.submission + ? { ...prevData, submission: res } + : prevData; + }, + ); + }, + }); + + return { query, mutation }; +} + +export function PRF2023() { + const { email } = useOutletContext<{ email: string }>(); + /* ensure user verification (JWT refresh) doesn't cause form to re-render */ + return useMemo(() => { + return ; + }, [email]); +} + +function PaymentRequestForm(props: { email: string }) { + const { email } = props; + + const navigate = useNavigate(); + const { id: rebateId } = useParams<"id">(); // CSB Rebate ID (6 digits) + + const content = useContentData(); + const configData = useConfigData(); + const bapSamData = useBapSamData(); + const { + displaySuccessNotification, + displayErrorNotification, + dismissNotification, + } = useNotificationsActions(); + const { rebateYear } = useRebateYearState(); + + const submissionsQueries = useSubmissionsQueries("2023"); + const submissions = useSubmissions("2023"); + + const { query, mutation } = useFormioSubmissionQueryAndMutation(rebateId); + const { userAccess, formSchema, submission } = query.data ?? {}; + + /** + * Stores when data is being posted to the server, so a loading overlay can + * be rendered over the form, preventing the user from losing input data when + * the form is re-rendered with data returned from the server's successful + * post response. + */ + const dataIsPosting = useRef(false); + + /** + * Stores when the form is being submitted, so it can be referenced in the + * Form component's `onSubmit` event prop to prevent double submits. + */ + const formIsBeingSubmitted = useRef(false); + + /** + * Stores the form data's state right after the user clicks the Save, Submit, + * or Next button. As soon as a post request to update the data succeeds, this + * pending submission data is reset to an empty object. This pending data, + * along with the submission data returned from the server is passed into the + * Form component's `submission` prop. + */ + const pendingSubmissionData = useRef<{ [field: string]: unknown }>({}); + + /** + * Stores the last succesfully submitted data, so it can be used in the Form + * component's `onNextPage` event prop's "dirty check" which determines if + * posting of updated data is needed (so we don't make needless requests if no + * field data in the form has changed). + */ + const lastSuccesfullySubmittedData = useRef<{ [field: string]: unknown }>({}); + + if (!configData || !bapSamData) { + return ; + } + + if (submissionsQueries.some((query) => query.isFetching)) { + return ; + } + + if (submissionsQueries.some((query) => query.isError)) { + return ; + } + + if (query.isInitialLoading) { + return ; + } + + if (query.isError || !userAccess || !formSchema || !submission) { + return ; + } + + const rebate = submissions.find((r) => r.rebateId === rebateId); + + const frfNeedsEdits = !rebate + ? false + : submissionNeedsEdits({ + formio: rebate.frf.formio, + bap: rebate.frf.bap, + }); + + const prfNeedsEdits = !rebate + ? false + : submissionNeedsEdits({ + formio: rebate.prf.formio, + bap: rebate.prf.bap, + }); + + const prfSubmissionPeriodOpen = + configData.submissionPeriodOpen[rebateYear].prf; + + const formIsReadOnly = + frfNeedsEdits || + ((submission.state === "submitted" || !prfSubmissionPeriodOpen) && + !prfNeedsEdits); + + /** matched SAM.gov entity for the Payment Request submission */ + const entity = bapSamData.entities.find((entity) => { + const { ENTITY_COMBO_KEY__c } = entity; + return ENTITY_COMBO_KEY__c === submission.data._bap_entity_combo_key; + }); + + if (!entity) { + return ; + } + + if (entity.ENTITY_STATUS__c !== "Active") { + return ; + } + + // const { + // UNIQUE_ENTITY_ID__c, + // ENTITY_EFT_INDICATOR__c, + // ELEC_BUS_POC_EMAIL__c, + // ALT_ELEC_BUS_POC_EMAIL__c, + // GOVT_BUS_POC_EMAIL__c, + // ALT_GOVT_BUS_POC_EMAIL__c, + // } = entity; + + const { title, name } = getUserInfo(email, entity); + + return ( +
+ {content && ( + + )} + + {frfNeedsEdits && ( + + )} + +
    +
  • +
    + +
    +
    + Rebate ID: {rebateId} +
    +
  • +
+ + {}}> +
+
+
+ + + +
+
+
+ +
+
{ + if (formIsReadOnly) return; + + // account for when form is being submitted to prevent double submits + if (formIsBeingSubmitted.current) return; + if (onSubmitSubmission.state === "submitted") { + formIsBeingSubmitted.current = true; + } + + const data = { ...onSubmitSubmission.data }; + + const updatedSubmission = { + mongoId: submission._id, + submission: { + ...onSubmitSubmission, + data, + }, + }; + + dismissNotification({ id: 0 }); + dataIsPosting.current = true; + pendingSubmissionData.current = data; + + mutation.mutate(updatedSubmission, { + onSuccess: (res, _payload, _context) => { + pendingSubmissionData.current = {}; + lastSuccesfullySubmittedData.current = cloneDeep(res.data); + + /** success notification id */ + const id = Date.now(); + + displaySuccessNotification({ + id, + body: ( +

+ {onSubmitSubmission.state === "submitted" ? ( + <> + Payment Request {rebateId} submitted + successfully. + + ) : ( + <>Draft saved successfully. + )} +

+ ), + }); + + if (onSubmitSubmission.state === "submitted") { + /** + * NOTE: we'll keep the success notification displayed and + * redirect the user to their dashboard + */ + navigate("/"); + } + + if (onSubmitSubmission.state === "draft") { + setTimeout(() => dismissNotification({ id }), 5000); + } + }, + onError: (_error, _payload, _context) => { + displayErrorNotification({ + id: Date.now(), + body: ( +

+ {onSubmitSubmission.state === "submitted" ? ( + <>Error submitting Payment Request form. + ) : ( + <>Error saving draft. + )} +

+ ), + }); + }, + onSettled: (_data, _error, _payload, _context) => { + dataIsPosting.current = false; + formIsBeingSubmitted.current = false; + }, + }); + }} + onNextPage={(onNextPageParam: { + page: number; + submission: { + data: { [field: string]: unknown }; + metadata: { [field: string]: unknown }; + }; + }) => { + if (formIsReadOnly) return; + + const data = { ...onNextPageParam.submission.data }; + + // "dirty check" – don't post an update if no changes have been made + // to the form (ignoring current user fields) + const currentData = { ...data }; + const submittedData = { ...lastSuccesfullySubmittedData.current }; + + delete currentData._user_email; + delete currentData._user_title; + delete currentData._user_name; + delete submittedData._user_email; + delete submittedData._user_title; + delete submittedData._user_name; + if (isEqual(currentData, submittedData)) return; + + const updatedSubmission = { + mongoId: submission._id, + submission: { + ...onNextPageParam.submission, + data, + state: "draft" as const, + }, + }; + + dismissNotification({ id: 0 }); + dataIsPosting.current = true; + pendingSubmissionData.current = data; + + mutation.mutate(updatedSubmission, { + onSuccess: (res, _payload, _context) => { + pendingSubmissionData.current = {}; + lastSuccesfullySubmittedData.current = cloneDeep(res.data); + + /** success notification id */ + const id = Date.now(); + + displaySuccessNotification({ + id, + body: ( +

+ Draft saved successfully. +

+ ), + }); + + setTimeout(() => dismissNotification({ id }), 5000); + }, + onError: (_error, _payload, _context) => { + displayErrorNotification({ + id: Date.now(), + body: ( +

+ Error saving draft. +

+ ), + }); + }, + onSettled: (_data, _error, _payload, _context) => { + dataIsPosting.current = false; + }, + }); + }} + /> +
+ + {frfNeedsEdits && ( + + )} +
+ ); +} From c398e27da8dc543c31745eda6eabb211e5588217 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Mon, 22 Jan 2024 15:03:27 -0500 Subject: [PATCH 05/35] Move fetching of prf submissions into new formio utility function for use across rebate years --- app/server/app/routes/formio2022.js | 24 +++-------------- app/server/app/routes/formio2023.js | 6 +++-- app/server/app/utilities/formio.js | 42 +++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/app/server/app/routes/formio2022.js b/app/server/app/routes/formio2022.js index 0da1cbe6..60c36b89 100644 --- a/app/server/app/routes/formio2022.js +++ b/app/server/app/routes/formio2022.js @@ -21,10 +21,13 @@ const { const { uploadS3FileMetadata, downloadS3FileMetadata, + // fetchFRFSubmissions, createFRFSubmission, fetchFRFSubmission, updateFRFSubmission, + // + fetchPRFSubmissions, } = require("../utilities/formio"); const log = require("../utilities/logger"); @@ -85,26 +88,7 @@ router.post( // --- get user's 2022 PRF submissions from Formio router.get("/prf-submissions", storeBapComboKeys, (req, res) => { - const { bapComboKeys } = req; - - const submissionsUrl = - `${formioPRFUrl}/submission` + - `?sort=-modified` + - `&limit=1000000` + - `&data.bap_hidden_entity_combo_key=${bapComboKeys.join( - "&data.bap_hidden_entity_combo_key=", - )}`; - - axiosFormio(req) - .get(submissionsUrl) - .then((axiosRes) => axiosRes.data) - .then((submissions) => res.json(submissions)) - .catch((error) => { - // NOTE: error is logged in axiosFormio response interceptor - const errorStatus = error.response?.status || 500; - const errorMessage = `Error getting Formio Payment Request form submissions.`; - return res.status(errorStatus).json({ message: errorMessage }); - }); + fetchPRFSubmissions({ rebateYear: "2022", req, res }); }); // --- post a new 2022 PRF submission to Formio diff --git a/app/server/app/routes/formio2023.js b/app/server/app/routes/formio2023.js index 2de8ea34..d8c0f3d9 100644 --- a/app/server/app/routes/formio2023.js +++ b/app/server/app/routes/formio2023.js @@ -21,10 +21,13 @@ const { const { uploadS3FileMetadata, downloadS3FileMetadata, + // fetchFRFSubmissions, createFRFSubmission, fetchFRFSubmission, updateFRFSubmission, + // + fetchPRFSubmissions, } = require("../utilities/formio"); const log = require("../utilities/logger"); @@ -82,8 +85,7 @@ router.post( // --- get user's 2023 PRF submissions from Formio router.get("/prf-submissions", storeBapComboKeys, (req, res) => { - // TODO - res.json([]); + fetchPRFSubmissions({ rebateYear: "2023", req, res }); }); // --- post a new 2023 PRF submission to Formio diff --git a/app/server/app/utilities/formio.js b/app/server/app/utilities/formio.js index 4f509c88..e8a9fb44 100644 --- a/app/server/app/utilities/formio.js +++ b/app/server/app/utilities/formio.js @@ -352,11 +352,53 @@ function updateFRFSubmission({ rebateYear, req, res }) { }); } +/** + * @param {Object} param + * @param {'2022' | '2023'} param.rebateYear + * @param {express.Request} param.req + * @param {express.Response} param.res + */ +function fetchPRFSubmissions({ rebateYear, req, res }) { + const { bapComboKeys } = req; + + const comboKeyFieldName = getComboKeyFieldName({ rebateYear }); + const comboKeySearchParam = `&data.${comboKeyFieldName}=`; + + const formioFormUrl = formUrl[rebateYear].prf; + + if (!formioFormUrl) { + const errorStatus = 400; + const errorMessage = `Formio form URL does not exist for ${rebateYear} PRF.`; + return res.status(errorStatus).json({ message: errorMessage }); + } + + const submissionsUrl = + `${formioFormUrl}/submission` + + `?sort=-modified` + + `&limit=1000000` + + comboKeySearchParam + + `${bapComboKeys.join(comboKeySearchParam)}`; + + axiosFormio(req) + .get(submissionsUrl) + .then((axiosRes) => axiosRes.data) + .then((submissions) => res.json(submissions)) + .catch((error) => { + // NOTE: error is logged in axiosFormio response interceptor + const errorStatus = error.response?.status || 500; + const errorMessage = `Error getting Formio ${rebateYear} Payment Request form submissions.`; + return res.status(errorStatus).json({ message: errorMessage }); + }); +} + module.exports = { uploadS3FileMetadata, downloadS3FileMetadata, + // fetchFRFSubmissions, createFRFSubmission, fetchFRFSubmission, updateFRFSubmission, + // + fetchPRFSubmissions, }; From 596f94a5c40ffd581a384009359901f32d4b6c97 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Mon, 22 Jan 2024 17:33:03 -0500 Subject: [PATCH 06/35] Move creation of a brand new prf submission into new formio utility function for use across rebate years --- app/server/app/routes/formio2022.js | 126 +--------------------- app/server/app/utilities/formio.js | 160 +++++++++++++++++++++++++++- 2 files changed, 161 insertions(+), 125 deletions(-) diff --git a/app/server/app/routes/formio2022.js b/app/server/app/routes/formio2022.js index 60c36b89..d5a4bfb3 100644 --- a/app/server/app/routes/formio2022.js +++ b/app/server/app/routes/formio2022.js @@ -14,7 +14,6 @@ const { } = require("../middleware"); const { getBapFormSubmissionsStatuses, - getBapDataForPRF, getBapDataForCRF, checkFormSubmissionPeriodAndBapStatus, } = require("../utilities/bap"); @@ -28,6 +27,7 @@ const { updateFRFSubmission, // fetchPRFSubmissions, + createPRFSubmission, } = require("../utilities/formio"); const log = require("../utilities/logger"); @@ -93,129 +93,7 @@ router.get("/prf-submissions", storeBapComboKeys, (req, res) => { // --- post a new 2022 PRF submission to Formio router.post("/prf-submission", storeBapComboKeys, (req, res) => { - const { bapComboKeys, body } = req; - const { mail } = req.user; - const { - email, - title, - name, - entity, - comboKey, - rebateId, - frfReviewItemId, - frfFormModified, - } = body; - - if (!submissionPeriodOpen["2022"].prf) { - const errorStatus = 400; - const errorMessage = `CSB Payment Request form enrollment period is closed.`; - return res.status(errorStatus).json({ message: errorMessage }); - } - - if (!bapComboKeys.includes(comboKey)) { - const logMessage = - `User with email '${mail}' attempted to post a new PRF submission ` + - `without a matching BAP combo key.`; - log({ level: "error", message: logMessage, req }); - - const errorStatus = 401; - const errorMessage = `Unauthorized.`; - return res.status(errorStatus).json({ message: errorMessage }); - } - - const { - UNIQUE_ENTITY_ID__c, - ENTITY_EFT_INDICATOR__c, - ELEC_BUS_POC_EMAIL__c, - ALT_ELEC_BUS_POC_EMAIL__c, - GOVT_BUS_POC_EMAIL__c, - ALT_GOVT_BUS_POC_EMAIL__c, - } = entity; - - return getBapDataForPRF(req, frfReviewItemId) - .then(({ frfRecordQuery, busRecordsQuery }) => { - const { - CSB_NCES_ID__c, - Primary_Applicant__r, - Alternate_Applicant__r, - Applicant_Organization__r, - CSB_School_District__r, - Fleet_Name__c, - School_District_Prioritized__c, - Total_Rebate_Funds_Requested__c, - Total_Infrastructure_Funds__c, - } = frfRecordQuery[0]; - - const busInfo = busRecordsQuery.map((record) => ({ - busNum: record.Rebate_Item_num__c, - oldBusNcesDistrictId: CSB_NCES_ID__c, - oldBusVin: record.CSB_VIN__c, - oldBusModelYear: record.CSB_Model_Year__c, - oldBusFuelType: record.CSB_Fuel_Type__c, - newBusFuelType: record.CSB_Replacement_Fuel_Type__c, - hidden_bap_max_rebate: record.CSB_Funds_Requested__c, - })); - - /** - * NOTE: `purchaseOrders` is initialized as an empty array to fix some - * issue with the field being changed to an object when the form loads - */ - const submission = { - data: { - bap_hidden_entity_combo_key: comboKey, - hidden_application_form_modified: frfFormModified, - hidden_current_user_email: email, - hidden_current_user_title: title, - hidden_current_user_name: name, - hidden_sam_uei: UNIQUE_ENTITY_ID__c, - hidden_sam_efti: ENTITY_EFT_INDICATOR__c || "0000", - hidden_sam_elec_bus_poc_email: ELEC_BUS_POC_EMAIL__c, - hidden_sam_alt_elec_bus_poc_email: ALT_ELEC_BUS_POC_EMAIL__c, - hidden_sam_govt_bus_poc_email: GOVT_BUS_POC_EMAIL__c, - hidden_sam_alt_govt_bus_poc_email: ALT_GOVT_BUS_POC_EMAIL__c, - hidden_bap_rebate_id: rebateId, - hidden_bap_district_id: CSB_NCES_ID__c, - hidden_bap_primary_name: Primary_Applicant__r?.Name, - hidden_bap_primary_title: Primary_Applicant__r?.Title, - hidden_bap_primary_phone_number: Primary_Applicant__r?.Phone, - hidden_bap_primary_email: Primary_Applicant__r?.Email, - hidden_bap_alternate_name: Alternate_Applicant__r?.Name || "", - hidden_bap_alternate_title: Alternate_Applicant__r?.Title || "", - hidden_bap_alternate_phone_number: Alternate_Applicant__r?.Phone || "", // prettier-ignore - hidden_bap_alternate_email: Alternate_Applicant__r?.Email || "", - hidden_bap_org_name: Applicant_Organization__r?.Name, - hidden_bap_district_name: CSB_School_District__r?.Name, - hidden_bap_fleet_name: Fleet_Name__c, - hidden_bap_prioritized: School_District_Prioritized__c, - hidden_bap_requested_funds: Total_Rebate_Funds_Requested__c, - hidden_bap_infra_max_rebate: Total_Infrastructure_Funds__c, - busInfo, - purchaseOrders: [], - }, - /** Add custom metadata to track formio submissions from wrapper. */ - metadata: { - ...formioCSBMetadata, - }, - state: "draft", - }; - - axiosFormio(req) - .post(`${formioPRFUrl}/submission`, submission) - .then((axiosRes) => axiosRes.data) - .then((submission) => res.json(submission)) - .catch((error) => { - // NOTE: error is logged in axiosFormio response interceptor - const errorStatus = error.response?.status || 500; - const errorMessage = `Error posting Formio Payment Request form submission.`; - return res.status(errorStatus).json({ message: errorMessage }); - }); - }) - .catch((error) => { - // NOTE: logged in bap verifyBapConnection - const errorStatus = 500; - const errorMessage = `Error getting data for a new Payment Request form submission from the BAP.`; - return res.status(errorStatus).json({ message: errorMessage }); - }); + createPRFSubmission({ rebateYear: "2022", req, res }); }); // --- get an existing 2022 PRF's schema and submission data from Formio diff --git a/app/server/app/utilities/formio.js b/app/server/app/utilities/formio.js index e8a9fb44..f9950353 100644 --- a/app/server/app/utilities/formio.js +++ b/app/server/app/utilities/formio.js @@ -6,7 +6,10 @@ const { submissionPeriodOpen, formioCSBMetadata, } = require("../config/formio"); -const { checkFormSubmissionPeriodAndBapStatus } = require("./bap"); +const { + getBapDataForPRF, + checkFormSubmissionPeriodAndBapStatus, +} = require("../utilities/bap"); const log = require("./logger"); /** @@ -21,6 +24,110 @@ function getComboKeyFieldName({ rebateYear }) { : ""; } +/** + * @param {Object} param + * @param {'2022' | '2023'} param.rebateYear + * @param {express.Request} param.req + * @param {express.Response} param.res + * @returns {Promise<{ data: Object, metadata: Object, state: 'draft' }>} + */ +function fetchDataForPRFSubmission({ rebateYear, req, res }) { + /** @type {{ + * email: string + * title: string + * name: string + * entity: import('./bap.js').BapSamEntity + * comboKey: ?string + * rebateId: ?string + * frfReviewItemId: ?string + * frfFormModified: ?string + * }} */ + const { + email, + title, + name, + entity, + comboKey, + rebateId, + frfReviewItemId, + frfFormModified, + } = req.body; + + return getBapDataForPRF(req, frfReviewItemId) + .then(({ frfRecordQuery, busRecordsQuery }) => { + const { + CSB_NCES_ID__c, + Primary_Applicant__r, + Alternate_Applicant__r, + Applicant_Organization__r, + CSB_School_District__r, + Fleet_Name__c, + School_District_Prioritized__c, + Total_Rebate_Funds_Requested__c, + Total_Infrastructure_Funds__c, + } = frfRecordQuery[0]; + + const busInfo = busRecordsQuery.map((record) => ({ + busNum: record.Rebate_Item_num__c, + oldBusNcesDistrictId: CSB_NCES_ID__c, + oldBusVin: record.CSB_VIN__c, + oldBusModelYear: record.CSB_Model_Year__c, + oldBusFuelType: record.CSB_Fuel_Type__c, + newBusFuelType: record.CSB_Replacement_Fuel_Type__c, + hidden_bap_max_rebate: record.CSB_Funds_Requested__c, + })); + + /** + * NOTE: `purchaseOrders` is initialized as an empty array to fix some + * issue with the field being changed to an object when the form loads + */ + const submission = { + data: { + bap_hidden_entity_combo_key: comboKey, + hidden_application_form_modified: frfFormModified, + hidden_current_user_email: email, + hidden_current_user_title: title, + hidden_current_user_name: name, + hidden_sam_uei: entity.UNIQUE_ENTITY_ID__c, + hidden_sam_efti: entity.ENTITY_EFT_INDICATOR__c || "0000", + hidden_sam_elec_bus_poc_email: entity.ELEC_BUS_POC_EMAIL__c, + hidden_sam_alt_elec_bus_poc_email: entity.ALT_ELEC_BUS_POC_EMAIL__c, + hidden_sam_govt_bus_poc_email: entity.GOVT_BUS_POC_EMAIL__c, + hidden_sam_alt_govt_bus_poc_email: entity.ALT_GOVT_BUS_POC_EMAIL__c, + hidden_bap_rebate_id: rebateId, + hidden_bap_district_id: CSB_NCES_ID__c, + hidden_bap_primary_name: Primary_Applicant__r?.Name, + hidden_bap_primary_title: Primary_Applicant__r?.Title, + hidden_bap_primary_phone_number: Primary_Applicant__r?.Phone, + hidden_bap_primary_email: Primary_Applicant__r?.Email, + hidden_bap_alternate_name: Alternate_Applicant__r?.Name || "", + hidden_bap_alternate_title: Alternate_Applicant__r?.Title || "", + hidden_bap_alternate_phone_number: Alternate_Applicant__r?.Phone || "", // prettier-ignore + hidden_bap_alternate_email: Alternate_Applicant__r?.Email || "", + hidden_bap_org_name: Applicant_Organization__r?.Name, + hidden_bap_district_name: CSB_School_District__r?.Name, + hidden_bap_fleet_name: Fleet_Name__c, + hidden_bap_prioritized: School_District_Prioritized__c, + hidden_bap_requested_funds: Total_Rebate_Funds_Requested__c, + hidden_bap_infra_max_rebate: Total_Infrastructure_Funds__c, + busInfo, + purchaseOrders: [], + }, + /** Add custom metadata to track formio submissions from wrapper. */ + metadata: { ...formioCSBMetadata }, + state: "draft", + }; + + return submission; + }) + .catch((error) => { + // NOTE: logged in bap verifyBapConnection + const errorStatus = 500; + const errorMessage = `Error getting data for a new Payment Request form submission from the BAP.`; + return res.status(errorStatus).json({ message: errorMessage }); + }); +} + /** * @param {Object} param * @param {'2022' | '2023'} param.rebateYear @@ -391,6 +498,56 @@ function fetchPRFSubmissions({ rebateYear, req, res }) { }); } +/** + * @param {Object} param + * @param {'2022' | '2023'} param.rebateYear + * @param {express.Request} param.req + * @param {express.Response} param.res + */ +function createPRFSubmission({ rebateYear, req, res }) { + const { bapComboKeys, body } = req; + const { mail } = req.user; + const { comboKey } = body; + + const formioFormUrl = formUrl[rebateYear].prf; + + if (!formioFormUrl) { + const errorStatus = 400; + const errorMessage = `Formio form URL does not exist for ${rebateYear} PRF.`; + return res.status(errorStatus).json({ message: errorMessage }); + } + + if (!submissionPeriodOpen[rebateYear].prf) { + const errorStatus = 400; + const errorMessage = `${rebateYear} CSB Payment Request form enrollment period is closed.`; + return res.status(errorStatus).json({ message: errorMessage }); + } + + if (!bapComboKeys.includes(comboKey)) { + const logMessage = + `User with email '${mail}' attempted to post a new ${rebateYear} ` + + `PRF submission without a matching BAP combo key.`; + log({ level: "error", message: logMessage, req }); + + const errorStatus = 401; + const errorMessage = `Unauthorized.`; + return res.status(errorStatus).json({ message: errorMessage }); + } + + fetchDataForPRFSubmission({ rebateYear, req, res }).then((submission) => { + axiosFormio(req) + .post(`${formioFormUrl}/submission`, submission) + .then((axiosRes) => axiosRes.data) + .then((submission) => res.json(submission)) + .catch((error) => { + // NOTE: error is logged in axiosFormio response interceptor + const errorStatus = error.response?.status || 500; + const errorMessage = `Error posting Formio ${rebateYear} Payment Request form submission.`; + return res.status(errorStatus).json({ message: errorMessage }); + }); + }); +} + module.exports = { uploadS3FileMetadata, downloadS3FileMetadata, @@ -401,4 +558,5 @@ module.exports = { updateFRFSubmission, // fetchPRFSubmissions, + createPRFSubmission, }; From f8798a01701ffc30d76a924b1c46185183855eec Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Mon, 22 Jan 2024 17:39:53 -0500 Subject: [PATCH 07/35] Update formio2023 server route file with route handler to create an PRF submission --- app/server/app/routes/formio2023.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/server/app/routes/formio2023.js b/app/server/app/routes/formio2023.js index d8c0f3d9..72a5e437 100644 --- a/app/server/app/routes/formio2023.js +++ b/app/server/app/routes/formio2023.js @@ -14,7 +14,6 @@ const { } = require("../middleware"); const { getBapFormSubmissionsStatuses, - getBapDataForPRF, getBapDataForCRF, checkFormSubmissionPeriodAndBapStatus, } = require("../utilities/bap"); @@ -28,6 +27,7 @@ const { updateFRFSubmission, // fetchPRFSubmissions, + createPRFSubmission, } = require("../utilities/formio"); const log = require("../utilities/logger"); @@ -89,6 +89,9 @@ router.get("/prf-submissions", storeBapComboKeys, (req, res) => { }); // --- post a new 2023 PRF submission to Formio +router.post("/prf-submission", storeBapComboKeys, (req, res) => { + createPRFSubmission({ rebateYear: "2023", req, res }); +}); // --- get an existing 2023 PRF's schema and submission data from Formio From 75facdece92fa6f10c0f3337791cfc23756904b8 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Mon, 22 Jan 2024 17:43:23 -0500 Subject: [PATCH 08/35] Update BAP query functions for getting 2022 PRF data to include rebate year in the function name --- app/server/app/utilities/bap.js | 18 ++-- app/server/app/utilities/formio.js | 151 +++++++++++++++-------------- 2 files changed, 86 insertions(+), 83 deletions(-) diff --git a/app/server/app/utilities/bap.js b/app/server/app/utilities/bap.js index 7bec316e..4e5baa2a 100644 --- a/app/server/app/utilities/bap.js +++ b/app/server/app/utilities/bap.js @@ -509,16 +509,16 @@ async function queryForBapFormSubmissionsStatuses(req, comboKeys) { } /** - * Uses cached JSforce connection to query the BAP for FRF submission data, for - * use in a brand new PRF submission. + * Uses cached JSforce connection to query the BAP for 2022 FRF submission data, + * for use in a brand new 2022 PRF submission. * * @param {express.Request} req * @param {string} frfReviewItemId CSB Rebate ID with the form/version ID (9 digits) * @returns {Promise} FRF submission fields */ -async function queryBapForPRFData(req, frfReviewItemId) { +async function queryBapFor2022PRFData(req, frfReviewItemId) { const logMessage = - `Querying the BAP for FRF submission associated with ` + + `Querying the BAP for 2022 FRF submission associated with ` + `FRF Review Item ID: '${frfReviewItemId}'.`; log({ level: "info", message: logMessage }); @@ -1048,15 +1048,15 @@ function getBapFormSubmissionsStatuses(req, comboKeys) { } /** - * Fetches FRF submission data associated with a FRF Review Item ID. + * Fetches 2022 FRF submission data associated with a FRF Review Item ID. * * @param {express.Request} req * @param {string} frfReviewItemId - * @returns {ReturnType} + * @returns {ReturnType} */ -function getBapDataForPRF(req, frfReviewItemId) { +function getBapDataFor2022PRF(req, frfReviewItemId) { return verifyBapConnection(req, { - name: queryBapForPRFData, + name: queryBapFor2022PRFData, args: [req, frfReviewItemId], }); } @@ -1126,7 +1126,7 @@ module.exports = { getBapComboKeys, getBapFormSubmissionData, getBapFormSubmissionsStatuses, - getBapDataForPRF, + getBapDataFor2022PRF, getBapDataForCRF, checkFormSubmissionPeriodAndBapStatus, }; diff --git a/app/server/app/utilities/formio.js b/app/server/app/utilities/formio.js index f9950353..9f8c2059 100644 --- a/app/server/app/utilities/formio.js +++ b/app/server/app/utilities/formio.js @@ -7,7 +7,7 @@ const { formioCSBMetadata, } = require("../config/formio"); const { - getBapDataForPRF, + getBapDataFor2022PRF, checkFormSubmissionPeriodAndBapStatus, } = require("../utilities/bap"); const log = require("./logger"); @@ -29,7 +29,6 @@ function getComboKeyFieldName({ rebateYear }) { * @param {'2022' | '2023'} param.rebateYear * @param {express.Request} param.req * @param {express.Response} param.res - * @returns {Promise<{ data: Object, metadata: Object, state: 'draft' }>} */ function fetchDataForPRFSubmission({ rebateYear, req, res }) { /** @type {{ @@ -53,79 +52,83 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { frfFormModified, } = req.body; - return getBapDataForPRF(req, frfReviewItemId) - .then(({ frfRecordQuery, busRecordsQuery }) => { - const { - CSB_NCES_ID__c, - Primary_Applicant__r, - Alternate_Applicant__r, - Applicant_Organization__r, - CSB_School_District__r, - Fleet_Name__c, - School_District_Prioritized__c, - Total_Rebate_Funds_Requested__c, - Total_Infrastructure_Funds__c, - } = frfRecordQuery[0]; - - const busInfo = busRecordsQuery.map((record) => ({ - busNum: record.Rebate_Item_num__c, - oldBusNcesDistrictId: CSB_NCES_ID__c, - oldBusVin: record.CSB_VIN__c, - oldBusModelYear: record.CSB_Model_Year__c, - oldBusFuelType: record.CSB_Fuel_Type__c, - newBusFuelType: record.CSB_Replacement_Fuel_Type__c, - hidden_bap_max_rebate: record.CSB_Funds_Requested__c, - })); - - /** - * NOTE: `purchaseOrders` is initialized as an empty array to fix some - * issue with the field being changed to an object when the form loads - */ - const submission = { - data: { - bap_hidden_entity_combo_key: comboKey, - hidden_application_form_modified: frfFormModified, - hidden_current_user_email: email, - hidden_current_user_title: title, - hidden_current_user_name: name, - hidden_sam_uei: entity.UNIQUE_ENTITY_ID__c, - hidden_sam_efti: entity.ENTITY_EFT_INDICATOR__c || "0000", - hidden_sam_elec_bus_poc_email: entity.ELEC_BUS_POC_EMAIL__c, - hidden_sam_alt_elec_bus_poc_email: entity.ALT_ELEC_BUS_POC_EMAIL__c, - hidden_sam_govt_bus_poc_email: entity.GOVT_BUS_POC_EMAIL__c, - hidden_sam_alt_govt_bus_poc_email: entity.ALT_GOVT_BUS_POC_EMAIL__c, - hidden_bap_rebate_id: rebateId, - hidden_bap_district_id: CSB_NCES_ID__c, - hidden_bap_primary_name: Primary_Applicant__r?.Name, - hidden_bap_primary_title: Primary_Applicant__r?.Title, - hidden_bap_primary_phone_number: Primary_Applicant__r?.Phone, - hidden_bap_primary_email: Primary_Applicant__r?.Email, - hidden_bap_alternate_name: Alternate_Applicant__r?.Name || "", - hidden_bap_alternate_title: Alternate_Applicant__r?.Title || "", - hidden_bap_alternate_phone_number: Alternate_Applicant__r?.Phone || "", // prettier-ignore - hidden_bap_alternate_email: Alternate_Applicant__r?.Email || "", - hidden_bap_org_name: Applicant_Organization__r?.Name, - hidden_bap_district_name: CSB_School_District__r?.Name, - hidden_bap_fleet_name: Fleet_Name__c, - hidden_bap_prioritized: School_District_Prioritized__c, - hidden_bap_requested_funds: Total_Rebate_Funds_Requested__c, - hidden_bap_infra_max_rebate: Total_Infrastructure_Funds__c, - busInfo, - purchaseOrders: [], - }, - /** Add custom metadata to track formio submissions from wrapper. */ - metadata: { ...formioCSBMetadata }, - state: "draft", - }; + if (rebateYear === "2022") { + return getBapDataFor2022PRF(req, frfReviewItemId) + .then(({ frfRecordQuery, busRecordsQuery }) => { + const { + CSB_NCES_ID__c, + Primary_Applicant__r, + Alternate_Applicant__r, + Applicant_Organization__r, + CSB_School_District__r, + Fleet_Name__c, + School_District_Prioritized__c, + Total_Rebate_Funds_Requested__c, + Total_Infrastructure_Funds__c, + } = frfRecordQuery[0]; + + const busInfo = busRecordsQuery.map((record) => ({ + busNum: record.Rebate_Item_num__c, + oldBusNcesDistrictId: CSB_NCES_ID__c, + oldBusVin: record.CSB_VIN__c, + oldBusModelYear: record.CSB_Model_Year__c, + oldBusFuelType: record.CSB_Fuel_Type__c, + newBusFuelType: record.CSB_Replacement_Fuel_Type__c, + hidden_bap_max_rebate: record.CSB_Funds_Requested__c, + })); + + /** + * NOTE: `purchaseOrders` is initialized as an empty array to fix some + * issue with the field being changed to an object when the form loads + */ + return { + data: { + bap_hidden_entity_combo_key: comboKey, + hidden_application_form_modified: frfFormModified, + hidden_current_user_email: email, + hidden_current_user_title: title, + hidden_current_user_name: name, + hidden_sam_uei: entity.UNIQUE_ENTITY_ID__c, + hidden_sam_efti: entity.ENTITY_EFT_INDICATOR__c || "0000", + hidden_sam_elec_bus_poc_email: entity.ELEC_BUS_POC_EMAIL__c, + hidden_sam_alt_elec_bus_poc_email: entity.ALT_ELEC_BUS_POC_EMAIL__c, + hidden_sam_govt_bus_poc_email: entity.GOVT_BUS_POC_EMAIL__c, + hidden_sam_alt_govt_bus_poc_email: entity.ALT_GOVT_BUS_POC_EMAIL__c, + hidden_bap_rebate_id: rebateId, + hidden_bap_district_id: CSB_NCES_ID__c, + hidden_bap_primary_name: Primary_Applicant__r?.Name, + hidden_bap_primary_title: Primary_Applicant__r?.Title, + hidden_bap_primary_phone_number: Primary_Applicant__r?.Phone, + hidden_bap_primary_email: Primary_Applicant__r?.Email, + hidden_bap_alternate_name: Alternate_Applicant__r?.Name || "", + hidden_bap_alternate_title: Alternate_Applicant__r?.Title || "", + hidden_bap_alternate_phone_number: Alternate_Applicant__r?.Phone || "", // prettier-ignore + hidden_bap_alternate_email: Alternate_Applicant__r?.Email || "", + hidden_bap_org_name: Applicant_Organization__r?.Name, + hidden_bap_district_name: CSB_School_District__r?.Name, + hidden_bap_fleet_name: Fleet_Name__c, + hidden_bap_prioritized: School_District_Prioritized__c, + hidden_bap_requested_funds: Total_Rebate_Funds_Requested__c, + hidden_bap_infra_max_rebate: Total_Infrastructure_Funds__c, + busInfo, + purchaseOrders: [], + }, + /** Add custom metadata to track formio submissions from wrapper. */ + metadata: { ...formioCSBMetadata }, + state: "draft", + }; + }) + .catch((error) => { + // NOTE: logged in bap verifyBapConnection + const errorStatus = 500; + const errorMessage = `Error getting data for a new Payment Request form submission from the BAP.`; + return res.status(errorStatus).json({ message: errorMessage }); + }); + } - return submission; - }) - .catch((error) => { - // NOTE: logged in bap verifyBapConnection - const errorStatus = 500; - const errorMessage = `Error getting data for a new Payment Request form submission from the BAP.`; - return res.status(errorStatus).json({ message: errorMessage }); - }); + if (rebateYear === "2023") { + // TODO + } } /** From 39e6c2e07673e7d8a851176c3f7fdc2c4319f104 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Mon, 22 Jan 2024 17:48:31 -0500 Subject: [PATCH 09/35] Update BAP query functions for getting 2022 CRF data to include rebate year in the function name --- app/server/app/routes/formio2022.js | 4 ++-- app/server/app/routes/formio2023.js | 1 - app/server/app/utilities/bap.js | 23 ++++++++++++----------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/app/server/app/routes/formio2022.js b/app/server/app/routes/formio2022.js index d5a4bfb3..03fd6a94 100644 --- a/app/server/app/routes/formio2022.js +++ b/app/server/app/routes/formio2022.js @@ -14,7 +14,7 @@ const { } = require("../middleware"); const { getBapFormSubmissionsStatuses, - getBapDataForCRF, + getBapDataFor2022CRF, checkFormSubmissionPeriodAndBapStatus, } = require("../utilities/bap"); const { @@ -358,7 +358,7 @@ router.post("/crf-submission", storeBapComboKeys, (req, res) => { ALT_GOVT_BUS_POC_EMAIL__c, } = entity; - return getBapDataForCRF(req, frfReviewItemId, prfReviewItemId) + return getBapDataFor2022CRF(req, frfReviewItemId, prfReviewItemId) .then(({ frfRecordQuery, prfRecordQuery, busRecordsQuery }) => { const { Fleet_Name__c, diff --git a/app/server/app/routes/formio2023.js b/app/server/app/routes/formio2023.js index 72a5e437..cdedfd3a 100644 --- a/app/server/app/routes/formio2023.js +++ b/app/server/app/routes/formio2023.js @@ -14,7 +14,6 @@ const { } = require("../middleware"); const { getBapFormSubmissionsStatuses, - getBapDataForCRF, checkFormSubmissionPeriodAndBapStatus, } = require("../utilities/bap"); const { diff --git a/app/server/app/utilities/bap.js b/app/server/app/utilities/bap.js index 4e5baa2a..5422e9f0 100644 --- a/app/server/app/utilities/bap.js +++ b/app/server/app/utilities/bap.js @@ -673,18 +673,19 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { } /** - * Uses cached JSforce connection to query the BAP for FRF submission data and - * PRF submission data, for use in a brand new CRF submission. + * Uses cached JSforce connection to query the BAP for 2022 FRF submission data + * and 2022 PRF submission data, for use in a brand new 2022 CRF submission. * * @param {express.Request} req * @param {string} frfReviewItemId CSB Rebate ID with the form/version ID (9 digits) * @param {string} prfReviewItemId CSB Rebate ID with the form/version ID (9 digits) * @returns {Promise} FRF and PRF submission fields */ -async function queryBapForCRFData(req, frfReviewItemId, prfReviewItemId) { +async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { const logMessage = - `Querying the BAP for FRF submission associated with ` + - `FRF Review Item ID: '${frfReviewItemId}' and PRF submission associated with ` + + `Querying the BAP for 2022 FRF submission associated with ` + + `FRF Review Item ID: '${frfReviewItemId}' ` + + `and 2022 PRF submission associated with ` + `PRF Review Item ID: '${prfReviewItemId}'.`; log({ level: "info", message: logMessage }); @@ -1062,17 +1063,17 @@ function getBapDataFor2022PRF(req, frfReviewItemId) { } /** - * Fetches FRF submission data and PRF submission data associated with a FRF - * Review Item ID and a PRF Review Item ID. + * Fetches 2022 FRF submission data and 2022 PRF submission data associated with + * a FRF Review Item ID and a PRF Review Item ID. * * @param {express.Request} req * @param {string} frfReviewItemId * @param {string} prfReviewItemId - * @returns {ReturnType} + * @returns {ReturnType} */ -function getBapDataForCRF(req, frfReviewItemId, prfReviewItemId) { +function getBapDataFor2022CRF(req, frfReviewItemId, prfReviewItemId) { return verifyBapConnection(req, { - name: queryBapForCRFData, + name: queryBapFor2022CRFData, args: [req, frfReviewItemId, prfReviewItemId], }); } @@ -1127,6 +1128,6 @@ module.exports = { getBapFormSubmissionData, getBapFormSubmissionsStatuses, getBapDataFor2022PRF, - getBapDataForCRF, + getBapDataFor2022CRF, checkFormSubmissionPeriodAndBapStatus, }; From 8f9ae2904ed73ac460d5ecd4dcda50c92662e45d Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Mon, 22 Jan 2024 22:45:14 -0500 Subject: [PATCH 10/35] Add initial BAP query for fetching BAP data for the 2023 PRF --- app/server/app/utilities/bap.js | 184 ++++++++++++++++++++++++++++- app/server/app/utilities/formio.js | 109 +++++++++++++++-- 2 files changed, 281 insertions(+), 12 deletions(-) diff --git a/app/server/app/utilities/bap.js b/app/server/app/utilities/bap.js index 5422e9f0..6caf3cd2 100644 --- a/app/server/app/utilities/bap.js +++ b/app/server/app/utilities/bap.js @@ -58,7 +58,7 @@ const { submissionPeriodOpen } = require("../config/formio"); */ /** - * @typedef {Object} BapDataForPRF + * @typedef {Object} BapDataFor2022PRF * @property {{ * Id: string * UEI_EFTI_Combo_Key__c: string @@ -101,7 +101,50 @@ const { submissionPeriodOpen } = require("../config/formio"); */ /** - * @typedef {Object} BapDataForForCRF + * @typedef {Object} BapDataFor2023PRF + * @property {{ + * Id: string + * Primary_Applicant__r: { + * FirstName: string + * LastName: string + * Title: string + * Email: string + * Phone: string + * } | null + * Alternate_Applicant__r: { + * FirstName: string + * LastName: string + * Title: string + * Email: string + * Phone: string + * } | null + * CSB_School_District__r: { + * Name: string + * BillingStreet: string + * BillingCity: string + * BillingState: string + * BillingPostalCode: string + * } | null + * School_District_Contact__r: { + * FirstName: string + * LastName: string + * Title: string + * Email: string + * Phone: string + * } | null + * CSB_NCES_ID__c: string + * Prioritized_as_High_Need__c: string + * Prioritized_as_Tribal__c: string + * Prioritized_as_Rural__c: string + * }[]} frfRecordQuery + * @property {{ + * type: string + * url: string + * }} attributes + */ + +/** + * @typedef {Object} BapDataForFor2022CRF * @property {{ * Fleet_Name__c: string * Fleet_Street_Address__c: string @@ -514,7 +557,7 @@ async function queryForBapFormSubmissionsStatuses(req, comboKeys) { * * @param {express.Request} req * @param {string} frfReviewItemId CSB Rebate ID with the form/version ID (9 digits) - * @returns {Promise} FRF submission fields + * @returns {Promise} 2022 FRF submission fields */ async function queryBapFor2022PRFData(req, frfReviewItemId) { const logMessage = @@ -672,6 +715,124 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { return { frfRecordQuery, busRecordsQuery }; } +/** + * Uses cached JSforce connection to query the BAP for 2023 FRF submission data, + * for use in a brand new 2023 PRF submission. + * + * @param {express.Request} req + * @param {string} frfReviewItemId CSB Rebate ID with the form/version ID (9 digits) + * @returns {Promise} 2023 FRF submission fields + */ +async function queryBapFor2023PRFData(req, frfReviewItemId) { + const logMessage = + `Querying the BAP for 2023 FRF submission associated with ` + + `FRF Review Item ID: '${frfReviewItemId}'.`; + log({ level: "info", message: logMessage }); + + /** @type {jsforce.Connection} */ + const { bapConnection } = req.app.locals; + + // `SELECT + // Id + // FROM + // RecordType + // WHERE + // DeveloperName = 'CSB_Funding_Request_2023' AND + // SObjectType = '${BAP_FORMS_TABLE}' + // LIMIT 1` + + const frfRecordTypeIdQuery = await bapConnection + .sobject("RecordType") + .find( + { + DeveloperName: "CSB_Funding_Request_2023", + SObjectType: BAP_FORMS_TABLE, + }, + { + // "*": 1, + Id: 1, // Salesforce record ID + }, + ) + .limit(1) + .execute(async (err, records) => ((await err) ? err : records)); + + const frfRecordTypeId = frfRecordTypeIdQuery["0"].Id; + + // `SELECT + // Id, + // Primary_Applicant__r.FirstName, + // Primary_Applicant__r.LastName, + // Primary_Applicant__r.Title, + // Primary_Applicant__r.Email, + // Primary_Applicant__r.Phone, + // Alternate_Applicant__r.FirstName, + // Alternate_Applicant__r.LastName, + // Alternate_Applicant__r.Title, + // Alternate_Applicant__r.Email, + // Alternate_Applicant__r.Phone, + // CSB_School_District__r.Name, + // CSB_School_District__r.BillingStreet, + // CSB_School_District__r.BillingCity, + // CSB_School_District__r.BillingState, + // CSB_School_District__r.BillingPostalCode, + // School_District_Contact__r.FirstName, + // School_District_Contact__r.LastName, + // School_District_Contact__r.Title, + // School_District_Contact__r.Email, + // School_District_Contact__r.Phone, + // CSB_NCES_ID__c, + // Prioritized_as_High_Need__c, + // Prioritized_as_Tribal__c, + // Prioritized_as_Rural__c, + // FROM + // ${BAP_FORMS_TABLE} + // WHERE + // RecordTypeId = '${frfRecordTypeId}' AND + // CSB_Review_Item_ID__c = '${frfReviewItemId}' AND + // Latest_Version__c = TRUE` + + const frfRecordQuery = await bapConnection + .sobject(BAP_FORMS_TABLE) + .find( + { + RecordTypeId: frfRecordTypeId, + CSB_Review_Item_ID__c: frfReviewItemId, + Latest_Version__c: true, + }, + { + // "*": 1, + Id: 1, // Salesforce record ID + "Primary_Applicant__r.FirstName": 1, + "Primary_Applicant__r.LastName": 1, + "Primary_Applicant__r.Title": 1, + "Primary_Applicant__r.Email": 1, + "Primary_Applicant__r.Phone": 1, + "Alternate_Applicant__r.FirstName": 1, + "Alternate_Applicant__r.LastName": 1, + "Alternate_Applicant__r.Title": 1, + "Alternate_Applicant__r.Email": 1, + "Alternate_Applicant__r.Phone": 1, + "CSB_School_District__r.Name": 1, + "CSB_School_District__r.BillingStreet": 1, + "CSB_School_District__r.BillingCity": 1, + "CSB_School_District__r.BillingState": 1, + "CSB_School_District__r.BillingPostalCode": 1, + "School_District_Contact__r.FirstName": 1, + "School_District_Contact__r.LastName": 1, + "School_District_Contact__r.Title": 1, + "School_District_Contact__r.Email": 1, + "School_District_Contact__r.Phone": 1, + CSB_NCES_ID__c: 1, + Prioritized_as_High_Need__c: 1, + Prioritized_as_Tribal__c: 1, + Prioritized_as_Rural__c: 1, + }, + ) + .execute(async (err, records) => ((await err) ? err : records)); + + return { frfRecordQuery }; +} + /** * Uses cached JSforce connection to query the BAP for 2022 FRF submission data * and 2022 PRF submission data, for use in a brand new 2022 CRF submission. @@ -679,7 +840,7 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { * @param {express.Request} req * @param {string} frfReviewItemId CSB Rebate ID with the form/version ID (9 digits) * @param {string} prfReviewItemId CSB Rebate ID with the form/version ID (9 digits) - * @returns {Promise} FRF and PRF submission fields + * @returns {Promise} 2022 FRF and 2022 PRF submission fields */ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { const logMessage = @@ -1062,6 +1223,20 @@ function getBapDataFor2022PRF(req, frfReviewItemId) { }); } +/** + * Fetches 2023 FRF submission data associated with a FRF Review Item ID. + * + * @param {express.Request} req + * @param {string} frfReviewItemId + * @returns {ReturnType} + */ +function getBapDataFor2023PRF(req, frfReviewItemId) { + return verifyBapConnection(req, { + name: queryBapFor2023PRFData, + args: [req, frfReviewItemId], + }); +} + /** * Fetches 2022 FRF submission data and 2022 PRF submission data associated with * a FRF Review Item ID and a PRF Review Item ID. @@ -1128,6 +1303,7 @@ module.exports = { getBapFormSubmissionData, getBapFormSubmissionsStatuses, getBapDataFor2022PRF, + getBapDataFor2023PRF, getBapDataFor2022CRF, checkFormSubmissionPeriodAndBapStatus, }; diff --git a/app/server/app/utilities/formio.js b/app/server/app/utilities/formio.js index 9f8c2059..bb3d0900 100644 --- a/app/server/app/utilities/formio.js +++ b/app/server/app/utilities/formio.js @@ -8,6 +8,7 @@ const { } = require("../config/formio"); const { getBapDataFor2022PRF, + getBapDataFor2023PRF, checkFormSubmissionPeriodAndBapStatus, } = require("../utilities/bap"); const log = require("./logger"); @@ -52,6 +53,21 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { frfFormModified, } = req.body; + const { + UNIQUE_ENTITY_ID__c, + ENTITY_EFT_INDICATOR__c, + LEGAL_BUSINESS_NAME__c, + PHYSICAL_ADDRESS_LINE_1__c, + PHYSICAL_ADDRESS_LINE_2__c, + PHYSICAL_ADDRESS_CITY__c, + PHYSICAL_ADDRESS_PROVINCE_OR_STATE__c, + PHYSICAL_ADDRESS_ZIPPOSTAL_CODE__c, + ELEC_BUS_POC_EMAIL__c, + ALT_ELEC_BUS_POC_EMAIL__c, + GOVT_BUS_POC_EMAIL__c, + ALT_GOVT_BUS_POC_EMAIL__c, + } = entity; + if (rebateYear === "2022") { return getBapDataFor2022PRF(req, frfReviewItemId) .then(({ frfRecordQuery, busRecordsQuery }) => { @@ -88,12 +104,12 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { hidden_current_user_email: email, hidden_current_user_title: title, hidden_current_user_name: name, - hidden_sam_uei: entity.UNIQUE_ENTITY_ID__c, - hidden_sam_efti: entity.ENTITY_EFT_INDICATOR__c || "0000", - hidden_sam_elec_bus_poc_email: entity.ELEC_BUS_POC_EMAIL__c, - hidden_sam_alt_elec_bus_poc_email: entity.ALT_ELEC_BUS_POC_EMAIL__c, - hidden_sam_govt_bus_poc_email: entity.GOVT_BUS_POC_EMAIL__c, - hidden_sam_alt_govt_bus_poc_email: entity.ALT_GOVT_BUS_POC_EMAIL__c, + hidden_sam_uei: UNIQUE_ENTITY_ID__c, + hidden_sam_efti: ENTITY_EFT_INDICATOR__c || "0000", + hidden_sam_elec_bus_poc_email: ELEC_BUS_POC_EMAIL__c, + hidden_sam_alt_elec_bus_poc_email: ALT_ELEC_BUS_POC_EMAIL__c, + hidden_sam_govt_bus_poc_email: GOVT_BUS_POC_EMAIL__c, + hidden_sam_alt_govt_bus_poc_email: ALT_GOVT_BUS_POC_EMAIL__c, hidden_bap_rebate_id: rebateId, hidden_bap_district_id: CSB_NCES_ID__c, hidden_bap_primary_name: Primary_Applicant__r?.Name, @@ -121,13 +137,90 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { .catch((error) => { // NOTE: logged in bap verifyBapConnection const errorStatus = 500; - const errorMessage = `Error getting data for a new Payment Request form submission from the BAP.`; + const errorMessage = `Error getting data for a new 2022 Payment Request form submission from the BAP.`; return res.status(errorStatus).json({ message: errorMessage }); }); } if (rebateYear === "2023") { - // TODO + return getBapDataFor2023PRF(req, frfReviewItemId) + .then(({ frfRecordQuery }) => { + const { + Primary_Applicant__r, + Alternate_Applicant__r, + CSB_School_District__r, + School_District_Contact__r, + CSB_NCES_ID__c, + Prioritized_as_High_Need__c, + Prioritized_as_Tribal__c, + Prioritized_as_Rural__c, + } = frfRecordQuery[0]; + + return { + data: { + _bap_entity_combo_key: comboKey, + _application_form_modified: frfFormModified, + _user_email: email, + _user_title: title, + _user_name: name, + _bap_applicant_email: email, + _bap_applicant_title: title, + _bap_applicant_name: name, + _bap_applicant_efti: ENTITY_EFT_INDICATOR__c || "0000", + _bap_applicant_uei: UNIQUE_ENTITY_ID__c, + _bap_applicant_organization_name: LEGAL_BUSINESS_NAME__c, // TODO: confirm + _bap_applicant_district_name: "", // TODO: get + _bap_applicant_street_address_1: PHYSICAL_ADDRESS_LINE_1__c, // TODO: confirm + _bap_applicant_street_address_2: PHYSICAL_ADDRESS_LINE_2__c, // TODO: confirm + _bap_applicant_county: "", // TODO: get + _bap_applicant_city: PHYSICAL_ADDRESS_CITY__c, // TODO: confirm + _bap_applicant_state: PHYSICAL_ADDRESS_PROVINCE_OR_STATE__c, // TODO: confirm + _bap_applicant_zip: PHYSICAL_ADDRESS_ZIPPOSTAL_CODE__c, // TODO: confirm + _bap_elec_bus_poc_email: ELEC_BUS_POC_EMAIL__c, + _bap_alt_elec_bus_poc_email: ALT_ELEC_BUS_POC_EMAIL__c, + _bap_govt_bus_poc_email: GOVT_BUS_POC_EMAIL__c, + _bap_alt_govt_bus_poc_email: ALT_GOVT_BUS_POC_EMAIL__c, + _bap_primary_fname: Primary_Applicant__r?.FirstName, + _bap_primary_lname: Primary_Applicant__r?.LastName, + _bap_primary_title: Primary_Applicant__r?.Title, + _bap_primary_email: Primary_Applicant__r?.Email, + _bap_primary_phone_number: Primary_Applicant__r?.Phone, + _bap_alternate_fname: Alternate_Applicant__r?.FirstName, + _bap_alternate_lname: Alternate_Applicant__r?.LastName, + _bap_alternate_title: Alternate_Applicant__r?.Title, + _bap_alternate_email: Alternate_Applicant__r?.Email, + _bap_alternate_phone_number: Alternate_Applicant__r?.Phone, + _bap_district_ncesID: CSB_NCES_ID__c, + _bap_district_name: CSB_School_District__r?.Name, + _bap_district_address_1: CSB_School_District__r?.BillingStreet, // TODO: confirm + _bap_district_address_2: "", // TODO: get + _bap_district_city: CSB_School_District__r?.BillingCity, // TODO: confirm + _bap_district_state: CSB_School_District__r?.BillingState, // TODO: confirm + _bap_district_zip: CSB_School_District__r?.BillingPostalCode, // TODO: confirm + _bap_district_priority: "", // TODO: get + _bap_district_selfCertify: "", // TODO: get + _bap_district_priorityReason: { + highNeed: Prioritized_as_High_Need__c, + tribal: Prioritized_as_Tribal__c, + rural: Prioritized_as_Rural__c, + }, + _bap_district_contactFName: School_District_Contact__r?.FirstName, + _bap_district_contactLName: School_District_Contact__r?.LastName, + _bap_district_contactTitle: School_District_Contact__r?.Title, + _bap_district_contactEmail: School_District_Contact__r?.Email, + _bap_district_contactPhone: School_District_Contact__r?.Phone, + }, + /** Add custom metadata to track formio submissions from wrapper. */ + metadata: { ...formioCSBMetadata }, + state: "draft", + }; + }) + .catch((error) => { + // NOTE: logged in bap verifyBapConnection + const errorStatus = 500; + const errorMessage = `Error getting data for a new 2023 Payment Request form submission from the BAP.`; + return res.status(errorStatus).json({ message: errorMessage }); + }); } } From eb34c8d9e01b2c64488bd00e3bb6352597c5410c Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Tue, 23 Jan 2024 14:10:35 -0500 Subject: [PATCH 11/35] Update BAP query for 2023 PRF data to include bus line item fields --- app/server/app/utilities/bap.js | 111 ++++++++++++++++++++++++++++- app/server/app/utilities/formio.js | 97 ++++++++++++++++++++----- 2 files changed, 191 insertions(+), 17 deletions(-) diff --git a/app/server/app/utilities/bap.js b/app/server/app/utilities/bap.js index 6caf3cd2..20af8fb6 100644 --- a/app/server/app/utilities/bap.js +++ b/app/server/app/utilities/bap.js @@ -133,11 +133,32 @@ const { submissionPeriodOpen } = require("../config/formio"); * Phone: string * } | null * CSB_NCES_ID__c: string + * School_District_Prioritized__c: string + * School_District_Poverty_Rate__c: string * Prioritized_as_High_Need__c: string * Prioritized_as_Tribal__c: string * Prioritized_as_Rural__c: string * }[]} frfRecordQuery * @property {{ + * Rebate_Item_num__c: string + * CSB_VIN__c: string + * CSB_Fuel_Type__c: string + * CSB_GVWR__c: string + * Old_Bus_Odometer_miles__c: string + * CSB_Model__c: string + * CSB_Model_Year__c: string + * CSB_Manufacturer__c: string + * CSB_Manufacturer_if_Other__c: string + * CSB_Annual_Fuel_Consumption__c: string + * Annual_Mileage__c: string + * Old_Bus_Estimated_Remaining_Life__c: string + * Old_Bus_Annual_Idling_Hours__c: string + * CSB_Funds_Requested__c: string + * New_Bus_Fuel_Type__c: string + * New_Bus_GVWR__c: string + * New_Bus_ADA_Compliant__c: string + * }[]} busRecordsQuery + * @property {{ * type: string * url: string * }} attributes @@ -781,6 +802,8 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { // School_District_Contact__r.Email, // School_District_Contact__r.Phone, // CSB_NCES_ID__c, + // School_District_Prioritized__c, + // School_District_Poverty_Rate__c, // Prioritized_as_High_Need__c, // Prioritized_as_Tribal__c, // Prioritized_as_Rural__c, @@ -823,6 +846,8 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { "School_District_Contact__r.Email": 1, "School_District_Contact__r.Phone": 1, CSB_NCES_ID__c: 1, + School_District_Prioritized__c: 1, + School_District_Poverty_Rate__c: 1, Prioritized_as_High_Need__c: 1, Prioritized_as_Tribal__c: 1, Prioritized_as_Rural__c: 1, @@ -830,7 +855,91 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { ) .execute(async (err, records) => ((await err) ? err : records)); - return { frfRecordQuery }; + const frfRecordId = frfRecordQuery["0"].Id; + + // `SELECT + // Id + // FROM + // RecordType + // WHERE + // DeveloperName = 'CSB_Rebate_Item' AND + // SObjectType = '${BAP_BUS_TABLE}' + // LIMIT 1` + + const busRecordTypeIdQuery = await bapConnection + .sobject("RecordType") + .find( + { + DeveloperName: "CSB_Rebate_Item", + SObjectType: BAP_BUS_TABLE, + }, + { + // "*": 1, + Id: 1, // Salesforce record ID + }, + ) + .limit(1) + .execute(async (err, records) => ((await err) ? err : records)); + + const busRecordTypeId = busRecordTypeIdQuery["0"].Id; + + // `SELECT + // Rebate_Item_num__c, + // CSB_VIN__c, + // CSB_Fuel_Type__c, + // CSB_GVWR__c, + // Old_Bus_Odometer_miles__c, + // CSB_Model__c, + // CSB_Model_Year__c, + // CSB_Manufacturer__c, + // CSB_Manufacturer_if_Other__c, + // CSB_Annual_Fuel_Consumption__c, + // Annual_Mileage__c, + // Old_Bus_Estimated_Remaining_Life__c, + // Old_Bus_Annual_Idling_Hours__c, + // CSB_Funds_Requested__c, + // New_Bus_Fuel_Type__c, + // New_Bus_GVWR__c, + // New_Bus_ADA_Compliant__c + // FROM + // ${BAP_BUS_TABLE} + // WHERE + // RecordTypeId = '${busRecordTypeId}' AND + // Related_Order_Request__c = '${frfRecordId}' AND + // CSB_Rebate_Item_Type__c = 'Old Bus'` + + const busRecordsQuery = await bapConnection + .sobject(BAP_BUS_TABLE) + .find( + { + RecordTypeId: busRecordTypeId, + Related_Order_Request__c: frfRecordId, + CSB_Rebate_Item_Type__c: "Old Bus", + }, + { + // "*": 1, + Rebate_Item_num__c: 1, + CSB_VIN__c: 1, + CSB_Fuel_Type__c: 1, + CSB_GVWR__c: 1, + Old_Bus_Odometer_miles__c: 1, + CSB_Model__c: 1, + CSB_Model_Year__c: 1, + CSB_Manufacturer__c: 1, + CSB_Manufacturer_if_Other__c: 1, + CSB_Annual_Fuel_Consumption__c: 1, + Annual_Mileage__c: 1, + Old_Bus_Estimated_Remaining_Life__c: 1, + Old_Bus_Annual_Idling_Hours__c: 1, + CSB_Funds_Requested__c: 1, + New_Bus_Fuel_Type__c: 1, + New_Bus_GVWR__c: 1, + New_Bus_ADA_Compliant__c: 1, + }, + ) + .execute(async (err, records) => ((await err) ? err : records)); + + return { frfRecordQuery, busRecordsQuery }; } /** diff --git a/app/server/app/utilities/formio.js b/app/server/app/utilities/formio.js index bb3d0900..038f3268 100644 --- a/app/server/app/utilities/formio.js +++ b/app/server/app/utilities/formio.js @@ -144,18 +144,81 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { if (rebateYear === "2023") { return getBapDataFor2023PRF(req, frfReviewItemId) - .then(({ frfRecordQuery }) => { + .then(({ frfRecordQuery, busRecordsQuery }) => { const { Primary_Applicant__r, Alternate_Applicant__r, CSB_School_District__r, School_District_Contact__r, + County__c, CSB_NCES_ID__c, + School_District_Prioritized__c, + School_District_Poverty_Rate__c, Prioritized_as_High_Need__c, Prioritized_as_Tribal__c, Prioritized_as_Rural__c, } = frfRecordQuery[0]; + // TODO: ask BAP for the query for the fields below. + // NOTE: the data from the 2023 FRF is in an 'organizations' field (array of objects) + // which has the exact same fields below, except for "_org_typeCombined" + const org_organizations = new Array(0).map((item) => ({ + org_number: Infinity, + org_type: { + existingBusOwner: true, + newBusOwner: true, + privateFleet: false, + }, + _org_typeCombined: "", // NOTE: was 'org_hidden_type' in the FRF (example value: 'Existing Bus Owner, New Bus Owner') + org_orgName: "", + org_contactFName: "", + org_contactLName: "", + org_contactTitle: "", + org_contactEmail: "", + org_contactPhone: "", + org_address1: "", + org_address2: "", + org_county: "", + org_city: "", + org_state: { + name: "", + abbreviation: "", + }, + org_zip: "", + })); + + const bus_buses = busRecordsQuery.map((item) => ({ + bus_busNumber: item.Rebate_Item_num__c, + bus_existingOwner: { + org: "", // TODO: Old_Bus_Owner__r.* or Old_Bus_Owner_Contact_ID__c + organization: "", + orgContactFName: "", + orgContactLName: "", + }, + bus_existingVin: item.CSB_VIN__c, + bus_existingFuelType: item.CSB_Fuel_Type__c, + bus_existingGvwr: item.CSB_GVWR__c, + bus_existingOdometer: item.Old_Bus_Odometer_miles__c, + bus_existingModel: item.CSB_Model__c, + bus_existingModelYear: item.CSB_Model_Year__c, + bus_existingManufacturer: item.CSB_Manufacturer__c, + bus_existingManufacturerOther: item.CSB_Manufacturer_if_Other__c, + bus_existingAnnualFuelConsumption: item.CSB_Annual_Fuel_Consumption__c, // prettier-ignore + bus_existingAnnualMileage: item.Annual_Mileage__c, + bus_existingRemainingLife: item.Old_Bus_Estimated_Remaining_Life__c, + bus_existingIdlingHours: item.Old_Bus_Annual_Idling_Hours__c, + bus_newOwner: { + org: "", // TODO: New_Bus_Owner__r.* or New_Bus_Owner_Contact_ID__c + organization: "", + orgContactFName: "", + orgContactLName: "", + }, + bus_rebate: item.CSB_Funds_Requested__c, + bus_newFuelType: item.New_Bus_Fuel_Type__c, + bus_newGvwr: item.New_Bus_GVWR__c, + _bus_newADAfromFRF: item.New_Bus_ADA_Compliant__c, + })); + return { data: { _bap_entity_combo_key: comboKey, @@ -168,14 +231,13 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { _bap_applicant_name: name, _bap_applicant_efti: ENTITY_EFT_INDICATOR__c || "0000", _bap_applicant_uei: UNIQUE_ENTITY_ID__c, - _bap_applicant_organization_name: LEGAL_BUSINESS_NAME__c, // TODO: confirm - _bap_applicant_district_name: "", // TODO: get - _bap_applicant_street_address_1: PHYSICAL_ADDRESS_LINE_1__c, // TODO: confirm - _bap_applicant_street_address_2: PHYSICAL_ADDRESS_LINE_2__c, // TODO: confirm - _bap_applicant_county: "", // TODO: get - _bap_applicant_city: PHYSICAL_ADDRESS_CITY__c, // TODO: confirm - _bap_applicant_state: PHYSICAL_ADDRESS_PROVINCE_OR_STATE__c, // TODO: confirm - _bap_applicant_zip: PHYSICAL_ADDRESS_ZIPPOSTAL_CODE__c, // TODO: confirm + _bap_applicant_organization_name: LEGAL_BUSINESS_NAME__c, + _bap_applicant_street_address_1: PHYSICAL_ADDRESS_LINE_1__c, + _bap_applicant_street_address_2: PHYSICAL_ADDRESS_LINE_2__c, + _bap_applicant_county: County__c, // TODO: confirm with BAP + _bap_applicant_city: PHYSICAL_ADDRESS_CITY__c, + _bap_applicant_state: PHYSICAL_ADDRESS_PROVINCE_OR_STATE__c, + _bap_applicant_zip: PHYSICAL_ADDRESS_ZIPPOSTAL_CODE__c, _bap_elec_bus_poc_email: ELEC_BUS_POC_EMAIL__c, _bap_alt_elec_bus_poc_email: ALT_ELEC_BUS_POC_EMAIL__c, _bap_govt_bus_poc_email: GOVT_BUS_POC_EMAIL__c, @@ -191,14 +253,15 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { _bap_alternate_email: Alternate_Applicant__r?.Email, _bap_alternate_phone_number: Alternate_Applicant__r?.Phone, _bap_district_ncesID: CSB_NCES_ID__c, + // TODO: confirm with BAP we should use the individual fields below and not the 'BillingAddress' object's fields _bap_district_name: CSB_School_District__r?.Name, - _bap_district_address_1: CSB_School_District__r?.BillingStreet, // TODO: confirm - _bap_district_address_2: "", // TODO: get - _bap_district_city: CSB_School_District__r?.BillingCity, // TODO: confirm - _bap_district_state: CSB_School_District__r?.BillingState, // TODO: confirm - _bap_district_zip: CSB_School_District__r?.BillingPostalCode, // TODO: confirm - _bap_district_priority: "", // TODO: get - _bap_district_selfCertify: "", // TODO: get + _bap_district_address_1: CSB_School_District__r?.BillingStreet, // TODO: nofity BAP this field is the district address 1 and 2 combined, when it should be two fields in the BAP + _bap_district_address_2: "", // TODO: see above + _bap_district_city: CSB_School_District__r?.BillingCity, + _bap_district_state: CSB_School_District__r?.BillingState, + _bap_district_zip: CSB_School_District__r?.BillingPostalCode, + _bap_district_priority: School_District_Prioritized__c, + _bap_district_selfCertify: School_District_Poverty_Rate__c, _bap_district_priorityReason: { highNeed: Prioritized_as_High_Need__c, tribal: Prioritized_as_Tribal__c, @@ -209,6 +272,8 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { _bap_district_contactTitle: School_District_Contact__r?.Title, _bap_district_contactEmail: School_District_Contact__r?.Email, _bap_district_contactPhone: School_District_Contact__r?.Phone, + org_organizations, + bus_buses, }, /** Add custom metadata to track formio submissions from wrapper. */ metadata: { ...formioCSBMetadata }, From c133ff512b4c46ea8ff399cc6c42248f279cb6de Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Tue, 23 Jan 2024 17:04:09 -0500 Subject: [PATCH 12/35] Destructure entity fields in frfNew component --- app/client/src/routes/frfNew.tsx | 69 ++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/app/client/src/routes/frfNew.tsx b/app/client/src/routes/frfNew.tsx index 182f8a38..622682ce 100644 --- a/app/client/src/routes/frfNew.tsx +++ b/app/client/src/routes/frfNew.tsx @@ -34,15 +34,22 @@ function createInitialSubmissionData(options: { const { rebateYear, email, entity } = options; const { title, name } = getUserInfo(email, entity); - const comboKey = entity.ENTITY_COMBO_KEY__c; - const uei = entity.UNIQUE_ENTITY_ID__c; - const efti = entity.ENTITY_EFT_INDICATOR__c; - const orgName = entity.LEGAL_BUSINESS_NAME__c; - const address1 = entity.PHYSICAL_ADDRESS_LINE_1__c; - const address2 = entity.PHYSICAL_ADDRESS_LINE_2__c; - const city = entity.PHYSICAL_ADDRESS_CITY__c; - const state = entity.PHYSICAL_ADDRESS_PROVINCE_OR_STATE__c; - const zip = entity.PHYSICAL_ADDRESS_ZIPPOSTAL_CODE__c; + + const { + ENTITY_COMBO_KEY__c, + UNIQUE_ENTITY_ID__c, + ENTITY_EFT_INDICATOR__c, + LEGAL_BUSINESS_NAME__c, + PHYSICAL_ADDRESS_LINE_1__c, + PHYSICAL_ADDRESS_LINE_2__c, + PHYSICAL_ADDRESS_CITY__c, + PHYSICAL_ADDRESS_PROVINCE_OR_STATE__c, + PHYSICAL_ADDRESS_ZIPPOSTAL_CODE__c, + ELEC_BUS_POC_EMAIL__c, + ALT_ELEC_BUS_POC_EMAIL__c, + GOVT_BUS_POC_EMAIL__c, + ALT_GOVT_BUS_POC_EMAIL__c, + } = entity; return rebateYear === "2022" ? { @@ -50,40 +57,40 @@ function createInitialSubmissionData(options: { hidden_current_user_email: email, hidden_current_user_title: title, hidden_current_user_name: name, - bap_hidden_entity_combo_key: comboKey, + bap_hidden_entity_combo_key: ENTITY_COMBO_KEY__c, sam_hidden_applicant_email: email, sam_hidden_applicant_title: title, sam_hidden_applicant_name: name, - sam_hidden_applicant_efti: efti, - sam_hidden_applicant_uei: uei, - sam_hidden_applicant_organization_name: orgName, - sam_hidden_applicant_street_address_1: address1, - sam_hidden_applicant_street_address_2: address2, - sam_hidden_applicant_city: city, - sam_hidden_applicant_state: state, - sam_hidden_applicant_zip_code: zip, + sam_hidden_applicant_efti: ENTITY_EFT_INDICATOR__c, + sam_hidden_applicant_uei: UNIQUE_ENTITY_ID__c, + sam_hidden_applicant_organization_name: LEGAL_BUSINESS_NAME__c, + sam_hidden_applicant_street_address_1: PHYSICAL_ADDRESS_LINE_1__c, + sam_hidden_applicant_street_address_2: PHYSICAL_ADDRESS_LINE_2__c, + sam_hidden_applicant_city: PHYSICAL_ADDRESS_CITY__c, + sam_hidden_applicant_state: PHYSICAL_ADDRESS_PROVINCE_OR_STATE__c, + sam_hidden_applicant_zip_code: PHYSICAL_ADDRESS_ZIPPOSTAL_CODE__c, } : rebateYear === "2023" ? { _user_email: email, _user_title: title, _user_name: name, - _bap_entity_combo_key: comboKey, - _bap_elec_bus_poc_email: entity.ELEC_BUS_POC_EMAIL__c, - _bap_alt_elec_bus_poc_email: entity.ALT_ELEC_BUS_POC_EMAIL__c, - _bap_govt_bus_poc_email: entity.GOVT_BUS_POC_EMAIL__c, - _bap_alt_govt_bus_poc_email: entity.ALT_GOVT_BUS_POC_EMAIL__c, + _bap_entity_combo_key: ENTITY_COMBO_KEY__c, + _bap_elec_bus_poc_email: ELEC_BUS_POC_EMAIL__c, + _bap_alt_elec_bus_poc_email: ALT_ELEC_BUS_POC_EMAIL__c, + _bap_govt_bus_poc_email: GOVT_BUS_POC_EMAIL__c, + _bap_alt_govt_bus_poc_email: ALT_GOVT_BUS_POC_EMAIL__c, _bap_applicant_email: email, _bap_applicant_title: title, _bap_applicant_name: name, - _bap_applicant_efti: efti, - _bap_applicant_uei: uei, - _bap_applicant_organization_name: orgName, - _bap_applicant_street_address_1: address1, - _bap_applicant_street_address_2: address2, - _bap_applicant_city: city, - _bap_applicant_state: state, - _bap_applicant_zip: zip, + _bap_applicant_efti: ENTITY_EFT_INDICATOR__c, + _bap_applicant_uei: UNIQUE_ENTITY_ID__c, + _bap_applicant_organization_name: LEGAL_BUSINESS_NAME__c, + _bap_applicant_street_address_1: PHYSICAL_ADDRESS_LINE_1__c, + _bap_applicant_street_address_2: PHYSICAL_ADDRESS_LINE_2__c, + _bap_applicant_city: PHYSICAL_ADDRESS_CITY__c, + _bap_applicant_state: PHYSICAL_ADDRESS_PROVINCE_OR_STATE__c, + _bap_applicant_zip: PHYSICAL_ADDRESS_ZIPPOSTAL_CODE__c, } : null; } From 4b548e9b7e38e6fd0ad38af1aaf0bc68dfd6df4a Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 24 Jan 2024 15:52:54 -0500 Subject: [PATCH 13/35] Add Id field to busRecordsQuery when querying for 2023 PRF data from the BAP --- app/server/app/utilities/bap.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/server/app/utilities/bap.js b/app/server/app/utilities/bap.js index 20af8fb6..99f5fe55 100644 --- a/app/server/app/utilities/bap.js +++ b/app/server/app/utilities/bap.js @@ -140,6 +140,7 @@ const { submissionPeriodOpen } = require("../config/formio"); * Prioritized_as_Rural__c: string * }[]} frfRecordQuery * @property {{ + * Id: string * Rebate_Item_num__c: string * CSB_VIN__c: string * CSB_Fuel_Type__c: string @@ -806,7 +807,7 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { // School_District_Poverty_Rate__c, // Prioritized_as_High_Need__c, // Prioritized_as_Tribal__c, - // Prioritized_as_Rural__c, + // Prioritized_as_Rural__c // FROM // ${BAP_FORMS_TABLE} // WHERE @@ -884,6 +885,7 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { const busRecordTypeId = busRecordTypeIdQuery["0"].Id; // `SELECT + // Id, // Rebate_Item_num__c, // CSB_VIN__c, // CSB_Fuel_Type__c, @@ -918,6 +920,7 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { }, { // "*": 1, + Id: 1, // Salesforce record ID Rebate_Item_num__c: 1, CSB_VIN__c: 1, CSB_Fuel_Type__c: 1, From 82c4ebf054f93a5389870ae33cddf11f8725571d Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 24 Jan 2024 21:19:48 -0500 Subject: [PATCH 14/35] Update capitalization of fields queried in BAP queries --- app/server/app/utilities/bap.js | 100 ++++++++++++++++---------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/app/server/app/utilities/bap.js b/app/server/app/utilities/bap.js index 99f5fe55..d99ad81d 100644 --- a/app/server/app/utilities/bap.js +++ b/app/server/app/utilities/bap.js @@ -396,7 +396,7 @@ async function queryForBapFormSubmissionData(req, formType, rebateId, mongoId) { /** @type {jsforce.Connection} */ const { bapConnection } = req.app.locals; - const developername = + const developerName = formType === "frf" ? "CSB_Funding_Request" : formType === "prf" @@ -405,23 +405,23 @@ async function queryForBapFormSubmissionData(req, formType, rebateId, mongoId) { ? "CSB_Closeout_Request" : null; // fallback - if (!developername) return null; + if (!developerName) return null; // `SELECT // Id // FROM - // recordtype + // RecordType // WHERE - // developername = '${developername}' AND - // sobjecttype = '${BAP_FORMS_TABLE}' + // DeveloperName = '${developerName}' AND + // SObjectType = '${BAP_FORMS_TABLE}' // LIMIT 1` const formRecordTypeIdQuery = await bapConnection - .sobject("recordtype") + .sobject("RecordType") .find( { - developername, - sobjecttype: BAP_FORMS_TABLE, + DeveloperName: developerName, + SObjectType: BAP_FORMS_TABLE, }, { // "*": 1, @@ -446,7 +446,7 @@ async function queryForBapFormSubmissionData(req, formType, rebateId, mongoId) { // FROM // ${BAP_FORMS_TABLE} // WHERE - // recordtypeid = '${formRecordTypeId}' AND + // RecordTypeId = '${formRecordTypeId}' AND // CSB_Form_ID__c = '${mongoId}' // Latest_Version__c = TRUE` @@ -454,7 +454,7 @@ async function queryForBapFormSubmissionData(req, formType, rebateId, mongoId) { .sobject(BAP_FORMS_TABLE) .find( { - recordtypeid: formRecordTypeId, + RecordTypeId: formRecordTypeId, ...(mongoId && { CSB_Form_ID__c: mongoId }), ...(rebateId && { Parent_Rebate_ID__c: rebateId }), Latest_Version__c: true, @@ -593,18 +593,18 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { // `SELECT // Id // FROM - // recordtype + // RecordType // WHERE - // developername = 'CSB_Funding_Request' AND - // sobjecttype = '${BAP_FORMS_TABLE}' + // DeveloperName = 'CSB_Funding_Request' AND + // SObjectType = '${BAP_FORMS_TABLE}' // LIMIT 1` const frfRecordTypeIdQuery = await bapConnection - .sobject("recordtype") + .sobject("RecordType") .find( { - developername: "CSB_Funding_Request", - sobjecttype: BAP_FORMS_TABLE, + DeveloperName: "CSB_Funding_Request", + SObjectType: BAP_FORMS_TABLE, }, { // "*": 1, @@ -637,7 +637,7 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { // FROM // ${BAP_FORMS_TABLE} // WHERE - // recordtypeid = '${frfRecordTypeId}' AND + // RecordTypeId = '${frfRecordTypeId}' AND // CSB_Review_Item_ID__c = '${frfReviewItemId}' AND // Latest_Version__c = TRUE` @@ -645,7 +645,7 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { .sobject(BAP_FORMS_TABLE) .find( { - recordtypeid: frfRecordTypeId, + RecordTypeId: frfRecordTypeId, CSB_Review_Item_ID__c: frfReviewItemId, Latest_Version__c: true, }, @@ -677,18 +677,18 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { // `SELECT // Id // FROM - // recordtype + // RecordType // WHERE - // developername = 'CSB_Rebate_Item' AND - // sobjecttype = '${BAP_BUS_TABLE}' + // DeveloperName = 'CSB_Rebate_Item' AND + // SObjectType = '${BAP_BUS_TABLE}' // LIMIT 1` const busRecordTypeIdQuery = await bapConnection - .sobject("recordtype") + .sobject("RecordType") .find( { - developername: "CSB_Rebate_Item", - sobjecttype: BAP_BUS_TABLE, + DeveloperName: "CSB_Rebate_Item", + SObjectType: BAP_BUS_TABLE, }, { // "*": 1, @@ -710,7 +710,7 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { // FROM // ${BAP_BUS_TABLE} // WHERE - // recordtypeid = '${busRecordTypeId}' AND + // RecordTypeId = '${busRecordTypeId}' AND // Related_Order_Request__c = '${frfRecordId}' AND // CSB_Rebate_Item_Type__c = 'Old Bus'` @@ -718,7 +718,7 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { .sobject(BAP_BUS_TABLE) .find( { - recordtypeid: busRecordTypeId, + RecordTypeId: busRecordTypeId, Related_Order_Request__c: frfRecordId, CSB_Rebate_Item_Type__c: "Old Bus", }, @@ -968,18 +968,18 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // `SELECT // Id // FROM - // recordtype + // RecordType // WHERE - // developername = 'CSB_Funding_Request' AND - // sobjecttype = '${BAP_FORMS_TABLE}' + // DeveloperName = 'CSB_Funding_Request' AND + // SObjectType = '${BAP_FORMS_TABLE}' // LIMIT 1` const frfRecordTypeIdQuery = await bapConnection - .sobject("recordtype") + .sobject("RecordType") .find( { - developername: "CSB_Funding_Request", - sobjecttype: BAP_FORMS_TABLE, + DeveloperName: "CSB_Funding_Request", + SObjectType: BAP_FORMS_TABLE, }, { // "*": 1, @@ -1006,7 +1006,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // FROM // ${BAP_FORMS_TABLE} // WHERE - // recordtypeid = '${frfRecordTypeId}' AND + // RecordTypeId = '${frfRecordTypeId}' AND // CSB_Review_Item_ID__c = '${frfReviewItemId}' AND // Latest_Version__c = TRUE` @@ -1014,7 +1014,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { .sobject(BAP_FORMS_TABLE) .find( { - recordtypeid: frfRecordTypeId, + RecordTypeId: frfRecordTypeId, CSB_Review_Item_ID__c: frfReviewItemId, Latest_Version__c: true, }, @@ -1038,18 +1038,18 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // `SELECT // Id // FROM - // recordtype + // RecordType // WHERE - // developername = 'CSB_Payment_Request' AND - // sobjecttype = '${BAP_FORMS_TABLE}' + // DeveloperName = 'CSB_Payment_Request' AND + // SObjectType = '${BAP_FORMS_TABLE}' // LIMIT 1` const prfRecordTypeIdQuery = await bapConnection - .sobject("recordtype") + .sobject("RecordType") .find( { - developername: "CSB_Payment_Request", - sobjecttype: BAP_FORMS_TABLE, + DeveloperName: "CSB_Payment_Request", + SObjectType: BAP_FORMS_TABLE, }, { // "*": 1, @@ -1092,7 +1092,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // FROM // ${BAP_FORMS_TABLE} // WHERE - // recordtypeid = '${prfRecordTypeId}' AND + // RecordTypeId = '${prfRecordTypeId}' AND // CSB_Review_Item_ID__c = '${prfReviewItemId}' AND // Latest_Version__c = TRUE` @@ -1100,7 +1100,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { .sobject(BAP_FORMS_TABLE) .find( { - recordtypeid: prfRecordTypeId, + RecordTypeId: prfRecordTypeId, CSB_Review_Item_ID__c: prfReviewItemId, Latest_Version__c: true, }, @@ -1142,18 +1142,18 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // `SELECT // Id // FROM - // recordtype + // RecordType // WHERE - // developername = 'CSB_Rebate_Item' AND - // sobjecttype = '${BAP_BUS_TABLE}' + // DeveloperName = 'CSB_Rebate_Item' AND + // SObjectType = '${BAP_BUS_TABLE}' // LIMIT 1` const busRecordTypeIdQuery = await bapConnection - .sobject("recordtype") + .sobject("RecordType") .find( { - developername: "CSB_Rebate_Item", - sobjecttype: BAP_BUS_TABLE, + DeveloperName: "CSB_Rebate_Item", + SObjectType: BAP_BUS_TABLE, }, { // "*": 1, @@ -1185,7 +1185,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // FROM // ${BAP_BUS_TABLE} // WHERE - // recordtypeid = '${busRecordTypeId}' AND + // RecordTypeId = '${busRecordTypeId}' AND // Related_Order_Request__c = '${prfRecordId}' AND // CSB_Rebate_Item_Type__c = 'New Bus'` @@ -1193,7 +1193,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { .sobject(BAP_BUS_TABLE) .find( { - recordtypeid: busRecordTypeId, + RecordTypeId: busRecordTypeId, Related_Order_Request__c: prfRecordId, CSB_Rebate_Item_Type__c: "New Bus", }, From 174ef51a6c5cfd15718d324f14c5884e07be70e9 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 24 Jan 2024 21:22:16 -0500 Subject: [PATCH 15/35] Inline BAP_SAM_TABLE value --- app/server/app/utilities/bap.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/server/app/utilities/bap.js b/app/server/app/utilities/bap.js index d99ad81d..346b0d64 100644 --- a/app/server/app/utilities/bap.js +++ b/app/server/app/utilities/bap.js @@ -252,7 +252,6 @@ const { BAP_URL, BAP_USER, BAP_PASSWORD, - BAP_SAM_TABLE, BAP_FORMS_TABLE, BAP_BUS_TABLE, } = process.env; @@ -328,7 +327,7 @@ async function queryForSamEntities(req, email) { // PHYSICAL_ADDRESS_ZIPPOSTAL_CODE__c, // PHYSICAL_ADDRESS_ZIP_CODE_4__c // FROM - // ${BAP_SAM_TABLE} + // Data_Staging__c // WHERE // ALT_ELEC_BUS_POC_EMAIL__c = '${email}' OR // GOVT_BUS_POC_EMAIL__c = '${email}' OR @@ -336,7 +335,7 @@ async function queryForSamEntities(req, email) { // ELEC_BUS_POC_EMAIL__c = '${email}'` return await bapConnection - .sobject(BAP_SAM_TABLE) + .sobject("Data_Staging__c") .find( { $or: [ From 1976732819affaffc07ba4102db5670a6f0efa8c Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 24 Jan 2024 21:26:08 -0500 Subject: [PATCH 16/35] Inline BAP_FORMS_TABLE value --- app/server/app/utilities/bap.js | 49 ++++++++++++++++----------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/app/server/app/utilities/bap.js b/app/server/app/utilities/bap.js index 346b0d64..23a55993 100644 --- a/app/server/app/utilities/bap.js +++ b/app/server/app/utilities/bap.js @@ -252,7 +252,6 @@ const { BAP_URL, BAP_USER, BAP_PASSWORD, - BAP_FORMS_TABLE, BAP_BUS_TABLE, } = process.env; @@ -412,7 +411,7 @@ async function queryForBapFormSubmissionData(req, formType, rebateId, mongoId) { // RecordType // WHERE // DeveloperName = '${developerName}' AND - // SObjectType = '${BAP_FORMS_TABLE}' + // SObjectType = 'Order_Request__c' // LIMIT 1` const formRecordTypeIdQuery = await bapConnection @@ -420,7 +419,7 @@ async function queryForBapFormSubmissionData(req, formType, rebateId, mongoId) { .find( { DeveloperName: developerName, - SObjectType: BAP_FORMS_TABLE, + SObjectType: "Order_Request__c", }, { // "*": 1, @@ -443,14 +442,14 @@ async function queryForBapFormSubmissionData(req, formType, rebateId, mongoId) { // Parent_CSB_Rebate__r.CSB_Payment_Request_Status__c, // Parent_CSB_Rebate__r.CSB_Closeout_Request_Status__c // FROM - // ${BAP_FORMS_TABLE} + // Order_Request__c // WHERE // RecordTypeId = '${formRecordTypeId}' AND // CSB_Form_ID__c = '${mongoId}' // Latest_Version__c = TRUE` const formRecordQuery = await bapConnection - .sobject(BAP_FORMS_TABLE) + .sobject("Order_Request__c") .find( { RecordTypeId: formRecordTypeId, @@ -496,7 +495,7 @@ async function queryForBapFormSubmissionsStatuses(req, comboKeys) { // `SELECT // Parent_Rebate_ID__c, // FROM - // ${BAP_FORMS_TABLE} + // Order_Request__c // WHERE // (${comboKeys // .map((key) => `UEI_EFTI_Combo_Key__c = '${key}'`) @@ -504,7 +503,7 @@ async function queryForBapFormSubmissionsStatuses(req, comboKeys) { // Latest_Version__c = TRUE` const parentRebateIdsQuery = await bapConnection - .sobject(BAP_FORMS_TABLE) + .sobject("Order_Request__c") .find( { UEI_EFTI_Combo_Key__c: { $in: comboKeys }, @@ -536,7 +535,7 @@ async function queryForBapFormSubmissionsStatuses(req, comboKeys) { // Parent_CSB_Rebate__r.CSB_Payment_Request_Status__c, // Parent_CSB_Rebate__r.CSB_Closeout_Request_Status__c // FROM - // ${BAP_FORMS_TABLE} + // Order_Request__c // WHERE // (${parentRebateIds // .map((id) => `Parent_CSB_Rebate__r.CSB_Rebate_ID__c = '${id}'`) @@ -546,7 +545,7 @@ async function queryForBapFormSubmissionsStatuses(req, comboKeys) { // CreatedDate DESC` const submissions = await bapConnection - .sobject(BAP_FORMS_TABLE) + .sobject("Order_Request__c") .find( { "Parent_CSB_Rebate__r.CSB_Rebate_ID__c": { $in: parentRebateIds }, @@ -595,7 +594,7 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { // RecordType // WHERE // DeveloperName = 'CSB_Funding_Request' AND - // SObjectType = '${BAP_FORMS_TABLE}' + // SObjectType = 'Order_Request__c' // LIMIT 1` const frfRecordTypeIdQuery = await bapConnection @@ -603,7 +602,7 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { .find( { DeveloperName: "CSB_Funding_Request", - SObjectType: BAP_FORMS_TABLE, + SObjectType: "Order_Request__c", }, { // "*": 1, @@ -634,14 +633,14 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { // Total_Rebate_Funds_Requested__c, // Total_Infrastructure_Funds__c // FROM - // ${BAP_FORMS_TABLE} + // Order_Request__c // WHERE // RecordTypeId = '${frfRecordTypeId}' AND // CSB_Review_Item_ID__c = '${frfReviewItemId}' AND // Latest_Version__c = TRUE` const frfRecordQuery = await bapConnection - .sobject(BAP_FORMS_TABLE) + .sobject("Order_Request__c") .find( { RecordTypeId: frfRecordTypeId, @@ -759,7 +758,7 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { // RecordType // WHERE // DeveloperName = 'CSB_Funding_Request_2023' AND - // SObjectType = '${BAP_FORMS_TABLE}' + // SObjectType = 'Order_Request__c' // LIMIT 1` const frfRecordTypeIdQuery = await bapConnection @@ -767,7 +766,7 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { .find( { DeveloperName: "CSB_Funding_Request_2023", - SObjectType: BAP_FORMS_TABLE, + SObjectType: "Order_Request__c", }, { // "*": 1, @@ -808,14 +807,14 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { // Prioritized_as_Tribal__c, // Prioritized_as_Rural__c // FROM - // ${BAP_FORMS_TABLE} + // Order_Request__c // WHERE // RecordTypeId = '${frfRecordTypeId}' AND // CSB_Review_Item_ID__c = '${frfReviewItemId}' AND // Latest_Version__c = TRUE` const frfRecordQuery = await bapConnection - .sobject(BAP_FORMS_TABLE) + .sobject("Order_Request__c") .find( { RecordTypeId: frfRecordTypeId, @@ -970,7 +969,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // RecordType // WHERE // DeveloperName = 'CSB_Funding_Request' AND - // SObjectType = '${BAP_FORMS_TABLE}' + // SObjectType = 'Order_Request__c' // LIMIT 1` const frfRecordTypeIdQuery = await bapConnection @@ -978,7 +977,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { .find( { DeveloperName: "CSB_Funding_Request", - SObjectType: BAP_FORMS_TABLE, + SObjectType: "Order_Request__c", }, { // "*": 1, @@ -1003,14 +1002,14 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // School_District_Contact__r.FirstName, // School_District_Contact__r.LastName // FROM - // ${BAP_FORMS_TABLE} + // Order_Request__c // WHERE // RecordTypeId = '${frfRecordTypeId}' AND // CSB_Review_Item_ID__c = '${frfReviewItemId}' AND // Latest_Version__c = TRUE` const frfRecordQuery = await bapConnection - .sobject(BAP_FORMS_TABLE) + .sobject("Order_Request__c") .find( { RecordTypeId: frfRecordTypeId, @@ -1040,7 +1039,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // RecordType // WHERE // DeveloperName = 'CSB_Payment_Request' AND - // SObjectType = '${BAP_FORMS_TABLE}' + // SObjectType = 'Order_Request__c' // LIMIT 1` const prfRecordTypeIdQuery = await bapConnection @@ -1048,7 +1047,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { .find( { DeveloperName: "CSB_Payment_Request", - SObjectType: BAP_FORMS_TABLE, + SObjectType: "Order_Request__c", }, { // "*": 1, @@ -1089,14 +1088,14 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // Total_DC_Fast_Charger_Costs__c, // Total_Other_Infrastructure_Costs__c // FROM - // ${BAP_FORMS_TABLE} + // Order_Request__c // WHERE // RecordTypeId = '${prfRecordTypeId}' AND // CSB_Review_Item_ID__c = '${prfReviewItemId}' AND // Latest_Version__c = TRUE` const prfRecordQuery = await bapConnection - .sobject(BAP_FORMS_TABLE) + .sobject("Order_Request__c") .find( { RecordTypeId: prfRecordTypeId, From 2da48030a6a8d06d95f75e05f8b11bc16f793447 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 24 Jan 2024 21:28:00 -0500 Subject: [PATCH 17/35] Inline BAP_BUS_TABLE value --- app/server/app/utilities/bap.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/app/server/app/utilities/bap.js b/app/server/app/utilities/bap.js index 23a55993..c0f52f91 100644 --- a/app/server/app/utilities/bap.js +++ b/app/server/app/utilities/bap.js @@ -252,7 +252,6 @@ const { BAP_URL, BAP_USER, BAP_PASSWORD, - BAP_BUS_TABLE, } = process.env; /** @@ -678,7 +677,7 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { // RecordType // WHERE // DeveloperName = 'CSB_Rebate_Item' AND - // SObjectType = '${BAP_BUS_TABLE}' + // SObjectType = 'Line_Item__c' // LIMIT 1` const busRecordTypeIdQuery = await bapConnection @@ -686,7 +685,7 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { .find( { DeveloperName: "CSB_Rebate_Item", - SObjectType: BAP_BUS_TABLE, + SObjectType: "Line_Item__c", }, { // "*": 1, @@ -706,14 +705,14 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { // CSB_Replacement_Fuel_Type__c, // CSB_Funds_Requested__c // FROM - // ${BAP_BUS_TABLE} + // Line_Item__c // WHERE // RecordTypeId = '${busRecordTypeId}' AND // Related_Order_Request__c = '${frfRecordId}' AND // CSB_Rebate_Item_Type__c = 'Old Bus'` const busRecordsQuery = await bapConnection - .sobject(BAP_BUS_TABLE) + .sobject("Line_Item__c") .find( { RecordTypeId: busRecordTypeId, @@ -862,7 +861,7 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { // RecordType // WHERE // DeveloperName = 'CSB_Rebate_Item' AND - // SObjectType = '${BAP_BUS_TABLE}' + // SObjectType = 'Line_Item__c' // LIMIT 1` const busRecordTypeIdQuery = await bapConnection @@ -870,7 +869,7 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { .find( { DeveloperName: "CSB_Rebate_Item", - SObjectType: BAP_BUS_TABLE, + SObjectType: "Line_Item__c", }, { // "*": 1, @@ -902,14 +901,14 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { // New_Bus_GVWR__c, // New_Bus_ADA_Compliant__c // FROM - // ${BAP_BUS_TABLE} + // Line_Item__c // WHERE // RecordTypeId = '${busRecordTypeId}' AND // Related_Order_Request__c = '${frfRecordId}' AND // CSB_Rebate_Item_Type__c = 'Old Bus'` const busRecordsQuery = await bapConnection - .sobject(BAP_BUS_TABLE) + .sobject("Line_Item__c") .find( { RecordTypeId: busRecordTypeId, @@ -1143,7 +1142,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // RecordType // WHERE // DeveloperName = 'CSB_Rebate_Item' AND - // SObjectType = '${BAP_BUS_TABLE}' + // SObjectType = 'Line_Item__c' // LIMIT 1` const busRecordTypeIdQuery = await bapConnection @@ -1151,7 +1150,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { .find( { DeveloperName: "CSB_Rebate_Item", - SObjectType: BAP_BUS_TABLE, + SObjectType: "Line_Item__c", }, { // "*": 1, @@ -1181,14 +1180,14 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // New_Bus_Rebate_Amount__c, // New_Bus_Purchase_Price__c // FROM - // ${BAP_BUS_TABLE} + // Line_Item__c // WHERE // RecordTypeId = '${busRecordTypeId}' AND // Related_Order_Request__c = '${prfRecordId}' AND // CSB_Rebate_Item_Type__c = 'New Bus'` const busRecordsQuery = await bapConnection - .sobject(BAP_BUS_TABLE) + .sobject("Line_Item__c") .find( { RecordTypeId: busRecordTypeId, From eed3aa2b35e5ac4662a8214fe2c3e0dd49d489e7 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 24 Jan 2024 21:28:15 -0500 Subject: [PATCH 18/35] Remove no longer used env variables --- app/server/.env.example | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/server/.env.example b/app/server/.env.example index 1b80f0ef..334f7a6d 100644 --- a/app/server/.env.example +++ b/app/server/.env.example @@ -31,8 +31,5 @@ BAP_CLIENT_SECRET= BAP_URL= BAP_USER= BAP_PASSWORD= -BAP_SAM_TABLE= -BAP_FORMS_TABLE= -BAP_BUS_TABLE= S3_PUBLIC_BUCKET= S3_PUBLIC_REGION= From 05b9b5a2d8a6737d24df971ad393e1a185d9619f Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 24 Jan 2024 21:46:26 -0500 Subject: [PATCH 19/35] Begin renaming variables used in BAP queries to be more clear --- app/server/app/utilities/bap.js | 44 +++++++++++++++--------------- app/server/app/utilities/formio.js | 6 ++-- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/app/server/app/utilities/bap.js b/app/server/app/utilities/bap.js index c0f52f91..a9ef6173 100644 --- a/app/server/app/utilities/bap.js +++ b/app/server/app/utilities/bap.js @@ -85,7 +85,7 @@ const { submissionPeriodOpen } = require("../config/formio"); * School_District_Prioritized__c: string * Total_Rebate_Funds_Requested__c: string * Total_Infrastructure_Funds__c: string - * }[]} frfRecordQuery + * }[]} frf2022RecordQuery * @property {{ * Rebate_Item_num__c: string * CSB_VIN__c: string @@ -93,7 +93,7 @@ const { submissionPeriodOpen } = require("../config/formio"); * CSB_Fuel_Type__c: string * CSB_Replacement_Fuel_Type__c: string * CSB_Funds_Requested__c: string - * }[]} busRecordsQuery + * }[]} frf2022BusRecordsQuery * @property {{ * type: string * url: string @@ -501,7 +501,7 @@ async function queryForBapFormSubmissionsStatuses(req, comboKeys) { // .join(" OR ")}) AND // Latest_Version__c = TRUE` - const parentRebateIdsQuery = await bapConnection + const csbRebateIdsQuery = await bapConnection .sobject("Order_Request__c") .find( { @@ -516,11 +516,11 @@ async function queryForBapFormSubmissionsStatuses(req, comboKeys) { .sort({ CreatedDate: -1 }) .execute(async (err, records) => ((await err) ? err : records)); - const parentRebateIds = Array.isArray(parentRebateIdsQuery) - ? parentRebateIdsQuery.map((item) => item.Parent_Rebate_ID__c) + const csbRebateIds = Array.isArray(csbRebateIdsQuery) + ? csbRebateIdsQuery.map((item) => item.Parent_Rebate_ID__c) : []; - if (parentRebateIds.length === 0) return []; + if (csbRebateIds.length === 0) return []; // `SELECT // UEI_EFTI_Combo_Key__c, @@ -536,7 +536,7 @@ async function queryForBapFormSubmissionsStatuses(req, comboKeys) { // FROM // Order_Request__c // WHERE - // (${parentRebateIds + // (${csbRebateIds // .map((id) => `Parent_CSB_Rebate__r.CSB_Rebate_ID__c = '${id}'`) // .join(" OR ")}) AND // Latest_Version__c = TRUE @@ -547,7 +547,7 @@ async function queryForBapFormSubmissionsStatuses(req, comboKeys) { .sobject("Order_Request__c") .find( { - "Parent_CSB_Rebate__r.CSB_Rebate_ID__c": { $in: parentRebateIds }, + "Parent_CSB_Rebate__r.CSB_Rebate_ID__c": { $in: csbRebateIds }, Latest_Version__c: true, }, { @@ -596,7 +596,7 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { // SObjectType = 'Order_Request__c' // LIMIT 1` - const frfRecordTypeIdQuery = await bapConnection + const frf2022RecordTypeIdQuery = await bapConnection .sobject("RecordType") .find( { @@ -611,7 +611,7 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { .limit(1) .execute(async (err, records) => ((await err) ? err : records)); - const frfRecordTypeId = frfRecordTypeIdQuery["0"].Id; + const frf2022RecordTypeId = frf2022RecordTypeIdQuery["0"].Id; // `SELECT // Id, @@ -634,15 +634,15 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { // FROM // Order_Request__c // WHERE - // RecordTypeId = '${frfRecordTypeId}' AND + // RecordTypeId = '${frf2022RecordTypeId}' AND // CSB_Review_Item_ID__c = '${frfReviewItemId}' AND // Latest_Version__c = TRUE` - const frfRecordQuery = await bapConnection + const frf2022RecordQuery = await bapConnection .sobject("Order_Request__c") .find( { - RecordTypeId: frfRecordTypeId, + RecordTypeId: frf2022RecordTypeId, CSB_Review_Item_ID__c: frfReviewItemId, Latest_Version__c: true, }, @@ -669,7 +669,7 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { ) .execute(async (err, records) => ((await err) ? err : records)); - const frfRecordId = frfRecordQuery["0"].Id; + const frf2022RecordId = frf2022RecordQuery["0"].Id; // `SELECT // Id @@ -680,7 +680,7 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { // SObjectType = 'Line_Item__c' // LIMIT 1` - const busRecordTypeIdQuery = await bapConnection + const rebateItemRecordTypeIdQuery = await bapConnection .sobject("RecordType") .find( { @@ -695,7 +695,7 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { .limit(1) .execute(async (err, records) => ((await err) ? err : records)); - const busRecordTypeId = busRecordTypeIdQuery["0"].Id; + const rebateItemRecordTypeId = rebateItemRecordTypeIdQuery["0"].Id; // `SELECT // Rebate_Item_num__c, @@ -707,16 +707,16 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { // FROM // Line_Item__c // WHERE - // RecordTypeId = '${busRecordTypeId}' AND - // Related_Order_Request__c = '${frfRecordId}' AND + // RecordTypeId = '${rebateItemRecordTypeId}' AND + // Related_Order_Request__c = '${frf2022RecordId}' AND // CSB_Rebate_Item_Type__c = 'Old Bus'` - const busRecordsQuery = await bapConnection + const frf2022BusRecordsQuery = await bapConnection .sobject("Line_Item__c") .find( { - RecordTypeId: busRecordTypeId, - Related_Order_Request__c: frfRecordId, + RecordTypeId: rebateItemRecordTypeId, + Related_Order_Request__c: frf2022RecordId, CSB_Rebate_Item_Type__c: "Old Bus", }, { @@ -731,7 +731,7 @@ async function queryBapFor2022PRFData(req, frfReviewItemId) { ) .execute(async (err, records) => ((await err) ? err : records)); - return { frfRecordQuery, busRecordsQuery }; + return { frf2022RecordQuery, frf2022BusRecordsQuery }; } /** diff --git a/app/server/app/utilities/formio.js b/app/server/app/utilities/formio.js index 038f3268..a20d36b9 100644 --- a/app/server/app/utilities/formio.js +++ b/app/server/app/utilities/formio.js @@ -70,7 +70,7 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { if (rebateYear === "2022") { return getBapDataFor2022PRF(req, frfReviewItemId) - .then(({ frfRecordQuery, busRecordsQuery }) => { + .then(({ frf2022RecordQuery, frf2022BusRecordsQuery }) => { const { CSB_NCES_ID__c, Primary_Applicant__r, @@ -81,9 +81,9 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { School_District_Prioritized__c, Total_Rebate_Funds_Requested__c, Total_Infrastructure_Funds__c, - } = frfRecordQuery[0]; + } = frf2022RecordQuery[0]; - const busInfo = busRecordsQuery.map((record) => ({ + const busInfo = frf2022BusRecordsQuery.map((record) => ({ busNum: record.Rebate_Item_num__c, oldBusNcesDistrictId: CSB_NCES_ID__c, oldBusVin: record.CSB_VIN__c, From 9b55a507480c2c5eb25005775d8ba4464eca0291 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 24 Jan 2024 21:54:35 -0500 Subject: [PATCH 20/35] Continue renaming variables used in BAP queries to be more clear --- app/server/app/utilities/bap.js | 32 +++++++++++++++--------------- app/server/app/utilities/formio.js | 6 +++--- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/server/app/utilities/bap.js b/app/server/app/utilities/bap.js index a9ef6173..22cc10cc 100644 --- a/app/server/app/utilities/bap.js +++ b/app/server/app/utilities/bap.js @@ -138,7 +138,7 @@ const { submissionPeriodOpen } = require("../config/formio"); * Prioritized_as_High_Need__c: string * Prioritized_as_Tribal__c: string * Prioritized_as_Rural__c: string - * }[]} frfRecordQuery + * }[]} frf2023RecordQuery * @property {{ * Id: string * Rebate_Item_num__c: string @@ -158,7 +158,7 @@ const { submissionPeriodOpen } = require("../config/formio"); * New_Bus_Fuel_Type__c: string * New_Bus_GVWR__c: string * New_Bus_ADA_Compliant__c: string - * }[]} busRecordsQuery + * }[]} frf2023BusRecordsQuery * @property {{ * type: string * url: string @@ -760,7 +760,7 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { // SObjectType = 'Order_Request__c' // LIMIT 1` - const frfRecordTypeIdQuery = await bapConnection + const frf2023RecordTypeIdQuery = await bapConnection .sobject("RecordType") .find( { @@ -775,7 +775,7 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { .limit(1) .execute(async (err, records) => ((await err) ? err : records)); - const frfRecordTypeId = frfRecordTypeIdQuery["0"].Id; + const frf2023RecordTypeId = frf2023RecordTypeIdQuery["0"].Id; // `SELECT // Id, @@ -808,15 +808,15 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { // FROM // Order_Request__c // WHERE - // RecordTypeId = '${frfRecordTypeId}' AND + // RecordTypeId = '${frf2023RecordTypeId}' AND // CSB_Review_Item_ID__c = '${frfReviewItemId}' AND // Latest_Version__c = TRUE` - const frfRecordQuery = await bapConnection + const frf2023RecordQuery = await bapConnection .sobject("Order_Request__c") .find( { - RecordTypeId: frfRecordTypeId, + RecordTypeId: frf2023RecordTypeId, CSB_Review_Item_ID__c: frfReviewItemId, Latest_Version__c: true, }, @@ -853,7 +853,7 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { ) .execute(async (err, records) => ((await err) ? err : records)); - const frfRecordId = frfRecordQuery["0"].Id; + const frf2023RecordId = frf2023RecordQuery["0"].Id; // `SELECT // Id @@ -864,7 +864,7 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { // SObjectType = 'Line_Item__c' // LIMIT 1` - const busRecordTypeIdQuery = await bapConnection + const rebateItemRecordTypeIdQuery = await bapConnection .sobject("RecordType") .find( { @@ -879,7 +879,7 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { .limit(1) .execute(async (err, records) => ((await err) ? err : records)); - const busRecordTypeId = busRecordTypeIdQuery["0"].Id; + const rebateItemRecordTypeId = rebateItemRecordTypeIdQuery["0"].Id; // `SELECT // Id, @@ -903,16 +903,16 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { // FROM // Line_Item__c // WHERE - // RecordTypeId = '${busRecordTypeId}' AND - // Related_Order_Request__c = '${frfRecordId}' AND + // RecordTypeId = '${rebateItemRecordTypeId}' AND + // Related_Order_Request__c = '${frf2023RecordId}' AND // CSB_Rebate_Item_Type__c = 'Old Bus'` - const busRecordsQuery = await bapConnection + const frf2023BusRecordsQuery = await bapConnection .sobject("Line_Item__c") .find( { - RecordTypeId: busRecordTypeId, - Related_Order_Request__c: frfRecordId, + RecordTypeId: rebateItemRecordTypeId, + Related_Order_Request__c: frf2023RecordId, CSB_Rebate_Item_Type__c: "Old Bus", }, { @@ -939,7 +939,7 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { ) .execute(async (err, records) => ((await err) ? err : records)); - return { frfRecordQuery, busRecordsQuery }; + return { frf2023RecordQuery, frf2023BusRecordsQuery }; } /** diff --git a/app/server/app/utilities/formio.js b/app/server/app/utilities/formio.js index a20d36b9..7b065e64 100644 --- a/app/server/app/utilities/formio.js +++ b/app/server/app/utilities/formio.js @@ -144,7 +144,7 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { if (rebateYear === "2023") { return getBapDataFor2023PRF(req, frfReviewItemId) - .then(({ frfRecordQuery, busRecordsQuery }) => { + .then(({ frf2023RecordQuery, frf2023BusRecordsQuery }) => { const { Primary_Applicant__r, Alternate_Applicant__r, @@ -157,7 +157,7 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { Prioritized_as_High_Need__c, Prioritized_as_Tribal__c, Prioritized_as_Rural__c, - } = frfRecordQuery[0]; + } = frf2023RecordQuery[0]; // TODO: ask BAP for the query for the fields below. // NOTE: the data from the 2023 FRF is in an 'organizations' field (array of objects) @@ -187,7 +187,7 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { org_zip: "", })); - const bus_buses = busRecordsQuery.map((item) => ({ + const bus_buses = frf2023BusRecordsQuery.map((item) => ({ bus_busNumber: item.Rebate_Item_num__c, bus_existingOwner: { org: "", // TODO: Old_Bus_Owner__r.* or Old_Bus_Owner_Contact_ID__c From 6939186b5dca7775b11975a118832dc9fcbf2242 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Wed, 24 Jan 2024 22:13:15 -0500 Subject: [PATCH 21/35] Finish renaming variables used in BAP queries to be more clear --- app/server/app/routes/formio2022.js | 264 ++++++++++++++-------------- app/server/app/utilities/bap.js | 44 ++--- 2 files changed, 155 insertions(+), 153 deletions(-) diff --git a/app/server/app/routes/formio2022.js b/app/server/app/routes/formio2022.js index 03fd6a94..3f0454d2 100644 --- a/app/server/app/routes/formio2022.js +++ b/app/server/app/routes/formio2022.js @@ -359,137 +359,139 @@ router.post("/crf-submission", storeBapComboKeys, (req, res) => { } = entity; return getBapDataFor2022CRF(req, frfReviewItemId, prfReviewItemId) - .then(({ frfRecordQuery, prfRecordQuery, busRecordsQuery }) => { - const { - Fleet_Name__c, - Fleet_Street_Address__c, - Fleet_City__c, - Fleet_State__c, - Fleet_Zip__c, - Fleet_Contact_Name__c, - Fleet_Contact_Title__c, - Fleet_Contact_Phone__c, - Fleet_Contact_Email__c, - School_District_Contact__r, - } = frfRecordQuery[0]; - - const { - CSB_NCES_ID__c, - Primary_Applicant__r, - Alternate_Applicant__r, - Applicant_Organization__r, - CSB_School_District__r, - School_District_Prioritized__c, - Total_Rebate_Funds_Requested_PO__c, - Total_Bus_And_Infrastructure_Rebate__c, - Total_Infrastructure_Funds__c, - Num_Of_Buses_Requested_From_Application__c, - Total_Price_All_Buses__c, - Total_Bus_Rebate_Amount__c, - Total_All_Eligible_Infrastructure_Costs__c, - Total_Infrastructure_Rebate__c, - Total_Level_2_Charger_Costs__c, - Total_DC_Fast_Charger_Costs__c, - Total_Other_Infrastructure_Costs__c, - } = prfRecordQuery[0]; - - const busInfo = busRecordsQuery.map((record) => ({ - busNum: record.Rebate_Item_num__c, - oldBusNcesDistrictId: CSB_NCES_ID__c, - oldBusVin: record.CSB_VIN__c, - oldBusModelYear: record.CSB_Model_Year__c, - oldBusFuelType: record.CSB_Fuel_Type__c, - oldBusEstimatedRemainingLife: record.Old_Bus_Estimated_Remaining_Life__c, // prettier-ignore - oldBusExclude: record.Old_Bus_Exclude__c, - hidden_prf_oldBusExclude: record.Old_Bus_Exclude__c, - newBusDealer: record.Related_Line_Item__r?.Vendor_Name__c, - newBusFuelType: record.New_Bus_Fuel_Type__c, - hidden_prf_newBusFuelType: record.New_Bus_Fuel_Type__c, - newBusMake: record.New_Bus_Make__c, - hidden_prf_newBusMake: record.New_Bus_Make__c, - newBusMakeOther: record.CSB_Manufacturer_if_Other__c, - hidden_prf_newBusMakeOther: record.CSB_Manufacturer_if_Other__c, - newBusModel: record.New_Bus_Model__c, - hidden_prf_newBusModel: record.New_Bus_Model__c, - newBusModelYear: record.New_Bus_Model_Year__c, - hidden_prf_newBusModelYear: record.New_Bus_Model_Year__c, - newBusGvwr: record.New_Bus_GVWR__c, - hidden_prf_newBusGvwr: record.New_Bus_GVWR__c, - newBusPurchasePrice: record.New_Bus_Purchase_Price__c, - hidden_prf_newBusPurchasePrice: record.New_Bus_Purchase_Price__c, - hidden_prf_rebate: record.New_Bus_Rebate_Amount__c, - })); - - const submission = { - data: { - bap_hidden_entity_combo_key: comboKey, - hidden_prf_modified: prfModified, - hidden_current_user_email: email, - hidden_current_user_title: title, - hidden_current_user_name: name, - hidden_bap_rebate_id: rebateId, - hidden_sam_uei: UNIQUE_ENTITY_ID__c, - hidden_sam_efti: ENTITY_EFT_INDICATOR__c || "0000", - hidden_sam_elec_bus_poc_email: ELEC_BUS_POC_EMAIL__c, - hidden_sam_alt_elec_bus_poc_email: ALT_ELEC_BUS_POC_EMAIL__c, - hidden_sam_govt_bus_poc_email: GOVT_BUS_POC_EMAIL__c, - hidden_sam_alt_govt_bus_poc_email: ALT_GOVT_BUS_POC_EMAIL__c, - hidden_bap_district_id: CSB_NCES_ID__c, - hidden_bap_district_name: CSB_School_District__r?.Name, - hidden_bap_primary_fname: Primary_Applicant__r?.FirstName, - hidden_bap_primary_lname: Primary_Applicant__r?.LastName, - hidden_bap_primary_title: Primary_Applicant__r?.Title, - hidden_bap_primary_phone_number: Primary_Applicant__r?.Phone, - hidden_bap_primary_email: Primary_Applicant__r?.Email, - hidden_bap_alternate_fname: Alternate_Applicant__r?.FirstName || "", - hidden_bap_alternate_lname: Alternate_Applicant__r?.LastName || "", - hidden_bap_alternate_title: Alternate_Applicant__r?.Title || "", - hidden_bap_alternate_phone_number: Alternate_Applicant__r?.Phone || "", // prettier-ignore - hidden_bap_alternate_email: Alternate_Applicant__r?.Email || "", - hidden_bap_org_name: Applicant_Organization__r?.Name, - hidden_bap_fleet_name: Fleet_Name__c, - hidden_bap_fleet_address: Fleet_Street_Address__c, - hidden_bap_fleet_city: Fleet_City__c, - hidden_bap_fleet_state: Fleet_State__c, - hidden_bap_fleet_zip: Fleet_Zip__c, - hidden_bap_fleet_contact_name: Fleet_Contact_Name__c, - hidden_bap_fleet_contact_title: Fleet_Contact_Title__c, - hidden_bap_fleet_phone: Fleet_Contact_Phone__c, - hidden_bap_fleet_email: Fleet_Contact_Email__c, - hidden_bap_prioritized: School_District_Prioritized__c, - hidden_bap_requested_funds: Total_Rebate_Funds_Requested_PO__c, - hidden_bap_received_funds: Total_Bus_And_Infrastructure_Rebate__c, - hidden_bap_prf_infra_max_rebate: Total_Infrastructure_Funds__c, - hidden_bap_buses_requested_app: Num_Of_Buses_Requested_From_Application__c, // prettier-ignore - hidden_bap_total_bus_costs_prf: Total_Price_All_Buses__c, - hidden_bap_total_bus_rebate_received: Total_Bus_Rebate_Amount__c, - hidden_bap_total_infra_costs_prf: Total_All_Eligible_Infrastructure_Costs__c, // prettier-ignore - hidden_bap_total_infra_rebate_received: Total_Infrastructure_Rebate__c, // prettier-ignore - hidden_bap_total_infra_level2_charger: Total_Level_2_Charger_Costs__c, - hidden_bap_total_infra_dc_fast_charger: Total_DC_Fast_Charger_Costs__c, // prettier-ignore - hidden_bap_total_infra_other_costs: Total_Other_Infrastructure_Costs__c, // prettier-ignore - hidden_bap_district_contact_fname: School_District_Contact__r?.FirstName, // prettier-ignore - hidden_bap_district_contact_lname: School_District_Contact__r?.LastName, // prettier-ignore - busInfo, - }, - /** Add custom metadata to track formio submissions from wrapper. */ - metadata: { - ...formioCSBMetadata, - }, - state: "draft", - }; - - axiosFormio(req) - .post(`${formioCRFUrl}/submission`, submission) - .then((axiosRes) => axiosRes.data) - .then((submission) => res.json(submission)) - .catch((error) => { - // NOTE: error is logged in axiosFormio response interceptor - const errorStatus = error.response?.status || 500; - const errorMessage = `Error posting Formio Close Out form submission.`; - return res.status(errorStatus).json({ message: errorMessage }); - }); - }) + .then( + ({ frf2022RecordQuery, prf2022RecordQuery, prf2022busRecordsQuery }) => { + const { + Fleet_Name__c, + Fleet_Street_Address__c, + Fleet_City__c, + Fleet_State__c, + Fleet_Zip__c, + Fleet_Contact_Name__c, + Fleet_Contact_Title__c, + Fleet_Contact_Phone__c, + Fleet_Contact_Email__c, + School_District_Contact__r, + } = frf2022RecordQuery[0]; + + const { + CSB_NCES_ID__c, + Primary_Applicant__r, + Alternate_Applicant__r, + Applicant_Organization__r, + CSB_School_District__r, + School_District_Prioritized__c, + Total_Rebate_Funds_Requested_PO__c, + Total_Bus_And_Infrastructure_Rebate__c, + Total_Infrastructure_Funds__c, + Num_Of_Buses_Requested_From_Application__c, + Total_Price_All_Buses__c, + Total_Bus_Rebate_Amount__c, + Total_All_Eligible_Infrastructure_Costs__c, + Total_Infrastructure_Rebate__c, + Total_Level_2_Charger_Costs__c, + Total_DC_Fast_Charger_Costs__c, + Total_Other_Infrastructure_Costs__c, + } = prf2022RecordQuery[0]; + + const busInfo = prf2022busRecordsQuery.map((record) => ({ + busNum: record.Rebate_Item_num__c, + oldBusNcesDistrictId: CSB_NCES_ID__c, + oldBusVin: record.CSB_VIN__c, + oldBusModelYear: record.CSB_Model_Year__c, + oldBusFuelType: record.CSB_Fuel_Type__c, + oldBusEstimatedRemainingLife: record.Old_Bus_Estimated_Remaining_Life__c, // prettier-ignore + oldBusExclude: record.Old_Bus_Exclude__c, + hidden_prf_oldBusExclude: record.Old_Bus_Exclude__c, + newBusDealer: record.Related_Line_Item__r?.Vendor_Name__c, + newBusFuelType: record.New_Bus_Fuel_Type__c, + hidden_prf_newBusFuelType: record.New_Bus_Fuel_Type__c, + newBusMake: record.New_Bus_Make__c, + hidden_prf_newBusMake: record.New_Bus_Make__c, + newBusMakeOther: record.CSB_Manufacturer_if_Other__c, + hidden_prf_newBusMakeOther: record.CSB_Manufacturer_if_Other__c, + newBusModel: record.New_Bus_Model__c, + hidden_prf_newBusModel: record.New_Bus_Model__c, + newBusModelYear: record.New_Bus_Model_Year__c, + hidden_prf_newBusModelYear: record.New_Bus_Model_Year__c, + newBusGvwr: record.New_Bus_GVWR__c, + hidden_prf_newBusGvwr: record.New_Bus_GVWR__c, + newBusPurchasePrice: record.New_Bus_Purchase_Price__c, + hidden_prf_newBusPurchasePrice: record.New_Bus_Purchase_Price__c, + hidden_prf_rebate: record.New_Bus_Rebate_Amount__c, + })); + + const submission = { + data: { + bap_hidden_entity_combo_key: comboKey, + hidden_prf_modified: prfModified, + hidden_current_user_email: email, + hidden_current_user_title: title, + hidden_current_user_name: name, + hidden_bap_rebate_id: rebateId, + hidden_sam_uei: UNIQUE_ENTITY_ID__c, + hidden_sam_efti: ENTITY_EFT_INDICATOR__c || "0000", + hidden_sam_elec_bus_poc_email: ELEC_BUS_POC_EMAIL__c, + hidden_sam_alt_elec_bus_poc_email: ALT_ELEC_BUS_POC_EMAIL__c, + hidden_sam_govt_bus_poc_email: GOVT_BUS_POC_EMAIL__c, + hidden_sam_alt_govt_bus_poc_email: ALT_GOVT_BUS_POC_EMAIL__c, + hidden_bap_district_id: CSB_NCES_ID__c, + hidden_bap_district_name: CSB_School_District__r?.Name, + hidden_bap_primary_fname: Primary_Applicant__r?.FirstName, + hidden_bap_primary_lname: Primary_Applicant__r?.LastName, + hidden_bap_primary_title: Primary_Applicant__r?.Title, + hidden_bap_primary_phone_number: Primary_Applicant__r?.Phone, + hidden_bap_primary_email: Primary_Applicant__r?.Email, + hidden_bap_alternate_fname: Alternate_Applicant__r?.FirstName || "", + hidden_bap_alternate_lname: Alternate_Applicant__r?.LastName || "", + hidden_bap_alternate_title: Alternate_Applicant__r?.Title || "", + hidden_bap_alternate_phone_number: Alternate_Applicant__r?.Phone || "", // prettier-ignore + hidden_bap_alternate_email: Alternate_Applicant__r?.Email || "", + hidden_bap_org_name: Applicant_Organization__r?.Name, + hidden_bap_fleet_name: Fleet_Name__c, + hidden_bap_fleet_address: Fleet_Street_Address__c, + hidden_bap_fleet_city: Fleet_City__c, + hidden_bap_fleet_state: Fleet_State__c, + hidden_bap_fleet_zip: Fleet_Zip__c, + hidden_bap_fleet_contact_name: Fleet_Contact_Name__c, + hidden_bap_fleet_contact_title: Fleet_Contact_Title__c, + hidden_bap_fleet_phone: Fleet_Contact_Phone__c, + hidden_bap_fleet_email: Fleet_Contact_Email__c, + hidden_bap_prioritized: School_District_Prioritized__c, + hidden_bap_requested_funds: Total_Rebate_Funds_Requested_PO__c, + hidden_bap_received_funds: Total_Bus_And_Infrastructure_Rebate__c, + hidden_bap_prf_infra_max_rebate: Total_Infrastructure_Funds__c, + hidden_bap_buses_requested_app: Num_Of_Buses_Requested_From_Application__c, // prettier-ignore + hidden_bap_total_bus_costs_prf: Total_Price_All_Buses__c, + hidden_bap_total_bus_rebate_received: Total_Bus_Rebate_Amount__c, + hidden_bap_total_infra_costs_prf: Total_All_Eligible_Infrastructure_Costs__c, // prettier-ignore + hidden_bap_total_infra_rebate_received: Total_Infrastructure_Rebate__c, // prettier-ignore + hidden_bap_total_infra_level2_charger: Total_Level_2_Charger_Costs__c, // prettier-ignore + hidden_bap_total_infra_dc_fast_charger: Total_DC_Fast_Charger_Costs__c, // prettier-ignore + hidden_bap_total_infra_other_costs: Total_Other_Infrastructure_Costs__c, // prettier-ignore + hidden_bap_district_contact_fname: School_District_Contact__r?.FirstName, // prettier-ignore + hidden_bap_district_contact_lname: School_District_Contact__r?.LastName, // prettier-ignore + busInfo, + }, + /** Add custom metadata to track formio submissions from wrapper. */ + metadata: { + ...formioCSBMetadata, + }, + state: "draft", + }; + + axiosFormio(req) + .post(`${formioCRFUrl}/submission`, submission) + .then((axiosRes) => axiosRes.data) + .then((submission) => res.json(submission)) + .catch((error) => { + // NOTE: error is logged in axiosFormio response interceptor + const errorStatus = error.response?.status || 500; + const errorMessage = `Error posting Formio Close Out form submission.`; + return res.status(errorStatus).json({ message: errorMessage }); + }); + }, + ) .catch((error) => { // NOTE: logged in bap verifyBapConnection const errorStatus = 500; diff --git a/app/server/app/utilities/bap.js b/app/server/app/utilities/bap.js index 22cc10cc..eb4a9068 100644 --- a/app/server/app/utilities/bap.js +++ b/app/server/app/utilities/bap.js @@ -181,7 +181,7 @@ const { submissionPeriodOpen } = require("../config/formio"); * FirstName: string * LastName: string * } - * }[]} frfRecordQuery + * }[]} frf2022RecordQuery * @property {{ * Id: string * UEI_EFTI_Combo_Key__c: string @@ -218,7 +218,7 @@ const { submissionPeriodOpen } = require("../config/formio"); * Total_Level_2_Charger_Costs__c: string * Total_DC_Fast_Charger_Costs__c: string * Total_Other_Infrastructure_Costs__c: string - * }[]} prfRecordQuery + * }[]} prf2022RecordQuery * @property {{ * Rebate_Item_num__c: string * CSB_VIN__c: string @@ -238,7 +238,7 @@ const { submissionPeriodOpen } = require("../config/formio"); * New_Bus_GVWR__c: string * New_Bus_Rebate_Amount__c: string * New_Bus_Purchase_Price__c: string - * }[]} busRecordsQuery + * }[]} prf2022busRecordsQuery * @property {{ * type: string * url: string @@ -971,7 +971,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // SObjectType = 'Order_Request__c' // LIMIT 1` - const frfRecordTypeIdQuery = await bapConnection + const frf2022RecordTypeIdQuery = await bapConnection .sobject("RecordType") .find( { @@ -986,7 +986,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { .limit(1) .execute(async (err, records) => ((await err) ? err : records)); - const frfRecordTypeId = frfRecordTypeIdQuery["0"].Id; + const frf2022RecordTypeId = frf2022RecordTypeIdQuery["0"].Id; // `SELECT // Fleet_Name__c, @@ -1003,15 +1003,15 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // FROM // Order_Request__c // WHERE - // RecordTypeId = '${frfRecordTypeId}' AND + // RecordTypeId = '${frf2022RecordTypeId}' AND // CSB_Review_Item_ID__c = '${frfReviewItemId}' AND // Latest_Version__c = TRUE` - const frfRecordQuery = await bapConnection + const frf2022RecordQuery = await bapConnection .sobject("Order_Request__c") .find( { - RecordTypeId: frfRecordTypeId, + RecordTypeId: frf2022RecordTypeId, CSB_Review_Item_ID__c: frfReviewItemId, Latest_Version__c: true, }, @@ -1041,7 +1041,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // SObjectType = 'Order_Request__c' // LIMIT 1` - const prfRecordTypeIdQuery = await bapConnection + const prf2022RecordTypeIdQuery = await bapConnection .sobject("RecordType") .find( { @@ -1056,7 +1056,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { .limit(1) .execute(async (err, records) => ((await err) ? err : records)); - const prfRecordTypeId = prfRecordTypeIdQuery["0"].Id; + const prf2022RecordTypeId = prf2022RecordTypeIdQuery["0"].Id; // `SELECT // Id, @@ -1089,15 +1089,15 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // FROM // Order_Request__c // WHERE - // RecordTypeId = '${prfRecordTypeId}' AND + // RecordTypeId = '${prf2022RecordTypeId}' AND // CSB_Review_Item_ID__c = '${prfReviewItemId}' AND // Latest_Version__c = TRUE` - const prfRecordQuery = await bapConnection + const prf2022RecordQuery = await bapConnection .sobject("Order_Request__c") .find( { - RecordTypeId: prfRecordTypeId, + RecordTypeId: prf2022RecordTypeId, CSB_Review_Item_ID__c: prfReviewItemId, Latest_Version__c: true, }, @@ -1134,7 +1134,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { ) .execute(async (err, records) => ((await err) ? err : records)); - const prfRecordId = prfRecordQuery["0"].Id; + const prf2022RecordId = prf2022RecordQuery["0"].Id; // `SELECT // Id @@ -1145,7 +1145,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // SObjectType = 'Line_Item__c' // LIMIT 1` - const busRecordTypeIdQuery = await bapConnection + const rebateItemRecordTypeIdQuery = await bapConnection .sobject("RecordType") .find( { @@ -1160,7 +1160,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { .limit(1) .execute(async (err, records) => ((await err) ? err : records)); - const busRecordTypeId = busRecordTypeIdQuery["0"].Id; + const rebateItemRecordTypeId = rebateItemRecordTypeIdQuery["0"].Id; // `SELECT // Rebate_Item_num__c, @@ -1182,16 +1182,16 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { // FROM // Line_Item__c // WHERE - // RecordTypeId = '${busRecordTypeId}' AND - // Related_Order_Request__c = '${prfRecordId}' AND + // RecordTypeId = '${rebateItemRecordTypeId}' AND + // Related_Order_Request__c = '${prf2022RecordId}' AND // CSB_Rebate_Item_Type__c = 'New Bus'` - const busRecordsQuery = await bapConnection + const prf2022busRecordsQuery = await bapConnection .sobject("Line_Item__c") .find( { - RecordTypeId: busRecordTypeId, - Related_Order_Request__c: prfRecordId, + RecordTypeId: rebateItemRecordTypeId, + Related_Order_Request__c: prf2022RecordId, CSB_Rebate_Item_Type__c: "New Bus", }, { @@ -1216,7 +1216,7 @@ async function queryBapFor2022CRFData(req, frfReviewItemId, prfReviewItemId) { ) .execute(async (err, records) => ((await err) ? err : records)); - return { frfRecordQuery, prfRecordQuery, busRecordsQuery }; + return { frf2022RecordQuery, prf2022RecordQuery, prf2022busRecordsQuery }; } /** From 7c2766d13a02dd933c12449e44ae476d98eaa902 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Thu, 25 Jan 2024 13:45:35 -0500 Subject: [PATCH 22/35] Update 2023 PRF external status for when funding is not approved to display 'Funding Denied' --- app/client/src/routes/submissions.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/client/src/routes/submissions.tsx b/app/client/src/routes/submissions.tsx index d39c4d80..b1e5b17c 100644 --- a/app/client/src/routes/submissions.tsx +++ b/app/client/src/routes/submissions.tsx @@ -1173,7 +1173,6 @@ function PRF2023Submission(props: { rebate: Rebate }) { bap: prf.bap, }); - // TODO: review statuses for 2023 PRF const prfNeedsClarification = prf.bap?.status === "Needs Clarification"; const prfHasBeenWithdrawn = prf.bap?.status === "Withdrawn"; @@ -1212,7 +1211,7 @@ function PRF2023Submission(props: { rebate: Rebate }) { : prfHasBeenWithdrawn ? "Withdrawn" : prfFundingNotApproved - ? "Funding Not Approved" + ? "Funding Denied" : prfFundingApproved ? "Funding Approved" : prf.formio.state === "draft" From da69fa990684022c61ae5f408555587ef6f1aa45 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Thu, 25 Jan 2024 14:27:30 -0500 Subject: [PATCH 23/35] Update data injected into a 2023 PRF submission, every time it's edited (SAM.gov POC contacts) --- app/client/src/routes/prf2023.tsx | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/app/client/src/routes/prf2023.tsx b/app/client/src/routes/prf2023.tsx index dc1f9ad6..6b20889d 100644 --- a/app/client/src/routes/prf2023.tsx +++ b/app/client/src/routes/prf2023.tsx @@ -223,14 +223,12 @@ function PaymentRequestForm(props: { email: string }) { return ; } - // const { - // UNIQUE_ENTITY_ID__c, - // ENTITY_EFT_INDICATOR__c, - // ELEC_BUS_POC_EMAIL__c, - // ALT_ELEC_BUS_POC_EMAIL__c, - // GOVT_BUS_POC_EMAIL__c, - // ALT_GOVT_BUS_POC_EMAIL__c, - // } = entity; + const { + ELEC_BUS_POC_EMAIL__c, + ALT_ELEC_BUS_POC_EMAIL__c, + GOVT_BUS_POC_EMAIL__c, + ALT_GOVT_BUS_POC_EMAIL__c, + } = entity; const { title, name } = getUserInfo(email, entity); @@ -287,15 +285,10 @@ function PaymentRequestForm(props: { email: string }) { _user_email: email, _user_title: title, _user_name: name, - // - // TODO: determine which fields are needed - // - // _bap_applicant_uei: UNIQUE_ENTITY_ID__c, - // _bap_applicant_efti: ENTITY_EFT_INDICATOR__c || "0000", - // hidden_sam_elec_bus_poc_email: ELEC_BUS_POC_EMAIL__c, - // hidden_sam_alt_elec_bus_poc_email: ALT_ELEC_BUS_POC_EMAIL__c, - // hidden_sam_govt_bus_poc_email: GOVT_BUS_POC_EMAIL__c, - // hidden_sam_alt_govt_bus_poc_email: ALT_GOVT_BUS_POC_EMAIL__c, + _bap_elec_bus_poc_email: ELEC_BUS_POC_EMAIL__c, + _bap_alt_elec_bus_poc_email: ALT_ELEC_BUS_POC_EMAIL__c, + _bap_govt_bus_poc_email: GOVT_BUS_POC_EMAIL__c, + _bap_alt_govt_bus_poc_email: ALT_GOVT_BUS_POC_EMAIL__c, ...pendingSubmissionData.current, }, }} From 7d28d40cbe2fdea8321cecb7e4c5e66fc9d1281b Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Thu, 25 Jan 2024 17:34:37 -0500 Subject: [PATCH 24/35] Update queryBapFor2022PRFData() to fetch 2023 FRF bus records contact info --- app/server/app/utilities/bap.js | 56 ++++++++++- app/server/app/utilities/formio.js | 150 ++++++++++++++++++++--------- 2 files changed, 159 insertions(+), 47 deletions(-) diff --git a/app/server/app/utilities/bap.js b/app/server/app/utilities/bap.js index eb4a9068..aa2e53f2 100644 --- a/app/server/app/utilities/bap.js +++ b/app/server/app/utilities/bap.js @@ -160,6 +160,16 @@ const { submissionPeriodOpen } = require("../config/formio"); * New_Bus_ADA_Compliant__c: string * }[]} frf2023BusRecordsQuery * @property {{ + * Id: string + * Related_Line_Item__c: string + * Relationship_Type__c: string + * Contact_Organization_Name__c: string + * Contact__r: { + * FirstName: string + * LastName: string + * } | null + * }[]} frf2023BusRecordsContactsQueries + * @property {{ * type: string * url: string * }} attributes @@ -939,7 +949,51 @@ async function queryBapFor2023PRFData(req, frfReviewItemId) { ) .execute(async (err, records) => ((await err) ? err : records)); - return { frf2023RecordQuery, frf2023BusRecordsQuery }; + const frf2023BusRecordsContactsQueries = await Promise.all( + frf2023BusRecordsQuery.map(async (frf2023BusRecord) => { + const frf2023BusRecordId = frf2023BusRecord.Id; + + // `SELECT + // Id, + // Related_Line_Item__c, + // Relationship_Type__c, + // Contact_Organization_Name__c, + // Contact__r.FirstName, + // Contact__r.LastName + // FROM + // Line_Item__c + // WHERE + // RecordTypeId = '${rebateItemRecordTypeId}' AND + // Related_Line_Item__c = '${frf2023BusRecordId}' AND + // CSB_Rebate_Item_Type__c = 'COF Relationship'` + + return await bapConnection + .sobject("Line_Item__c") + .find( + { + RecordTypeId: rebateItemRecordTypeId, + Related_Line_Item__c: frf2023BusRecordId, + CSB_Rebate_Item_Type__c: "COF Relationship", + }, + { + // "*": 1, + Id: 1, // Salesforce record ID + Related_Line_Item__c: 1, + Relationship_Type__c: 1, + Contact_Organization_Name__c: 1, + "Contact__r.FirstName": 1, + "Contact__r.LastName": 1, + }, + ) + .execute(async (err, records) => ((await err) ? err : records)); + }), + ); + + return { + frf2023RecordQuery, + frf2023BusRecordsQuery, + frf2023BusRecordsContactsQueries: frf2023BusRecordsContactsQueries.flat(), + }; } /** diff --git a/app/server/app/utilities/formio.js b/app/server/app/utilities/formio.js index 7b065e64..bd89e790 100644 --- a/app/server/app/utilities/formio.js +++ b/app/server/app/utilities/formio.js @@ -70,7 +70,9 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { if (rebateYear === "2022") { return getBapDataFor2022PRF(req, frfReviewItemId) - .then(({ frf2022RecordQuery, frf2022BusRecordsQuery }) => { + .then((results) => { + const { frf2022RecordQuery, frf2022BusRecordsQuery } = results; + const { CSB_NCES_ID__c, Primary_Applicant__r, @@ -83,15 +85,26 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { Total_Infrastructure_Funds__c, } = frf2022RecordQuery[0]; - const busInfo = frf2022BusRecordsQuery.map((record) => ({ - busNum: record.Rebate_Item_num__c, - oldBusNcesDistrictId: CSB_NCES_ID__c, - oldBusVin: record.CSB_VIN__c, - oldBusModelYear: record.CSB_Model_Year__c, - oldBusFuelType: record.CSB_Fuel_Type__c, - newBusFuelType: record.CSB_Replacement_Fuel_Type__c, - hidden_bap_max_rebate: record.CSB_Funds_Requested__c, - })); + const busInfo = frf2022BusRecordsQuery.map((frf2022BusRecord) => { + const { + Rebate_Item_num__c, + CSB_VIN__c, + CSB_Model_Year__c, + CSB_Fuel_Type__c, + CSB_Replacement_Fuel_Type__c, + CSB_Funds_Requested__c, + } = frf2022BusRecord; + + return { + busNum: Rebate_Item_num__c, + oldBusNcesDistrictId: CSB_NCES_ID__c, + oldBusVin: CSB_VIN__c, + oldBusModelYear: CSB_Model_Year__c, + oldBusFuelType: CSB_Fuel_Type__c, + newBusFuelType: CSB_Replacement_Fuel_Type__c, + hidden_bap_max_rebate: CSB_Funds_Requested__c, + }; + }); /** * NOTE: `purchaseOrders` is initialized as an empty array to fix some @@ -144,13 +157,18 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { if (rebateYear === "2023") { return getBapDataFor2023PRF(req, frfReviewItemId) - .then(({ frf2023RecordQuery, frf2023BusRecordsQuery }) => { + .then((results) => { + const { + frf2023RecordQuery, + frf2023BusRecordsQuery, + frf2023BusRecordsContactsQueries, + } = results; + const { Primary_Applicant__r, Alternate_Applicant__r, CSB_School_District__r, School_District_Contact__r, - County__c, CSB_NCES_ID__c, School_District_Prioritized__c, School_District_Poverty_Rate__c, @@ -187,37 +205,78 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { org_zip: "", })); - const bus_buses = frf2023BusRecordsQuery.map((item) => ({ - bus_busNumber: item.Rebate_Item_num__c, - bus_existingOwner: { - org: "", // TODO: Old_Bus_Owner__r.* or Old_Bus_Owner_Contact_ID__c - organization: "", - orgContactFName: "", - orgContactLName: "", - }, - bus_existingVin: item.CSB_VIN__c, - bus_existingFuelType: item.CSB_Fuel_Type__c, - bus_existingGvwr: item.CSB_GVWR__c, - bus_existingOdometer: item.Old_Bus_Odometer_miles__c, - bus_existingModel: item.CSB_Model__c, - bus_existingModelYear: item.CSB_Model_Year__c, - bus_existingManufacturer: item.CSB_Manufacturer__c, - bus_existingManufacturerOther: item.CSB_Manufacturer_if_Other__c, - bus_existingAnnualFuelConsumption: item.CSB_Annual_Fuel_Consumption__c, // prettier-ignore - bus_existingAnnualMileage: item.Annual_Mileage__c, - bus_existingRemainingLife: item.Old_Bus_Estimated_Remaining_Life__c, - bus_existingIdlingHours: item.Old_Bus_Annual_Idling_Hours__c, - bus_newOwner: { - org: "", // TODO: New_Bus_Owner__r.* or New_Bus_Owner_Contact_ID__c - organization: "", - orgContactFName: "", - orgContactLName: "", - }, - bus_rebate: item.CSB_Funds_Requested__c, - bus_newFuelType: item.New_Bus_Fuel_Type__c, - bus_newGvwr: item.New_Bus_GVWR__c, - _bus_newADAfromFRF: item.New_Bus_ADA_Compliant__c, - })); + const bus_buses = frf2023BusRecordsQuery.map((frf2023BusRecord) => { + const { + Id, + Rebate_Item_num__c, + CSB_VIN__c, + CSB_Fuel_Type__c, + CSB_GVWR__c, + Old_Bus_Odometer_miles__c, + CSB_Model__c, + CSB_Model_Year__c, + CSB_Manufacturer__c, + CSB_Manufacturer_if_Other__c, + CSB_Annual_Fuel_Consumption__c, + Annual_Mileage__c, + Old_Bus_Estimated_Remaining_Life__c, + Old_Bus_Annual_Idling_Hours__c, + CSB_Funds_Requested__c, + New_Bus_Fuel_Type__c, + New_Bus_GVWR__c, + New_Bus_ADA_Compliant__c, + } = frf2023BusRecord; + + const existingOwnerRecord = frf2023BusRecordsContactsQueries.find( + ({ Related_Line_Item__c, Relationship_Type__c }) => { + return ( + Related_Line_Item__c === Id && + Relationship_Type__c === "Old Bus Private Fleet Owner (if changed)" // prettier-ignore + ); + }, + ); + + const newOwnerRecord = frf2023BusRecordsContactsQueries.find( + ({ Related_Line_Item__c, Relationship_Type__c }) => { + return ( + Related_Line_Item__c === Id && + Relationship_Type__c === "New Bus Owner" + ); + }, + ); + + return { + bus_busNumber: Rebate_Item_num__c, + bus_existingOwner: { + org: "", // TODO: ask BAP how to get this value + organization: existingOwnerRecord?.Contact_Organization_Name__c, + orgContactFName: existingOwnerRecord?.Contact__r?.FirstName, + orgContactLName: existingOwnerRecord?.Contact__r?.LastName, + }, + bus_existingVin: CSB_VIN__c, + bus_existingFuelType: CSB_Fuel_Type__c, + bus_existingGvwr: CSB_GVWR__c, + bus_existingOdometer: Old_Bus_Odometer_miles__c, + bus_existingModel: CSB_Model__c, + bus_existingModelYear: CSB_Model_Year__c, + bus_existingManufacturer: CSB_Manufacturer__c, + bus_existingManufacturerOther: CSB_Manufacturer_if_Other__c, + bus_existingAnnualFuelConsumption: CSB_Annual_Fuel_Consumption__c, + bus_existingAnnualMileage: Annual_Mileage__c, + bus_existingRemainingLife: Old_Bus_Estimated_Remaining_Life__c, + bus_existingIdlingHours: Old_Bus_Annual_Idling_Hours__c, + bus_newOwner: { + org: "", // TODO: ask BAP how to get this value + organization: newOwnerRecord?.Contact_Organization_Name__c, + orgContactFName: newOwnerRecord?.Contact__r?.FirstName, + orgContactLName: newOwnerRecord?.Contact__r?.LastName, + }, + bus_rebate: CSB_Funds_Requested__c, + bus_newFuelType: New_Bus_Fuel_Type__c, + bus_newGvwr: New_Bus_GVWR__c, + _bus_newADAfromFRF: New_Bus_ADA_Compliant__c, + }; + }); return { data: { @@ -234,7 +293,7 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { _bap_applicant_organization_name: LEGAL_BUSINESS_NAME__c, _bap_applicant_street_address_1: PHYSICAL_ADDRESS_LINE_1__c, _bap_applicant_street_address_2: PHYSICAL_ADDRESS_LINE_2__c, - _bap_applicant_county: County__c, // TODO: confirm with BAP + _bap_applicant_county: "", // TODO: ask BAP how to get this value _bap_applicant_city: PHYSICAL_ADDRESS_CITY__c, _bap_applicant_state: PHYSICAL_ADDRESS_PROVINCE_OR_STATE__c, _bap_applicant_zip: PHYSICAL_ADDRESS_ZIPPOSTAL_CODE__c, @@ -253,9 +312,8 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { _bap_alternate_email: Alternate_Applicant__r?.Email, _bap_alternate_phone_number: Alternate_Applicant__r?.Phone, _bap_district_ncesID: CSB_NCES_ID__c, - // TODO: confirm with BAP we should use the individual fields below and not the 'BillingAddress' object's fields _bap_district_name: CSB_School_District__r?.Name, - _bap_district_address_1: CSB_School_District__r?.BillingStreet, // TODO: nofity BAP this field is the district address 1 and 2 combined, when it should be two fields in the BAP + _bap_district_address_1: CSB_School_District__r?.BillingStreet, // TODO: once BAP returns this field with a new line character, split on it for address line 1 and 2 _bap_district_address_2: "", // TODO: see above _bap_district_city: CSB_School_District__r?.BillingCity, _bap_district_state: CSB_School_District__r?.BillingState, From 6466e91feb6f5a242d453e3e93d1f030c72c590b Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Thu, 25 Jan 2024 22:19:53 -0500 Subject: [PATCH 25/35] Move function for fetching an existing prf's schema and submission data from Formio out of formio2022 route and into a reusable function that can be used for 2023 PRFs --- app/server/app/routes/formio2022.js | 66 +------------------ app/server/app/utilities/formio.js | 98 +++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 64 deletions(-) diff --git a/app/server/app/routes/formio2022.js b/app/server/app/routes/formio2022.js index 3f0454d2..1d6e7fa8 100644 --- a/app/server/app/routes/formio2022.js +++ b/app/server/app/routes/formio2022.js @@ -28,6 +28,7 @@ const { // fetchPRFSubmissions, createPRFSubmission, + fetchPRFSubmission, } = require("../utilities/formio"); const log = require("../utilities/logger"); @@ -98,70 +99,7 @@ router.post("/prf-submission", storeBapComboKeys, (req, res) => { // --- get an existing 2022 PRF's schema and submission data from Formio router.get("/prf-submission/:rebateId", storeBapComboKeys, async (req, res) => { - const { bapComboKeys } = req; - const { mail } = req.user; - const { rebateId } = req.params; // CSB Rebate ID (6 digits) - - const matchedPRFSubmissions = - `${formioPRFUrl}/submission` + - `?data.hidden_bap_rebate_id=${rebateId}` + - `&select=_id,data.bap_hidden_entity_combo_key`; - - Promise.all([ - axiosFormio(req).get(matchedPRFSubmissions), - axiosFormio(req).get(formioPRFUrl), - ]) - .then((axiosResponses) => axiosResponses.map((axiosRes) => axiosRes.data)) - .then(([submissions, schema]) => { - const submission = submissions[0]; - const mongoId = submission._id; - const comboKey = submission.data.bap_hidden_entity_combo_key; - - if (!bapComboKeys.includes(comboKey)) { - const logMessage = - `User with email '${mail}' attempted to access PRF submission '${rebateId}' ` + - `that they do not have access to.`; - log({ level: "warn", message: logMessage, req }); - - return res.json({ - userAccess: false, - formSchema: null, - submission: null, - }); - } - - /** NOTE: verifyMongoObjectId */ - if (mongoId && !ObjectId.isValid(mongoId)) { - const errorStatus = 400; - const errorMessage = `MongoDB ObjectId validation error for: '${mongoId}'.`; - return res.status(errorStatus).json({ message: errorMessage }); - } - - /** - * NOTE: We can't just use the returned submission data here because - * Formio returns the string literal 'YES' instead of a base64 encoded - * image string for signature fields when you query for all submissions - * matching on a field's value (`/submission?data.hidden_bap_rebate_id=${rebateId}`). - * We need to query for a specific submission (e.g. `/submission/${mongoId}`), - * to have Formio return the correct signature field data. - */ - axiosFormio(req) - .get(`${formioPRFUrl}/submission/${mongoId}`) - .then((axiosRes) => axiosRes.data) - .then((submission) => { - return res.json({ - userAccess: true, - formSchema: { url: formioPRFUrl, json: schema }, - submission, - }); - }); - }) - .catch((error) => { - // NOTE: error is logged in axiosFormio response interceptor - const errorStatus = error.response?.status || 500; - const errorMessage = `Error getting Formio Payment Request form submission '${rebateId}'.`; - return res.status(errorStatus).json({ message: errorMessage }); - }); + fetchPRFSubmission({ rebateYear: "2022", req, res }); }); // --- post an update to an existing draft 2022 PRF submission to Formio diff --git a/app/server/app/utilities/formio.js b/app/server/app/utilities/formio.js index bd89e790..82bb1b81 100644 --- a/app/server/app/utilities/formio.js +++ b/app/server/app/utilities/formio.js @@ -1,4 +1,5 @@ const express = require("express"); +const ObjectId = require("mongodb").ObjectId; // --- const { axiosFormio, @@ -25,6 +26,18 @@ function getComboKeyFieldName({ rebateYear }) { : ""; } +/** + * @param {Object} param + * @param {'2022' | '2023'} param.rebateYear + */ +function getRebateIdFieldName({ rebateYear }) { + return rebateYear === "2022" + ? "hidden_bap_rebate_id" + : rebateYear === "2023" + ? "_bap_rebate_id" + : ""; +} + /** * @param {Object} param * @param {'2022' | '2023'} param.rebateYear @@ -767,6 +780,90 @@ function createPRFSubmission({ rebateYear, req, res }) { }); } +/** + * @param {Object} param + * @param {'2022' | '2023'} param.rebateYear + * @param {express.Request} param.req + * @param {express.Response} param.res + */ +function fetchPRFSubmission({ rebateYear, req, res }) { + const { bapComboKeys } = req; + const { mail } = req.user; + const { rebateId } = req.params; // CSB Rebate ID (6 digits) + + const comboKeyFieldName = getComboKeyFieldName({ rebateYear }); + const rebateIdFieldName = getRebateIdFieldName({ rebateYear }); + + const formioFormUrl = formUrl[rebateYear].prf; + + if (!formioFormUrl) { + const errorStatus = 400; + const errorMessage = `Formio form URL does not exist for ${rebateYear} PRF.`; + return res.status(errorStatus).json({ message: errorMessage }); + } + + const matchedPRFSubmissions = + `${formioFormUrl}/submission` + + `?data.${rebateIdFieldName}=${rebateId}` + + `&select=_id,data.${comboKeyFieldName}`; + + Promise.all([ + axiosFormio(req).get(matchedPRFSubmissions), + axiosFormio(req).get(formioFormUrl), + ]) + .then((axiosResponses) => axiosResponses.map((axiosRes) => axiosRes.data)) + .then(([submissions, schema]) => { + const submission = submissions[0]; + const mongoId = submission._id; + const comboKey = submission.data?.[comboKeyFieldName]; + + if (!bapComboKeys.includes(comboKey)) { + const logMessage = + `User with email '${mail}' attempted to access ${rebateYear} ` + + `PRF submission '${mongoId}' that they do not have access to.`; + log({ level: "warn", message: logMessage, req }); + + return res.json({ + userAccess: false, + formSchema: null, + submission: null, + }); + } + + /** NOTE: verifyMongoObjectId */ + if (mongoId && !ObjectId.isValid(mongoId)) { + const errorStatus = 400; + const errorMessage = `MongoDB ObjectId validation error for: '${mongoId}'.`; + return res.status(errorStatus).json({ message: errorMessage }); + } + + /** + * NOTE: We can't just use the returned submission data here because + * Formio returns the string literal 'YES' instead of a base64 encoded + * image string for signature fields when you query for all submissions + * matching on a field's value (`/submission?data.${rebateIdFieldName}=${rebateId}`). + * We need to query for a specific submission (e.g. `/submission/${mongoId}`), + * to have Formio return the correct signature field data. + */ + axiosFormio(req) + .get(`${formioFormUrl}/submission/${mongoId}`) + .then((axiosRes) => axiosRes.data) + .then((submission) => { + return res.json({ + userAccess: true, + formSchema: { url: formioFormUrl, json: schema }, + submission, + }); + }); + }) + .catch((error) => { + // NOTE: error is logged in axiosFormio response interceptor + const errorStatus = error.response?.status || 500; + const errorMessage = `Error getting Formio ${rebateYear} Payment Request form submission '${rebateId}'.`; + return res.status(errorStatus).json({ message: errorMessage }); + }); +} + module.exports = { uploadS3FileMetadata, downloadS3FileMetadata, @@ -778,4 +875,5 @@ module.exports = { // fetchPRFSubmissions, createPRFSubmission, + fetchPRFSubmission, }; From ce71f58b685abf45b47018864f433f7281490ee9 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Thu, 25 Jan 2024 22:34:04 -0500 Subject: [PATCH 26/35] Add commented out stub of CRF2023Submission component to submissions component --- app/client/src/routes/submissions.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/client/src/routes/submissions.tsx b/app/client/src/routes/submissions.tsx index b1e5b17c..508a7195 100644 --- a/app/client/src/routes/submissions.tsx +++ b/app/client/src/routes/submissions.tsx @@ -1283,9 +1283,9 @@ function PRF2023Submission(props: { rebate: Rebate }) { ); } -function CRF2023Submission(props: { rebate: Rebate }) { - // -} +// function CRF2023Submission(props: { rebate: Rebate }) { +// // +// } function Submissions2022() { const content = useContentData(); From e301beb33dcab11eb7d0297882bfcc6dce050d7a Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Thu, 25 Jan 2024 22:50:04 -0500 Subject: [PATCH 27/35] Move function for updating an existing prf's submission data from Formio out of formio2022 route and into a reusable function that can be used for 2023 PRFs --- app/server/app/routes/formio2022.js | 61 +--------------------- app/server/app/utilities/formio.js | 79 +++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 59 deletions(-) diff --git a/app/server/app/routes/formio2022.js b/app/server/app/routes/formio2022.js index 1d6e7fa8..6a0c295d 100644 --- a/app/server/app/routes/formio2022.js +++ b/app/server/app/routes/formio2022.js @@ -29,6 +29,7 @@ const { fetchPRFSubmissions, createPRFSubmission, fetchPRFSubmission, + updatePRFSubmission, } = require("../utilities/formio"); const log = require("../utilities/logger"); @@ -104,65 +105,7 @@ router.get("/prf-submission/:rebateId", storeBapComboKeys, async (req, res) => { // --- post an update to an existing draft 2022 PRF submission to Formio router.post("/prf-submission/:rebateId", storeBapComboKeys, (req, res) => { - const { bapComboKeys, body } = req; - const { mail } = req.user; - const { rebateId } = req.params; // CSB Rebate ID (6 digits) - const { mongoId, submission } = body; - const comboKey = submission.data?.bap_hidden_entity_combo_key; - - checkFormSubmissionPeriodAndBapStatus({ - rebateYear: "2022", - formType: "prf", - mongoId, - comboKey, - req, - }) - .then(() => { - if (!bapComboKeys.includes(comboKey)) { - const logMessage = - `User with email '${mail}' attempted to update PRF submission '${rebateId}' ` + - `without a matching BAP combo key.`; - log({ level: "error", message: logMessage, req }); - - const errorStatus = 401; - const errorMessage = `Unauthorized.`; - return res.status(errorStatus).json({ message: errorMessage }); - } - - /** NOTE: verifyMongoObjectId */ - if (mongoId && !ObjectId.isValid(mongoId)) { - const errorStatus = 400; - const errorMessage = `MongoDB ObjectId validation error for: '${mongoId}'.`; - return res.status(errorStatus).json({ message: errorMessage }); - } - - /** Add custom metadata to track formio submissions from wrapper. */ - submission.metadata = { - ...submission.metadata, - ...formioCSBMetadata, - }; - - axiosFormio(req) - .put(`${formioPRFUrl}/submission/${mongoId}`, submission) - .then((axiosRes) => axiosRes.data) - .then((submission) => res.json(submission)) - .catch((error) => { - // NOTE: error is logged in axiosFormio response interceptor - const errorStatus = error.response?.status || 500; - const errorMessage = `Error updating Formio Payment Request form submission '${rebateId}'.`; - return res.status(errorStatus).json({ message: errorMessage }); - }); - }) - .catch((error) => { - const logMessage = - `User with email '${mail}' attempted to update PRF submission '${rebateId}' ` + - `when the CSB PRF enrollment period was closed.`; - log({ level: "error", message: logMessage, req }); - - const errorStatus = 400; - const errorMessage = `CSB Payment Request form enrollment period is closed.`; - return res.status(errorStatus).json({ message: errorMessage }); - }); + updatePRFSubmission({ rebateYear: "2022", req, res }); }); // --- delete an existing 2022 PRF submission from Formio diff --git a/app/server/app/utilities/formio.js b/app/server/app/utilities/formio.js index 82bb1b81..f8a878a9 100644 --- a/app/server/app/utilities/formio.js +++ b/app/server/app/utilities/formio.js @@ -864,6 +864,84 @@ function fetchPRFSubmission({ rebateYear, req, res }) { }); } +/** + * @param {Object} param + * @param {'2022' | '2023'} param.rebateYear + * @param {express.Request} param.req + * @param {express.Response} param.res + */ +function updatePRFSubmission({ rebateYear, req, res }) { + const { bapComboKeys, body } = req; + const { mail } = req.user; + const { rebateId } = req.params; // CSB Rebate ID (6 digits) + const { mongoId, submission } = body; + + const comboKeyFieldName = getComboKeyFieldName({ rebateYear }); + const comboKey = submission.data?.[comboKeyFieldName]; + + const formioFormUrl = formUrl[rebateYear].prf; + + if (!formioFormUrl) { + const errorStatus = 400; + const errorMessage = `Formio form URL does not exist for ${rebateYear} PRF.`; + return res.status(errorStatus).json({ message: errorMessage }); + } + + checkFormSubmissionPeriodAndBapStatus({ + rebateYear, + formType: "prf", + mongoId, + comboKey, + req, + }) + .then(() => { + if (!bapComboKeys.includes(comboKey)) { + const logMessage = + `User with email '${mail}' attempted to update ${rebateYear} PRF ` + + `submission '${rebateId}' without a matching BAP combo key.`; + log({ level: "error", message: logMessage, req }); + + const errorStatus = 401; + const errorMessage = `Unauthorized.`; + return res.status(errorStatus).json({ message: errorMessage }); + } + + /** NOTE: verifyMongoObjectId */ + if (mongoId && !ObjectId.isValid(mongoId)) { + const errorStatus = 400; + const errorMessage = `MongoDB ObjectId validation error for: '${mongoId}'.`; + return res.status(errorStatus).json({ message: errorMessage }); + } + + /** Add custom metadata to track formio submissions from wrapper. */ + submission.metadata = { + ...submission.metadata, + ...formioCSBMetadata, + }; + + axiosFormio(req) + .put(`${formioFormUrl}/submission/${mongoId}`, submission) + .then((axiosRes) => axiosRes.data) + .then((submission) => res.json(submission)) + .catch((error) => { + // NOTE: error is logged in axiosFormio response interceptor + const errorStatus = error.response?.status || 500; + const errorMessage = `Error updating Formio ${rebateYear} Payment Request form submission '${rebateId}'.`; + return res.status(errorStatus).json({ message: errorMessage }); + }); + }) + .catch((error) => { + const logMessage = + `User with email '${mail}' attempted to update ${rebateYear} PRF ` + + `submission '${rebateId}' when the CSB PRF enrollment period was closed.`; + log({ level: "error", message: logMessage, req }); + + const errorStatus = 400; + const errorMessage = `${rebateYear} CSB Payment Request form enrollment period is closed.`; + return res.status(errorStatus).json({ message: errorMessage }); + }); +} + module.exports = { uploadS3FileMetadata, downloadS3FileMetadata, @@ -876,4 +954,5 @@ module.exports = { fetchPRFSubmissions, createPRFSubmission, fetchPRFSubmission, + updatePRFSubmission, }; From 78960bd5401ed2b50d6f1534ef0fc7be8c75088d Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Thu, 25 Jan 2024 22:52:15 -0500 Subject: [PATCH 28/35] Update formio2023 router to include routes for fetching and updating prf submissions --- app/server/app/routes/formio2023.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/server/app/routes/formio2023.js b/app/server/app/routes/formio2023.js index cdedfd3a..54413e74 100644 --- a/app/server/app/routes/formio2023.js +++ b/app/server/app/routes/formio2023.js @@ -1,5 +1,4 @@ const express = require("express"); -const ObjectId = require("mongodb").ObjectId; // --- const { axiosFormio, @@ -27,6 +26,8 @@ const { // fetchPRFSubmissions, createPRFSubmission, + fetchPRFSubmission, + updatePRFSubmission, } = require("../utilities/formio"); const log = require("../utilities/logger"); @@ -93,8 +94,14 @@ router.post("/prf-submission", storeBapComboKeys, (req, res) => { }); // --- get an existing 2023 PRF's schema and submission data from Formio +router.get("/prf-submission/:rebateId", storeBapComboKeys, async (req, res) => { + fetchPRFSubmission({ rebateYear: "2023", req, res }); +}); // --- post an update to an existing draft 2023 PRF submission to Formio +router.post("/prf-submission/:rebateId", storeBapComboKeys, (req, res) => { + updatePRFSubmission({ rebateYear: "2023", req, res }); +}); // --- delete an existing 2023 PRF submission from Formio router.post("/delete-prf-submission", storeBapComboKeys, (req, res) => { From d4ebc61b7ac3143d2528ef1738e8069df34fca9a Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 26 Jan 2024 10:32:11 -0500 Subject: [PATCH 29/35] Move function for deleting an existing prf's submission data from Formio out of formio2022 route and into a reusable function that can be used for 2023 PRFs --- app/server/app/routes/formio2022.js | 65 +---------------------- app/server/app/utilities/formio.js | 80 +++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 63 deletions(-) diff --git a/app/server/app/routes/formio2022.js b/app/server/app/routes/formio2022.js index 6a0c295d..d27c4149 100644 --- a/app/server/app/routes/formio2022.js +++ b/app/server/app/routes/formio2022.js @@ -13,7 +13,6 @@ const { verifyMongoObjectId, } = require("../middleware"); const { - getBapFormSubmissionsStatuses, getBapDataFor2022CRF, checkFormSubmissionPeriodAndBapStatus, } = require("../utilities/bap"); @@ -30,10 +29,10 @@ const { createPRFSubmission, fetchPRFSubmission, updatePRFSubmission, + deletePRFSubmission, } = require("../utilities/formio"); const log = require("../utilities/logger"); -const formioPRFUrl = formUrl["2022"].prf; const formioCRFUrl = formUrl["2022"].crf; const router = express.Router(); @@ -110,67 +109,7 @@ router.post("/prf-submission/:rebateId", storeBapComboKeys, (req, res) => { // --- delete an existing 2022 PRF submission from Formio router.post("/delete-prf-submission", storeBapComboKeys, (req, res) => { - const { bapComboKeys, body } = req; - const { mail } = req.user; - const { mongoId, rebateId, comboKey } = body; - - // verify post data includes one of user's BAP combo keys - if (!bapComboKeys.includes(comboKey)) { - const logMessage = - `User with email '${mail}' attempted to delete PRF submission '${rebateId}' ` + - `without a matching BAP combo key.`; - log({ level: "error", message: logMessage, req }); - - const errorStatus = 401; - const errorMessage = `Unauthorized.`; - return res.status(errorStatus).json({ message: errorMessage }); - } - - /** - * ensure the BAP status of the corresponding FRF submission is "Edits - * Requested" before deleting the FRF submission from Formio - */ - getBapFormSubmissionsStatuses(req, req.bapComboKeys) - .then((submissions) => { - const frf = submissions.find((submission) => { - return ( - submission.Parent_Rebate_ID__c === rebateId && - submission.Record_Type_Name__c === "CSB Funding Request" - ); - }); - - const frfNeedsEdits = - frf?.Parent_CSB_Rebate__r.CSB_Funding_Request_Status__c === - "Edits Requested"; - - if (!frfNeedsEdits) { - const errorStatus = 400; - const errorMessage = `Application form submission '${mongoId}' does not need edits.`; - return res.status(errorStatus).json({ message: errorMessage }); - } - - axiosFormio(req) - .delete(`${formioPRFUrl}/submission/${mongoId}`) - .then((axiosRes) => axiosRes.data) - .then((response) => { - const logMessage = `User with email '${mail}' successfully deleted PRF submission '${rebateId}'.`; - log({ level: "info", message: logMessage, req }); - - res.json(response); - }) - .catch((error) => { - // NOTE: error is logged in axiosFormio response interceptor - const errorStatus = error.response?.status || 500; - const errorMessage = `Error deleting Formio Payment Request form submission '${rebateId}'.`; - return res.status(errorStatus).json({ message: errorMessage }); - }); - }) - .catch((error) => { - // NOTE: logged in bap verifyBapConnection - const errorStatus = 500; - const errorMessage = `Error getting form submissions statuses from the BAP.`; - return res.status(errorStatus).json({ message: errorMessage }); - }); + deletePRFSubmission({ rebateYear: "2022", req, res }); }); // --- get user's 2022 CRF submissions from Formio diff --git a/app/server/app/utilities/formio.js b/app/server/app/utilities/formio.js index f8a878a9..75a67c13 100644 --- a/app/server/app/utilities/formio.js +++ b/app/server/app/utilities/formio.js @@ -8,6 +8,7 @@ const { formioCSBMetadata, } = require("../config/formio"); const { + getBapFormSubmissionsStatuses, getBapDataFor2022PRF, getBapDataFor2023PRF, checkFormSubmissionPeriodAndBapStatus, @@ -942,6 +943,84 @@ function updatePRFSubmission({ rebateYear, req, res }) { }); } +/** + * @param {Object} param + * @param {'2022' | '2023'} param.rebateYear + * @param {express.Request} param.req + * @param {express.Response} param.res + */ +function deletePRFSubmission({ rebateYear, req, res }) { + const { bapComboKeys, body } = req; + const { mail } = req.user; + const { mongoId, rebateId, comboKey } = body; + + const formioFormUrl = formUrl[rebateYear].prf; + + if (!formioFormUrl) { + const errorStatus = 400; + const errorMessage = `Formio form URL does not exist for ${rebateYear} PRF.`; + return res.status(errorStatus).json({ message: errorMessage }); + } + + // verify post data includes one of user's BAP combo keys + if (!bapComboKeys.includes(comboKey)) { + const logMessage = + `User with email '${mail}' attempted to delete ${rebateYear} PRF ` + + `submission '${rebateId}' without a matching BAP combo key.`; + log({ level: "error", message: logMessage, req }); + + const errorStatus = 401; + const errorMessage = `Unauthorized.`; + return res.status(errorStatus).json({ message: errorMessage }); + } + + /** + * ensure the BAP status of the corresponding FRF submission is "Edits + * Requested" before deleting the FRF submission from Formio + */ + getBapFormSubmissionsStatuses(req, req.bapComboKeys) + .then((submissions) => { + const frf = submissions.find((submission) => { + return ( + submission.Parent_Rebate_ID__c === rebateId && + submission.Record_Type_Name__c.startsWith("CSB Funding Request") + ); + }); + + const frfNeedsEdits = + frf?.Parent_CSB_Rebate__r.CSB_Funding_Request_Status__c === + "Edits Requested"; + + if (!frfNeedsEdits) { + const errorStatus = 400; + const errorMessage = `${rebateYear} Application form submission '${mongoId}' does not need edits.`; + return res.status(errorStatus).json({ message: errorMessage }); + } + + axiosFormio(req) + .delete(`${formioFormUrl}/submission/${mongoId}`) + .then((axiosRes) => axiosRes.data) + .then((response) => { + const logMessage = `User with email '${mail}' successfully deleted ${rebateYear} PRF submission '${rebateId}'.`; + log({ level: "info", message: logMessage, req }); + + res.json(response); + }) + .catch((error) => { + // NOTE: error is logged in axiosFormio response interceptor + const errorStatus = error.response?.status || 500; + const errorMessage = `Error deleting ${rebateYear} Formio Payment Request form submission '${rebateId}'.`; + return res.status(errorStatus).json({ message: errorMessage }); + }); + }) + .catch((error) => { + // NOTE: logged in bap verifyBapConnection + const errorStatus = 500; + const errorMessage = `Error getting form submissions statuses from the BAP.`; + return res.status(errorStatus).json({ message: errorMessage }); + }); +} + module.exports = { uploadS3FileMetadata, downloadS3FileMetadata, @@ -955,4 +1034,5 @@ module.exports = { createPRFSubmission, fetchPRFSubmission, updatePRFSubmission, + deletePRFSubmission, }; From 6c785905fdc7c3cbb9d12c661a5517fab6e70c87 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 26 Jan 2024 10:34:20 -0500 Subject: [PATCH 30/35] Update formio2023 router's /delete-prf-submission to call deletePRFSubmission() function from shared formio utility file --- app/server/app/routes/formio2023.js | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/app/server/app/routes/formio2023.js b/app/server/app/routes/formio2023.js index 54413e74..d950a903 100644 --- a/app/server/app/routes/formio2023.js +++ b/app/server/app/routes/formio2023.js @@ -1,20 +1,10 @@ const express = require("express"); // --- -const { - axiosFormio, - formUrl, - submissionPeriodOpen, - formioCSBMetadata, -} = require("../config/formio"); const { ensureAuthenticated, storeBapComboKeys, verifyMongoObjectId, } = require("../middleware"); -const { - getBapFormSubmissionsStatuses, - checkFormSubmissionPeriodAndBapStatus, -} = require("../utilities/bap"); const { uploadS3FileMetadata, downloadS3FileMetadata, @@ -28,8 +18,8 @@ const { createPRFSubmission, fetchPRFSubmission, updatePRFSubmission, + deletePRFSubmission, } = require("../utilities/formio"); -const log = require("../utilities/logger"); const router = express.Router(); @@ -105,7 +95,7 @@ router.post("/prf-submission/:rebateId", storeBapComboKeys, (req, res) => { // --- delete an existing 2023 PRF submission from Formio router.post("/delete-prf-submission", storeBapComboKeys, (req, res) => { - // TODO + deletePRFSubmission({ rebateYear: "2023", req, res }); }); // --- get user's 2022 CRF submissions from Formio From 3f146ec7744e3cce24cf6ef38695dea4a2e5a50c Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 26 Jan 2024 10:37:33 -0500 Subject: [PATCH 31/35] Store rebateYear variable in formio2022 and formio2023 routes, so it can be used throughout the file --- app/server/app/routes/formio2022.js | 25 +++++++++++++------------ app/server/app/routes/formio2023.js | 23 ++++++++++++----------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/app/server/app/routes/formio2022.js b/app/server/app/routes/formio2022.js index d27c4149..8cb79814 100644 --- a/app/server/app/routes/formio2022.js +++ b/app/server/app/routes/formio2022.js @@ -35,6 +35,7 @@ const log = require("../utilities/logger"); const formioCRFUrl = formUrl["2022"].crf; +const rebateYear = "2022"; const router = express.Router(); router.use(ensureAuthenticated); @@ -44,7 +45,7 @@ router.get( "/s3/:formType/:mongoId/:comboKey/storage/s3", storeBapComboKeys, (req, res) => { - downloadS3FileMetadata({ rebateYear: "2022", req, res }); + downloadS3FileMetadata({ rebateYear, req, res }); }, ); @@ -53,18 +54,18 @@ router.post( "/s3/:formType/:mongoId/:comboKey/storage/s3", storeBapComboKeys, (req, res) => { - uploadS3FileMetadata({ rebateYear: "2022", req, res }); + uploadS3FileMetadata({ rebateYear, req, res }); }, ); // --- get user's 2022 FRF submissions from Formio router.get("/frf-submissions", storeBapComboKeys, (req, res) => { - fetchFRFSubmissions({ rebateYear: "2022", req, res }); + fetchFRFSubmissions({ rebateYear, req, res }); }); // --- post a new 2022 FRF submission to Formio router.post("/frf-submission", storeBapComboKeys, (req, res) => { - createFRFSubmission({ rebateYear: "2022", req, res }); + createFRFSubmission({ rebateYear, req, res }); }); // --- get an existing 2022 FRF's schema and submission data from Formio @@ -73,7 +74,7 @@ router.get( verifyMongoObjectId, storeBapComboKeys, (req, res) => { - fetchFRFSubmission({ rebateYear: "2022", req, res }); + fetchFRFSubmission({ rebateYear, req, res }); }, ); @@ -83,33 +84,33 @@ router.post( verifyMongoObjectId, storeBapComboKeys, (req, res) => { - updateFRFSubmission({ rebateYear: "2022", req, res }); + updateFRFSubmission({ rebateYear, req, res }); }, ); // --- get user's 2022 PRF submissions from Formio router.get("/prf-submissions", storeBapComboKeys, (req, res) => { - fetchPRFSubmissions({ rebateYear: "2022", req, res }); + fetchPRFSubmissions({ rebateYear, req, res }); }); // --- post a new 2022 PRF submission to Formio router.post("/prf-submission", storeBapComboKeys, (req, res) => { - createPRFSubmission({ rebateYear: "2022", req, res }); + createPRFSubmission({ rebateYear, req, res }); }); // --- get an existing 2022 PRF's schema and submission data from Formio router.get("/prf-submission/:rebateId", storeBapComboKeys, async (req, res) => { - fetchPRFSubmission({ rebateYear: "2022", req, res }); + fetchPRFSubmission({ rebateYear, req, res }); }); // --- post an update to an existing draft 2022 PRF submission to Formio router.post("/prf-submission/:rebateId", storeBapComboKeys, (req, res) => { - updatePRFSubmission({ rebateYear: "2022", req, res }); + updatePRFSubmission({ rebateYear, req, res }); }); // --- delete an existing 2022 PRF submission from Formio router.post("/delete-prf-submission", storeBapComboKeys, (req, res) => { - deletePRFSubmission({ rebateYear: "2022", req, res }); + deletePRFSubmission({ rebateYear, req, res }); }); // --- get user's 2022 CRF submissions from Formio @@ -397,7 +398,7 @@ router.post("/crf-submission/:rebateId", storeBapComboKeys, (req, res) => { const comboKey = submission.data?.bap_hidden_entity_combo_key; checkFormSubmissionPeriodAndBapStatus({ - rebateYear: "2022", + rebateYear, formType: "crf", mongoId, comboKey, diff --git a/app/server/app/routes/formio2023.js b/app/server/app/routes/formio2023.js index d950a903..a8e46dca 100644 --- a/app/server/app/routes/formio2023.js +++ b/app/server/app/routes/formio2023.js @@ -21,6 +21,7 @@ const { deletePRFSubmission, } = require("../utilities/formio"); +const rebateYear = "2023"; const router = express.Router(); router.use(ensureAuthenticated); @@ -30,7 +31,7 @@ router.get( "/s3/:formType/:mongoId/:comboKey/storage/s3", storeBapComboKeys, (req, res) => { - downloadS3FileMetadata({ rebateYear: "2023", req, res }); + downloadS3FileMetadata({ rebateYear, req, res }); }, ); @@ -39,18 +40,18 @@ router.post( "/s3/:formType/:mongoId/:comboKey/storage/s3", storeBapComboKeys, (req, res) => { - uploadS3FileMetadata({ rebateYear: "2023", req, res }); + uploadS3FileMetadata({ rebateYear, req, res }); }, ); // --- get user's 2023 FRF submissions from Formio router.get("/frf-submissions", storeBapComboKeys, (req, res) => { - fetchFRFSubmissions({ rebateYear: "2023", req, res }); + fetchFRFSubmissions({ rebateYear, req, res }); }); // --- post a new 2023 FRF submission to Formio router.post("/frf-submission", storeBapComboKeys, (req, res) => { - createFRFSubmission({ rebateYear: "2023", req, res }); + createFRFSubmission({ rebateYear, req, res }); }); // --- get an existing 2023 FRF's schema and submission data from Formio @@ -59,7 +60,7 @@ router.get( verifyMongoObjectId, storeBapComboKeys, (req, res) => { - fetchFRFSubmission({ rebateYear: "2023", req, res }); + fetchFRFSubmission({ rebateYear, req, res }); }, ); @@ -69,33 +70,33 @@ router.post( verifyMongoObjectId, storeBapComboKeys, (req, res) => { - updateFRFSubmission({ rebateYear: "2023", req, res }); + updateFRFSubmission({ rebateYear, req, res }); }, ); // --- get user's 2023 PRF submissions from Formio router.get("/prf-submissions", storeBapComboKeys, (req, res) => { - fetchPRFSubmissions({ rebateYear: "2023", req, res }); + fetchPRFSubmissions({ rebateYear, req, res }); }); // --- post a new 2023 PRF submission to Formio router.post("/prf-submission", storeBapComboKeys, (req, res) => { - createPRFSubmission({ rebateYear: "2023", req, res }); + createPRFSubmission({ rebateYear, req, res }); }); // --- get an existing 2023 PRF's schema and submission data from Formio router.get("/prf-submission/:rebateId", storeBapComboKeys, async (req, res) => { - fetchPRFSubmission({ rebateYear: "2023", req, res }); + fetchPRFSubmission({ rebateYear, req, res }); }); // --- post an update to an existing draft 2023 PRF submission to Formio router.post("/prf-submission/:rebateId", storeBapComboKeys, (req, res) => { - updatePRFSubmission({ rebateYear: "2023", req, res }); + updatePRFSubmission({ rebateYear, req, res }); }); // --- delete an existing 2023 PRF submission from Formio router.post("/delete-prf-submission", storeBapComboKeys, (req, res) => { - deletePRFSubmission({ rebateYear: "2023", req, res }); + deletePRFSubmission({ rebateYear, req, res }); }); // --- get user's 2022 CRF submissions from Formio From 0a857f2c2b7c59bb40ec5f595e39f25070390568 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 26 Jan 2024 10:43:18 -0500 Subject: [PATCH 32/35] Move function for fetching crf's submission data from Formio out of formio2022 route and into a reusable function that can be used for 2023 CRFs --- app/server/app/routes/formio2022.js | 23 +++------------- app/server/app/utilities/formio.js | 41 +++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/app/server/app/routes/formio2022.js b/app/server/app/routes/formio2022.js index 8cb79814..7aa73bc7 100644 --- a/app/server/app/routes/formio2022.js +++ b/app/server/app/routes/formio2022.js @@ -30,6 +30,8 @@ const { fetchPRFSubmission, updatePRFSubmission, deletePRFSubmission, + // + fetchCRFSubmissions, } = require("../utilities/formio"); const log = require("../utilities/logger"); @@ -115,26 +117,7 @@ router.post("/delete-prf-submission", storeBapComboKeys, (req, res) => { // --- get user's 2022 CRF submissions from Formio router.get("/crf-submissions", storeBapComboKeys, (req, res) => { - const { bapComboKeys } = req; - - const submissionsUrl = - `${formioCRFUrl}/submission` + - `?sort=-modified` + - `&limit=1000000` + - `&data.bap_hidden_entity_combo_key=${bapComboKeys.join( - "&data.bap_hidden_entity_combo_key=", - )}`; - - axiosFormio(req) - .get(submissionsUrl) - .then((axiosRes) => axiosRes.data) - .then((submissions) => res.json(submissions)) - .catch((error) => { - // NOTE: error is logged in axiosFormio response interceptor - const errorStatus = error.response?.status || 500; - const errorMessage = `Error getting Formio Close Out form submissions.`; - return res.status(errorStatus).json({ message: errorMessage }); - }); + fetchCRFSubmissions({ rebateYear, req, res }); }); // --- post a new 2022 CRF submission to Formio diff --git a/app/server/app/utilities/formio.js b/app/server/app/utilities/formio.js index 75a67c13..63997f19 100644 --- a/app/server/app/utilities/formio.js +++ b/app/server/app/utilities/formio.js @@ -1021,6 +1021,45 @@ function deletePRFSubmission({ rebateYear, req, res }) { }); } +/** + * @param {Object} param + * @param {'2022' | '2023'} param.rebateYear + * @param {express.Request} param.req + * @param {express.Response} param.res + */ +function fetchCRFSubmissions({ rebateYear, req, res }) { + const { bapComboKeys } = req; + + const comboKeyFieldName = getComboKeyFieldName({ rebateYear }); + const comboKeySearchParam = `&data.${comboKeyFieldName}=`; + + const formioFormUrl = formUrl[rebateYear].crf; + + if (!formioFormUrl) { + const errorStatus = 400; + const errorMessage = `Formio form URL does not exist for ${rebateYear} CRF.`; + return res.status(errorStatus).json({ message: errorMessage }); + } + + const submissionsUrl = + `${formioFormUrl}/submission` + + `?sort=-modified` + + `&limit=1000000` + + comboKeySearchParam + + `${bapComboKeys.join(comboKeySearchParam)}`; + + axiosFormio(req) + .get(submissionsUrl) + .then((axiosRes) => axiosRes.data) + .then((submissions) => res.json(submissions)) + .catch((error) => { + // NOTE: error is logged in axiosFormio response interceptor + const errorStatus = error.response?.status || 500; + const errorMessage = `Error getting Formio ${rebateYear} Close Out form submissions.`; + return res.status(errorStatus).json({ message: errorMessage }); + }); +} + module.exports = { uploadS3FileMetadata, downloadS3FileMetadata, @@ -1035,4 +1074,6 @@ module.exports = { fetchPRFSubmission, updatePRFSubmission, deletePRFSubmission, + // + fetchCRFSubmissions, }; From c765f14ab40f6c7c445087dfed226167410bb88a Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 26 Jan 2024 10:49:12 -0500 Subject: [PATCH 33/35] Correct 2023 PRF CSB rebate Id and entity combo key fields to be the correct field names, so the correct data is posted to the api/formio/2023/delete-prf-submission server endpoint --- app/client/src/routes/frf2023.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/client/src/routes/frf2023.tsx b/app/client/src/routes/frf2023.tsx index 9862361f..a7f7c2c6 100644 --- a/app/client/src/routes/frf2023.tsx +++ b/app/client/src/routes/frf2023.tsx @@ -280,8 +280,8 @@ function FundingRequestForm(props: { email: string }) { postData(url, { mongoId: prf._id, - rebateId: prf.data.hidden_bap_rebate_id, - comboKey: prf.data.bap_hidden_entity_combo_key, + rebateId: prf.data._bap_rebate_id, + comboKey: prf.data._bap_entity_combo_key, }) .then((_res) => { window.location.reload(); From e7fbb4387e3c78715a244b9697a2d2db2cb737a2 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 26 Jan 2024 15:31:16 -0500 Subject: [PATCH 34/35] Update data injected into a brand new 2023 PRF submission to include the BAP Rebate Id field --- app/server/app/utilities/formio.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/server/app/utilities/formio.js b/app/server/app/utilities/formio.js index 63997f19..350abe33 100644 --- a/app/server/app/utilities/formio.js +++ b/app/server/app/utilities/formio.js @@ -294,8 +294,9 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { return { data: { - _bap_entity_combo_key: comboKey, _application_form_modified: frfFormModified, + _bap_entity_combo_key: comboKey, + _bap_rebate_id: rebateId, _user_email: email, _user_title: title, _user_name: name, From f347dd3b8d009cd00b1c40344161b9aefe8a2ee7 Mon Sep 17 00:00:00 2001 From: Courtney Myers Date: Fri, 26 Jan 2024 15:33:37 -0500 Subject: [PATCH 35/35] Update existingOwnerRecord in fetchDataForPRFSubmission() to be set when the relationship type is 'Existing Bus Owner' --- app/server/app/utilities/formio.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/server/app/utilities/formio.js b/app/server/app/utilities/formio.js index 350abe33..bac8fbf9 100644 --- a/app/server/app/utilities/formio.js +++ b/app/server/app/utilities/formio.js @@ -245,7 +245,7 @@ function fetchDataForPRFSubmission({ rebateYear, req, res }) { ({ Related_Line_Item__c, Relationship_Type__c }) => { return ( Related_Line_Item__c === Id && - Relationship_Type__c === "Old Bus Private Fleet Owner (if changed)" // prettier-ignore + Relationship_Type__c === "Existing Bus Owner" ); }, );