Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
28 kB
0
Indexable
package com.lwo.processing.issuingservice.util.document;

import com.lwo.processing.commonapi.bean.cache.DimensionCache;
import com.lwo.processing.commonapi.dim.dto.DimItemDto;
import com.lwo.processing.issuingservice.model.CardEntity;
import com.lwo.processing.issuingservice.model.EventEntity;
import com.lwo.processing.issuingservice.model.TransactionEntity;
import com.lwo.processing.issuingservice.repository.EventRepository;
import com.lwo.processing.issuingservice.service.CommissionService;
import com.lwo.processing.issuingservice.util.cache.IssuingServiceCache;
import com.lwo.processing.springcore.config.exception.BaseRestResponseException;
import lombok.RequiredArgsConstructor;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static org.springframework.context.i18n.LocaleContextHolder.getLocale;


@Component
@RequiredArgsConstructor
public class StatementPreparation {
    private final EventRepository eventRepository;
    private final CommissionService commissionService;
    private final IssuingServiceCache issuingServiceCache;
    private final DimensionCache<DimItemDto> dimensionCache;
    private final MessageSource messageSource;

    private static final String NO_CARD_TRANSACTIONS_KEY = "NoCardTransactions";
    private static final String ACCOUNT_STATEMENT_DATE_FORMAT = "dd.MM.yyyy";

    public Map<String, String> groupAccountTransactionsByCards(List<TransactionEntity> accountTransactions, List<TransactionEntity> financialCommissionsTransactions,
                                                        List<CardEntity> accountCards, Long accountId, ZonedDateTime startTime, ZonedDateTime endTime) {
        Map<String, String> cardTransactions = new HashMap<>();
        List<TransactionEntity> transactionsWithNoCard;
        List<EventEntity> eventsBySpecificCard;
        String stringValueOfTransactionsWithNoCard;
        List<TransactionEntity> transactionsBySpecificCard;
        List<TransactionEntity> financialCommissionsTransactionsBySpecificCard;
        String stringValueOfTransactionsBySpecificCard;
        for (CardEntity accountCard : accountCards) {
            transactionsBySpecificCard = accountTransactions.stream()
                    .filter(transaction -> Objects.equals(transaction.getCardId(), accountCard.getCardId()))
                    .toList();
            financialCommissionsTransactionsBySpecificCard = financialCommissionsTransactions.stream()
                    .filter(transaction -> Objects.equals(transaction.getCardId(), accountCard.getCardId()))
                    .toList();
            eventsBySpecificCard = eventRepository.findAllByAccountIdAndCardIdAndRequestTimeBetweenAndUnblockingTypeIdIsNullOrderByRequestTimeDesc(accountId, accountCard.getCardId(), startTime, endTime);
            stringValueOfTransactionsBySpecificCard = writeTransactionsBySpecificCardAsString(transactionsBySpecificCard, financialCommissionsTransactionsBySpecificCard,
                    eventsBySpecificCard, accountCard);
            cardTransactions.put(accountCard.getCardNumberTruncated(), stringValueOfTransactionsBySpecificCard);
        }
        transactionsWithNoCard = accountTransactions.stream()
                .filter(transaction -> transaction.getCardId() == null)
                .toList();
        stringValueOfTransactionsWithNoCard = writeTransactionsWithNoCardsString(transactionsWithNoCard);
        cardTransactions.put(NO_CARD_TRANSACTIONS_KEY, stringValueOfTransactionsWithNoCard);
        return cardTransactions;
    }

