Skip to content

Commit

Permalink
feat : fix archunit violations
Browse files Browse the repository at this point in the history
  • Loading branch information
rajadilipkolli committed Apr 29, 2024
1 parent 7cf1358 commit 0f8efcc
Show file tree
Hide file tree
Showing 11 changed files with 161 additions and 160 deletions.
40 changes: 0 additions & 40 deletions src/main/java/com/learning/mfscreener/helper/NavSearchHelper.java

This file was deleted.

22 changes: 0 additions & 22 deletions src/main/java/com/learning/mfscreener/helper/SpringContext.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.learning.mfscreener.models.portfolio;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

public class MergedTransaction {
private final LocalDate date;
private final List<UserTransactionDTO> transactions;

public MergedTransaction(LocalDate date) {
this.date = date;
this.transactions = new ArrayList<>();
}

public void add(UserTransactionDTO txn) {
this.transactions.add(txn);
}

public LocalDate getDate() {
return date;
}

public List<UserTransactionDTO> getTransactions() {
return transactions;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.learning.mfscreener.models.portfolio;

import java.math.BigDecimal;
import java.time.LocalDate;

public record Transaction(LocalDate txnDate, BigDecimal units, BigDecimal nav, BigDecimal tax) {}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ where upper(m.fundHouse) like upper(:fName) order by m.schemeId
@Transactional(readOnly = true)
List<FundDetailProjection> findByFundHouseLikeIgnoringCaseOrderBySchemeIdAsc(@Param("fName") String fName);

@Cacheable("schemeIdByISIN")
@Query("select m.schemeId from MFSchemeEntity m where m.payOut = :isin")
Optional<Long> getSchemeIdByISIN(@Param("isin") String isin);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
import com.learning.mfscreener.models.portfolio.UserSchemeDTO;
import com.learning.mfscreener.models.portfolio.UserTransactionDTO;
import com.learning.mfscreener.models.response.ProcessCasResponse;
import com.learning.mfscreener.utils.FIFOUnits;
import com.learning.mfscreener.utils.GainEntry;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
Expand All @@ -32,9 +30,15 @@ public class CapitalGainsService {

private BigDecimal investedAmount = BigDecimal.ZERO;
private Double currentValue = 0D;
private final List<GainEntry> gainEntries = new ArrayList<>();
private final List<GainEntryService> gainEntries = new ArrayList<>();
private final List<String> errors = new ArrayList<>();

private final FIFOUnitsService fifoUnitsService;

public CapitalGainsService(FIFOUnitsService fifoUnitsService) {
this.fifoUnitsService = fifoUnitsService;
}

@Loggable(params = false)
ProcessCasResponse processData(CasDTO casDTO) throws IncompleteCASError {
casDTO.folios().forEach(this::processFolio);
Expand Down Expand Up @@ -64,7 +68,7 @@ void validateOpenBalance(UserSchemeDTO scheme) {

void processTransactions(Fund fund, List<UserTransactionDTO> transactions, UserSchemeDTO scheme) {
try {
FIFOUnits fifo = new FIFOUnits(fund, transactions);
FIFOUnitsService fifo = fifoUnitsService.init(fund, transactions);
investedAmount = this.investedAmount.add(fifo.getTotalInvested());
currentValue += scheme.valuation().value();
gainEntries.addAll(fifo.getRecordedGains());
Expand All @@ -73,11 +77,12 @@ void processTransactions(Fund fund, List<UserTransactionDTO> transactions, UserS
}
}

Map<String, Map<String, Object>> prepareGains(List<GainEntry> gainEntries) {
Map<String, Map<String, Object>> prepareGains(List<GainEntryService> gainEntries) {

gainEntries.sort(Comparator.comparing(GainEntry::getFinYear).thenComparing(GainEntry::getFundType));
gainEntries.sort(
Comparator.comparing(GainEntryService::getFinYear).thenComparing(GainEntryService::getFundType));

Map<String, List<GainEntry>> groupedGains =
Map<String, List<GainEntryService>> groupedGains =
gainEntries.stream().collect(Collectors.groupingBy(txn -> txn.getFinYear() + "#" + txn.getFundType()));

Map<String, Map<String, Object>> summary = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package com.learning.mfscreener.utils;
package com.learning.mfscreener.service;

import com.learning.mfscreener.exception.GainsException;
import com.learning.mfscreener.models.portfolio.Fund;
import com.learning.mfscreener.models.portfolio.FundType;
import com.learning.mfscreener.models.portfolio.MergedTransaction;
import com.learning.mfscreener.models.portfolio.Transaction;
import com.learning.mfscreener.models.portfolio.TransactionType;
import com.learning.mfscreener.models.portfolio.UserTransactionDTO;
import com.learning.mfscreener.utils.AppConstants;
import com.learning.mfscreener.utils.FundTypeUtility;
import com.learning.mfscreener.utils.LocalDateUtility;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
Expand All @@ -19,31 +24,38 @@
import java.util.stream.IntStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

public class FIFOUnits {
@Service
public class FIFOUnitsService {

private static final Logger LOGGER = LoggerFactory.getLogger(FIFOUnits.class);
private static final Logger LOGGER = LoggerFactory.getLogger(FIFOUnitsService.class);

private final Fund fund;
private final FundType fundType;
private Fund fund;
private FundType fundType;
private final Deque<Transaction> transactionsQueue = new ArrayDeque<>();
private final GainEntryService gainEntryService;

private BigDecimal totalInvested = BigDecimal.ZERO;
private BigDecimal currentBalance = BigDecimal.ZERO;
private List<GainEntry> recordedGains = new ArrayList<>();
private List<GainEntryService> recordedGains = new ArrayList<>();

public FIFOUnits(Fund fund, List<UserTransactionDTO> userTransactionDTOList) throws GainsException {
public FIFOUnitsService(GainEntryService gainEntryService) {
this.gainEntryService = gainEntryService;
}

public FIFOUnitsService init(Fund fund, List<UserTransactionDTO> userTransactionDTOList) {
this.fund = fund;
this.fundType = determineFundType(fund.type(), userTransactionDTOList);
Map<LocalDate, MergedTransaction> mergedTransactions = mergeTransactions(userTransactionDTOList);

processTransactions(mergedTransactions);
return this;
}

FundType determineFundType(String type, List<UserTransactionDTO> transactions) {
FundType fundType;
if (!"EQUITY".equals(type) && !"DEBT".equals(type)) {
fundType = deriveFundTypeFromTransactions(transactions);
fundType = FundTypeUtility.deriveFundTypeFromTransactions(transactions);
} else {
fundType = FundType.valueOf(type);
}
Expand Down Expand Up @@ -77,8 +89,8 @@ void processTransactions(Map<LocalDate, MergedTransaction> mergedTransactions) {
transactionDates.forEach(localDate -> processTransactionDate(localDate, mergedTransactions.get(localDate)));
}

private void processTransactionDate(LocalDate dt, MergedTransaction mergedTransaction) {
List<UserTransactionDTO> userTransactionDTOS = mergedTransaction.transactions;
void processTransactionDate(LocalDate dt, MergedTransaction mergedTransaction) {
List<UserTransactionDTO> userTransactionDTOS = mergedTransaction.getTransactions();
if (userTransactionDTOS.size() == 2 && dt.isAfter(AppConstants.TAX_STARTED_DATE)) {
findTaxFromTransactionsAndProcess(userTransactionDTOS, dt);
} else if (userTransactionDTOS.size() > 2 && dt.isAfter(AppConstants.TAX_STARTED_DATE)) {
Expand All @@ -88,7 +100,7 @@ private void processTransactionDate(LocalDate dt, MergedTransaction mergedTransa
}
}

private void processMultipleTransactions(List<UserTransactionDTO> userTransactionDTOS, LocalDate dt) {
void processMultipleTransactions(List<UserTransactionDTO> userTransactionDTOS, LocalDate dt) {
int splitIndex = 0;
boolean found = false;
for (int i = 0; i < userTransactionDTOS.size(); i++) {
Expand All @@ -112,16 +124,15 @@ private void processMultipleTransactions(List<UserTransactionDTO> userTransactio
processesGroupedTransactions(dt, sellTransactionList, true);
}

private void processesGroupedTransactions(
void processesGroupedTransactions(
LocalDate dt, List<UserTransactionDTO> userTransactionDTOList, boolean sellOrder) {
if (!userTransactionDTOList.isEmpty()) {
groupTransactions(userTransactionDTOList, sellOrder)
.forEach(groupedTransaction -> findTaxFromTransactionsAndProcess(groupedTransaction, dt));
}
}

private List<List<UserTransactionDTO>> groupTransactions(
List<UserTransactionDTO> transactionDTOList, boolean sellOrder) {
List<List<UserTransactionDTO>> groupTransactions(List<UserTransactionDTO> transactionDTOList, boolean sellOrder) {
// If list size is less than or equal to 2, no need to regroup
if (transactionDTOList.size() <= 2) {
return Collections.singletonList(transactionDTOList);
Expand All @@ -145,7 +156,7 @@ private List<List<UserTransactionDTO>> groupTransactions(
.toList();
}

private void processStandardTransactions(List<UserTransactionDTO> userTransactionDTOS) {
void processStandardTransactions(List<UserTransactionDTO> userTransactionDTOS) {
userTransactionDTOS.forEach(userTransactionDTO -> {
if (userTransactionDTO.units() == null) {
LOGGER.error("Unhandled dividend Transactions");
Expand All @@ -155,7 +166,7 @@ private void processStandardTransactions(List<UserTransactionDTO> userTransactio
});
}

private void processTransaction(UserTransactionDTO userTransactionDTO) {
void processTransaction(UserTransactionDTO userTransactionDTO) {
if (userTransactionDTO.units() > 0) {
buy(
userTransactionDTO.date(),
Expand All @@ -171,7 +182,7 @@ private void processTransaction(UserTransactionDTO userTransactionDTO) {
}
}

private void findTaxFromTransactionsAndProcess(List<UserTransactionDTO> userTransactionDTOS, LocalDate dt) {
void findTaxFromTransactionsAndProcess(List<UserTransactionDTO> userTransactionDTOS, LocalDate dt) {
// if buy we will have STAMP_DUTY_TAX, for sale we will have STT_TAX
if (userTransactionDTOS.size() == 2) {
if (userTransactionDTOS.get(1).type().compareTo(TransactionType.STAMP_DUTY_TAX) == 0) {
Expand Down Expand Up @@ -210,13 +221,13 @@ private void findTaxFromTransactionsAndProcess(List<UserTransactionDTO> userTran
}
}

private void buy(LocalDate txnDate, BigDecimal quantity, BigDecimal nav, BigDecimal tax) {
void buy(LocalDate txnDate, BigDecimal quantity, BigDecimal nav, BigDecimal tax) {
transactionsQueue.add(new Transaction(txnDate, quantity, nav, tax));
totalInvested = totalInvested.add(quantity.multiply(nav));
currentBalance = currentBalance.add(quantity);
}

private void sell(LocalDate sellDate, BigDecimal quantity, BigDecimal nav, BigDecimal tax) throws GainsException {
void sell(LocalDate sellDate, BigDecimal quantity, BigDecimal nav, BigDecimal tax) throws GainsException {
String finYear = LocalDateUtility.getFinYear(sellDate);
BigDecimal originalQuantity = quantity.abs();
BigDecimal pendingUnits = originalQuantity;
Expand All @@ -239,7 +250,7 @@ private void sell(LocalDate sellDate, BigDecimal quantity, BigDecimal nav, BigDe
BigDecimal stampDuty = purchaseTax.multiply(gainUnits).divide(units, 2, RoundingMode.HALF_UP);
BigDecimal stt = tax.multiply(gainUnits).divide(originalQuantity, 2, RoundingMode.HALF_UP);

GainEntry ge = new GainEntry(
GainEntryService ge = gainEntryService.init(
finYear,
fund,
fundType,
Expand Down Expand Up @@ -267,61 +278,21 @@ private void sell(LocalDate sellDate, BigDecimal quantity, BigDecimal nav, BigDe
}
}

/**
*
* Detect Fund Type.
* - UNKNOWN if there are no redemption transactions
* - EQUITY if STT_TAX transactions are present in the portfolio
* - DEBT if no STT_TAX transactions are present along with redemptions
*
* @param transactions list of transactions for a single fund parsed from the CAS
* @return type of fund
*/
private FundType deriveFundTypeFromTransactions(List<UserTransactionDTO> transactions) {
boolean valid = transactions.stream()
.anyMatch(x -> x.units() != null && x.units() < 0 && x.type() != TransactionType.REVERSAL);

if (!valid) {
return FundType.UNKNOWN;
}
if (transactions.stream().anyMatch(x -> x.type() == TransactionType.STT_TAX)) {
return FundType.EQUITY;
} else {
return FundType.DEBT;
}
}

public BigDecimal getTotalInvested() {
return totalInvested;
}

public FIFOUnits setTotalInvested(BigDecimal totalInvested) {
public FIFOUnitsService setTotalInvested(BigDecimal totalInvested) {
this.totalInvested = totalInvested;
return this;
}

public List<GainEntry> getRecordedGains() {
public List<GainEntryService> getRecordedGains() {
return recordedGains;
}

public FIFOUnits setRecordedGains(List<GainEntry> recordedGains) {
public FIFOUnitsService setRecordedGains(List<GainEntryService> recordedGains) {
this.recordedGains = recordedGains;
return this;
}

private static class MergedTransaction {
private final LocalDate date;
private final List<UserTransactionDTO> transactions;

public MergedTransaction(LocalDate date) {
this.date = date;
this.transactions = new ArrayList<>();
}

public void add(UserTransactionDTO txn) {
this.transactions.add(txn);
}
}

private record Transaction(LocalDate txnDate, BigDecimal units, BigDecimal nav, BigDecimal tax) {}
}
Loading

0 comments on commit 0f8efcc

Please sign in to comment.