/// <summary> /// /// Overloaded: Calculate the greenzorro & Fund fees on any amount that greenzorro offered an investment service. /// Returns the individual fees as out parameters. /// /// </summary> /// <param name="vintageYearMonthStr"></param> /// <param name="liquidationAmount"></param> /// <param name="vintageCashInvestment"></param> /// <returns>Total greenzorro + Fund fees on a investment amount.</returns> public FeesDto GetWithdrawnFees(decimal vintageCashInvestment, string vintageYearMonthStr, decimal liquidationAmount) { var confRow = confRepo.GetConfRow(); var isAnEarlyWithdrawal = IsAnEarlyWithdrawal(vintageYearMonthStr, confRow); // beyond the unleash day? (early withdrawal fee) decimal earlyCashoutFee = GetEarlyCashoutFee(liquidationAmount, isAnEarlyWithdrawal, (decimal)confRow.EARLY_WITHDRAWAL_FEE_PCNT); var gzFeesAmount = GetGzFeesAmount(liquidationAmount, isAnEarlyWithdrawal, (decimal)confRow.COMMISSION_PCNT); var fundsFeesAmount = GetFundsFeesAmount(liquidationAmount, isAnEarlyWithdrawal, (decimal)confRow.FUND_FEE_PCNT); // hurdle fee var hurdleFee = GetHurdleFee( vintageCashInvestment, liquidationAmount, isAnEarlyWithdrawal, (decimal)confRow.HURDLE_TRIGGER_GAIN_PCNT, (decimal)confRow.EARLY_WITHDRAWAL_FEE_PCNT); // Return all fees var fees = new FeesDto() { EarlyCashoutFee = earlyCashoutFee, FundFee = fundsFeesAmount, GzFee = gzFeesAmount, HurdleFee = hurdleFee, Total = gzFeesAmount + fundsFeesAmount + earlyCashoutFee + hurdleFee }; return(fees); }
/// <summary> /// /// Slack Q and A: /// "Post 3 months to sell a vintage" -> On the 4th month Regardless of the number of days. /// /// Biz logic for withdrawal eligibility /// /// </summary> /// <param name="customerId"></param> /// <returns></returns> private Tuple <bool, DateTime, int> IsWithdrawalEligible(int customerId) { var lockInDays = (confRepo.GetConfRow()).LOCK_IN_NUM_DAYS; var nowUtc = DateTime.UtcNow; var monthsLockCnt = lockInDays / 30; var oldestVintageYm = GetAndCacheOldestVintageYm(customerId); var oldestVintage = oldestVintageYm != null?DbExpressions.GetDtYearMonthStrTo1StOfMonth(oldestVintageYm) : nowUtc; var eligibleWithdrawDate = oldestVintage.AddMonths(monthsLockCnt + 1); // the 1st of the 4th month var okToWithdraw = eligibleWithdrawDate <= nowUtc; return(Tuple.Create(okToWithdraw, eligibleWithdrawDate, lockInDays)); }
/// <summary> /// /// Get the customer selected portfolio for any given month in their history. /// /// </summary> /// <param name="customerId"></param> /// <param name="nextYearMonthStr">+1 Month from Present To be safe we have the latest</param> /// <returns></returns> public Portfolio GetUserPortfolioForThisMonthOrBefore(int customerId, string nextYearMonthStr) { Portfolio customerMonthPortfolioReturn; // userPortfolioMaxMonthSet typically comes back as the present month or -1 // if no portfolio back-end management has run yet. var userPortfolioMaxMonthSet = GetUserPortfolioLastYearMonthSet(customerId, nextYearMonthStr); if (userPortfolioMaxMonthSet != null) { // Don't cache portfolio. Portfolio selections occur within the current month customerMonthPortfolioReturn = db.CustPortfolios .Where(p => p.YearMonth == userPortfolioMaxMonthSet && p.CustomerId == customerId) .Select(cp => cp.Portfolio) .SingleOrDefault(); } /** * Edge Case for leaky user registrations: * Use default portfolio for new registered users without * portfolio in their account. Portfolio management adds a portfolio next time * it runs. */ else { // Cached already var defaultRisk = (confRepo .GetConfRow()).FIRST_PORTFOLIO_RISK_VAL; customerMonthPortfolioReturn = db .Portfolios .DeferredSingle(p => p.RiskTolerance == defaultRisk && p.IsActive) .FromCache(DateTime.UtcNow.AddHours(2)); } return(customerMonthPortfolioReturn); }