public async Task Update_AgencyCurrency_From_BudgetForm_For_Aipe_InitialStage_Cost() { //Arrange var userId = _userId; var costId = _costId; var costStageRevisionId = _costStageRevisionId; const string initialAgencyCurrency = "GBP"; const string expectedAgencyCurrency = "EUR"; _stageDetails.AgencyCurrency = initialAgencyCurrency; var entries = new ExcelCellValueLookup { ["currency.agency"] = new ExcelCellValue { Value = expectedAgencyCurrency } }; var aipeStage = new CostStage { Key = CostStages.Aipe.ToString() }; _costStageRevision.CostStage = aipeStage; _costStageRevision.IsPaymentCurrencyLocked = false; //Act ServiceResult result = await _target.Update(entries, userId, costId, costStageRevisionId); //Assert result.Should().NotBeNull(); result.Success.Should().BeTrue(); _stageFormData.Data.Should().Contain(expectedAgencyCurrency); }
private string GetDpvCurrencyCode(ExcelCellValueLookup entries, PgStageDetailsForm stageDetails) { if (stageDetails.ProductionType?.Key == Constants.ProductionType.FullProduction) { return(GetSectionCurrencyCode(entries, Production)); } return(GetSectionCurrencyCode(entries, PostProduction)); }
private static string GetSectionCurrencyCode(ExcelCellValueLookup entries, string section) { // See excel_cell_lookups.json file for a list of currency.* mappings. string key = $"currency.{section.ToLower()}"; if (entries.ContainsKey(key)) { return(entries[key].Value); } return(string.Empty); }
public async Task Empty_Entries_Returns_No_Updated_CostLineItems() { //Arrange var entries = new ExcelCellValueLookup(); var costId = _costId; var costStageRevisionId = _costStageRevisionId; //Act ServiceResult <List <CostLineItem> > result = await _target.Update(entries, _userIdentity, costId, costStageRevisionId); //Assert result.Should().NotBeNull(); result.Success.Should().BeFalse(); }
public async Task Do_Not_Update_AgencyCurrency_From_BudgetForm_For_LockedPaymentCurrency() { //Arrange var userId = _userId; var costId = _costId; var costStageRevisionId = _costStageRevisionId; const string initialAgencyCurrency = "GBP"; const string expectedAgencyCurrency = "EUR"; _stageDetails.AgencyCurrency = initialAgencyCurrency; var entries = new ExcelCellValueLookup { ["currency.agency"] = new ExcelCellValue { Value = expectedAgencyCurrency } }; var originalEstimateStage = new CostStage { Key = CostStages.OriginalEstimate.ToString() }; var originalEstimateRevisionStage = new CostStage { Key = CostStages.OriginalEstimateRevision.ToString() }; _costStageRevision.CostStage = originalEstimateRevisionStage; _costStageRevision.IsPaymentCurrencyLocked = true; var firstRevision = new CostStageRevision(); firstRevision.CostStage = originalEstimateStage; firstRevision.IsPaymentCurrencyLocked = false; originalEstimateRevisionStage.CostStageRevisions = new List <CostStageRevision> { firstRevision, _costStageRevision }; //Act ServiceResult result = await _target.Update(entries, userId, costId, costStageRevisionId); //Assert result.Should().NotBeNull(); result.Success.Should().BeFalse(); result.Errors.Should().NotBeNull(); result.Errors.Should().HaveCount(1); _stageFormData.Data.Should().NotContain(expectedAgencyCurrency); }
public async Task Empty_Entries_Returns_False_Success() { //Arrange var entries = new ExcelCellValueLookup(); var userId = _userId; var costId = _costId; var costStageRevisionId = _costStageRevisionId; //Act ServiceResult result = await _target.Update(entries, userId, costId, costStageRevisionId); //Assert result.Should().NotBeNull(); result.Success.Should().BeFalse(); }
private async Task <Currency> GetCurrency(ExcelCellValueLookup entries, CostLineItemSectionTemplateModel costSection, CostLineItemSectionTemplateItemModel item) { string code; var key = GetItemCurrencyKey(costSection, item); if (entries.ContainsKey(key)) { code = entries[key].Value; } else { key = GetSectionCurrencyKey(costSection); code = entries.ContainsKey(key) ? entries[key].Value : entries[GetAgencyCurrencyKey()].Value; } return(await _efContext.Currency.Where(c => c.Code == code).FirstOrDefaultAsync()); }
public async Task <ServiceResult <List <CostLineItem> > > Update(ExcelCellValueLookup entries, UserIdentity userIdentity, Guid costId, Guid costStageRevisionId) { if (entries == null) { Logger.Warning("Param entries is null reference. This means the uploaded budget form was not read correctly."); return(ServiceResult <List <CostLineItem> > .CreateFailedResult(TechnicalErrorMessage)); } if (userIdentity == null) { Logger.Warning("Param userIdentity is null reference."); return(ServiceResult <List <CostLineItem> > .CreateFailedResult(TechnicalErrorMessage)); } if (costId == Guid.Empty) { Logger.Warning("Param costId is Guid.Empty."); return(ServiceResult <List <CostLineItem> > .CreateFailedResult(TechnicalErrorMessage)); } if (costStageRevisionId == Guid.Empty) { Logger.Warning("Param costStageRevisionId is Guid.Empty."); return(ServiceResult <List <CostLineItem> > .CreateFailedResult(TechnicalErrorMessage)); } if (entries.Count == 0) { Logger.Warning("Param entries is empty collection. This means the uploaded budget form was not read correctly."); return(ServiceResult <List <CostLineItem> > .CreateFailedResult(TechnicalErrorMessage)); } var updatedItems = new List <CostLineItem>(); var serviceResult = new ServiceResult <List <CostLineItem> >(updatedItems); var stageForm = await _costStageRevisionService.GetStageDetails <PgStageDetailsForm>(costStageRevisionId); var contentType = stageForm.GetContentType(); var production = stageForm.GetProductionType(); //Get the form var cost = await _efContext.Cost .Include(c => c.CostTemplateVersion) .ThenInclude(ctv => ctv.CostTemplate) .ThenInclude(ct => ct.FieldDefinitions) .FirstOrDefaultAsync(c => c.Id == costId); var costStageRevision = await _efContext.CostStageRevision .Include(c => c.CostLineItems) .FirstOrDefaultAsync(c => c.Id == costStageRevisionId); var templateModel = await _costTemplateVersionService.GetCostTemplateVersionModel(cost.CostTemplateVersionId); var formResult = _costSectionFinder.GetCostSection(templateModel, contentType, production); if (!formResult.Success) { serviceResult.AddErrorRange(formResult.Errors); return(serviceResult); } var form = formResult.Result; // SPB-3005 --> ADC-2892 var exchangeRates = await _costExchangeRateService.GetExchangeRatesByDefaultCurrency(costId); //Iterate through the cost line items foreach (var costSection in form.CostLineItemSections) { foreach (var item in costSection.Items) { //Build a lookup key that will look in the LookupKey column for an exact match. // lookupKey format is form.costSection.item.currency or costSection.item.currency var defaultLookupKey = GetDefaultCurrencyLookupKey(form, costSection, item); var localLookupKey = GetLocalCurrencyLookupKey(form, costSection, item); if (!entries.ContainsKey(defaultLookupKey)) { // if the lookupKey does not exist with the form.Name included, try without the form. var message = $"BF001: {form.Name}:{costSection.Name}:{item.Name} not found for cost: {costId} in uploaded budget form. Trying {costSection.Name}:{item.Name}..."; Logger.Warning(message); defaultLookupKey = GetDefaultCurrencyLookupKey(costSection, item); } if (!entries.ContainsKey(localLookupKey)) { localLookupKey = GetLocalCurrencyLookupKey(costSection, item); } if (entries.ContainsKey(defaultLookupKey) && entries.ContainsKey(localLookupKey)) { var defaultCurrencyStringValue = entries[defaultLookupKey].Value; var localCurrencyStringValue = entries[localLookupKey].Value; var updateCell = true; if (!decimal.TryParse(localCurrencyStringValue, out var localCurrencyValue)) { var warning = $"BF002: Invalid entry '{localCurrencyStringValue}' for {costSection.Name}:{item.Name} for cost: {costId} in uploaded budget form."; Logger.Warning(warning); var userError = $"Invalid entry '{localCurrencyStringValue}' in cell '{entries[localLookupKey].Name}'."; serviceResult.AddError(userError); updateCell = false; } if (!decimal.TryParse(defaultCurrencyStringValue, out var defaultCurrencyValue)) { var warning = $"BF003: Invalid entry '{defaultCurrencyStringValue}' for {costSection.Name}:{item.Name} for cost: {costId} in uploaded budget form."; Logger.Warning(warning); var userError = $"Invalid entry '{defaultCurrencyStringValue}' in cell '{entries[defaultLookupKey].Name}'."; serviceResult.AddError(userError); updateCell = false; } if (updateCell) { var cli = GetOrCreateCostLineItem(costStageRevision, userIdentity.Id, costSection, item); var currency = await GetCurrency(entries, costSection, item); if (HasCurrencyChanged(currency, cli) && !CanUpdateCurrency(costStageRevision)) { var costSectionCurrency = await GetCurrencyCode(cli.LocalCurrencyId); var error = new FeedbackMessage( $"The currency you have chosen in the budget form, {currency.Code} does not match the cost section currency of {costSectionCurrency}. There are two options to progress this:"); error.AddSuggestion("You may change the currency of your budget form to match the cost section currency and re-upload the Budget form."); error.AddSuggestion( "You may cancel this datasheet, create a new cost and select the required currency. After cancelling your cost please contact P&G. They will raise and issue credit for any monies you have received against the original PO."); serviceResult.AddError(error); return(serviceResult); } //Update the cost line item cli.LocalCurrencyId = currency.Id; var exchangeRate = exchangeRates.FirstOrDefault(ex => ex.FromCurrency == cli.LocalCurrencyId); cli.ValueInDefaultCurrency = (exchangeRate?.Rate * localCurrencyValue) ?? 0; //we calculate it because we can't trust the sent value from front-end cli.ValueInLocalCurrency = localCurrencyValue; cli.SetModifiedNow(); updatedItems.Add(cli); } } else { var userError = $"BF004: {costSection.Name}:{item.Name} not found for cost: {costId} in uploaded budget form. Adding Zero as default value."; Logger.Warning(userError); serviceResult.AddWarning(userError); //Create a default value if (item.Mandatory.HasValue && item.Mandatory.Value) { var cli = GetOrCreateCostLineItem(costStageRevision, userIdentity.Id, costSection, item); var currency = await GetCurrency(entries, costSection, item); //Update the cost line item cli.LocalCurrencyId = currency.Id; cli.ValueInDefaultCurrency = 0; cli.ValueInLocalCurrency = 0; cli.SetModifiedNow(); updatedItems.Add(cli); } } } } return(serviceResult); }
public async Task <ServiceResult <Dictionary <string, Guid> > > Update(ExcelCellValueLookup entries, Guid userId, Guid costId, Guid costStageRevisionId) { if (entries == null) { Logger.Warning("Param entries is null reference. This means the uploaded budget form was not read correctly."); return(ServiceResult <Dictionary <string, Guid> > .CreateFailedResult(TechnicalErrorMessage)); } if (userId == Guid.Empty) { Logger.Warning("Param userId is Guid.Empty."); return(ServiceResult <Dictionary <string, Guid> > .CreateFailedResult(TechnicalErrorMessage)); } if (costId == Guid.Empty) { Logger.Warning("Param costId is Guid.Empty."); return(ServiceResult <Dictionary <string, Guid> > .CreateFailedResult(TechnicalErrorMessage)); } if (costStageRevisionId == Guid.Empty) { Logger.Warning("Param costStageRevisionId is Guid.Empty."); return(ServiceResult <Dictionary <string, Guid> > .CreateFailedResult(TechnicalErrorMessage)); } if (entries.Count == 0) { Logger.Warning("Param entries is empty collection. This means the uploaded budget form was not read correctly."); return(ServiceResult <Dictionary <string, Guid> > .CreateFailedResult(TechnicalErrorMessage)); } var stageForm = await _costStageRevisionService.GetStageDetails <PgStageDetailsForm>(costStageRevisionId); var productionForm = await _costStageRevisionService.GetProductionDetails <PgProductionDetailsForm>(costStageRevisionId); var costStageRevision = await _efContext.CostStageRevision .Include(csr => csr.CostStage) .ThenInclude(csr => csr.CostStageRevisions) .FirstOrDefaultAsync(c => c.Id == costStageRevisionId); //Update the Agency Currency, if different var agencyCurrencyCode = GetAgencyCurrencyCode(entries); // return a dictionary of the currencies that have been modified i.e. agency, dpv, section. // Key is agency, dpv or section name and value is the currencyId. The FE has all the Ids and can update itself. var currencies = new Dictionary <string, Guid>(); var serviceResult = new ServiceResult <Dictionary <string, Guid> >(currencies); if (stageForm.AgencyCurrency != agencyCurrencyCode) { if (CanUpdateAgencyCurrency(costStageRevision)) { var stageDetails = await _efContext.CustomFormData.FirstOrDefaultAsync(c => c.Id == costStageRevision.StageDetailsId); UpdateAgencyCurrency(stageDetails, agencyCurrencyCode); var agencyCurrencyId = await GetCurrencyId(agencyCurrencyCode); currencies[AgencyCurrencyKey] = agencyCurrencyId; } else { var error = new FeedbackMessage( $"The agency currency you have chosen in the budget form, {agencyCurrencyCode} does not match your datasheet of {stageForm.AgencyCurrency}. There are two options to progress this:"); error.AddSuggestion("You may change the currency of your budget form to match the datasheet currency and re-upload the Budget form."); error.AddSuggestion( "You may cancel this datasheet, create a new cost and select the required agency currency. After cancelling your cost please contact P&G. They will raise and issue credit for any monies you have received against the original PO."); serviceResult.AddError(error); return(serviceResult); } } // The Cost Section Currencies done by the ICostLineItemUpdater because each CostLineItem has a currency. // On the UI, the Cost Section currency is set by rolling up from the first CostLineItem. // Here we extrapolate the currencies for the DPV and the cost line item sections in order to simplify the // front end code. At this present time, the FE calculates the CLI Section currency based on the first item it finds. if (productionForm.DirectPaymentVendor != null) { var dpvCurrencyCode = GetDpvCurrencyCode(entries, stageForm); var dpvCurrencyId = await GetCurrencyId(dpvCurrencyCode); var productionDetails = await _efContext.CustomFormData.FirstOrDefaultAsync(c => c.Id == costStageRevision.ProductDetailsId); UpdateDpvCurrency(productionDetails, dpvCurrencyId); currencies[DirectPaymentVendorCurrencyKey] = dpvCurrencyId; } return(serviceResult); }
private static string GetAgencyCurrencyCode(ExcelCellValueLookup entries) { return(entries[AgencyCurrencyMappingKey].Value); }