    public Map<String, String> groupTransactionsByCards(List<TransactionEntity> accountTransactions, List<TransactionEntity> financialCommissionsTransactions,
                                                         List<CardEntity> accountCards, Long accountId, ZonedDateTime startTime, ZonedDateTime endTime) {
        Map<String, String> cardTransactions = new HashMap<>();
        List<EventEntity> eventsBySpecificCard;
        List<TransactionEntity> transactionsBySpecificCard;
        List<TransactionEntity> financialCommissionsTransactionsBySpecificCard;
        String stringValueOfTransactionsBySpecificCard;
        for (CardEntity accountCard : accountCards) {
            transactionsBySpecificCard = accountTransactions.stream()
                    .filter(transaction -> Objects.equals(transaction.getCardId(), accountCard.getCardId()))
                    .toList();
            financialCommissionsTransactionsBySpecificCard = financialCommissionsTransactions.stream()
                    .filter(transaction -> Objects.equals(transaction.getCardId(), accountCard.getCardId()))
                    .toList();
            eventsBySpecificCard = eventRepository.findAllByAccountIdAndCardIdAndRequestTimeBetweenAndUnblockingTypeIdIsNullOrderByRequestTimeDesc(accountId, accountCard.getCardId(), startTime, endTime);
            stringValueOfTransactionsBySpecificCard = writeTransactionsBySpecificCardAsString(transactionsBySpecificCard, financialCommissionsTransactionsBySpecificCard,
                    eventsBySpecificCard, accountCard);
            cardTransactions.put(accountCard.getCardNumberTruncated(), stringValueOfTransactionsBySpecificCard);
        }
        System.out.println(cardTransactions);
        return cardTransactions;
    }


    public void clearCardTransaction(Map<String, String> cardTransactions) {
        List<String> emptyCardNumbers = new ArrayList<>();
        for (Map.Entry<String, String> card : cardTransactions.entrySet()) {
            if (card.getKey().equals("NoCardTransactions")) {
                continue;
            }
            String[] cardHolderNameAndTransactions = card.getValue().split("\n");
            if (cardHolderNameAndTransactions.length == 1) {
                emptyCardNumbers.add(card.getKey());
            }
        }
        for (String emptyCardNumber : emptyCardNumbers) {
            cardTransactions.remove(emptyCardNumber);
        }
    }

    public void checkPeriod(LocalDate startDate, LocalDate endDate) {
        if (startDate.isAfter(endDate)) {
            throw new BaseRestResponseException("ISSUING_37", "ISSUING_37", "ISSUING_37", messageSource.getMessage("ISSUING_37", null, getLocale()));
        }
        if (startDate.plusDays(90).isBefore(endDate)) {
            throw new BaseRestResponseException("ISSUING_38", "ISSUING_38", "ISSUING_38", messageSource.getMessage("ISSUING_38", null, getLocale()));
        }
    }


    private String writeTransactionsWithNoCardsString(List<TransactionEntity> transactionsWithNoCard) {
        StringBuilder stringValueOfTransactionsWithNoCard = new StringBuilder();
        String amount;
        String description;
        for (TransactionEntity transaction : transactionsWithNoCard) {
            amount = processAmountForCustomerReadability(transaction.getAmount());
            description = Objects.nonNull(transaction.getDescription()) ? transaction.getDescription() : "";
            stringValueOfTransactionsWithNoCard
                    .append(transaction.getBusinessDate().format(DateTimeFormatter.ofPattern(ACCOUNT_STATEMENT_DATE_FORMAT)))
                    .append("|")
                    .append(amount)
                    .append("|")
                    .append(description)
                    .append("\n");
        }
        return stringValueOfTransactionsWithNoCard.toString();
    }

