public ProfilesUpdateSummaryResultModel BatchUpdateProfiles(string currentInvestor) { // Partially updates all investors' asset Profiles (freq, months, & payday), based on *12 month* revenue history. int updateCount = 0; IncomeData.IncomeDataProcessing incomeDataAccessComponent = new IncomeData.IncomeDataProcessing(_ctx); CommonSvc svc = new CommonSvc(_ctx); ProfilesUpdateSummaryResultModel results = new ProfilesUpdateSummaryResultModel(); ProfileForUpdateVm processedResults = incomeDataAccessComponent.Process12MosRevenueHistory(svc.GetInvestorIdFromInvestor(currentInvestor)); if (!processedResults.UpdateHasErrors) { List <Data.Entities.Profile> profilesToUpdate = processedResults.BatchProfilesList; try { _ctx.UpdateRange(profilesToUpdate); updateCount = _ctx.SaveChanges(); } catch (Exception ex) { Log.Error("Error updating Profile(s) via ProfileDataProcessing.BatchUpdateProfiles(), due to :{0} '", ex.InnerException + "'"); return(null); } } else { Log.Error("Error processing revenue history for dividend payment data, recorded via ProfileDataProcessing.BatchUpdateProfiles()."); return(null); } // Initialize with just relevant info, for use by UI. results.ProcessedTickersCount = updateCount > 0 ? updateCount : 0; results.OmittedTickers = processedResults.ExceptionTickerSymbols != string.Empty ? processedResults.ExceptionTickerSymbols.Trim() : string.Empty; Log.Information("Updated " + results.ProcessedTickersCount + " Profiles based on revenue history, for " + currentInvestor); if (results.OmittedTickers != string.Empty) { Log.Information("Omitted Profile updates based on revenue history for " + results.OmittedTickers); } return(results); }
public ProfileForUpdateVm Process12MosRevenueHistory(string investorId) { // Revenue processing in response to investor-initiated Profile updating. ProfileForUpdateVm vm = new ProfileForUpdateVm(); try { string exceptionTickers = string.Empty; IQueryable <string> currentPositions = _ctx.Position.Where(p => p.PositionAsset.InvestorId == investorId && p.Status == "A") .Select(p => p.PositionAsset.Profile.TickerSymbol) .Distinct() .AsQueryable(); IQueryable <PositionIncomeVm> joinedPositionIncome = _ctx.Position.Where(p => p.PositionAsset.InvestorId == investorId && p.Status == "A") .Join(_ctx.Income, p => p.PositionId, i => i.PositionId, (p, i) => new PositionIncomeVm { ProfileId = p.PositionAsset.Profile.ProfileId, PositionId = p.PositionId, TickerSymbol = p.PositionAsset.Profile.TickerSymbol, Account = p.AccountType.AccountTypeDesc, DateRecvd = i.DateRecvd, DividendYield = Convert.ToDecimal(p.PositionAsset.Profile.DividendYield), TickerDescription = p.PositionAsset.Profile.TickerDescription }) .OrderBy(results => results.TickerSymbol) .ThenBy(results => results.Account) .AsQueryable(); joinedPositionIncome.OrderBy(pi => pi.DateRecvd); // To be initialized return collection. List <Data.Entities.Profile> updateProfileModelList = new List <Data.Entities.Profile>(); foreach (string currentTicker in currentPositions) { // Do we have income data for this position that is greater than or equal to a least a year old, as is necessary // for accurate calculation of both 1) dividend distribution frequency, and 2) dividend payout months values. // Back-dated info is always from the 1st of the calculated year ago month. int olderThanOneYearRevenueCount = joinedPositionIncome .Where(pi => pi.TickerSymbol == currentTicker && pi.DateRecvd <= DateTime.Now.AddMonths(-12).AddDays(-DateTime.Now.Day)).Count(); if (olderThanOneYearRevenueCount > 0) { Data.Entities.Profile updateProfileModel = new Data.Entities.Profile { TickerSymbol = currentTicker }; IQueryable <PositionIncomeVm> withinLastYearData = joinedPositionIncome .Where(pi => pi.TickerSymbol == currentTicker && pi.DateRecvd >= DateTime.Now.AddMonths(-12).AddDays(-DateTime.Now.Day)) .AsQueryable(); // Investor may have same position in multiple accounts, e.g. IRA, Roth-IRA. int dupAcctCount = withinLastYearData.Select(pi => pi.Account).Distinct().Count(); if (dupAcctCount > 1) { IQueryable <PositionIncomeVm> withUniqueAcct = withinLastYearData .Where(pi => pi.Account == withinLastYearData.First().Account).OrderBy(pi => pi.TickerSymbol); updateProfileModel.DividendFreq = CalculateDividendFrequency(withUniqueAcct); updateProfileModel.DividendMonths = updateProfileModel.DividendFreq != "M" ? CalculateDividendMonths(withUniqueAcct) : "N/A"; updateProfileModel.DividendPayDay = CommonSvc.CalculateMedianValue(BuildDivDaysList((withUniqueAcct))); } else { updateProfileModel.DividendFreq = CalculateDividendFrequency(withinLastYearData); updateProfileModel.DividendMonths = updateProfileModel.DividendFreq != "M" ? CalculateDividendMonths(withinLastYearData) : "N/A"; updateProfileModel.DividendPayDay = CommonSvc.CalculateMedianValue(BuildDivDaysList((withinLastYearData))); } // Satisfy 'required' Profile attributes & ProfileId for updating. updateProfileModel.ProfileId = joinedPositionIncome.Where(d => d.TickerSymbol == currentTicker).First().ProfileId; updateProfileModel.DividendYield = joinedPositionIncome.Where(d => d.TickerSymbol == currentTicker).First().DividendYield; updateProfileModel.TickerDescription = joinedPositionIncome.Where(d => d.TickerSymbol == currentTicker).First().TickerDescription; updateProfileModel.LastUpdate = DateTime.Now; updateProfileModelList.Add(updateProfileModel); } else { exceptionTickers += currentTicker + ", "; } } if (exceptionTickers.Length > 0) { exceptionTickers.Trim(); exceptionTickers = exceptionTickers.Remove(exceptionTickers.LastIndexOf(','), 1); } vm.BatchProfilesList = updateProfileModelList; vm.ExceptionTickerSymbols = (exceptionTickers.Length > 0 ? exceptionTickers : ""); vm.UpdateHasErrors = false; } catch (Exception) { vm.UpdateHasErrors = true; } return(vm); }