GENERALBYTESCOM / batm_public

BATM Public Repository
www.generalbytes.com
Other
98 stars 241 forks source link

How to add different Transaction Listener's for different Cryptocurrency #765

Open mxicoderspl opened 2 years ago

mxicoderspl commented 2 years ago

I added Transaction Listeners for some Crypto Currencies with reference to the Transaction extension.

But I got the issue that if I restrict any one currencies listener that restriction will apply to all other currencies in which transaction listener is added.

So how i can create different transaction listeners for every different cryptocurrency?

This is how i implemented the transaction Listener:-

@Override public void init(IExtensionContext ctx) { super.init(ctx); this.context_1 = ctx; }

@Override public boolean isTransactionPreparationApproved(ITransactionPreparation preparation) { return true; //approve all transactions }

@Override public boolean isTransactionApproved(ITransactionRequest transactionRequest) { if(Objects.equals(transactionRequest.getCryptoAmount(), new BigDecimal(1))) { return true; } else { return false; } }

@Override public OutputQueueInsertConfig overrideOutputQueueInsertConfig(ITransactionQueueRequest transactionQueueRequest, OutputQueueInsertConfig outputQueueInsertConfig) { return null; }

@Override public Map<String, String> onTransactionCreated(ITransactionDetails transactionDetails) { String terminalSerialNumber = transactionDetails.getTerminalSerialNumber(); Long previousValue = ticketCounters.get(terminalSerialNumber); Map<String, String> result = new HashMap<>(); Long value = (previousValue == null) ? 1 : (previousValue + 1); ticketCounters.put(terminalSerialNumber, value); result.put("ticket.counter", "" + value); log.info("Ticket Counter"+ value); result.put("ticket.previous.counter", ( (previousValue == null) ? "N/A" : "" + previousValue ) ); //result will be stored into database, linked to transdaction record and later be available in ticket template under key ticket.previous.counter if(transactionDetails.getStatus() == 1){ context_1.addTransactionListener(this); log.info("The mail address is:- "+transactionDetails.getCryptoAddress()); try{ log.info("Sending the mail"); EmailProviderForVoucher.sendEmailForBuyVoucher(context_1,transactionDetails.getCryptoAddress(),transactionDetails,locale); }catch(Exception e){ e.printStackTrace(); } } return result; }

@Override public Map<String, String> onTransactionUpdated(ITransactionDetails transactionDetails) { Map<String, String> result = new HashMap<>(); result.put("last.updated.at", "" + System.currentTimeMillis()); log.info("The mail address is:- "+transactionDetails.getCryptoAddress()); return result; }

@Override public void receiptSent(IReceiptDetails receiptDetails) { log.info("Extension - receipt sent from {} - phone: {}, email: {}", receiptDetails.getTerminalSerialNumber(), receiptDetails.getCellphone(), receiptDetails.getEmail()); }

pvyhnal-generalbytes commented 2 years ago

hi, in your listener you can return different results based on the crypto currency of the current transaction, see com.generalbytes.batm.server.extensions.ITransactionRequest#getCryptoCurrency, com.generalbytes.batm.server.extensions.ITransactionDetails#getCryptoCurrency etc. Would that resolve your issue?

mxicoderspl commented 1 year ago

Hello @pvyhnal-generalbytes, I am using com.generalbytes.batm.server.extensions.ITransactionRequest.isTransactionApproved method for restricting the transactions. For example, if a particular ATM has distributed 1 BTC, then for that day, users cannot buy BTC from that ATM. When users attempt the transaction, the ATM will accept the banknotes but immediately display an error message stating 'Processing transaction failed.' We want to ensure that if the provided limit is reached for any cryptocurrency, the ATM will not accept the banknotes and will directly decline the transaction, similar to when a user reaches their AML (Anti-Money Laundering) limits.

pvyhnal-generalbytes commented 1 year ago

Hi, try using com.generalbytes.batm.server.extensions.ExtensionContext#isTransactionPreparationApproved instead of com.generalbytes.batm.server.extensions.ExtensionContext#isTransactionApproved

mxicoderspl commented 1 year ago

Thank you @pvyhnal-generalbytes, I tried this but this always throws NullPointerException for transactionPreparation.getCashAmount() so how to resolve it because I am using this for checking the limits. Below is the code which throws the exception:-

`private final Map<String,Double> atmPerDayLimitsInEUR = new HashMap<>(); private final Map<String,Double> atmPerDayLimitsInPieces = new HashMap<>();

public void fillLimitsHashmap(){ List allTerminals = context.findAllTerminals(); for(ITerminal terminalDetail: allTerminals){ atmPerDayLimitsInEUR.put(terminalDetail.getSerialNumber(),100.0); atmPerDayLimitsInPieces.put(terminalDetail.getSerialNumber(),2.0); }

}

@Override public boolean isTransactionPreparationApproved(ITransactionPreparation transactionPreparation) {

    if(transactionPreparation.getCryptoCurrency().equalsIgnoreCase("VE")) {
        boolean perPieceLimitInEUR = transactionPreparation.getCashAmount().doubleValue() <= 995;
        checkAtmLimitIsUsedInPiece = atmPerDayLimitsInPieces.get(transactionPreparation.getTerminalSerialNumber()) > 0 ;
        checkAtmLimitIsUsedInEUR = transactionPreparation.getCashAmount().doubleValue() <= atmPerDayLimitsInEUR.get(transactionPreparation.getTerminalSerialNumber());

        if(transactionPreparation.getCashCurrency().equalsIgnoreCase("EUR")){
            return checkAtmLimitIsUsedInPiece && checkAtmLimitIsUsedInEUR ;
        }
        return true;
    }
    else{
    return true;
    }
}`

By checking the code u can find that we need the transactionPreparation.getCashAmount() at many places so can u please help us that how we can do this?

Thank You.

pvyhnal-generalbytes commented 1 year ago

com.generalbytes.batm.server.extensions.ITransactionPreparation#getCashAmount is not available for Buy transactions because the customer didn't insert any cash into the machine at the time this method is called.

Would this value be useful for you instead?


    /**
     * Maximum cash amount that customer can insert/sell into/to machine
     * @return
     */
    Map<String, BigDecimal> getCashTransactionLimit();
mxicoderspl commented 1 year ago

Thank you, @pvyhnal-generalbytes, for your valuable response. However, the solution you provided only allows us to check AML/KYC limits per user. Our main requirement is to set limits per ATM per day for a specific cryptocurrency.

Here's an example scenario to illustrate our concern: Let's say we store all transaction amounts per day, and we check that the amount used is 950 Euros, while our set limit for that ATM is 1000 Euros. If a user creates a transaction, they will be allowed to insert notes because that ATMs limit for that day is 950 Euros, which is below our set limit. In this case, the user could potentially insert 200 Euros and buy the cryptocurrency for that amount, which violates our condition.

We need to find a way to restrict this behavior. If we implement the restriction in com.generalbytes.batm.server.extensions.ExtensionContext#isTransactionApproved, the ATM will take the banknote, the transaction will fail, and the ATM will not return the banknote to the user.

Could you please assist me in finding a solution to this problem?

Thank you.

mxicoderspl commented 1 year ago

Hello @pvyhnal-generalbytes,

Do you have any updates on this so I can close this issue ??

Thank You