    private String writeTransactionsBySpecificCardAsString(List<TransactionEntity> transactionsBySpecificCard, List<TransactionEntity> commissionsTransactionsBySpecificCard,
                                                           List<EventEntity> eventsBySpecificCard, CardEntity specificCard) {
        StringBuilder stringValueOfTransactionsBySpecificCard = new StringBuilder();
        stringValueOfTransactionsBySpecificCard.append(specificCard.getPrintedName()).append("\n");
        /*
        String amount;
        String notFormattedDateTime;
        String formattedDateTime;
        String description;
        for (TransactionEntity transaction : transactionsBySpecificCard) {
            amount = processAmountForCustomerReadability(transaction.getAmount());
            if (Objects.nonNull(transaction.getTransactionDate())) {
                if (Objects.nonNull(transaction.getTransactionDate().get("Date")) && Objects.nonNull(transaction.getTransactionDate().get("Time"))) {
                    notFormattedDateTime = String.valueOf(transaction.getTransactionDate().get("Date")).concat(String.valueOf(transaction.getTransactionDate().get("Time")));
                    formattedDateTime = formatDateAndTime(notFormattedDateTime);
                } else {
                    formattedDateTime = "";
                }
            } else {
                formattedDateTime = "";
            }
            description = Objects.nonNull(transaction.getDescription()) ? transaction.getDescription() : "";

            stringValueOfTransactionsBySpecificCard
                    .append(transaction.getTransactionTime().format(DateTimeFormatter.ofPattern(ACCOUNT_STATEMENT_DATE_FORMAT)))
                    .append("|")
                    .append(amount)
                    .append("|")
                    .append(formattedDateTime)
                    .append("|")
                    .append(description)
                    .append("\n");
        }

         */
        String iterator;
        String procDate;
        String status;
        String transactionDateTime;
        String description;
        String mcc;
        String place;
        String rrn;
        String authCode;
        String currency;
        String currencyAmount;
        String commission;
        String amount;

        List<Long> commissionsTransactionTypes = commissionService.getCommissionTransactionTypes()
                .stream()
                .map(DimItemDto::getDimId)
                .collect(Collectors.toList());

        List<ZonedDateTime> transactionDates = transactionsBySpecificCard.stream().map(TransactionEntity::getTransactionTime).toList();
        List<ZonedDateTime> eventDates = eventsBySpecificCard.stream().map(EventEntity::getRequestTime).toList();
        List<ZonedDateTime> allDates = new ArrayList<>();
        eventDates = eventDates.stream().sorted(Comparator.reverseOrder()).distinct().collect(Collectors.toList());
        transactionDates = transactionDates.stream().sorted(Comparator.reverseOrder()).distinct().collect(Collectors.toList());

        allDates.addAll(eventDates);
        allDates.addAll(transactionDates);

//        allDates = allDates.stream().sorted(Comparator.reverseOrder()).distinct().collect(Collectors.toList());
        //DimItemDto nonFinFeeDimDimension = dimensionCache.dimCodeToItem("TRANSACTION_TYPE", "NONFIN_FEE");

        int iteratorValue = 0;
        for (ZonedDateTime date : allDates) {
            List<TransactionEntity> transactionsByDate = transactionsBySpecificCard.stream().filter(transaction -> transaction.getTransactionTime().isEqual(date)).toList();
            List<EventEntity> eventsByDate = eventsBySpecificCard.stream().filter(event -> event.getRequestTime().isEqual(date)).toList();

            for (TransactionEntity transaction : transactionsByDate) {
                List<TransactionEntity> commissionsByTransaction = commissionsTransactionsBySpecificCard.stream()
                        .filter(commissionTransaction -> transaction.getTransactionId().equals(commissionTransaction.getMainTransactionId()))
                        .collect(Collectors.toList());
                iteratorValue++;
                stringValueOfTransactionsBySpecificCard.append(generateStatementByTransaction(iteratorValue, transaction, commissionsTransactionTypes));
                if (!commissionsByTransaction.isEmpty())
                    for (TransactionEntity commissionTransaction : commissionsByTransaction) {
                        stringValueOfTransactionsBySpecificCard.append(generateStatementByTransaction(null, commissionTransaction, commissionsTransactionTypes));
                    }
            }

            for (EventEntity event : eventsByDate) {
                iteratorValue++;
                iterator = String.valueOf(iteratorValue);
                procDate = "";
                status = "ЗАБЛОКИРОВАНА";
                /*nonFormattedTransactionDateTime = String.valueOf(event.getRequestTime());
                transactionDateTime = formatDateAndTime(nonFormattedTransactionDateTime);*/
                transactionDateTime = event.getRequestTime().format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"));

                description = "";
                if (Objects.nonNull(event.getMsgType()) && Objects.nonNull(event.getFld003())) {
                    Integer isReversal;
                    if (event.getMsgType().startsWith("14")) {
                        isReversal = 1;
                    } else {
                        isReversal = 0;
                    }

                    DimItemDto eventTransactionType = issuingServiceCache.getTransactionTypeByProcCodeAndReversalAttr(
                            event.getFld003().substring(0, 2),
                            isReversal
                    );

                    if (Objects.nonNull(eventTransactionType)) {
                        description = eventTransactionType.getName();
                    }
                }

                BigDecimal eventAmountSign = getAmountSign(event);

                if (Objects.nonNull(event.getEventData())) {
                    if (Objects.nonNull(event.getEventData().get("fld026"))) {
                        mcc = (String) event.getEventData().get("fld026");
                    } else {
                        mcc = "";
                    }
                } else {
                    mcc = "";
                }
                if (Objects.nonNull(event.getEventData())) {
                    if (Objects.nonNull(event.getEventData().get("fld043"))) {
                        place = (String) event.getEventData().get("fld043");
                    } else {
                        place = "";
                    }
                } else {
                    place = "";
                }
                if (Objects.nonNull(event.getEventData())) {
                    if (Objects.nonNull(event.getEventData().get("fld037"))) {
                        rrn = (String) event.getEventData().get("fld037");
                    } else {
                        rrn = "";
                    }
                } else {
                    rrn = "";
                }
                if (Objects.nonNull(event.getEventData())) {
                    if (Objects.nonNull(event.getEventData().get("fld038"))) {
                        authCode = (String) event.getEventData().get("fld038");
                    } else {
                        authCode = "";
                    }
                } else {
                    authCode = "";
                }
                DimItemDto eventTransactionCurrency = null;
                if (Objects.nonNull(event.getEventData())) {
                    if (Objects.nonNull(event.getEventData().get("fld049"))) {
                        eventTransactionCurrency = issuingServiceCache.getCurrencyByNumericCode(event.getEventData().get("fld049").toString());
                        currency = eventTransactionCurrency.getCode();
                    } else {
                        currency = "";
                    }
                } else {
                    currency = "";
                }
                if (Objects.nonNull(event.getEventData())) {
                    if (Objects.nonNull(event.getEventData().get("fld004"))) {
                        Integer exponent = eventTransactionCurrency.getAttributes().get("EXPONENT").getIntValue();
                        BigDecimal eventAmountWithExponent = new BigDecimal(event.getEventData().get("fld004").toString())
                                .movePointLeft(exponent)
                                .setScale(exponent, RoundingMode.HALF_UP);
                        eventAmountWithExponent = eventAmountWithExponent.multiply(eventAmountSign);
                        currencyAmount = processAmountForCustomerReadability(eventAmountWithExponent);
                    } else {
                        currencyAmount = "";
                    }
                } else {
                    currencyAmount = "";
                }
                commission = "";
                if (Objects.nonNull(event.getEventData())) {
                    if (Objects.nonNull(event.getEventData().get("fld006"))) {
                        DimItemDto eventCurrency = issuingServiceCache.getCurrencyByNumericCode(event.getEventData().get("fld051").toString());
                        Integer exponent = eventCurrency.getAttributes().get("EXPONENT").getIntValue();
                        BigDecimal eventAmount = new BigDecimal(event.getEventData().get("fld006").toString())
                                .movePointLeft(exponent)
                                .setScale(exponent, RoundingMode.HALF_UP);
                        eventAmount = eventAmount.multiply(eventAmountSign);
                        amount = processAmountForCustomerReadability(eventAmount);
                    } else {
                        amount = "";
                    }
                } else {
                    amount = "";
                }
                stringValueOfTransactionsBySpecificCard
                        .append(iterator)
                        .append("|")
                        .append(procDate)
                        .append("|")
                        .append(status)
                        .append("|")
                        .append(transactionDateTime)
                        .append("|")
                        .append(description)
                        .append("|")
                        .append(mcc)
                        .append("|")
                        .append(place)
                        .append("|")
                        .append(rrn)
                        .append("|")
                        .append(authCode)
                        .append("|")
                        .append(currency)
                        .append("|")
                        .append(currencyAmount)
                        .append("|")
                        .append(commission)
                        .append("|")
                        .append(amount)
                        .append("\n");
            }
        }

        return stringValueOfTransactionsBySpecificCard.toString();
    }

