// ReSharper disable once InconsistentNaming public async void Can_GET_All_Account_Types() { // Arrange _ctrl = new AccountTypeController(_repository, _repositoryAsset, _identityService) { Request = new HttpRequestMessage { RequestUri = new Uri(UrlBase + "/AccountType") }, Configuration = new HttpConfiguration() }; // Act var acctTypes = await _ctrl.GetAllAccounts(); // Assert Assert.IsNotNull(acctTypes); }
private Position MapVmToPosition(PositionVm sourceData) { var acctTypeCtrl = new AccountTypeController(_repositoryAccountType, _repositoryAsset, _identityService, _repositoryInvestor); return new Position { // ReSharper disable once PossibleInvalidOperationException PurchaseDate = (DateTime) sourceData.DateOfPurchase, Quantity = sourceData.Qty, MarketPrice = sourceData.UnitCosts, InvestorKey = Utilities.GetInvestorId(_repositoryInvestor, _identityService.CurrentUser).ToString(), AcctTypeId = sourceData.ReferencedAccount.KeyId, PositionAssetId = sourceData.ReferencedAssetId, LastUpdate = DateTime.Now, TickerSymbol = sourceData.ReferencedTickerSymbol, Account = acctTypeCtrl.MapVmToAccountType(sourceData.ReferencedAccount), Url = sourceData.Url }; }
// ReSharper disable once InconsistentNaming public async Task Controller_can_GET_all_entered_account_types_for_an_investor() { // Arrange _ctrl = new AccountTypeController(_mockRepoAcctType.Object, _mockRepoAsset.Object, _mockIdentitySvc.Object) { Request = new HttpRequestMessage { RequestUri = new Uri("http://localhost/Pims.Web.Api/api/AccountType/none") }, Configuration = new HttpConfiguration() }; // Act var accountTypes = await _ctrl.GetAllAccountsForInvestor("none") as OkNegotiatedContentResult<IQueryable<string>>; // Assert Assert.IsNotNull(accountTypes); Assert.That(accountTypes.Content.Contains("Roth-IRA")); Assert.That(accountTypes.Content.All(s => s != string.Empty)); Assert.That(accountTypes.Content.Count(), Is.GreaterThanOrEqualTo(3)); }
public async Task<IHttpActionResult> CreateNewAsset([FromBody] AssetCreationVm submittedAsset) { _currentInvestor = _identityService.CurrentUser; _repositoryInvestor.UrlAddress = ControllerContext.Request.RequestUri.ToString(); // Confirm investors' registration for idempotent operations. var registeredInvestor = await Task.FromResult(_repositoryInvestor.Retreive(u => u.EMailAddr.Trim() == _currentInvestor.Trim())); if (!registeredInvestor.Any()) return BadRequest("Unable to create new Asset, no registration found for investor : " + _currentInvestor); if (!ModelState.IsValid) { return ResponseMessage(new HttpResponseMessage { StatusCode = HttpStatusCode.BadRequest, ReasonPhrase = "Invalid/Incomplete required 'ModelState' data received for new Asset creation." }); } // Reconfirm required Position data exist. if (!submittedAsset.PositionsCreated.Any()) return BadRequest("Unable to create new Asset, no Position data found."); // ACCOUNT TYPE. var acctTypeCtrl = new AccountTypeController(_repositoryAccountType, _repository, _identityService, _repositoryInvestor); var existingAcctTypes = await acctTypeCtrl.GetAllAccounts() as OkNegotiatedContentResult<IList<AccountTypeVm>>; if(existingAcctTypes == null) return BadRequest("Unable to retreive required AccountType data for Asset creation."); var duplicateCheck = GetByTicker(submittedAsset.AssetTicker.Trim()); if(duplicateCheck.Result.ToString().Contains("OkNegotiatedContent")) return ResponseMessage(new HttpResponseMessage { StatusCode = HttpStatusCode.Conflict, ReasonPhrase = "No Asset created; duplicate Asset found for " + submittedAsset.AssetTicker.Trim() }); submittedAsset.AssetInvestorId = registeredInvestor.First().InvestorId.ToString(); // Required entry. submittedAsset.AssetClassificationId = await Task.FromResult(_repositoryAssetClass.Retreive(ac => ac.Description.Trim() == submittedAsset.AssetClassification.Trim()) .AsQueryable() .First() .KeyId.ToString()); // Required entry. // PROFILE. // Submited Asset must contain the following minimum Profile information, per client validation checks. var profileLastUpdate = Convert.ToDateTime(submittedAsset.ProfileToCreate.LastUpdate) ; if(submittedAsset.ProfileToCreate.TickerSymbol.IsEmpty() || submittedAsset.ProfileToCreate.TickerDescription.IsEmpty() || submittedAsset.ProfileToCreate.Price == 0 || profileLastUpdate == DateTime.MinValue || // unassigned submittedAsset.ProfileToCreate.Url.IsEmpty()) return BadRequest("Asset creation aborted: minimum Profile data [ticker,tickerDesc,Price,lastUpDate, or Url] is missing or invalid."); var existingProfile = await Task.FromResult(_repositoryProfile.Retreive(p => p.TickerSymbol.Trim() == submittedAsset.AssetTicker.Trim()) .AsQueryable()); var profileCtrl = new ProfileController(_repositoryProfile); if (existingProfile.Any()) { if (existingProfile.First().LastUpdate >= DateTime.Now.AddHours(-24)) submittedAsset.ProfileToCreate.ProfileId = existingProfile.First().ProfileId; else { var updatedResponse = await profileCtrl.UpdateProfile(submittedAsset.ProfileToCreate) as OkNegotiatedContentResult<string>; // We'll cancel Asset creation here, as out-of-date Profile data would render inaccurate income projections, should the user // choose to use these projections real-time. if (updatedResponse == null || !updatedResponse.Content.Contains("successfully")) return BadRequest("Asset creation aborted: unable to update Profile data."); } } else { var createdProfile = await profileCtrl.CreateNewProfile(submittedAsset.ProfileToCreate) as CreatedNegotiatedContentResult<Profile>; if (createdProfile == null) return BadRequest("Error creating new Profile."); submittedAsset.ProfileToCreate.ProfileId = createdProfile.Content.ProfileId; } // ASSET. var newAsset = await SaveAssetAndGetId(submittedAsset) as CreatedNegotiatedContentResult<Asset>;; if (newAsset == null) return BadRequest("Error creating new Asset or AssetId."); submittedAsset.AssetIdentification = newAsset.Content.AssetId.ToString(); // POSITION(S). var positionCtrl = new PositionController(_identityService, _repository, _repositoryInvestor, _repositoryPosition, _repositoryAccountType); for(var pos = 0; pos < submittedAsset.PositionsCreated.Count; pos++) { // ReSharper disable once AccessToModifiedClosure var positionAcctTypeId = existingAcctTypes.Content.Where(at => at.AccountTypeDesc.Trim().ToUpper() == submittedAsset.PositionsCreated.ElementAt(pos) .PreEditPositionAccount .ToUpper() .Trim()) .AsQueryable() .Select(at => at.KeyId); if (!positionAcctTypeId.Any()) { // Rollback Asset creation (via NH Cascade). var deleteResponse = await DeleteAsset(submittedAsset.AssetTicker.Trim()) as OkNegotiatedContentResult<string>; if(deleteResponse == null || deleteResponse.Content.Contains("Error")) return BadRequest("Asset-Position creation aborted due to Asset rollback error for bad AccountType: " + submittedAsset.PositionsCreated.ElementAt(pos).PreEditPositionAccount.Trim().ToUpper()); return BadRequest("Asset-Position creation aborted due to error retreiving AccountType for: " + submittedAsset.PositionsCreated.ElementAt(pos).PreEditPositionAccount.Trim().ToUpper()); } submittedAsset.PositionsCreated.ElementAt(pos).ReferencedAccount.KeyId = positionAcctTypeId.First(); // Required entry. submittedAsset.PositionsCreated.ElementAt(pos).ReferencedAssetId = new Guid(submittedAsset.AssetIdentification); // Required entry. submittedAsset.PositionsCreated.ElementAt(pos).Url = Utilities.GetBaseUrl(_repositoryInvestor.UrlAddress) + "Asset/" + submittedAsset.AssetTicker.Trim() + "/Position/" + submittedAsset.PositionsCreated.ElementAt(pos).PreEditPositionAccount.Trim(); var createdPosition = await positionCtrl.CreateNewPosition(submittedAsset.PositionsCreated.ElementAt(pos)) as CreatedNegotiatedContentResult<Position>; if (createdPosition == null) { // Rollback Asset creation. var deleteResponse = await DeleteAsset(submittedAsset.AssetTicker.Trim()) as OkNegotiatedContentResult<string>; if (deleteResponse == null || deleteResponse.Content.Contains("Error")) return BadRequest("Asset-Position creation aborted due to Asset rollback error for Position: " + submittedAsset.PositionsCreated.ElementAt(pos).PreEditPositionAccount.Trim().ToUpper()); return BadRequest("Asset-Position creation aborted due to error creating Position for : " + submittedAsset.PositionsCreated.ElementAt(pos).PreEditPositionAccount.Trim().ToUpper()); } submittedAsset.PositionsCreated.ElementAt(pos).CreatedPositionId = createdPosition.Content.PositionId; } // INCOME (optional). if (!submittedAsset.RevenueCreated.Any()) return ResponseMessage(new HttpResponseMessage { StatusCode = HttpStatusCode.Created, ReasonPhrase = "Asset created w/o submitted Income - affiliated Profile, and Position(s) recorded." }); var incomeCtrl = new IncomeController(_identityService, _repository, _repositoryInvestor, _repositoryIncome); foreach (var incomeRecord in submittedAsset.RevenueCreated) { incomeRecord.Url = Utilities.GetBaseUrl(_repositoryInvestor.UrlAddress) + "Asset/" + submittedAsset.AssetTicker.Trim() + "/Income/"; var createdIncome = await incomeCtrl.CreateNewIncome2(incomeRecord) as CreatedNegotiatedContentResult<Income>; if (createdIncome == null) return BadRequest("Error creating new Income record(s). Please resubmit Income."); } return ResponseMessage(new HttpResponseMessage { StatusCode = HttpStatusCode.Created, ReasonPhrase = "Asset created - affiliated Profile, Position(s), and Income recorded." }); }