Untitled
unknown
plain_text
a year ago
8.6 kB
6
Indexable
import { APIGatewayEvent } from "aws-lambda"; import * as B from "fp-ts/boolean"; import * as C from "fp-ts/Console"; import { pipe } from "fp-ts/function"; import * as TE from "fp-ts/TaskEither"; import { readUrl } from "@lambdas/shared/configuration"; import { catchAndLogTE } from "@lambdas/shared/errors/CatchAndLog"; import * as Json from "@lambdas/shared/json"; import { EDDAMandate } from "@lambdas/shared/models/EDDAMandate"; import { LAMBDA_FUNCTION_TIMEOUT_DURATION, calculateSentryTimeoutWarningLimit, } from "@lambdas/shared/monitoring/lambda"; import { decryptDbsNotificationMessage } from "@lambdas/shared/pgp"; import { EDDAMandateRepository } from "@lambdas/shared/repositories/EDDAMandateRepository"; import { getBankDetailsRepository, getEddaCollectFundsRequestRepo, getEddaMandateRepo, } from "@lambdas/shared/repositoryFactory"; import { sendEddaAccountLinkFailEvent } from "@lambdas/shared/services/blueshift/sendEddaAccountLinkFailEvent"; import { sendEgiroLinkAbortedDuplicateAccountPendingCollection } from "@lambdas/shared/services/blueshift/sendEgiroLinkAbortedDuplicateAccountPendingCollection"; import { initializeSentry, sentryWrapHandler, } from "@lambdas/shared/services/sentry"; import { genericApiHandler } from "@lambdas/shared/sharedApiHandler"; import { sendMessagesToQueue } from "@lambdas/shared/sqs/sendMessagesToQueue"; import { HandlerContext, noPayload } from "@lambdas/shared/types"; import * as creationCallbackPayloadParser from "./creationCallbackParser"; import { getRequestIdFromEvent } from "./getRequestIdFromEvent"; import { encodeError, encodeSuccess } from "./httpResponseEncoder"; import { isLinkedAccountExistError, linkedAccountExistError, } from "./linkedAccountExistError"; import { logError, logSuccess } from "./logger"; import { duplicateAccountPendingCollectionError, isDuplicateAccountPendingCollectionError } from "./duplicateAccountPendingCollection"; initializeSentry(); export const handler = sentryWrapHandler( (event: APIGatewayEvent, context: HandlerContext) => genericApiHandler( { event, name: "dbs-egiro-creation-callback", context, isEventBodyRequired: true, }, (event: APIGatewayEvent) => pipe( TE.Do, TE.bindW("requestId", () => TE.fromEither(getRequestIdFromEvent(event)) ), TE.bindW("payload", ({ requestId }) => getRequestPayload(event, requestId) ), TE.bindW("eddaMandateRepo", getEddaMandateRepo), TE.bindW("eddaMandate", ({ eddaMandateRepo, payload }) => eddaMandateRepo.findByTransactionIdWithBankAndUser( payload.boTransactionRefNo ) ), TE.bindW("validBankAccount", ({ eddaMandate, payload }) => validateBankAccount( eddaMandate.userId, payload.applicantBankCode!, payload.applicantBankAccNo! ) ), TE.chainFirstW(({ eddaMandateRepo, payload, validBankAccount }) => completeTokenReceipt(validBankAccount, eddaMandateRepo, payload) ), TE.bindW("oldEddaMandate", ({ eddaMandateRepo, payload }) => eddaMandateRepo.findCompleteAccountByAndBicAndBankAccountNumber(payload.applicantBankCode!, payload.applicantBankAccNo!)), TE.bindW("hasPendingRequest", ({ oldEddaMandate }) => checkPendingRequest(oldEddaMandate)), // TE.chainFirstW(({ payload, hasPendingRequest, eddaMandateRepo, oldEddaMandate }) => // !!payload.errorMessage && oldEddaMandate // ? handleExistPendingRequest(eddaMandateRepo, oldEddaMandate, hasPendingRequest) // : TE.of(undefined) // ), TE.chainFirstW(({ payload, hasPendingRequest }) => !!payload.errorMessage ? catchAndLogTE(C)( "Send edda linking fail event error with reason" )(publishRejectEventToBlueshift(payload.boTransactionRefNo)) : handleSendMessageToQueue(payload) ), TE.orElseFirstW((error) => { if (isDuplicateAccountPendingCollectionError(error)) { return sendEgiroLinkAbortedDuplicateAccountPendingCollection(error.userId); } return TE.right(undefined); }), TE.orElseFirstIOK(logError), TE.chainFirstIOK(logSuccess), TE.match(encodeError, ({ requestId }) => encodeSuccess(requestId)) )() ), { timeoutWarningLimit: calculateSentryTimeoutWarningLimit( LAMBDA_FUNCTION_TIMEOUT_DURATION.dbsEgiroCreationToken ), } ); const getRequestPayload = (event: APIGatewayEvent, requestId: string) => pipe( event.body, TE.fromNullable(noPayload()), TE.chainW(decryptDbsNotificationMessage), TE.chainEitherKW(Json.decode), TE.chainEitherKW((payload) => creationCallbackPayloadParser.parse(payload, requestId) ) ); const composeMessage = ( payload: creationCallbackPayloadParser.CreationCallbackPayload ) => ({ Id: payload.boTransactionRefNo, MessageGroupId: payload.boTransactionRefNo, MessageBody: JSON.stringify({ applicantBankAccNo: payload.applicantBankAccNo, applicantBankCode: payload.applicantBankCode, boDDARefNo: payload.boDDARefNo, boTransactionRefNo: payload.boTransactionRefNo, bankToken: payload.bankToken, maxAmount: payload.maxAmount, fromDate: payload.fromDate?.toFormat("dd-MM-yyyy"), toDate: payload.toDate?.toFormat("dd-MM-yyyy"), }), }); const handleSendMessageToQueue = ( payload: creationCallbackPayloadParser.CreationCallbackPayload, ) => pipe( readUrl("QUEUE_URL"), TE.fromEither, TE.chainW((queueUrl) => sendMessagesToQueue(queueUrl, [composeMessage(payload)]) ), TE.map(() => undefined) ); const publishRejectEventToBlueshift = (transactionId: string) => pipe( getEddaMandateRepo(), TE.chainW((repo) => repo.findByTransactionIdWithBankAndUser(transactionId)), TE.chainW(sendEddaAccountLinkFailEvent) ); const validateBankAccount = ( userId: string, bic: string, accountNumber: string ) => pipe( getBankDetailsRepository(), TE.chainW((repo) => repo.findByBicAndAccountNumber(bic, accountNumber)), TE.chainW( TE.fromPredicate( (bankDetail) => !bankDetail || bankDetail.userId === userId, linkedAccountExistError ) ), TE.chainW(() => TE.of(true)), TE.orElseW((error) => { if (isLinkedAccountExistError(error)) { console.error("The requested bank account was already registered"); return TE.right(false); } return TE.left(error); }) ); const completeTokenReceipt = ( validBankAccount: boolean, eddaMandateRepo: EDDAMandateRepository, payload: creationCallbackPayloadParser.CreationCallbackPayload ) => pipe( validBankAccount, B.foldW( () => eddaMandateRepo.completeTokenReceipt( payload.boTransactionRefNo, payload.boDDARefNo, false, undefined, `Complete token receipt: The requested bank account was already registered` ), () => eddaMandateRepo.completeTokenReceipt( payload.boTransactionRefNo, payload.boDDARefNo, !payload.errorMessage, payload.applicantBankAccNo, payload.errorMessage && `Complete token receipt: ${payload.errorMessage}`, payload.toDate ) ) ); const checkPendingRequest = ( oldEddaMandate: EDDAMandate | null, ) => pipe( oldEddaMandate === null, B.foldW( () => pipe( getEddaCollectFundsRequestRepo(), TE.chainW((repo) => repo.findPendingRequestsByMandateTransactionId(oldEddaMandate!.transactionId)), TE.chainW( TE.fromPredicate( (pendingRequest) => pendingRequest.length === 0, () => duplicateAccountPendingCollectionError(oldEddaMandate!.userId) ) ) ), () => TE.of(undefined) ) ) const handleExistPendingRequest = (eddaMandateRepo: EDDAMandateRepository, oldEddaMandate: EDDAMandate, hasPendingRequest: boolean) => pipe( hasPendingRequest, B.foldW( () => eddaMandateRepo.deleteByTransactionId(oldEddaMandate.transactionId), // () => TE.right(undefined), () => sendEgiroLinkAbortedDuplicateAccountPendingCollection(oldEddaMandate.userId), // () => pipe( // TE.Do, // TE.chainW(() => sendEgiroLinkAbortedDuplicateAccountPendingCollection(oldEddaMandate.userId)) // ) ) )
Editor is loading...
Leave a Comment