From 1a1d9f2696eb4d4a5064f9cefc4b8979352c2ced Mon Sep 17 00:00:00 2001 From: Joona Laamanen Date: Thu, 30 Mar 2023 14:10:05 +0300 Subject: [PATCH] Added SAP project ID validation --- backend/src/components/project/base.ts | 7 +++ backend/src/components/sap/dataImport.ts | 7 +++ backend/src/router/project/detailplan.ts | 1 - docker/sap-mock/mock-server.clj | 76 ++++++++++++++++++------ shared/src/language/fi.json | 1 + 5 files changed, 72 insertions(+), 20 deletions(-) diff --git a/backend/src/components/project/base.ts b/backend/src/components/project/base.ts index 4436ca79..59046da3 100644 --- a/backend/src/components/project/base.ts +++ b/backend/src/components/project/base.ts @@ -11,6 +11,7 @@ import { UpsertProject, projectIdSchema } from '@shared/schema/project/base'; import { User } from '@shared/schema/user'; import { codeIdFragment } from '../code'; +import { sapProjectExists } from '../sap/dataImport'; async function upsertBaseProject( tx: DatabaseTransactionConnection, @@ -94,6 +95,12 @@ export async function validateUpsertProject( ) { const validationErrors: FormErrors = { errors: {} }; + if (values?.sapProjectId) { + if (!(await sapProjectExists(values.sapProjectId))) { + validationErrors.errors['sapProjectId'] = fieldError('project.error.sapProjectNotFound'); + } + } + if (values?.id) { const estimateRange = await getPool().maybeOne(sql.untyped` SELECT diff --git a/backend/src/components/sap/dataImport.ts b/backend/src/components/sap/dataImport.ts index 0d5a1367..fb97f8c4 100644 --- a/backend/src/components/sap/dataImport.ts +++ b/backend/src/components/sap/dataImport.ts @@ -371,3 +371,10 @@ export async function getSapActuals(sapProjectId: string, year: string) { return maybeCacheSapActuals(sapProjectId, year, actuals); } } + +export async function sapProjectExists(projectId: string) { + const wsClient = ProjectInfoService.getClient(); + const [wsResult] = await wsClient.SI_ZPS_WS_GET_PROJECT_INFOAsync({ PROJECT: projectId }); + const containsErrorItem = wsResult.MESSAGES?.item?.some((item: any) => item.TYPE === 'E'); + return !containsErrorItem; +} diff --git a/backend/src/router/project/detailplan.ts b/backend/src/router/project/detailplan.ts index 8b3213a4..b6c5d1b5 100644 --- a/backend/src/router/project/detailplan.ts +++ b/backend/src/router/project/detailplan.ts @@ -10,7 +10,6 @@ import { } from '@backend/components/project/detailplan'; import { startSendMailJob } from '@backend/components/taskQueue/mailQueue'; import { getUser } from '@backend/components/user'; -import { getPool, sql } from '@backend/db'; import { env } from '@backend/env'; import { TRPC } from '@backend/router'; diff --git a/docker/sap-mock/mock-server.clj b/docker/sap-mock/mock-server.clj index 08983729..d3c717ab 100755 --- a/docker/sap-mock/mock-server.clj +++ b/docker/sap-mock/mock-server.clj @@ -146,7 +146,7 @@ (defn random-project-data [project-id] (let [;; decode mock data parameters from the id part ;; e.g. I1112_34567 - ;; -> 3 WBS elements, 4 activities per WBS + ;; -> 3 WBS elements, 4 activities per WBS [_ id] (str/split project-id #"_") [wbs-count activity-count] (take 2 id) wbs-count (- (int wbs-count) 48) @@ -334,9 +334,43 @@ [:BEKNZ BEKNZ]]) actuals)]) +(def not-found-response + [[:MESSAGES [:item + [:TYPE "E"] + [:ID] + [:NUMBER "000"] + [:MESSAGE "Projektia ei löydy"] + [:LOG_NO] + [:MESSAGE_V1] + [:MESSAGE_V2] + [:MESSAGE_V3] + [:MESSAGE_V4] + [:PARAMETER] + [:ROW] + [:FIELD] + [:SYSTEM]]] + [:PROJECT_INFO + [:PSPNR "00000000"] + [:PSPID] + [:POST1] + [:ERNAM] + [:ERDAT "0000-00-00"] + [:AENAM] + [:AEDAT] + [:VERNR "00000000"] + [:VERNA] + [:ASTNR "00000000"] + [:ASTNA] + [:VBUKR] + [:PRCTR] + [:PLFAZ "0000-00-00"] + [:PLSEZ "0000-00-00"] + [:WERKS] + [:WBS]]]) + ;; ;; XML utils -;; +;; (defn tag-name [tag] (some-> tag name keyword)) @@ -352,12 +386,15 @@ (some? tag) {tag (apply merge (map preprocess-elem content))}))) -(defn ->soap-envelope [body] - (xml/indent-str - (xml/sexp-as-element - [:SOAP:Envelope - {:xmlns:SOAP "http://schemas.xmlsoap.org/soap/envelope/"} - [:SOAP:Body body]]))) +(defn ->soap-response [operation & body] + (let [operation-kw (keyword (str "rfc:" (name operation) ".Response"))] + (xml/indent-str + (xml/sexp-as-element + [:SOAP:Envelope + {:xmlns:SOAP "http://schemas.xmlsoap.org/soap/envelope/"} + [:SOAP:Body [operation-kw + {:xmlns:rfc "urn:sap-com:document:sap:rfc:functions"} + body]]])))) ;; ;; SOAP endpoints @@ -376,15 +413,17 @@ project-id (get-in root-elem [:Envelope :Body :ZPS_WS_GET_PROJECT_INFO :PROJECT]) [_ id] (str/split project-id #"_") _ (set-seed! (Integer/parseInt id)) - project (random-project-data project-id)] + project (random-project-data project-id) + not-found? (= id "404") + make-response (partial apply ->soap-response :ZPS_WS_GET_PROJECT_INFO)] (s/validate ProjectInfoSoapMessage root-elem) {:status 200 :content-type "text/xml" - :body (->soap-envelope - [:rfc:ZPS_WS_GET_PROJECT_INFO.Response - {:xmlns:rfc "urn:sap-com:document:sap:rfc:functions"} - [:MESSAGES] - (generate-project-data project)])}))) + :body (make-response + (if not-found? + not-found-response + [[:MESSAGES] + (generate-project-data project)]))}))) (s/defschema ActualsSoapMessage {:Envelope @@ -423,11 +462,10 @@ (filter-by-date-range query-date-range))] {:status 200 :content-type "text/xml" - :body (->soap-envelope - [:rfc:ZPS_WS_GET_ACTUALS.Response - {:xmlns:rfc "urn:sap-com:document:sap:rfc:functions"} - [:MESSAGES] - (generate-actuals-data actuals)])})))) + :body (->soap-response + :ZPS_WS_GET_ACTUALS + [:MESSAGES] + (generate-actuals-data actuals))})))) ;; ;; Web server diff --git a/shared/src/language/fi.json b/shared/src/language/fi.json index 5e2a5ff5..564afa29 100644 --- a/shared/src/language/fi.json +++ b/shared/src/language/fi.json @@ -67,6 +67,7 @@ "project.error.endDateBeforeStartDate": "Loppuajankohdan oltava alkuajankohdan jälkeen", "project.error.existingProjectObjectWBS": "Hankkeen kohteilla rakenneosia", "project.error.costEstimateNotIncluded": "Kustannusarvioita ajankohdan ulkopuolella", + "project.error.sapProjectNotFound": "SAP-projektia ei löytynyt annetulla ID:llä", "projectForm.saveBtnLabel": "Tallenna", "projectForm.editBtnLabel": "Muokkaa", "projectForm.undoBtnLabel": "Peruuta muutokset",