Beispiel #1
0
        public async Task <List <SupportingDocumentModel> > BuildSupportingDocuments(IStageDetails stageDetails, CostType costType, IEnumerable <string> stageKeys,
                                                                                     Guid costStageRevisionId, bool totalCostIncreased = false)
        {
            var stageDetailsForm = stageDetails.Data.ToModel <PgStageDetailsForm>();

            var rules            = (await _ruleService.GetCompiledByRuleType <SupportingDocumentRule>(RuleType.SupportingDocument)).ToArray();
            var supportingDocs   = new List <SupportingDocumentModel>();
            var previousRevision = await _costStageRevisionService.GetPreviousRevision(costStageRevisionId);

            foreach (var stage in stageKeys)
            {
                var supportingDocRule = new SupportingDocumentRule
                {
                    BudgetRegion       = stageDetailsForm.BudgetRegion?.Key,
                    ContentType        = stageDetailsForm.ContentType?.Key,
                    CostStage          = stage,
                    ProductionType     = stageDetailsForm.ProductionType?.Key,
                    CostType           = costType.ToString(),
                    TotalCostIncreased = totalCostIncreased,
                    PreviousCostStage  = previousRevision != null ? previousRevision?.Name : string.Empty
                };
                List <SupportingDocumentModel> output;
                Func <SupportingDocumentRule, Rule, List <SupportingDocumentModel> > matched = (supportingDocumentRule, rule) =>
                {
                    var ruleDefinition = JsonConvert.DeserializeObject <SupportingDocumentRuleDefinition>(rule.Definition);
                    return(new List <SupportingDocumentModel>
                    {
                        new SupportingDocumentModel
                        {
                            CanManuallyUpload = ruleDefinition.CanManuallyUpload,
                            Name = ruleDefinition.Name,
                            Key = ruleDefinition.Key ?? string.Empty,
                            Generated = true,
                            Required = ruleDefinition.Mandatory
                        }
                    });
                };

                Func <List <SupportingDocumentModel>, List <SupportingDocumentModel>, List <SupportingDocumentModel> > aggregator = (total, result) =>
                {
                    total.AddRange(result);
                    return(total);
                };

                _ruleService.TryMatchRule(rules, supportingDocRule, matched, aggregator, out output);

                if (output != null)
                {
                    supportingDocs.AddRange(output);
                }
            }

            return(supportingDocs);
        }
Beispiel #2
0
        private static StageModel GetFirstStage(IStageDetails stageDetails, PgStageDetailsForm stageDetailsForm, Dictionary <string, StageModel> stages)
        {
            // if AIPE is applicable & selected, the initial stage is AIPE (1), otherwise - Original Estimate (2)
            var firstStageKey = stageDetailsForm.IsAIPE
                ? CostStages.Aipe.ToString()
                : !string.IsNullOrEmpty(stageDetailsForm.ApprovalStage)
                    ? stageDetailsForm.ApprovalStage
                    : CostStages.OriginalEstimate.ToString();

            if (!ValidateStage(stages, CostStages.New.ToString(), firstStageKey))
            {
                throw new ValidationException($"{firstStageKey} can't be first stage for {JsonConvert.SerializeObject(stageDetails.Data)}");
            }

            return(stages[firstStageKey]);
        }
Beispiel #3
0
        private async Task <CostStageModel> BuildCostFirstStageModel(PgStageDetailsForm stageDetailsForm, Guid userId, CostType costType, IStageDetails stageDetails)
        {
            var stages = await GetStages(stageDetailsForm, costType);

            var firstStage = GetFirstStage(stageDetails, stageDetailsForm, stages);

            var stagesToBuildDocs = GetStagesToBuildDocs(stages, firstStage.Key, firstStage.Key);

            return(new CostStageModel
            {
                Key = firstStage.Key,
                Name = firstStage.Name,
                Order = 1,
                Revisions = new[]
                {
                    new CostStageRevisionModel
                    {
                        Name = firstStage.Key,
                        Status = CostStageRevisionStatus.Draft,
                        StageDetails = JsonConvert.SerializeObject(stageDetails.Data),
                        SupportingDocuments = await BuildSupportingDocuments(stageDetails, costType, stagesToBuildDocs, Guid.Empty)
                    }
                }
            });
        }
Beispiel #4
0
        public async Task <List <ApprovalModel> > GetApprovals(CostType costType, IStageDetails stageDetails, Guid userId, Guid costStageRevisionId, Guid costId)
        {
            var costStageKey = await _efContext.CostStageRevision
                               .Where(csr => csr.Id == costStageRevisionId)
                               .Select(c => c.CostStage.Key)
                               .FirstAsync();

            var stageDetailsForm = stageDetails.Data.ToModel <PgStageDetailsForm>();
            var currentTotals    = await GetTotals(costStageRevisionId);

            var costTotalIncreased = true;
            var previousRevision   = await _costStageRevisionService.GetPreviousRevision(costStageRevisionId);

            // Always need brand approval if prvious stage is aipe  https://jira.adstream.com/browse/ADC-1585
            if (previousRevision != null && previousRevision.Name != CostStages.Aipe.ToString())
            {
                var previousTotals = await GetTotals(previousRevision.Id);

                // rounding to account for decimal precision differences during currency conversion
                if (Math.Round(currentTotals.TotalCostAmountTotal, 2) <= Math.Round(previousTotals.TotalCostAmountTotal, 2))
                {
                    costTotalIncreased = false;
                }
            }

            // we only perform a "soft" calculation, withput saving it to the DB
            //var totalPayments = await _paymentService.GetPaymentAmount(costStageRevisionId, false);
            var brandApprovalEnabled = costTotalIncreased;

            var agency = await _agencyService.GetAgencyByCostId(costId);

            var agencyIsCyclone = agency?.IsCyclone() ?? false;

            var approvalRule = new PgApprovalRule
            {
                ProductionType  = stageDetailsForm.ProductionType?.Key,
                CostType        = costType.ToString(),
                BudgetRegion    = stageDetailsForm.BudgetRegion?.Key,
                ContentType     = stageDetailsForm.ContentType?.Key,
                TotalCostAmount = currentTotals.TotalCostAmountTotal,
                IsCyclone       = agencyIsCyclone
            };

            var rules = await _ruleService.GetCompiledByRuleType <PgApprovalRule>(RuleType.ApprovalRule);

            var costStage          = (CostStages)Enum.Parse(typeof(CostStages), costStageKey);
            var isContractCostOnNa = stageDetailsForm?.UsageBuyoutType?.Key == Constants.UsageBuyoutType.Contract &&
                                     stageDetailsForm.BudgetRegion?.Key == Constants.BudgetRegion.NorthAmerica;
            Func <PgApprovalRule, Rule, ApprovalRule> matchFunc = (t, r) =>
            {
                var ruleFlags = JsonConvert.DeserializeObject <PgApprovalRuleDefinition>(r.Definition);

                // https://jira.adstream.com/browse/ADC-1152
                var ipmEnabled = false;
                var ccEnabled  = false;
                if (costStage != CostStages.Aipe && !isContractCostOnNa)
                {
                    ipmEnabled = ruleFlags.IpmApprovalEnabled;
                    ccEnabled  = ruleFlags.CostConsultantIpmAllowed;
                }

                // https://jira.adstream.com/browse/ADC-812
                var brandApprovalRequired = false;
                if (brandApprovalEnabled)
                {
                    brandApprovalRequired = ruleFlags.BrandApprovalEnabled;
                }

                var res = new ApprovalRule
                {
                    CostType                 = costType,
                    ContentType              = t.ContentType,
                    BudgetRegion             = t.BudgetRegion,
                    TotalCostAmount          = t.TotalCostAmount,
                    BrandApprovalEnabled     = brandApprovalRequired,
                    CostConsultantIpmAllowed = ccEnabled,
                    IpmApprovalEnabled       = ipmEnabled,
                    HasExternalIntegration   = ruleFlags.HasExternalIntegration
                };

                return(res);
            };

            _ruleService.TryMatchRule(rules, approvalRule, matchFunc, out var fResult);

            return(fResult != null?fResult.Approvals() : new List <ApprovalModel>());
        }
