Untitled
unknown
plain_text
2 years ago
8.6 kB
10
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