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); }
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]); }
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) } } }); }
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>()); }
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); }
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); }