Skip to content

Instantly share code, notes, and snippets.

@gordonbyron
Created July 3, 2015 13:27
Show Gist options
  • Save gordonbyron/30e3caac68e4d8c56163 to your computer and use it in GitHub Desktop.
Save gordonbyron/30e3caac68e4d8c56163 to your computer and use it in GitHub Desktop.
package novofront.service.business;
import com.barcapint.schemas.cerberus.association.account.x2015.x06.x01.AccountDto;
import novofront.api.command.GetLiquidityCommand;
import novofront.api.command.GetLiquidityCommandResponse;
import novofront.api.command.account.IndividualBalanceCommand;
import novofront.api.command.account.IndividualBalanceCommandResponse;
import novofront.api.view.AccountBalance;
import novofront.api.view.*;
import novofront.api.view.balance.ConsolidatedBalanceItem;
import novofront.api.view.balance.ConsolidatedCurrentBalanceItem;
import novofront.core.Constants;
import novofront.dto.ClientLiquidity;
import novofront.dto.ClientLiquidityKey;
import novofront.dto.LiquidityPosition;
import novofront.model.jpa.*;
import novofront.repository.filter.LiquidityFilter;
import novofront.service.orient.OrientDbService;
import org.joda.time.DateTime;
import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.*;
/**
* Provides services for building up a liquidity model
*
* @author Werner Weber
*/
@Service
public class LiquidityService implements ILiquidityService {
private final Logger logger = LoggerFactory.getLogger(LiquidityService.class);
@Autowired
OrientDbService orientDbService;
@Autowired
ClientService clientService;
@Autowired
AccountService accountService;
@Autowired
UserService userService;
@Autowired
ExchangeRateService exhangeRateService;
public GetLiquidityCommandResponse GetLiquidity(GetLiquidityCommand command) {
logger.debug("LiquidityService.GetLiquidity(GetLiquidityCommand {0}) - start", command);
GetLiquidityCommandResponse response = new GetLiquidityCommandResponse(command);
//a list that contains all the client ids that we need to fetch account data for
//this list is resolved either via resolving all the children for the root element
//or we use the list given in the entityFilter list for the command.
ArrayList<String> clientIds = new ArrayList<String>();
LegalEntity rootEntity = null;
try {
rootEntity = orientDbService.getEntityHierarchy(command.getClientId(), 3); //TODO: Decide on the default depth at which to query for the client hierarchy
if (rootEntity == null) {
response.addError(String.format("Could not load client with id: %s", command.getClientId()), Constants.ERROR_CODE_ENTITY_NOT_FOUND, "Please check input parameters for client id filter");
response.setSuccess(false);
response.setMessage(String.format("Could not load client with id: %s", command.getClientId()));
response.setLiquidity(null);
response.setCompletedTime(DateTime.now());
return response;
}
//we know our entity is not null so we can add it to the list of client ids
clientIds.add(rootEntity.getClientID());
if (command.getEntityFilter().size() > 0) {
//if we are given the entity filter we just use it as is. This is the easiest route.//we are using the parent company in the inclu
clientIds.addAll(command.getEntityFilter());
} else {
//if we are not given the entity filter we use the root entity and resolve all the client id's contained in the hierarchy
clientIds.addAll(getChildrenIds(rootEntity));
}
} catch (Exception e) {
logger.error("Could not retrieve data due to an excpetion thrown from Orient error", e);
response.addError("Could not retrieve data due to a system error", Constants.ERROR_CODE_SYSTEM_ERROR_ORIENT, "Please try again later, or contact support should this be resolved.");
}
//build a list of accounts that we need to fetch balances for
List<Account> accounts = new ArrayList<Account>();
for (String clientId : clientIds) {
accounts.addAll(accountService.listAllAccountsForClient(clientId));
}
WorkingCapital workingCapital = new WorkingCapital();
CashBalance cashBalance = new CashBalance();
Liquidity liquidity = new Liquidity();
liquidity.setWorkingCapital(workingCapital);
liquidity.setCashBalance(cashBalance);
LiquidityFilter filter = new LiquidityFilter();
List<AccountBalance> cashBalances = new ArrayList<AccountBalance>();
List<AccountBalance> workingCapitalBalances = new ArrayList<AccountBalance>();
for (Account account : accounts) {
//get the account balances for the account and the period defined
account.setBalanceEntries(accountService.getAccountBalanceForAccountAndDateRange(account.getAccountId(), command.getStartDateFilter(), command.getEndDateFilter()));
//iterate through account balances
for (novofront.model.jpa.AccountBalance balance : account.getBalanceEntries()) {
//whatever logic applies to put them in either bucket
boolean isCashbalance = false;
AccountBalance vbalance = new AccountBalance();
vbalance.setPreferredCurrencyCode(command.getPreferredCurrencyCode());
vbalance.setAccountId(balance.getAccount().getAccountId());
vbalance.setBalance(balance.getBalance());
vbalance.setFacility(balance.getFacility());
vbalance.setBalanceDate(balance.getBalanceDate());
if (vbalance.getCategory().toLowerCase() == novofront.treasurydashboard.Constants.ACCOUNT_BALANCE_CATEGORY_CASH.toLowerCase()) {
isCashbalance = true;
} else {
//some additional logic may apply here to decide if it is a cash balance
}
vbalance.setCountryCode(balance.getAccount().getCountryCode());
vbalance.setCategory(balance.getCategory());
vbalance.setClientId(balance.getAccount().getClient().getClientId());
vbalance.setCurrencyCode(balance.getAccount().getCurrency().getCurrencyCode());
if (vbalance.requiresMultiplier())//set the multiplier for the currency conversion
vbalance.setMultiplier(exhangeRateService.getMultiplier(vbalance.getCurrencyCode(), vbalance.getPreferredCurrencyCode(), DateTime.now()));
if (isCashbalance) {
cashBalances.add(vbalance);
} else {
workingCapitalBalances.add(vbalance);
}
}
}
for (AccountBalance balance : cashBalances) {
//do whatever work is required
CashBalanceItem cbItem = new CashBalanceItem();
}
Map<String, WorkingCapitalItem> workingCapitalMap = new HashMap<String, WorkingCapitalItem>();
for (AccountBalance balance : workingCapitalBalances) {
//do whatever work is required
WorkingCapitalItem wcItem = null;
if (workingCapitalMap.containsKey(balance.getCurrencyCode())) {
wcItem = (WorkingCapitalItem) workingCapitalMap.get(balance.getCurrencyCode());
} else {
wcItem = new WorkingCapitalItem();
wcItem.setCurrencyCode(balance.getCurrencyCode());
wcItem.setBalance(BigDecimal.ZERO);
wcItem.setFacility(BigDecimal.ZERO);
}
ContributingCountryItem contributingCountryItem = null;
contributingCountryItem = wcItem.getContributingCountryItemForCountry(balance.getCountryCode());
if (contributingCountryItem == null) {
contributingCountryItem = new ContributingCountryItem();
contributingCountryItem.setFacility(BigDecimal.ZERO);
contributingCountryItem.setBalance(BigDecimal.ZERO);
contributingCountryItem.setCurrencyCode(balance.getCurrencyCode());
contributingCountryItem.setBalanceDate(DateTime.now());
contributingCountryItem.setCountryCode(balance.getCountryCode());
contributingCountryItem.setPreferredCurrencyCode(command.getPreferredCurrencyCode());
contributingCountryItem.setMultiplier(exhangeRateService.getMultiplier(balance.getCurrencyCode(), command.getPreferredCurrencyCode(), DateTime.now()));
}
contributingCountryItem.addAccountBalance(balance);
workingCapitalMap.put(balance.getCurrencyCode(), wcItem);
}
for (WorkingCapitalItem wcItem : workingCapitalMap.values()) {
liquidity.getWorkingCapital().addWorkingCapitalItem(wcItem);
}
response.setLiquidity(liquidity);
return response;
}
private List<String> getChildrenIds(LegalEntity entity) {
ArrayList<String> ids = new ArrayList<String>();
for (LegalEntity child : entity.getSubsidiaries()) {
//check if the command filters allows us to add the legal entity to the list of clients we
//are looking for
ids.add(child.getClientID());
ids.addAll(getChildrenIds(child));
}
return ids;
}
public List<ConsolidatedCurrentBalanceItem> getConsolidatedBalancesCurrent(List<String> clientIds, List<String> currencyCodes, List<String> countryCodes, String convertToCurrency) {
List<ConsolidatedBalanceItem> items = getConsolidatedBalances(clientIds, currencyCodes, countryCodes, null, null, false);
logger.info("Convert to Currency is ::-- {}", convertToCurrency);
List<ConsolidatedCurrentBalanceItem> currentItems = new ArrayList<ConsolidatedCurrentBalanceItem>();
for (ConsolidatedBalanceItem item : items) {
currentItems.add(ConsolidatedCurrentBalanceItem.from(item));
}
if (convertToCurrency != null) {
DateTime now = DateTime.now();
DateTime start = DateTime.parse(String.format(novofront.core.Constants.DATE_FORMAT_STRING_MIDNIGHT, now.getYear(), now.getMonthOfYear(), now.getDayOfMonth()));
DateTime end = DateTime.parse(String.format(novofront.core.Constants.DATE_FORMAT_STRING_MIDNIGHT, now.getYear(), now.getMonthOfYear(), now.getDayOfMonth() + 1));
logger.info("The start is ::-- {}", start);
logger.info("The end is ::-- {}", end);
for (ConsolidatedCurrentBalanceItem item : currentItems) {
//List<ExchangeRate> exchangeRates = exhangeRateService.getByBaseCurrencyCodeInAndTargetCurrencyCodeInAndExchangeDateBetween(item.getCurrencyCode(), convertToCurrency, start, end);
List<ExchangeRate> exchangeRates = exhangeRateService.findByBaseCurrencyCodeAndTargetCurrencyCodeAndExchangeDateBetween(item.getCurrencyCode(), convertToCurrency, start, end);
if (exchangeRates != null && !exchangeRates.isEmpty()) {
logger.info("The Currency is ::-- {}", item.getCurrencyCode());
logger.info("The Exchange rate is ::-- {}", exchangeRates.get(0).getFactor());
item.setCash(item.getCash().multiply(BigDecimal.valueOf(exchangeRates.get(0).getFactor())).setScale(0, BigDecimal.ROUND_DOWN));
item.setLiquidity(item.getLiquidity().multiply(BigDecimal.valueOf(exchangeRates.get(0).getFactor())).setScale(0, BigDecimal.ROUND_DOWN));
item.setAvailableFacilities(item.getAvailableFacilities().multiply(BigDecimal.valueOf(exchangeRates.get(0).getFactor())).setScale(0, BigDecimal.ROUND_DOWN));
item.setTotalFacilities(item.getTotalFacilities().multiply(BigDecimal.valueOf(exchangeRates.get(0).getFactor())).setScale(0, BigDecimal.ROUND_DOWN));
item.setUsedFacilities(item.getUsedFacilities().multiply(BigDecimal.valueOf(exchangeRates.get(0).getFactor())).setScale(0, BigDecimal.ROUND_DOWN));
}
}
}
return currentItems;
}
public List<ConsolidatedBalanceItem> getConsolidatedBalances(List<String> clientIds, List<String> currencyCodes, List<String> countryCodes, DateTime startDate, DateTime endDate, boolean useDefaults) {
User user = userService.getCurrentUser();
List<String> clientIdsToItterate = new ArrayList<String>();
clientIdsToItterate.addAll(clientIds);
if (clientIdsToItterate.isEmpty()) {
for (Client client : user.getClients()) {
clientIdsToItterate.add(client.getClientId());
}
}
List<String> countryCodesToUse;
List<String> currencyCodesToUse;
if (useDefaults) {
countryCodesToUse = userService.getCountryCodesForCurrentUser(countryCodes);
currencyCodesToUse = userService.getCurrencyCodesForCurrentUser(currencyCodes);
} else {
currencyCodesToUse = currencyCodes;
countryCodesToUse = countryCodes;
}
HashMap<ClientLiquidityKey, ConsolidatedBalanceItem> map = new HashMap<ClientLiquidityKey, ConsolidatedBalanceItem>();
final List<ClientLiquidity> liquidityPositionPerClient = getLiquidityPositionPerClient(clientIdsToItterate, currencyCodesToUse, countryCodesToUse, startDate, endDate);
for (ClientLiquidity clientLiquidity : liquidityPositionPerClient) {
final Iterator<LiquidityPosition> iterator = clientLiquidity.iterator();
while (iterator.hasNext()) {
final LiquidityPosition liquidityPosition = iterator.next();
//day without time
Date balanceDate = liquidityPosition.getDate();
final String currencyCode = liquidityPosition.getCurrencyCode();
final ClientLiquidityKey key = new ClientLiquidityKey(balanceDate, currencyCode);
ConsolidatedBalanceItem item = null;
item = map.get(key);
if (item == null) {
item = new ConsolidatedBalanceItem();
item.setBalanceDate(new LocalDateTime(balanceDate).toDateTime());
item.setCurrencyCode(currencyCode);
}
item.setTotalFacilities(liquidityPosition.getTotalFacilities());
item.setCash(item.getCash().add(liquidityPosition.getCash()));
item.setUsedFacilities(item.getUsedFacilities().add(liquidityPosition.getUsedFacilities()));
map.put(key, item);
}
}
List<ConsolidatedBalanceItem> consolidatedBalances = new ArrayList<ConsolidatedBalanceItem>();
for (ConsolidatedBalanceItem item : map.values()) {
item.setNetCash(item.getUsedFacilities().add(item.getCash()));
item.setAvailableFacilities(item.getUsedFacilities().add(item.getTotalFacilities()));
if (item.getAvailableFacilities().compareTo(BigDecimal.ZERO) < 0)
item.setAvailableFacilities(BigDecimal.ZERO);
item.setLiquidity(item.getCash().add(item.getAvailableFacilities()));
consolidatedBalances.add(item);
}
Collections.sort(consolidatedBalances);
return consolidatedBalances;
}
private BigDecimal getTotalFacilities(Client client) {
BigDecimal totalFacilities = BigDecimal.ZERO;
for (ClientLimit limit : client.getClientLimits()) {
switch (limit.getProductSet()) {
case novofront.treasurydashboard.Constants.CLIENT_LIMIT_CATEGORY_CFC_FACILITY: {
}
case novofront.treasurydashboard.Constants.CLIENT_LIMIT_CATEGORY_OVERDRAFT_FACILITY: {
}
case novofront.treasurydashboard.Constants.CLIENT_LIMIT_CATEGORY_PRIMARY_LENDING_FACILITY: {
totalFacilities = totalFacilities.add(new BigDecimal(limit.getAmount()));
break;
}
}
}
return totalFacilities;
}
public IndividualBalanceCommandResponse getIndividualBalances(IndividualBalanceCommand command) {
IndividualBalanceCommandResponse commandResponse = new IndividualBalanceCommandResponse();
List<String> countryCodesToUse = userService.getCountryCodesForCurrentUser(command.getCountryCodes());
List<String> currencyCodesToUse = userService.getCurrencyCodesForCurrentUser(command.getCurrencies());
List<String> clientIds = userService.getClientIdsForCurrentUser(command.getClientIds());
final List<ClientLiquidity> liquidityPositionPerClient = getLiquidityPositionPerClient(clientIds, currencyCodesToUse, countryCodesToUse, null, null);
logger.info("The number of clients retrieved is {}", clientIds.size());
for (ClientLiquidity client : liquidityPositionPerClient) {
final Iterator<LiquidityPosition> iterator = client.iterator();
while (iterator.hasNext()) {
final LiquidityPosition liquidityPosition = iterator.next();
final IndividualBalance individualBalance = new IndividualBalance();
individualBalance.setCurrencyCode(liquidityPosition.getCurrencyCode());
individualBalance.setClientID(client.getClient().getClientId());
individualBalance.setClientName(client.getClient().getLegalName());
individualBalance.setCountryCode(liquidityPosition.getCountryCode());
final Financials financials = new Financials();
financials.setAvailableFacilities(liquidityPosition.getAvailableFacilities());
financials.setCash(liquidityPosition.getCash());
financials.setLiquidity(liquidityPosition.getLiquidity());
financials.setUsedFacilities(liquidityPosition.getUsedFacilities());
financials.setCurrency(liquidityPosition.getCurrencyCode());
//TODO fix this
BigDecimal limitUtilised = BigDecimal.ZERO;
for (ClientLimit clientLimit : client.getClient().getClientLimits()) {
limitUtilised = limitUtilised.add(new BigDecimal(clientLimit.getUtilised()));
}
financials.setCreditLimitUtilisation(limitUtilised);
financials.setUsedLimit(BigDecimal.ZERO);
individualBalance.getFinancials().add(financials);
commandResponse.getIndividualBalancesResponse().add(individualBalance);
}
}
return commandResponse;
}
public List<ClientLiquidity> getLiquidityPositionPerClient(List<String> clientIds, List<String> currencyCodes, List<String> countryCodes, DateTime startDate, DateTime endDate) {
HashMap<String, ClientLiquidity> map = new HashMap<String, ClientLiquidity>();
for (String clientId : clientIds) {
Client client = clientService.getByClientId(clientId);
BigDecimal totalFacilities = getTotalFacilities(client);
List<Account> accounts = accountService.listAllAccountsForClient(clientId, currencyCodes, countryCodes);
boolean latest = false;
if (startDate == null || endDate == null)
latest = true;
List<novofront.model.jpa.AccountBalance> balances = accountService.listAccountBalances(accounts, latest, startDate, endDate);
ClientLiquidity clientLiquidity = map.get(clientId);
if (clientLiquidity == null) {
clientLiquidity = new ClientLiquidity();
clientLiquidity.setClient(client);
map.put(clientId, clientLiquidity);
}
for (novofront.model.jpa.AccountBalance balance : balances) {
//day without time
Date balanceDate = balance.getBalanceDate().toLocalDate().toDate();
String currency = balance.getAccount().getCurrencyCode();
final ClientLiquidityKey key = new ClientLiquidityKey(balanceDate, currency);
LiquidityPosition liquidityPosition = clientLiquidity.getLiquidityAt(key);
if (liquidityPosition == null) {
liquidityPosition = new LiquidityPosition();
liquidityPosition.setDate(balanceDate);
liquidityPosition.setTotalFacilities(totalFacilities);
liquidityPosition.setCurrencyCode(balance.getAccount().getCurrencyCode());
}
switch (balance.getAccount().getCategory()) {
case novofront.treasurydashboard.Constants.ACCOUNT_CATEGORY_CASH_AND_WORKING_CAPITAL: {
if (balance.getBalance().compareTo(BigDecimal.ZERO) > 0) {
liquidityPosition.setCash(liquidityPosition.getCash().add(balance.getBalance()));
} else {
liquidityPosition.setUsedFacilities(liquidityPosition.getUsedFacilities().add(balance.getBalance()));
}
break;
}
}
clientLiquidity.addLiquidityAt(key, liquidityPosition);
}
List<LiquidityPosition> consolidatedBalances = new ArrayList<LiquidityPosition>();
final Iterator<LiquidityPosition> iterator = clientLiquidity.iterator();
while (iterator.hasNext()) {
LiquidityPosition item = iterator.next();
item.setNetCash(item.getUsedFacilities().add(item.getCash()));
item.setAvailableFacilities(item.getUsedFacilities().add(item.getTotalFacilities()));
if (item.getAvailableFacilities().compareTo(BigDecimal.ZERO) < 0)
item.setAvailableFacilities(BigDecimal.ZERO);
item.setLiquidity(item.getCash().add(item.getAvailableFacilities()));
}
}
return new ArrayList<ClientLiquidity>(map.values());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment