Esempio n. 1
0
        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();
        }
Esempio n. 5
0
        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);
        }
Esempio n. 6
0
        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();
        }
Esempio n. 7
0
        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());
        }
Esempio n. 8
0
        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);
 }