public ActionResult <bool> PersistProfile([FromBody] dynamic createdProfile) { ProfileDataProcessing profileDataAccessComponent = new ProfileDataProcessing(_dbCtx); bool profileIsCreated = profileDataAccessComponent.SaveProfile(MapToProfile(createdProfile, true)); return(Ok(profileIsCreated)); }
public ActionResult <bool> UpdateProfile([FromBody] dynamic editedProfile) { ProfileDataProcessing profileDataAccessComponent = new ProfileDataProcessing(_dbCtx); bool isOkUpdate = profileDataAccessComponent.UpdateProfile(MapToProfile(editedProfile)); if (isOkUpdate) { Log.Information("Profile successfully updated for ticker: " + editedProfile.tickerSymbol); } return(Ok(isOkUpdate)); }
public Profile BuildProfileForProjections(Profile profile, Data.PIMS3Context ctx) { profileToBeInitialized = profile; ProfileDataProcessing profileDataAccessComponent = new ProfileDataProcessing(ctx); // try-catch here, or done in data access component? profileToBeInitialized = profileDataAccessComponent.BuildProfile(profile.TickerSymbol.Trim()); // Fetched dividend rate via 3rd party service is unreliable. Reinitializing frequency; needed. profileToBeInitialized.DividendFreq = profile.DividendFreq; CalculateDividendYield(); return(profileToBeInitialized); }
public ActionResult <Profile> GetProfile(string ticker, bool useDb, string loggedInName) { ProfileDataProcessing profileDataAccessComponent = new ProfileDataProcessing(_dbCtx); try { IQueryable <Profile> dBProfile = profileDataAccessComponent.FetchDbProfile(ticker, loggedInName); return(Ok(dBProfile)); // dBProfile : null || valid Profile. } catch { Log.Warning("No Db profile found for {0}; expected outcome if duplicate profile check, otherwise potential error in ProfileController.GetProfile().", ticker); return(BadRequest(new { errorMsg = "Error fetching custom Profile." })); } }
public ActionResult <DistributionScheduleVm> GetDistributionSchedules(string loggedInvestorId) { ProfileDataProcessing profileDataAccessComponent = new ProfileDataProcessing(_dbCtx); try { var profileSchedules = profileDataAccessComponent.FetchProfileDividendSchedules(loggedInvestorId); return(Ok(profileSchedules)); } catch (Exception) { Log.Warning("Error fetching profiles for {0}, via ProfileController.GetDistributionSchedules().", loggedInvestorId); return(BadRequest(new { errorMsg = "Error fetching custom Profile." })); } }
public ActionResult <string> UpdateAllProfiles(string investorLogin) { // Investor-initiated portfolio profile updates. string serializedBatchResponse = string.Empty; ProfileDataProcessing profileDataAccessComponent = new ProfileDataProcessing(_dbCtx); ProfilesUpdateSummaryResultModel batchResponse = profileDataAccessComponent.BatchUpdateProfiles(investorLogin); if (batchResponse != null || batchResponse.ProcessedTickersCount > 0) { serializedBatchResponse = JsonConvert.SerializeObject(batchResponse); return(serializedBatchResponse); } else { Log.Error("Error updating Profiles via ProfileController.UpdateAllProfiles() for investor: " + investorLogin); return(string.Empty); } }
public Dictionary <string, string> CalculateDivFreqAndDivMonths(string tickerSymbol, Data.PIMS3Context ctx) { StringBuilder oneYearDivPayMonths_1 = new StringBuilder(); string oneYearDivPayMonths_2 = string.Empty; int divFreqCounter = 0; string tempDate = ""; var profileDataAccessComponent = new ProfileDataProcessing(ctx); JArray orderedJsonTickerPriceData = profileDataAccessComponent.FetchDividendSpecsForTicker(tickerSymbol); if (orderedJsonTickerPriceData == null) { Log.Warning("ProfileProcessing.CalculateDivFreqAndDivMonths() - found unresolved ticker in Tiingo service, unable to update Profile price data for {0}: ", tickerSymbol); return(null); } List <int> divPayoutDays = new List <int>(); foreach (JObject objChild in orderedJsonTickerPriceData.Children <JObject>()) { // Loop will key in on "divCash" for gathering needed freq & month specs. foreach (var property in objChild.Properties()) { if (property.Name == "date") { tempDate = property.Value.ToString(); } if (property.Name == "divCash") { if (decimal.Parse(property.Value.ToString()) > 0) { divFreqCounter += 1; oneYearDivPayMonths_1.Append(ExtractMonthFromDivPayDate(tempDate)); divPayoutDays.Add(ExtractDivPayDay(tempDate)); oneYearDivPayMonths_1.Append(","); } } } } int medianDivPayoutDay = CommonSvc.CalculateMedianValue(divPayoutDays); if (oneYearDivPayMonths_1.Length == 0) { return(null); } // Strip trailing comma. oneYearDivPayMonths_2 = oneYearDivPayMonths_1.ToString().Substring(0, oneYearDivPayMonths_1.Length - 1); string[] oneYearDivPayMonths_3 = oneYearDivPayMonths_2.Split(','); Dictionary <string, string> finalProfileSpecs = new Dictionary <string, string>(); int monthsCount = oneYearDivPayMonths_3.Length; /* == finalProfileSpecs Keys legend: == * "DF"(dividend frequency) * "DM"(dividend months) * "DPD"(dividend payout day) */ if (monthsCount >= 3 && monthsCount <= 5) { // Due to possible inconsistent number of income receipts made within the last 12 month price history obtained // from our 3rd party service (Tiingo), we'll account for this by designating as (Q)uarterly dividend frequency. finalProfileSpecs.Add("DF", "Q"); finalProfileSpecs.Add("DM", oneYearDivPayMonths_2); } else if (monthsCount >= 5) { finalProfileSpecs.Add("DF", "M"); finalProfileSpecs.Add("DM", "-"); } else if (monthsCount == 2) { finalProfileSpecs.Add("DF", "S"); finalProfileSpecs.Add("DM", oneYearDivPayMonths_2); } else { finalProfileSpecs.Add("DF", "A"); finalProfileSpecs.Add("DM", oneYearDivPayMonths_2); } if (medianDivPayoutDay > 0) { finalProfileSpecs.Add("DPD", medianDivPayoutDay.ToString()); } return(finalProfileSpecs); }
public IEnumerable <AssetCreationVm> ParsePortfolioSpreadsheetForAssetRecords(string filePath, ImportFileDataProcessing dataAccessComponent, string id) { List <AssetCreationVm> assetsToCreateList = new List <AssetCreationVm>(); var profileDataAccessComponent = new ProfileDataProcessing(_ctx); var existingProfileId = string.Empty; var existingAssetClassId = "6215631D-5788-4718-A1D0-A2FC00A5B1A7";; var newAssetId = Guid.NewGuid().ToString(); List <Position> positionsToBeSaved = null; try { string lastTickerProcessed = string.Empty; var importFile = new FileInfo(filePath); using (ExcelPackage package = new ExcelPackage(importFile)) { ExcelWorksheet workSheet = package.Workbook.Worksheets[0]; int totalRows = workSheet.Dimension.End.Row; int totalColumns = workSheet.Dimension.End.Column; AssetCreationVm newAsset = new AssetCreationVm(); // Iterate XLS/CSV, ignoring column headings (row 1). for (var rowNum = 2; rowNum <= totalRows; rowNum++) { // Validate XLS var headerRow = workSheet.Cells[1, 1, rowNum, totalColumns].Select(c => c.Value == null ? string.Empty : c.Value.ToString()); if (!ValidateFileType(filePath)) { return(null); } // Args: Cells[fromRow, fromCol, toRow, toCol] var row = workSheet.Cells[rowNum, 1, rowNum, totalColumns].Select(c => c.Value == null ? string.Empty : c.Value.ToString()); var enumerableCells = row as string[] ?? row.ToArray(); var positionDataAccessComponent = new PositionDataProcessing(_ctx); // Existing Position-Account implies Profile existence. IQueryable <Asset> positionAccount = positionDataAccessComponent.GetPositionAssetByTickerAndAccount(enumerableCells.ElementAt(1).Trim(), enumerableCells.ElementAt(0).Trim(), id); if (!positionAccount.Any()) // No Position-Account found. { IQueryable <Profile> profilePersisted = null; // Are we processing a different ticker symbol? if (lastTickerProcessed.Trim().ToUpper() != enumerableCells.ElementAt(1).Trim().ToUpper()) { lastTickerProcessed = enumerableCells.ElementAt(1).Trim().ToUpper(); // Do we first have a standard web-derived Profile (via 3rd party) record in our database? profilePersisted = profileDataAccessComponent.FetchDbProfile(enumerableCells.ElementAt(1).Trim(), ""); if (profilePersisted == null) { // Do we secondly have a Customized Profile (via 3rd party) record in our database? // Check for lost _investorSvc reference. if (_investorSvc == null) { _investorSvc = new InvestorSvc(_ctx); } ; Investor currentInvestor = _investorSvc.GetById(id); profilePersisted = profileDataAccessComponent.FetchDbProfile(enumerableCells.ElementAt(1).Trim(), currentInvestor.LoginName); } if (profilePersisted != null) { // Bypassing Profile creation for new Position. existingProfileId = profilePersisted.First().ProfileId; if (assetIdForPosition == string.Empty) { assetIdForPosition = newAssetId; } // Are we processing our first XLSX Position record? if (positionsToBeSaved == null) { positionsToBeSaved = InitializePositions(new List <Position>(), enumerableCells); } else { positionsToBeSaved = InitializePositions(positionsToBeSaved, enumerableCells); } // Error seeding collection. if (positionsToBeSaved == null) { return(null); } assetsToCreateList.Add(new AssetCreationVm { AssetId = Guid.NewGuid().ToString(), AssetClassId = existingAssetClassId, InvestorId = id, ProfileId = existingProfileId, LastUpdate = DateTime.Now, Positions = positionsToBeSaved }); } else { // Obtain a new Profile via Tiingo API. var webProfileData = profileDataAccessComponent.BuildProfile(enumerableCells.ElementAt(1).Trim().ToUpper()); if (webProfileData == null) { dataAccessComponent._exceptionTickers = enumerableCells.ElementAt(1).Trim().ToUpper(); return(null); // any necessary logging done via component. } else { // Dividend freq, months, & payDay all may be edited via 'Asset Profile' // functionality for any created *customized* Profile only. Any standard // Profile may NOT be edited this way, as this would impact many investors. Profile newProfile = new Profile { ProfileId = webProfileData.ProfileId, DividendYield = webProfileData.DividendYield > 0 ? webProfileData.DividendYield : 0, CreatedBy = null, DividendRate = webProfileData.DividendRate > 0 ? webProfileData.DividendRate : 0, ExDividendDate = webProfileData.ExDividendDate ?? new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day), DividendFreq = webProfileData.DividendFreq ?? "M", DividendMonths = null, DividendPayDay = 15, EarningsPerShare = webProfileData.EarningsPerShare > 0 ? webProfileData.EarningsPerShare : 0, LastUpdate = DateTime.Now, PERatio = webProfileData.PERatio > 0 ? webProfileData.PERatio : 0, TickerDescription = webProfileData.TickerDescription.Trim(), TickerSymbol = webProfileData.TickerSymbol.ToUpper().Trim(), UnitPrice = webProfileData.UnitPrice }; assetIdForPosition = newAssetId; assetsToCreateList.Add(new AssetCreationVm { AssetId = Guid.NewGuid().ToString(), AssetClassId = existingAssetClassId, InvestorId = id, //INVESTORID, ProfileId = newProfile.ProfileId, LastUpdate = DateTime.Now, Positions = positionsToBeSaved == null ? InitializePositions(new List <Position>(), enumerableCells) : InitializePositions(positionsToBeSaved, enumerableCells), Profile = newProfile }); foreach (var asset in assetsToCreateList) { if (asset.Positions.Count == 0) { Log.Error("Error creating new Position(s) for assetsToCreateList in ImportFileProcessing.ParsePortfolioSpreadsheetForAssetRecords()."); return(null); } } ; } } } else { // Asset header initialization & Profile check bypassed; processing SAME ticker - DIFFERENT account. // Adding to existing AssetCreationVm.Positions. var updatedPositions = InitializePositions(assetsToCreateList.Last().Positions.ToList(), enumerableCells); assetsToCreateList.Last().Positions.Add(updatedPositions.Last()); } } else { // Attempted duplicate Position-Account insertion. lastTickerProcessed = enumerableCells.ElementAt(1).Trim(); } } // end 'for' } // end 'using' } catch (Exception ex) { if (ex.Message.Length > 0) { Log.Error("Error found within ImportFileProcessing.ParsePortfolioSpreadsheetForAssetRecords(), due to {0}.", ex.Message); } else { Log.Error("Error found within ImportFileProcessing.ParsePortfolioSpreadsheetForAssetRecords()."); } return(null); } return(assetsToCreateList); }
public DataImportVm SaveAssets(DataImportVm importVmToSave, PIMS3Context _ctx, string id) { ImportFileProcessing busLogicComponent = new ImportFileProcessing(importVmToSave, _ctx, null); if (busLogicComponent.ValidateVm()) { assetListingToSave = busLogicComponent.ParsePortfolioSpreadsheetForAssetRecords(importVmToSave.ImportFilePath.Trim(), this, id); if (assetListingToSave == null || assetListingToSave.Count() == 0) { if (!string.IsNullOrEmpty(importVmToSave.ExceptionTickers)) { importVmToSave.MiscMessage = "Error saving position(s) for " + importVmToSave.ExceptionTickers + ". Check position(s)"; } else { importVmToSave.MiscMessage = BuildLogMessage("position(s)"); } return(importVmToSave); } else { List <Data.Entities.Profile> profilesToSave = new List <Data.Entities.Profile>(); List <Data.Entities.Asset> assetsToSave = new List <Data.Entities.Asset>(); List <Data.Entities.Position> positionsToSave = new List <Data.Entities.Position>(); for (int vmRecordIdx = 0; vmRecordIdx < assetListingToSave.Count(); vmRecordIdx++) { if (assetListingToSave.ElementAt(vmRecordIdx).Profile != null) { profilesToSave.Add(MapVmToEntities(assetListingToSave.ElementAt(vmRecordIdx).Profile) as Data.Entities.Profile); } else { profileDataAccessComponent = new ProfileDataProcessing(_ctx); } // "Asset" must first be initialized before referenced "Positions" can be added. assetsToSave.Add(MapVmToEntities(assetListingToSave.ElementAt(vmRecordIdx)) as Data.Entities.Asset); positionsToSave.Clear(); for (var position = 0; position < assetListingToSave.ElementAt(vmRecordIdx).Positions.Count(); position++) { positionsToSave.Add(MapVmToEntities(assetListingToSave.ElementAt(vmRecordIdx).Positions.ElementAt(position)) as Data.Entities.Position); assetsToSave.ElementAt(vmRecordIdx).Positions.Add(positionsToSave.ElementAt(position)); } } // Persist to PIMS2Db. try { // Omitting "using{}": DI handles disposing of ctx; *non-disposed ctx* needed for later // call to profileDataAccessComponent.FetchDbProfileTicker(). if (profilesToSave.Count > 0) { _ctx.AddRange(profilesToSave); } _ctx.AddRange(assetsToSave); recordsSaved = _ctx.SaveChanges(); } catch (Exception ex) { Exception err = ex.InnerException; Log.Error("Error persisting Profile(s)/Asset(s) to database within ImportFileDataProcessing.SaveAssets() due to {0}", err.Message); return(null); } } } return(HandleDbProcessingResults(importVmToSave, null, assetListingToSave)); }