Beispiel #5
0
        public async Task <IUpdateCostFormResponse> UpdateCostForm(UserIdentity userIdentity, Guid costId, Guid latestRevisionId, CostType costType, IStageDetails stageDetails,
                                                                   ICostFormDetails costFormDetails, CustomFormDefinition formDefinition, FormSectionDefinition formSectionDefinition)
        {
            var costFormJson = JObject.FromObject(costFormDetails.Data);
            var response     = new UpdateCostFormResponse();

            // validate json

            var sectionFound = false;

            foreach (var node in costFormJson)
            {
                if (node.Value.Type == JTokenType.Object && formSectionDefinition.Label.Equals(node.Key, StringComparison.OrdinalIgnoreCase))
                {
                    sectionFound = true;
                    break;
                }
            }

            if (!sectionFound)
            {
                var errMsg = $"section '{formSectionDefinition.Name}' is missing from form";
                response.Errors.Add(errMsg);
            }


            if (response.Errors.Count == 0)
            {
                if (formDefinition.CostFormDetails.Id == Guid.Empty)
                {
                    response.Details = new CostFormDetails
                    {
                        FormDefinitionId = formSectionDefinition.FormDefinitionId
                    };
                }
                else
                {
                    response.Details = formDefinition.CostFormDetails;
                }

                response.Form = formDefinition.FormDataDetailsId != Guid.Empty ? formDefinition.CustomFormData : new CustomFormData();
            }

            response.Approvals = await GetApprovals(costType, stageDetails, userIdentity.Id, latestRevisionId, costId);

            return(response);
        }
Beispiel #6
0
        public async Task <IUpdateCostResponse> UpdateCost(UserIdentity userIdentity, Guid costId, Guid latestRevisionId, CostType costType, IStageDetails stageDetails,
                                                           IProductionDetails productionDetails)
        {
            var currentCost = await _efContext.Cost
                              .Include(c => c.LatestCostStageRevision)
                              .ThenInclude(c => c.CostStage)
                              .Include(c => c.LatestCostStageRevision)
                              .ThenInclude(x => x.StageDetails)
                              .Include(c => c.LatestCostStageRevision)
                              .ThenInclude(x => x.ProductDetails)
                              .Where(c => c.Id == costId)
                              .FirstAsync();

            var oldStageForm             = JsonConvert.DeserializeObject <PgStageDetailsForm>(currentCost.LatestCostStageRevision.StageDetails.Data);
            var oldProductionForm        = JsonConvert.DeserializeObject <PgProductionDetailsForm>(currentCost.LatestCostStageRevision.ProductDetails.Data);
            var newStageDetailsForm      = stageDetails.Data.ToModel <PgStageDetailsForm>();
            var newProductionDetailsForm = productionDetails.Data.ToModel <PgProductionDetailsForm>();

            var newProductionDetails = new CustomFormData {
                Data = JsonConvert.SerializeObject(productionDetails.Data)
            };
            var newStageDetails = new CustomFormData {
                Data = JsonConvert.SerializeObject(stageDetails.Data)
            };
            var costStageModel = currentCost.LatestCostStageRevision.CostStage.StageOrder == 1
                ? await BuildCostFirstStageModel(newStageDetailsForm, userIdentity.Id, costType, stageDetails)
                : null;

            //var newCurrency = await _currencyService.GetCurrency(stageDetailsForm, productionDetailsForm);
            var newCurrency = await _currencyService.GetCurrencyIfChanged(oldStageForm, oldProductionForm, newStageDetailsForm, newProductionDetailsForm);

            var response = new UpdateCostResponse
            {
                Approvals         = await GetApprovals(costType, stageDetails, userIdentity.Id, latestRevisionId, costId),
                ProductionDetails = newProductionDetails,
                StageDetails      = newStageDetails,
                // Re-generate first stage model only. It can't be changed later
                CurrentCostStageModel = costStageModel,
                NewCurrency           = newCurrency,
                DpvSelected           = newProductionDetailsForm.DirectPaymentVendor != null && oldProductionForm?.DirectPaymentVendor == null,
                AipeSelected          = newStageDetailsForm.IsAIPE && (oldStageForm == null || !oldStageForm.IsAIPE)
            };

            return(response);
        }