    private String generateStatementByTransaction(Integer iteratorValue, TransactionEntity transaction, List<Long> commissionTransactionsTypes) {
        String status;
        String nonFormattedTransactionDateTime;
        String rrn;
        String transactionDateTime;
        String commission;
        String place;
        String description;
        String amount;
        String procDate;
        String mcc;
        String currency;
        String iterator;
        String authCode;
        String currencyAmount;
        iterator = iteratorValue != null ? String.valueOf(iteratorValue) : "";
        if (Objects.nonNull(transaction.getTransactionDate())) {
            //if (Objects.nonNull(transaction.getTransactionDate().get("Date"))) {
            // nonFormattedProcDate = String.valueOf(transaction.getTransactionDate().get("Date"));
            procDate = transaction.getBusinessDate().format(DateTimeFormatter.ofPattern("dd.MM.yyyy"));
            //}
        } else {
            procDate = "";
        }
        status = "ПРОВЕДЕНА";
        if (Objects.nonNull(transaction.getTransactionDate())) {
            if (Objects.nonNull(transaction.getTransactionDate().get("Date")) && Objects.nonNull(transaction.getTransactionDate().get("Time"))) {
                nonFormattedTransactionDateTime = String.valueOf(transaction.getTransactionDate().get("Date")).concat(String.valueOf(transaction.getTransactionDate().get("Time")));
                transactionDateTime = formatDateAndTime(nonFormattedTransactionDateTime);
            } else {
                transactionDateTime = "";
            }
        } else {
            transactionDateTime = "";
        }
        if (!commissionTransactionsTypes.contains(transaction.getTransactionTypeId())) {
            description = Objects.nonNull(transaction.getDescription()) ? transaction.getDescription() : "";
        } else {
            description = dimensionCache.dimIdToItem(Long.valueOf((Integer) transaction.getTransactionDate().get("FEE_commission_LCIS_code_id"))).getName();
        }
        if (Objects.nonNull(transaction.getTransactionDate())) {
            if (Objects.nonNull(transaction.getTransactionDate().get("MCC_code"))) {
                mcc = (String) transaction.getTransactionDate().get("MCC_code");
            } else {
                mcc = "";
            }
        } else {
            mcc = "";
        }
        if (Objects.nonNull(transaction.getTransactionDate())) {
            if (Objects.nonNull(transaction.getTransactionDate().get("Abvr_name"))) {
                place = (String) transaction.getTransactionDate().get("Abvr_name");
            } else {
                place = "";
            }
        } else {
            place = "";
        }
        if (Objects.nonNull(transaction.getTransactionDate())) {
            if (Objects.nonNull(transaction.getTransactionDate().get("Ref_number"))) {
                rrn = (String) transaction.getTransactionDate().get("Ref_number");
            } else {
                rrn = "";
            }
        } else {
            rrn = "";
        }
        if (Objects.nonNull(transaction.getTransactionDate())) {
            if (Objects.nonNull(transaction.getTransactionDate().get("Appr_code"))) {
                authCode = (String) transaction.getTransactionDate().get("Appr_code");
            } else {
                authCode = "";
            }
        } else {
            authCode = "";
        }
        if (Objects.nonNull(transaction.getTransactionDate())) {
            if (Objects.nonNull(transaction.getTransactionDate().get("Currency"))) {
                currency = (String) transaction.getTransactionDate().get("Currency");
            } else {
                currency = "";
            }
        } else {
            currency = "";
        }
        if (Objects.nonNull(transaction.getTransactionDate())) {
            if (Objects.nonNull(transaction.getTransactionDate().get("Amount")) && Objects.nonNull(transaction.getTransactionDate().get("Currency"))) {
                currencyAmount = processCurrencyAmount(transaction.getTransactionDate().get("Amount").toString(), dimensionCache.dimCodeToItem("CURRENCY", currency).getAttributes().get("EXPONENT").getIntValue());
                currencyAmount = processAmountForCustomerReadability(currencyAmount, dimensionCache.dimIdToItem(transaction.getTransactionTypeId()));
            } else {
                currencyAmount = "";
            }
        } else {
            currencyAmount = "";
        }
        commission = "";
        amount = "";
        if (commissionTransactionsTypes.contains(transaction.getTransactionTypeId())) {
            commission = processAmountForCustomerReadability(transaction.getAmount());
        } else {
            amount = processAmountForCustomerReadability(transaction.getAmount());
        }
        return iterator +
                "|" + procDate +
                "|" + status +
                "|" + transactionDateTime +
                "|" + description +
                "|" + mcc +
                "|" + place +
                "|" + rrn +
                "|" + authCode +
                "|" + currency +
                "|" + currencyAmount +
                "|" + commission +
                "|" + amount +
                "|" + "end" + "\n";
    }

