You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
UCO-BS/src/main/java/com/mfsys/uco/service/TransactionService.java

444 lines
25 KiB
Java

package com.mfsys.uco.service;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mfsys.comm.util.MapValueExtractorUtil;
import com.mfsys.uco.UCOURI;
import com.mfsys.uco.dto.*;
import com.mfsys.uco.dto.Transaction.TransactionOtpRequestModel;
import com.mfsys.uco.exception.*;
import com.mfsys.uco.model.*;
import com.mfsys.uco.repository.CustomerProfileRepository;
import com.mfsys.uco.repository.GLAccountMasterTransactionTrailRepository;
import com.mfsys.uco.repository.PinRepository;
import com.mfsys.uco.repository.TransactionTrailRepository;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Currency;
import java.util.*;
@Service
@Data
@RequiredArgsConstructor
public class TransactionService {
private final CustomerProfileRepository customerProfileRepository;
private final NotificationService notificationService;
private final TransactionPinService transactionPinService;
private final TransactionTrailRepository transactionTrailRepository;
private final PinRepository pinRepository;
private final UcoAccountService ucoAccountService;
private final WebClientDepositService webClientDepositService;
private final GLAccountMasterTransactionTrailRepository glAccountMasterTransactionTrailRepository;
public TransactionPinResponseModel sendOtpAndValidateTranPin(TransactionOtpRequestModel transactionOtpRequestModel, boolean isResendOtp) {
CustomerProfile customerProfile = verifyOldPinAndGetCmpProfile(transactionOtpRequestModel.getPorOrgacode(), transactionOtpRequestModel.getTransPincode(), transactionOtpRequestModel.getCmpCustcode(), isResendOtp);
Long notificationId = transactionPinService.sendOtp(customerProfile, transactionOtpRequestModel.getChannelCode(), transactionOtpRequestModel.getPinType(), "Transaction Verification OTP", transactionOtpRequestModel.isOtpRequired());
Pin pin = pinRepository.findLatestActiveOtpByUserName(transactionOtpRequestModel.getEmail(), transactionOtpRequestModel.getPinType())
.orElseThrow(()->new TranVerificationPinException());
return TransactionPinResponseModel.builder()
.notificationId(notificationId)
.obpPincode(pin.getPincode())
.pinCreation(pin.getPinCreatedate())
.pinExpiry(pin.getPinExpirydate())
.build();
}
public Map<String, Object> cashInTransaction(CashInTransactionRequest transactionRequest) {
if(transactionRequest.getSgtGntramtfc()<=0){
throw new InvalidTransactionAmountException();
}
validation(transactionRequest);
TransactionTrail transactionTrail = TransactionTrail.builder()
.porOrgacode(transactionRequest.getPorOrgacode())
.drMbmBkmsnumber(transactionRequest.getDrMbmBkmsnumber())
.crMbmBkmsnumber(transactionRequest.getCrMbmBkmsnumber())
.dmpProdcode(transactionRequest.getDmpProdCode())
.drmbmBkmstitle(transactionRequest.getDrMbmBkmstitle())
.drpcrCurrdesc(transactionRequest.getDrPcrCurrdesc())
.drPcrCurrshort(transactionRequest.getDrPcrCurrshort())
.cmpCustcode(transactionRequest.getCmpCustcode())
.drPcrCurrcode(transactionRequest.getDrPcrCurrcode())
.crMbmBkmstitle(transactionRequest.getCrMbmBkmstitle())
.drSgtGntramt(BigDecimal.valueOf(convertToPKR(transactionRequest.getDrPcrCurrcode(),transactionRequest.getSgtGntramtfc(), transactionRequest.getPorOrgacode())))
.crSgtGntramt(null)
.crPcrCurrdesc(transactionRequest.getCrPcrCurrdesc())
.crPcrCurrcode(transactionRequest.getCrPcrCurrcode())
.crPcrCurrshort(transactionRequest.getCrPcrCurrshort())
.sgtSentGntrnumber(null)
.drSgtGntrdate(LocalDate.now())
.sgtGntramt(BigDecimal.valueOf(transactionRequest.getSgtGntramtfc()))
.batAcnttranSend(false)
.batAcnttranReceived(false)
.sgtReceiveGntrnumber(null)
.build();
CoreCashInTransaction coreCashInTransaction = CoreCashInTransaction.builder()
.drMbmBkmsnumber(transactionRequest.getDrMbmBkmsnumber())
.drPcrCurrcode(transactionTrail.getDrPcrCurrcode())
.accSgtGntramtfc(transactionRequest.getSgtGntramtfc())
.sgtGntramtfc(transactionTrail.getCrSgtGntramt())
.otdTrancomment(transactionRequest.getOtdTrancomment())
.porOrgacode(transactionRequest.getPorOrgacode())
.pcaGlaccode("A01011003")
.build();
Map<String, Object> response = (Map<String, Object>) webClientDepositService.postTransaction(coreCashInTransaction, UCOURI.BANKING_CASH_IN, transactionRequest.getPorOrgacode());
transactionTrail.setSgtSentGntrnumber(String.valueOf(response.get("tran_id")));
transactionTrail.setSgtSentNodeId(String.valueOf(response.get("node_id")));
transactionTrail.setBatAcnttranSend(true);
if(Objects.nonNull(transactionRequest.getCmpRefcode())) {
transactionTrail.setCmpRefcode(transactionTrail.getSgtSentGntrnumber() + transactionRequest.getCmpRefcode());
}
transactionTrail.setDrMbmBkmsbalance(MapValueExtractorUtil.getValueAsBigDecimal(response, "mbmBkmsbalance"));
transactionTrailRepository.save(transactionTrail);
return response;
}
private void validation(CashInTransactionRequest transactionRequest) {
if (transactionRequest.getCrMbmBkmsnumber().equals(transactionRequest.getDrMbmBkmsnumber())) {
throw new SameCrDrAccountExistsException();
}
notificationService.verifyOtpViaOtpId(transactionRequest.getNotificationId(), transactionRequest.getPinType(), transactionRequest.getObpPincode());
}
public List<TransactionTrail> fetchPendingCrTransactions(String porOrgacode, String mbmBkmsnumber) {
List<TransactionTrail> transactionTrails = findPendingCrTransactions(porOrgacode,mbmBkmsnumber);
if(!transactionTrails.isEmpty()){
transactionTrails.stream().forEach(t -> {
LocalDate datePlus14Days = t.getDrSgtGntrdate().plusDays(14);
t.setExpSgtGntrdate((datePlus14Days.minusDays(ChronoUnit.DAYS.between(LocalDate.now(),datePlus14Days))));
t.setDaysToExpire(Math.toIntExact(ChronoUnit.DAYS.between(LocalDate.now(), datePlus14Days)));
});
}
return transactionTrails;
}
public List<TransactionTrail> findPendingCrTransactions(String porOrgacode , String mbmBkmsnumber)
{
Optional<List<TransactionTrail>> optionalTransactions = transactionTrailRepository.findByPorOrgacodeAndCrMbmBkmsnumberAndBatAcnttranReceivedFalse(porOrgacode, mbmBkmsnumber);
return optionalTransactions.orElseGet(Collections::emptyList);
}
public List<TransactionTrail> fetchDepositAccountStatement(String porOrgacode, String mbmBkmsnumber) {
Optional<List<TransactionTrail>> optionalTransactions = transactionTrailRepository.fetchDepositAccountStatement(mbmBkmsnumber);
return optionalTransactions.orElseGet(Collections::emptyList);
}
public Map<String, Object> cashOutTransaction(CashOutTransactionRequest cashOutTransactionRequest) {
verifyOldPinAndGetCmpProfile(cashOutTransactionRequest.getPorOrgacode(),
cashOutTransactionRequest.getCmpTranpin(), cashOutTransactionRequest.getCmpCustcode(), true);
Map<String, Object> response = new HashMap<>();
Optional<TransactionTrail> transactionTrail = transactionTrailRepository.findById(Math.toIntExact(cashOutTransactionRequest.getId()));
if (transactionTrail.isPresent()) {
if(Objects.nonNull(cashOutTransactionRequest.getCmpRefcode())) {
if (!(transactionTrail.get().getSgtSentGntrnumber() + cashOutTransactionRequest.getCmpRefcode()).equals(transactionTrail.get().getCmpRefcode())) {
throw new ReferenceNumberNotValidException();
}
}
transactionTrail.get().setCrSgtGntramt(BigDecimal.valueOf(convertFromPKR(transactionTrail.get().getCrPcrCurrcode(),Double.valueOf(String.valueOf(transactionTrail.get().getDrSgtGntramt())),transactionTrail.get().getPorOrgacode())));;
CoreCashOutTransaction cashOutTransaction = CoreCashOutTransaction.builder()
.crPcrCurrcode(transactionTrail.get().getCrPcrCurrcode())
.crMbmBkmsnumber(transactionTrail.get().getCrMbmBkmsnumber())
.porOrgacode(cashOutTransactionRequest.getPorOrgacode())
.otdTrancomment(cashOutTransactionRequest.getId() + "_Received")
.sgtGntramtfc(transactionTrail.get().getDrSgtGntramt())
.accSgtGntramtfc(transactionTrail.get().getCrSgtGntramt())
.pcaGlaccode("A01011003")
.build();
response = (Map<String, Object>) webClientDepositService.postTransaction(cashOutTransaction, UCOURI.BANKING_CASH_OUT, transactionTrail.get().getPorOrgacode());
transactionTrail.get().setSgtReceiveGntrnumber((String.valueOf(response.get("tran_id"))));
transactionTrail.get().setSgtSentNodeId(String.valueOf(response.get("node_id")));
transactionTrail.get().setBatAcnttranReceived(true);
transactionTrail.get().setCrMbmBkmsbalance(MapValueExtractorUtil.getValueAsBigDecimal(response, "mbmBkmsbalance"));
transactionTrailRepository.save(transactionTrail.get());
}
return response;
}
private CustomerProfile verifyOldPinAndGetCmpProfile(String porOrgacode, String transPincode, String cmpCustcode, boolean isResendOtp) {
CustomerProfile customerProfile = transactionPinService.fetchCustomer(porOrgacode,
cmpCustcode);
if (isResendOtp) {
transactionPinService.validateOldPin(customerProfile, transPincode);
}
return customerProfile;
}
private CustomerProfile fetchCustomerBasedOnCmpCustcode(String porOrgacode, String cmpCustcode) {
return customerProfileRepository.findById(new CustomerProfileId(porOrgacode, cmpCustcode))
.orElseThrow(() -> new IllegalArgumentException("Customer profile not found for ID: " + cmpCustcode));
}
private String extractTranNumber(List<Object> args) {
if (args != null && args.size() > 0) {
return String.valueOf(args.get(0)).replace("[", "").replace("]", "");
}
throw new RuntimeException("may day");
}
public EvaluatedCurrencyReponse getEvaluatedCurrency(String porOrgacode, String baseCurrencyCode, String targetCurrencyCode, double sgtGntramtfc) {
List<ExchangeRateModel> exchangeRateModelList = fetchExchangeRate(porOrgacode);
if (exchangeRateModelList == null || exchangeRateModelList.isEmpty()) {
throw new RuntimeException("No exchange rates configured for organization " + porOrgacode + ". Please configure exchange rates first.");
}
String normalizedBase = normalizeCurrencyCode(baseCurrencyCode, exchangeRateModelList);
String normalizedTarget = normalizeCurrencyCode(targetCurrencyCode, exchangeRateModelList);
double pkrAmt = convertToPKR(normalizedBase, sgtGntramtfc, porOrgacode, exchangeRateModelList);
double convertFromPkr = convertFromPKR(normalizedTarget, pkrAmt, porOrgacode, exchangeRateModelList);
Optional<Double> rate = exchangeRateModelList.stream()
.filter(x -> x.isPcrCurrbase() && currencyCodeMatches(x.getPcrCurrcode(), normalizedTarget))
.map(x -> {
BigDecimal bd = BigDecimal.valueOf(1 / x.getPerEratrateact());
bd = bd.setScale(2, RoundingMode.HALF_UP);
return bd.doubleValue();
})
.findFirst();
if (!rate.isPresent()) {
rate = exchangeRateModelList.stream()
.filter(x -> !x.isPcrCurrbase() && currencyCodeMatches(x.getPcrCurrcode(), normalizedTarget))
.map(x -> {
BigDecimal bd = BigDecimal.valueOf(x.getPerEratrateact());
bd = bd.setScale(2, RoundingMode.HALF_UP);
return bd.doubleValue();
})
.findFirst();
}
double targetPerEratrateact = rate.orElse(0.0);
return EvaluatedCurrencyReponse.builder()
.targetPerEratrateact(targetPerEratrateact)
.serviceCharges(0.0)
.pcrCurrcode(targetCurrencyCode)
.sgtGntramtfc(BigDecimal.valueOf(convertFromPkr).setScale(2, RoundingMode.HALF_UP))
.build();
}
public double convertToPKR(String fromcrCurrcode, double amount, String porOrgacode) {
List<ExchangeRateModel> exchangeRateModelList = fetchExchangeRate(porOrgacode);
return convertToPKR(fromcrCurrcode, amount, porOrgacode, exchangeRateModelList);
}
private double convertToPKR(String fromcrCurrcode, double amount, String porOrgacode, List<ExchangeRateModel> exchangeRateModelList) {
if (exchangeRateModelList == null || exchangeRateModelList.isEmpty()) {
throw new RuntimeException("No exchange rates configured for organization " + porOrgacode + ". Please configure exchange rates first.");
}
String baseCurrencyCode = exchangeRateModelList.stream()
.filter(ExchangeRateModel::isPcrCurrbase)
.findFirst()
.map(ExchangeRateModel::getPcrCurrcode)
.orElse(null);
if (currencyCodeMatches(baseCurrencyCode, fromcrCurrcode)) {
return amount;
}
return exchangeRateModelList.stream()
.filter(k -> currencyCodeMatches(k.getPcrCurrcode(), fromcrCurrcode))
.findFirst()
.map(k -> amount * k.getPerEratrateact())
.orElseThrow(() -> new RuntimeException(
"Exchange rate not found for currency " + fromcrCurrcode + " (organization: " + porOrgacode + "). Available: " + formatAvailableCurrencies(exchangeRateModelList)
));
}
public List<ExchangeRateModel> fetchExchangeRate(String porOrgacode) {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.convertValue(ucoAccountService.fetchExchangeRate(porOrgacode),
new TypeReference<List<ExchangeRateModel>>() {
});
}
public double convertFromPKR(String todrCurrcode, double amount, String porOrgacode) {
List<ExchangeRateModel> exchangeRateModelList = fetchExchangeRate(porOrgacode);
return convertFromPKR(todrCurrcode, amount, porOrgacode, exchangeRateModelList);
}
private double convertFromPKR(String todrCurrcode, double amount, String porOrgacode, List<ExchangeRateModel> exchangeRateModelList) {
if (exchangeRateModelList == null || exchangeRateModelList.isEmpty()) {
throw new RuntimeException("No exchange rates configured for organization " + porOrgacode + ". Please configure exchange rates first.");
}
String baseCurrencyCode = exchangeRateModelList.stream()
.filter(ExchangeRateModel::isPcrCurrbase)
.findFirst()
.map(ExchangeRateModel::getPcrCurrcode)
.orElse(null);
if (currencyCodeMatches(baseCurrencyCode, todrCurrcode)) {
return amount;
}
return exchangeRateModelList.stream()
.filter(k -> currencyCodeMatches(k.getPcrCurrcode(), todrCurrcode))
.findFirst()
.map(k -> amount / k.getPerEratrateact())
.orElseThrow(() -> new RuntimeException(
"Exchange rate not found for currency " + todrCurrcode + " (organization: " + porOrgacode + "). Available: " + formatAvailableCurrencies(exchangeRateModelList)
));
}
private boolean currencyCodeMatches(String storedCode, String requestedCode) {
if (requestedCode == null) return storedCode == null;
if (storedCode == null) return false;
return storedCode.trim().equals(requestedCode.trim());
}
private String normalizeCurrencyCode(String currencyCode, List<ExchangeRateModel> exchangeRates) {
if (currencyCode == null) return null;
String raw = currencyCode.trim();
if (raw.isEmpty()) return raw;
String upper = raw.toUpperCase(Locale.ROOT);
if (exchangeRates != null && exchangeRates.stream().anyMatch(r -> upper.equals(safeTrimUpper(r.getPcrCurrcode())))) {
return upper;
}
if (exchangeRates != null) {
Optional<String> byShort = exchangeRates.stream()
.filter(r -> upper.equals(safeTrimUpper(r.getPcrCurrshort())))
.map(ExchangeRateModel::getPcrCurrcode)
.filter(Objects::nonNull)
.findFirst();
if (byShort.isPresent()) {
return byShort.get();
}
}
if (upper.length() == 3 && upper.chars().allMatch(Character::isLetter)) {
try {
int numeric = Currency.getInstance(upper).getNumericCode();
String numericStr = String.valueOf(numeric);
if (exchangeRates != null && exchangeRates.stream().anyMatch(r -> numericStr.equals(safeTrimUpper(r.getPcrCurrcode())))) {
return numericStr;
}
} catch (Exception ignored) {
}
}
if (upper.chars().allMatch(Character::isDigit)) {
try {
int numeric = Integer.parseInt(upper);
for (Currency c : Currency.getAvailableCurrencies()) {
if (c.getNumericCode() == numeric) {
String alpha = c.getCurrencyCode();
if (exchangeRates != null && exchangeRates.stream().anyMatch(r -> alpha.equals(safeTrimUpper(r.getPcrCurrcode())))) {
return alpha;
}
break;
}
}
} catch (Exception ignored) {
}
}
return upper;
}
private String safeTrimUpper(String s) {
return s == null ? null : s.trim().toUpperCase(Locale.ROOT);
}
private String formatAvailableCurrencies(List<ExchangeRateModel> exchangeRates) {
if (exchangeRates == null || exchangeRates.isEmpty()) return "[]";
return exchangeRates.stream()
.map(r -> {
String shortCode = (r.getPcrCurrshort() == null || r.getPcrCurrshort().isBlank()) ? "?" : r.getPcrCurrshort().trim();
String code = (r.getPcrCurrcode() == null || r.getPcrCurrcode().isBlank()) ? "?" : r.getPcrCurrcode().trim();
return shortCode + "(" + code + ")";
})
.distinct()
.limit(20)
.toList()
.toString();
}
public Map<String, Object> glAccountTransaction(GLAccontTranasctionRequestModel glAccontTranasctionRequestModel) {
Map<String, Object> response = new HashMap<>();
if(glAccontTranasctionRequestModel.getSgtGntramtfc()<=0){
throw new InvalidTransactionAmountException();
}
notificationService.verifyOtpViaOtpId(glAccontTranasctionRequestModel.getNotificationId(),glAccontTranasctionRequestModel.getPinType(),glAccontTranasctionRequestModel.getObpPincode());
CoreCashOutTransaction cashOutTransaction = CoreCashOutTransaction.builder()
.pcaGlaccode(glAccontTranasctionRequestModel.getDrPcaGlaccode())
.crMbmBkmsnumber(glAccontTranasctionRequestModel.getCrMbmBkmsnumber())
.otdTrancomment(glAccontTranasctionRequestModel.getOtdTrancomment())
.porOrgacode(glAccontTranasctionRequestModel.getPorOrgacode())
.accSgtGntramtfc(BigDecimal.valueOf(glAccontTranasctionRequestModel.getSgtGntramtfc()))
.sgtGntramtfc(BigDecimal.valueOf(convertToPKR(glAccontTranasctionRequestModel.getCrPcrCurrcode(),glAccontTranasctionRequestModel.getSgtGntramtfc(),glAccontTranasctionRequestModel.getPorOrgacode())))
.crPcrCurrcode(glAccontTranasctionRequestModel.getCrPcrCurrcode())
.plcLocacode(glAccontTranasctionRequestModel.getPlcLocacode())
.dmpProdcode(glAccontTranasctionRequestModel.getDmpProdCode())
.build();
response = (Map<String, Object>) webClientDepositService.postTransaction(cashOutTransaction, UCOURI.BANKING_CASH_OUT, glAccontTranasctionRequestModel.getPorOrgacode());
TransactionTrail transactionTrail = TransactionTrail.builder()
.porOrgacode(glAccontTranasctionRequestModel.getPorOrgacode())
.drMbmBkmsnumber(glAccontTranasctionRequestModel.getDrPcaGlaccode())
.crMbmBkmsnumber(glAccontTranasctionRequestModel.getCrMbmBkmsnumber())
.dmpProdcode(glAccontTranasctionRequestModel.getDmpProdCode())
.drmbmBkmstitle(glAccontTranasctionRequestModel.getDrPcaGlacdesc())
.drpcrCurrdesc(glAccontTranasctionRequestModel.getCrPcrCurrdesc())
.drPcrCurrshort(glAccontTranasctionRequestModel.getCrPcrCurrshort())
.cmpCustcode(glAccontTranasctionRequestModel.getCmpCustcode())
.drPcrCurrcode(glAccontTranasctionRequestModel.getCrPcrCurrcode())
.crMbmBkmstitle(glAccontTranasctionRequestModel.getCrMbmBkmstitle())
.drSgtGntramt(BigDecimal.valueOf(glAccontTranasctionRequestModel.getSgtGntramtfc()))
.crSgtGntramt(null)
.crPcrCurrdesc(glAccontTranasctionRequestModel.getCrPcrCurrdesc())
.crPcrCurrcode(glAccontTranasctionRequestModel.getCrPcrCurrcode())
.crPcrCurrshort(glAccontTranasctionRequestModel.getCrPcrCurrshort())
.sgtSentGntrnumber((String.valueOf(response.get("tran_id"))))
.sgtSentNodeId(String.valueOf(response.get("node_id")))
.drSgtGntrdate(LocalDate.now())
.sgtGntramt(BigDecimal.valueOf(glAccontTranasctionRequestModel.getSgtGntramtfc()))
.batAcnttranSend(true)
.batAcnttranReceived(true)
.sgtReceiveGntrnumber((String.valueOf(response.get("tran_id"))))
.sgtReceiveNodeId(String.valueOf(response.get("node_id")))
.build();
transactionTrailRepository.save(transactionTrail);
GLAccountMasterTransaction glAccountMasterTransaction = GLAccountMasterTransaction.builder()
.porOrgacode(glAccontTranasctionRequestModel.getPorOrgacode())
.cmpCustcode(glAccontTranasctionRequestModel.getCmpCustcode())
.crMbmBkmsnumber(glAccontTranasctionRequestModel.getCrMbmBkmsnumber())
.crMbmBkmstitle(glAccontTranasctionRequestModel.getCrMbmBkmstitle())
.crPcrCurrcode(glAccontTranasctionRequestModel.getCrPcrCurrcode())
.crPcrCurrdesc(glAccontTranasctionRequestModel.getCrPcrCurrdesc())
.crPcrCurrshort(glAccontTranasctionRequestModel.getCrPcrCurrshort())
.drPcaGlaccode(glAccontTranasctionRequestModel.getDrPcaGlaccode())
.drPcaGlacdesc(glAccontTranasctionRequestModel.getDrPcaGlacdesc())
.dmpProdcode(glAccontTranasctionRequestModel.getDmpProdCode())
.sgtGntramt(BigDecimal.valueOf(glAccontTranasctionRequestModel.getSgtGntramtfc()))
.drSgtGntramt(BigDecimal.valueOf(glAccontTranasctionRequestModel.getSgtGntramtfc()))
.drSgtGntrdate(LocalDate.now())
.sgtSentGntrnumber(String.valueOf(response.get("node_id"))+(response.get("tran_id")))
.build();
glAccountMasterTransactionTrailRepository.save(glAccountMasterTransaction);
return response;
}
public Object reverseTransacion(String porOrgacode, String nodeId, String sgtGntrnumber) {
Object reponse = webClientDepositService.postTransaction(CoreReverseTransaction.builder().porOrgacode(porOrgacode).sgtGntrtranlink(sgtGntrnumber).nodeId(nodeId).sgtGntrcreateat("2003").build(), UCOURI.CORE_REVERSE_TRANSACTION, porOrgacode);
TransactionTrail trail = transactionTrailRepository.findByPorOrgacodeAndSgtSentNodeIdAndSgtSentGntrnumber(porOrgacode,nodeId,sgtGntrnumber);
Double balance = ucoAccountService.fetchAccountBalance(trail.getPorOrgacode(), trail.getDrMbmBkmsnumber());
trail.setBatAcnttranReversed(true);
trail.setBatAcnttranReceived(true);
trail.setDrMbmBkmsbalance(BigDecimal.valueOf(balance));
transactionTrailRepository.save(trail);
return reponse;
}
}