示例#1
0
        public ActionResult <DataImportVm> ProcessImportFile([FromBody] DataImportVm importFile, string Id, bool isRevenue = true)
        {
            if (!ModelState.IsValid)
            {
                Log.Error("Unable to process import file via ProcessImportFile() due to invalid model state for {0}", ModelState);
                return(BadRequest("Invalid model state: " + ModelState));
            }

            var dataAccessComponent = new ImportFileDataProcessing();

            if (importFile.IsRevenueData)
            {
                processedVm = dataAccessComponent.SaveRevenue(importFile, _dbCtx, Id);

                // UI to interpret updated Vm attributes.
                if (processedVm.RecordsSaved == 0)
                {
                    // Possible invalid file path or bad network connectivity.
                    if (!string.IsNullOrEmpty(processedVm.MiscMessage))
                    {
                        Log.Warning("Aborted in ImportFileController.ProcessImportFile() due to {0} in {1}.", processedVm.MiscMessage.Trim(),
                                    processedVm.ImportFilePath.Trim());
                        return(BadRequest(new { exceptionMessage = processedVm.MiscMessage.Trim(), isRevenueData = true }));
                    }
                    else if (importFile.ExceptionTickers != string.Empty)
                    {
                        return(BadRequest(new { exceptionTickers = processedVm.ExceptionTickers }));
                    }
                    else
                    {
                        return(BadRequest(new { exceptionMessage = "Unable to persist revenue" }));
                    }
                }

                processedVm.AmountSaved = decimal.Parse(string.Format("{0:0.00}", processedVm.AmountSaved));
                Log.Information("Revenue import successful for {0} record(s), totaling ${1}.", processedVm.RecordsSaved, processedVm.AmountSaved);
                return(CreatedAtAction("ProcessImportFile", new { count = processedVm.RecordsSaved, amount = processedVm.AmountSaved }, processedVm));
            }
            else  // aka 'Positions' (Asset) processing.
            {
                processedVm = dataAccessComponent.SaveAssets(importFile, _dbCtx, Id);
                if (processedVm.RecordsSaved == 0)
                {
                    Log.Error("ImportFileController.ProcessImportFile() : {0}", processedVm.MiscMessage.Trim());
                    return(BadRequest(new { exceptionMessage = "Error saving new Position(s).", isRevenueData = false }));
                }

                // Returned customized anonymous object to be data-import.service catchError().
                if (processedVm.ExceptionTickers != string.Empty)
                {
                    return(BadRequest(new { exceptionTickers = processedVm.ExceptionTickers, isRevenueData = false }));
                }

                Log.Information("Position import successful for {0} record(s), representing {1}.", processedVm.RecordsSaved, processedVm.MiscMessage);
                return(CreatedAtAction("ProcessImportFile", new { count = processedVm.RecordsSaved, savedTickers = processedVm.MiscMessage }, processedVm));
            }
        }
示例#2
0
        private DataImportVm HandleDbProcessingResults(DataImportVm vmToProcess, IEnumerable <Data.Entities.Income> incomeListing,
                                                       IEnumerable <AssetCreationVm> assetListing)
        {
            totalAmtSaved = 0M;
            recordsSaved  = 0;

            if (assetListing != null)
            {
                for (var record = 0; record < assetListing.Count(); record++)
                {
                    recordsSaved += 1;
                    if (recordsSaved == 1)
                    {
                        if (assetListing.ElementAt(record).Profile != null)
                        {
                            tickersProcessed = assetListing.ElementAt(record).Profile.TickerSymbol.ToUpper();
                        }
                        else
                        {
                            // Db Profile already exists, hence no Profile instance in vm with a ProfileId.
                            var id = assetListing.ElementAt(record).ProfileId;
                            tickersProcessed = profileDataAccessComponent.FetchDbProfileTicker(id).First();
                        }
                    }
                    else
                    {
                        tickersProcessed += ", " + assetListing.ElementAt(record).Profile.TickerSymbol.ToUpper();
                    }
                }
            }
            else
            {
                foreach (var record in incomeListing)
                {
                    recordsSaved  += 1;
                    totalAmtSaved += record.AmountRecvd;
                }
                vmToProcess.AmountSaved = totalAmtSaved;
            }

            vmToProcess.RecordsSaved = recordsSaved;
            vmToProcess.MiscMessage  = tickersProcessed;

            return(vmToProcess);
        }
示例#3
0
 public ImportFileProcessing(DataImportVm viewModel, PIMS3Context ctx, InvestorSvc investorSvc)
 {
     _viewModel   = viewModel;
     _ctx         = ctx;
     _investorSvc = investorSvc;
 }
