Untitled

mail@pastecode.io avatar
unknown
plain_text
5 months ago
5.4 kB
10
Indexable
public abstract class AbstractBatchTransactionService<T extends BatchTransaction> {

    private final AccountService accountService;
    private final CardPropertyConfig cardPropertyConfig;
    private final MJSHelperImpl mjsHelper;
    private static final String TRANSACTION_NARRATION_FORMAT = "Transaction from %s to %s";

    protected AbstractBatchTransactionService(AccountService accountService, CardPropertyConfig cardPropertyConfig, MJSHelperImpl mjsHelper) {
        this.accountService = accountService;
        this.cardPropertyConfig = cardPropertyConfig;
        this.mjsHelper = mjsHelper;
    }

    protected abstract TransactionRepository<T> getTransactionRepository();

    protected T createTransaction(T transaction, long amount) {
        transaction.setAmount(amount);
        return getTransactionRepository().save(transaction);
    }

    protected TransactionStatus handlePayment(T transaction, String sourceAccount, String destinationAccount, boolean forceDebit) {
        try {
            WalletTransactionResponse walletTransactionResponse = debitWallet(sourceAccount, destinationAccount, transaction.getAmount(), transaction.getTransactionReference(), forceDebit);

            if (isTransactionFailed(walletTransactionResponse)) {
                handleTransactionFailure(transaction, walletTransactionResponse);
                handleReversalForFailure(transaction, walletTransactionResponse);
                return TransactionStatus.FAILED;
            }

            updateTransactionForSuccess(transaction, walletTransactionResponse);
            return TransactionStatus.COMPLETED;
        } catch (Exception ex) {
            log.error("Error during debit: {}", ex.getMessage(), ex);
            return TransactionStatus.FAILED;
        }
    }

    protected void processReversalResult(T transaction, WalletTransactionResponse reverseTransactionResponse) {
        transaction.setReversalResponseBody(convertToJsonString(reverseTransactionResponse));
        transaction.setCbaReversalCode(reverseTransactionResponse.getResponseCode());

        if (TransactionResponseCode.SUCCESS.getCode().equalsIgnoreCase(reverseTransactionResponse.getResponseCode())) {
            transaction.setReversed(Boolean.TRUE);
            transaction.setShouldBeReversed(Boolean.FALSE);
        } else {
            transaction.setReversed(Boolean.FALSE);
        }
    }

    protected void handleTransactionFailure(T transaction, WalletTransactionResponse response) {
        transaction.setResponseMessage(PostilionResponse.getDescription(response.getResponseCode()));
        transaction.setResponseCode(response.getResponseCode());
        transaction.setStatus(TransactionStatus.FAILED);
        getTransactionRepository().save(transaction);
    }

    protected void handleReversalForFailure(T transaction, WalletTransactionResponse walletTransactionResponse) {
        if (PostilionResponse._96.getCode().equalsIgnoreCase(walletTransactionResponse.getResponseCode())) {
            mjsHelper.createBackOffNewJob(
                    MJSJobType.CARD_BATCH_TRANSACTION_PROCESS,
                    transaction.getTransactionReference(),
                    cardPropertyConfig.getReversalDeferRetries(),
                    TimeUtil.addMinutesToTimestamp(TimeUtil.getCurrentTimestamp(), 1)
            );
        }
    }

    private WalletTransactionResponse debitWallet(String sourceAccountNumber, String destinationAccountNumber, long debitAmount, String transactionReference, boolean forceDebit) {
        String narration = String.format(TRANSACTION_NARRATION_FORMAT, Util.maskAccountNumber(sourceAccountNumber), Util.maskAccountNumber(destinationAccountNumber));

        DebitAccountRequest debitAccountRequest = DebitAccountRequest.builder()
                .sourceAccountNumber(sourceAccountNumber)
                .destinationAccountNumber(destinationAccountNumber)
                .transactionReference(transactionReference)
                .amount(debitAmount)
                .transactionAmount(debitAmount)
                .narration(narration)
                .useLedgerAccount(Boolean.TRUE)
                .forceDebit(forceDebit)
                .transactionType(MonnifyTransactionType.CARD_BATCH_TRANSACTION)
                .build();

        return accountService.debitAccount(debitAccountRequest);
    }

    private void updateTransactionForSuccess(T transaction, WalletTransactionResponse walletTransactionResponse) {
        transaction.setShouldBeReversed(Boolean.FALSE);
        transaction.setReversed(Boolean.TRUE);
        transaction.setReversalResponseBody(convertToJsonString(walletTransactionResponse));
        transaction.setResponseBody(convertToJsonString(walletTransactionResponse));
        transaction.setResponseCode(walletTransactionResponse.getResponseCode());
        transaction.setResponseMessage(walletTransactionResponse.getResponseMessage());
        transaction.setStatus(TransactionStatus.COMPLETED);
        getTransactionRepository().save(transaction);
    }

    private boolean isTransactionFailed(WalletTransactionResponse walletTransactionResponse) {
        return !"00".equalsIgnoreCase(walletTransactionResponse.getResponseCode());
    }

    private String convertToJsonString(Object object) {
        // Use Gson or Jackson to convert object to JSON string
        return new Gson().toJson(object);
    }
}
Leave a Comment