    private String processCurrencyAmount(String amount, Integer exponent) {
        BigDecimal bdAmount = new BigDecimal(amount);
        bdAmount = bdAmount.setScale(exponent, RoundingMode.HALF_UP);
        return bdAmount.toString();
    }

    private String processAmountForCustomerReadability(String amount, DimItemDto transactionType) {
        if (transactionType.getAttributes().containsKey("DEBIT_CREDIT")){
            if ("C".equals(transactionType.getAttributes().get("DEBIT_CREDIT").getStringValue())) {
                return amount + "+";
            } else if ("D".equals(transactionType.getAttributes().get("DEBIT_CREDIT").getStringValue())) {
                return amount + "-";
            } else {
                return "";
            }
        } else {
            return "";
        }
    }
    private String formatDateAndTime(String notFormattedDateTime) {
        DateTimeFormatter toStringParser = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss");
        DateTimeFormatter toDateParser = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        ZonedDateTime dateValue;
        try {
            dateValue = LocalDateTime.parse(notFormattedDateTime, toDateParser).atZone(ZoneId.systemDefault());
        } catch (Exception e) {
            dateValue = ZonedDateTime.of(LocalDate.parse(notFormattedDateTime, toDateParser), LocalTime.MIN, ZoneId.systemDefault());
        }
        return dateValue.format(toStringParser);
    }

    private BigDecimal getAmountSign(EventEntity event) {
        if (event.getMsgType().startsWith("11")) {
            if (event.getFld003().startsWith("00") || event.getFld003().startsWith("01") || event.getFld003().startsWith("10") || event.getFld003().startsWith("11")) {
                return BigDecimal.ONE.negate();
            } else if (event.getFld003().startsWith("21") || event.getFld003().startsWith("26")) {
                return BigDecimal.ONE;
            } else {
                return BigDecimal.ONE;
            }
        } else if (event.getMsgType().startsWith("14")) {
            if (event.getFld003().startsWith("21") || event.getFld003().startsWith("26")) {
                return BigDecimal.ONE.negate();
            } else if (event.getFld003().startsWith("00") || event.getFld003().startsWith("01") || event.getFld003().startsWith("10") || event.getFld003().startsWith("11")) {
                return BigDecimal.ONE;
            } else {
                return BigDecimal.ONE;
            }
        } else {
            return BigDecimal.ONE;
        }
    }

    private String processAmountForCustomerReadability(BigDecimal amount) {
        if (amount.toString().startsWith("-")) {
            return amount.toString().replaceAll("-", "").concat("-");
        }
        return amount.toString().concat("+");
    }


}