示例#4
0
        public DataImportVm SaveRevenue(DataImportVm importVmToUpdate, PIMS3Context _ctx, string investorId)
        {
            //  Processing includes:
            //  1. persisting revenue,
            //  2. persisting revenue delinquencies, and
            //  3. updating Positions ("PymtDue") where applicable.

            ImportFileProcessing   busLayerComponent = new ImportFileProcessing(importVmToUpdate, _ctx, null);
            IEnumerable <Income>   revenueListingToSave;
            PositionDataProcessing positionDataAccessComponent = new PositionDataProcessing(_ctx);

            if (busLayerComponent.ValidateVm())
            {
                revenueListingToSave = busLayerComponent.ParseRevenueSpreadsheetForIncomeRecords(importVmToUpdate.ImportFilePath.Trim(), this, investorId);

                if (revenueListingToSave == null || revenueListingToSave.Count() == 0)
                {
                    if (!string.IsNullOrEmpty(importVmToUpdate.ExceptionTickers))
                    {
                        importVmToUpdate.MiscMessage = "Error saving revenue for " + importVmToUpdate.ExceptionTickers + ". Check position(s).";
                    }
                    else
                    {
                        importVmToUpdate.MiscMessage = BuildLogMessage("revenue");
                    }

                    return(importVmToUpdate);
                }
                else
                {
                    // Persist to 'Income'. Deferring use of using{}: ctx scope needed.
                    _ctx.AddRange(revenueListingToSave);
                    recordsSaved = _ctx.SaveChanges();
                }

                if (recordsSaved > 0)
                {
                    totalAmtSaved = 0M;
                    foreach (var record in revenueListingToSave)
                    {
                        totalAmtSaved += record.AmountRecvd;
                    }

                    // Returned values to UI.
                    importVmToUpdate.AmountSaved  = totalAmtSaved;
                    importVmToUpdate.RecordsSaved = recordsSaved;

                    // Update Positions.
                    positionDataAccessComponent.UpdatePositionPymtDueFlags(ExtractPositionIdsForPymtDueProcessing(revenueListingToSave), true);

                    /* === Month-end delinquent revenue processing === */

                    // If at month end/beginning, we'll query Positions for any now delinquent income receivables via "PymtDue" flag.
                    // Any unpaid income receivables, those not marked as received via 'Income due', will STILL have their 'PymtDue' flag set as
                    // True, and hence will now be considered a delinquent Position, resulting in persistence to 'DelinquentIncome' table.
                    // Delinquent position searches may ONLY be performed during month-end xLSX processing, as income receipts are still being
                    // accepted during the month via 'Income due'. During 'Income due' payments, flags are set accordingly: [PymtDue : True -> False].
                    // Any delinquent Positions will automatically be added to the 'Income due' collection that is broadcast via the UI schedule,
                    // for necessary action.
                    if (DateTime.Now.Day <= 3 && DateTime.Now.DayOfWeek.ToString() != "Saturday" && DateTime.Now.DayOfWeek.ToString() != "Sunday")
                    {
                        //PositionDataProcessing positionDataAccessComponent = new PositionDataProcessing(_ctx);
                        IQueryable <dynamic>     filteredPositionAssetJoinData = positionDataAccessComponent.GetCandidateDelinquentPositions(investorId);
                        IList <DelinquentIncome> pastDueListing = new List <DelinquentIncome>();
                        string delinquentMonth = DateTime.Now.AddMonths(-1).Month.ToString().Trim();
                        int    matchingPositionDelinquencyCount       = 0;
                        IList <DelinquentIncome> existingDelinqencies = positionDataAccessComponent.GetSavedDelinquentRecords(investorId, "");
                        int duplicateDelinquencyCount = 0;

                        foreach (dynamic joinData in filteredPositionAssetJoinData)
                        {
                            // 'DelinquentIncome' PKs: InvestorId, MonthDue, PositionId
                            // Do we have a match based on PositionId & InvestorId ? If so, Position is eligible for omitting setting 'PymtDue' to True.
                            matchingPositionDelinquencyCount = existingDelinqencies.Where(d => d.PositionId == joinData.PositionId &&
                                                                                          d.InvestorId == joinData.InvestorId).Count();

                            if (matchingPositionDelinquencyCount >= 1)
                            {
                                // Do we have a duplicate entry ?
                                duplicateDelinquencyCount = existingDelinqencies.Where(d => d.PositionId == joinData.PositionId &&
                                                                                       d.InvestorId == joinData.InvestorId &&
                                                                                       d.MonthDue == delinquentMonth).Count();
                            }

                            if (joinData.DividendFreq == "M")
                            {
                                if (matchingPositionDelinquencyCount > 0 && duplicateDelinquencyCount == 0)
                                {
                                    pastDueListing.Add(InitializeDelinquentIncome(joinData));
                                }
                                else
                                {
                                    continue;
                                }
                            }
                            else
                            {
                                string[] divMonths = joinData.DividendMonths.Split(',');
                                for (var i = 0; i < divMonths.Length; i++)
                                {
                                    if (divMonths[i].Trim() == delinquentMonth)
                                    {
                                        if (matchingPositionDelinquencyCount > 0 && duplicateDelinquencyCount == 0)
                                        {
                                            pastDueListing.Add(InitializeDelinquentIncome(joinData));
                                        }
                                        else
                                        {
                                            continue;
                                        }
                                    }
                                }
                            }
                            matchingPositionDelinquencyCount = 0;
                        }

                        // Persist to 'DelinquentIncome' as needed.
                        if (pastDueListing.Any())
                        {
                            bool pastDueSaved = positionDataAccessComponent.SaveDelinquencies(pastDueListing.ToList());
                            if (pastDueSaved)
                            {
                                importVmToUpdate.MiscMessage = "Found & stored " + pastDueListing.Count() + " Position(s) with delinquent revenue.";
                                Log.Information("Saved {0} delinquent position(s) to 'DelinquentIncome' via ImportFileDataProcessing.SaveRevenue()", pastDueListing.Count());
                            }
                        }

                        // Finally, update PymtDue flags on received XLSX positions.
                        positionDataAccessComponent.UpdatePositionPymtDueFlags(ExtractPositionIdsForPymtDueProcessing(revenueListingToSave), true);
                    }
                }
                _ctx.Dispose();
            }

            // Missing amount & record count reflects error condition.
            return(importVmToUpdate);
        }
示例#5
0
        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));
        }