Skip to content

Instantly share code, notes, and snippets.

@MarwanT
Created October 17, 2023 16:01
Show Gist options
  • Save MarwanT/bc5db905baad13f41aec8cc07f6dc9dd to your computer and use it in GitHub Desktop.
Save MarwanT/bc5db905baad13f41aec8cc07f6dc9dd to your computer and use it in GitHub Desktop.
import "reflect-metadata"
import { singleton } from "tsyringe"
import { APIResponse } from "../../data/types/interfaces/api-response.interface"
import { Handler } from "../../data/types/interfaces/handler.interface"
import { APIHeaders } from "../../data/types/models/headers"
import { Logging } from "../../utils/logging"
import { ModernTreasuryService } from "../../services/modern-treasury-service"
import { UserRepository } from "../../repositories/user-repository"
import { APIGatewayEvent } from "../../data/types/interfaces/handler.interface"
import { PaymentOrderStatus } from "../../data/types/models/modern-treasury"
import { FailedInvestment, FailedInvestmentType } from "../../data/types/models/investment"
import { ClientUser } from "../../data/types/interfaces/models.interface"
import { ServerError } from "../../data/types/models/errors"
import { IServerError } from "../../data/types/interfaces/error.interface"
@singleton()
export class MTPaymentOrderWebhookController {
private event: APIGatewayEvent<any>
private counterpartyId: string
private ledgerTransactionId: string
private bodyHash: string
constructor(
private userRepository: UserRepository = new UserRepository(),
private mtService: ModernTreasuryService = new ModernTreasuryService(),
) {}
handler: Handler<any, APIResponse<void>> = async (event, _) => {
Logging.always.info("=> Event", event)
this.event = event
let {
event: paymentEvent,
data: { id, status, counterparty_id, ledger_transaction_id, current_return: { code } },
hash,
} = event.body
this.counterpartyId = counterparty_id
this.ledgerTransactionId = ledger_transaction_id
this.bodyHash = hash
// 1. Check if the call is authorized
this.isAuthorized()
// 2. Handle payments statuses change
if (PaymentOrderStatus.FailingStatuses.includes(status)) {
Logging.always.info("=> Payment failed")
await this.handlePaymentFailure(status)
} else if (PaymentOrderStatus.SuccessfulStatuses.includes(status)) {
Logging.always.info("=> Payment Succeeded")
await this.handlePaymentSuccessful()
} else if (PaymentOrderStatus.ProcessingStatuses.includes(status)) {
Logging.always.info("=> Payment is processing")
await this.handlePaymentProcessing()
} else {
Logging.always.info("=> Payment State Not Determined")
throw new ServerError("Payment State Not Determined", IServerError.InternalServerError, event)
}
return {
isBase64Encoded: false,
statusCode: 200,
headers: APIHeaders.default,
body: null,
}
}
private async handlePaymentFailure(paymentOrderStatus: string, code) {
const { clientUser, ledgerTransaction } = await this.getClientUserAndTransaction()
Logging.always.log("=> handlePaymentFailure", { clientUser, ledgerTransaction })
const failedInvestmentType = PaymentOrderStatus.mapToFailedInvestmentType(code)
const failedInvestment = new FailedInvestment(
clientUser.data,
ledgerTransaction,
this.event.body.data,
failedInvestmentType,
)
await failedInvestment.remove()
}
private async handlePaymentProcessing() {
if (this.ledgerTransactionId) {
const { clientUser, ledgerTransaction } = await this.getClientUserAndTransaction()
Logging.always.log("=> handlePaymentProcessing", { clientUser, ledgerTransaction })
clientUser.addBankTransaction(ledgerTransaction)
await this.userRepository.updateUser(clientUser.data)
}
}
private async handlePaymentSuccessful() {}
private isAuthorized() {
if (this.event.headers["x-signature"] !== this.bodyHash) {
Logging.always.info("=> x-signature", this.event.headers["x-signature"])
Logging.always.info("=> event.body", this.event.body)
return {
isBase64Encoded: false,
statusCode: 401,
headers: APIHeaders.default,
body: null,
}
}
}
private async getClientUserAndTransaction() {
const [clientUser, ledgerTransaction] = await Promise.all([
this.userRepository.getUserFromCounterpartyId(this.counterpartyId),
this.mtService.getLedgerTransaction(this.ledgerTransactionId),
])
return {
clientUser: new ClientUser(clientUser),
ledgerTransaction,
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment