private async Task SaveResponse(PgPurchaseOrderResponse payload, Cost cost, SystemAdminUserIdentity adminUser) { var purchaseOrderData = await _customDataService .GetCustomData <PgPurchaseOrderResponse>(cost.LatestCostStageRevisionId.Value, CustomObjectDataKeys.PgPurchaseOrderResponse) ?? new PgPurchaseOrderResponse(); _mapper.Map(payload, purchaseOrderData); if (string.Compare(payload.ApprovalStatus, ApprovalStatuses.Rejected, StringComparison.OrdinalIgnoreCase) == 0) { //null requisition ID should be allowed here purchaseOrderData.Requisition = payload.Requisition; purchaseOrderData.ApprovalStatus = payload.ApprovalStatus; } await _customDataService.Save(cost.LatestCostStageRevisionId.Value, CustomObjectDataKeys.PgPurchaseOrderResponse, purchaseOrderData, adminUser); await UpdatePaymentDetails(cost.LatestCostStageRevisionId.Value, purchaseOrderData, adminUser); var logEntries = new List <IActivityLogEntry> { new PoCreated(cost.CostNumber, purchaseOrderData.PoNumber, adminUser), new GoodsReceiptAllocated(cost.CostNumber, purchaseOrderData.GrNumber, adminUser), new RequisitionNumber(cost.CostNumber, purchaseOrderData.Requisition, adminUser) }; await _activityLogService.LogRange(logEntries); }
private async Task<Dictionary<string, ActionModel>> GetCostActions(UserIdentity userIdentity, Cost cost, CostStageRevision costStageRevision, CostUser user) { var isCostNeverSubmitted = costStageRevision.Status == CostStageRevisionStatus.Draft && costStageRevision.Name == CostStageConstants.OriginalEstimate; var stageDetails = JsonConvert.DeserializeObject<PgStageDetailsForm>(costStageRevision.StageDetails?.Data); var costUser = new { isApprover = user.UserUserGroups.Any(uug => uug.UserGroup.ObjectId == cost.Id && uug.UserGroup.Role.Name == Roles.CostApprover), isAdmin = user.UserUserGroups.Any(x => x.UserGroup.Role.Name == Roles.ClientAdmin && x.UserGroup.ObjectId == userIdentity.ModuleId), authLimit = user.ApprovalLimit, isFinanceManager = user.UserBusinessRoles.Any(ubr => ubr.BusinessRole != null && ubr.BusinessRole.Key == Constants.BusinessRole.FinanceManager && (ubr.ObjectId != null || ubr.Labels.Contains(stageDetails.SmoName))) }; var purchaseOrderResponse = _customObjectDataService .GetCustomData<PgPurchaseOrderResponse>(costStageRevision.CustomObjectData, CustomObjectDataKeys.PgPurchaseOrderResponse); // current user is IPM user and is approved var userIsIPMAndApproved = costStageRevision.Approvals .Any(s => s.ApprovalMembers.Any(a => a.MemberId == userIdentity.Id && !a.IsExternal && a.Status == ApprovalStatus.Approved)); var isLatestRevision = cost.LatestCostStageRevisionId == costStageRevision.Id; var paymentBelowAuthLimit = true; decimal costTotal = 0; if (cost.Status != CostStageRevisionStatus.Draft && costUser.authLimit.HasValue) { costTotal = costStageRevision.CostLineItems.Sum(cli => cli.ValueInDefaultCurrency); paymentBelowAuthLimit = costUser.authLimit.Value >= costTotal; } var actionRule = new PgActionRule { CostStage = costStageRevision.CostStage.Key, Status = costStageRevision.Status.ToString(), IsRevision = RevisionStages.Contains(costStageRevision.CostStage.Key), IsOwner = cost.OwnerId.Equals(userIdentity.Id), IsApprover = costUser.isApprover, HasPONumber = !string.IsNullOrEmpty(purchaseOrderResponse?.PoNumber), NeverSubmitted = isCostNeverSubmitted, HasExternalIntegration = cost.IsExternalPurchases, CostStageTotal = costTotal, CostTotalBelowAuthLimit = paymentBelowAuthLimit, IsAdmin = costUser.isAdmin, UserIsIPMAndApproved = userIsIPMAndApproved, UserIsFinanceManager = costUser.isFinanceManager, IsLatestRevision = isLatestRevision }; var actions = await GetActions(actionRule); return actions; }
private async Task PopulateOtherFieldsForRecall(EmailNotificationMessage <CostNotificationObject> message, string parent, DateTime timestamp, Guid costId, Guid costStageRevisionId) { PopulateOtherFields(message, parent, timestamp, costId, costStageRevisionId); // Add fields specific to Recall notification message var obj = message.Object; var cost = obj.Cost; var stageForm = _costStageRevisionService.GetStageDetails <PgStageDetailsForm>(costStageRevisionId).Result; var buyoutDetails = _costFormService.GetCostFormDetails <BuyoutDetails>(costStageRevisionId).Result; cost.AgencyTrackingNumber = stageForm.AgencyTrackingNumber; cost.Region = stageForm.BudgetRegion?.Name; cost.AiringCountries = string.Join(";", (buyoutDetails?.AiringCountries ?? new BuyoutDetails.Country[0]).Select(c => c.Name).ToArray()); cost.Requisition = (await _customObjectDataService.GetCustomData <PgPurchaseOrderResponse>(costStageRevisionId, CustomObjectDataKeys.PgPurchaseOrderResponse))?.Requisition; }
// TODO cover this logc by unit tests private void AddCoupaApprovalEmail(List <EmailNotificationMessage <CostNotificationObject> > notifications, Cost cost, CostUser costOwner, Guid costStageRevisionId, DateTime timestamp) { var previousCostStage = _costStageService.GetPreviousCostStage(cost.LatestCostStageRevision.CostStageId).Result; if (previousCostStage == null) { // No need to send COUPA apprvoal email because this is the first time cost gets submitted for Brand Approval return; } var latestRevisionOfPreviousStage = CostStageRevisionService.GetLatestRevision(previousCostStage.Id).Result; if (latestRevisionOfPreviousStage == null) { throw new Exception($"Couldn't find latest revision for stage {previousCostStage.Id}"); } var previousPaymentAmount = _pgPaymentService.GetPaymentAmount(latestRevisionOfPreviousStage.Id, false).Result; var currentPaymentAmount = _pgPaymentService.GetPaymentAmount(costStageRevisionId, false).Result; if (currentPaymentAmount.TotalCostAmount == previousPaymentAmount.TotalCostAmount) { return; } // Send COUPA approval email because total amount changed var paymentDetails = _customObjectDataService.GetCustomData <PgPaymentDetails>(costStageRevisionId, CustomObjectDataKeys.PgPaymentDetails).Result; if (!string.IsNullOrEmpty(paymentDetails?.PoNumber)) { var actionType = core.Constants.EmailNotificationActionType.Submitted; var parent = core.Constants.EmailNotificationParents.Coupa; var coupaNotification = new EmailNotificationMessage <CostNotificationObject>(actionType); MapEmailNotificationObject(coupaNotification.Object, cost, costOwner); PopulateOtherFields(coupaNotification, parent, timestamp, cost.Id, cost.LatestCostStageRevision.Id); AddSharedTo(coupaNotification); var notificationCost = coupaNotification.Object.Cost; notificationCost.PurchaseOrder = new PurchaseOrder(); Mapper.Map(currentPaymentAmount, notificationCost.PurchaseOrder); Mapper.Map(paymentDetails, notificationCost.PurchaseOrder); coupaNotification.Parameters.EmailService.AdditionalEmails.Add(AppSettings.CoupaApprovalEmail); notifications.Add(coupaNotification); } }
private async Task <string> GetIoNumberOwner(Guid costStageRevisionId) { var pgPurchaseOrder = await _customObjectDataService.GetCustomData <PgPaymentDetails>(costStageRevisionId, CustomObjectDataKeys.PgPaymentDetails); return(pgPurchaseOrder.IoNumberOwner); }
public async Task <PgLedgerMaterialCodeModel> GetLedgerMaterialCodes(Guid costStageRevisionId) { var codes = await _customDataService.GetCustomData <PgLedgerMaterialCodeModel>(costStageRevisionId, CustomObjectDataKeys.PgMaterialLedgerCodes); return(codes); }
public async Task <PgPurchaseOrder> GetPurchaseOrder(CostStageRevisionStatusChanged stageRevisionStatusChanged) { var costData = await _efContext.Cost .Include(c => c.LatestCostStageRevision) .ThenInclude(csr => csr.CostStage) .Where(c => c.Id == stageRevisionStatusChanged.AggregateId) .Include(c => c.Parent) .ThenInclude(p => p.Agency) .Select(c => new { BrandName = c.Project.Brand != null ? c.Project.Brand.Name : string.Empty, CostNumber = c.CostNumber, CostId = c.Id, StageDetailsData = c.LatestCostStageRevision.StageDetails.Data, ProductionDetailsData = c.LatestCostStageRevision.ProductDetails.Data, LatestCostStageRevisionId = c.LatestCostStageRevision.Id, AgencyLabels = c.Parent.Agency.Labels, CostStageRevisionKey = c.LatestCostStageRevision.CostStage.Key, CostStageRevisionName = c.LatestCostStageRevision.CostStage.Name, Requisitioner = c.LatestCostStageRevision.Approvals .Where(a => a.Type == ApprovalType.Brand && a.Requisitioners.Any()) .SelectMany(a => a.Requisitioners) .Select(r => r.CostUser) .FirstOrDefault(), CostType = c.CostType, ExchangeRate = c.ExchangeRate }) .FirstOrDefaultAsync(); if (costData == null) { _logger.Error($"Couldn't find cost with id {stageRevisionStatusChanged.AggregateId}"); return(null); } var purchaseOrderDto = new PgPurchaseOrderDTO { BrandName = costData.BrandName, CostNumber = costData.CostNumber, StageDetailsData = costData.StageDetailsData, ProductionDetailsData = costData.ProductionDetailsData, LatestCostStageRevisionId = costData.LatestCostStageRevisionId, AgencyLabels = costData.AgencyLabels, CostStageRevisionKey = costData.CostStageRevisionKey, CostStageRevisionName = costData.CostStageRevisionName, RequisitionerEmail = costData.Requisitioner?.Email, TNumber = costData.Requisitioner?.FederationId }; var stageDetailsForm = JsonConvert.DeserializeObject <PgStageDetailsForm>(purchaseOrderDto.StageDetailsData); var productionDetailsForm = purchaseOrderDto.ProductionDetailsData != null?JsonConvert.DeserializeObject <PgProductionDetailsForm>(purchaseOrderDto.ProductionDetailsData) : null; var paymentAmount = await GetTotals(stageRevisionStatusChanged.CostStageRevisionId, costData.ExchangeRate); var applicableCurrencyCode = await _currencyService.GetCurrencyCode(stageDetailsForm.AgencyCurrency, productionDetailsForm); var ledgerMaterialCode = await _ledgerMaterialCode.GetLedgerMaterialCodes(purchaseOrderDto.LatestCostStageRevisionId); var purchaseOrderResponse = await _customDataService.GetCustomData <PgPurchaseOrderResponse>(purchaseOrderDto.LatestCostStageRevisionId, CustomObjectDataKeys.PgPurchaseOrderResponse); var paymentDetails = await _customDataService.GetCustomData <PgPaymentDetails>(purchaseOrderDto.LatestCostStageRevisionId, CustomObjectDataKeys.PgPaymentDetails); var purchaseOrder = new PgPurchaseOrder { BasketName = GetBasketName(purchaseOrderDto, stageDetailsForm), Description = GetDescription(purchaseOrderDto, stageDetailsForm), TotalAmount = paymentAmount.TotalAmount, PaymentAmount = paymentAmount.PaymentAmount, StartDate = stageRevisionStatusChanged.TimeStamp, CostNumber = purchaseOrderDto.CostNumber ?? "", Currency = applicableCurrencyCode, CategoryId = ledgerMaterialCode?.MgCode ?? "", GL = ledgerMaterialCode?.GlCode ?? "", DeliveryDate = GetDeliveryDate(stageRevisionStatusChanged.TimeStamp), IONumber = !string.IsNullOrEmpty(paymentDetails?.IoNumber) ? $"00{paymentDetails.IoNumber}" : "", LongText = GetLongTextField(stageRevisionStatusChanged, purchaseOrderDto, stageDetailsForm, purchaseOrderResponse, paymentAmount.PaymentAmount, applicableCurrencyCode, costData.CostType), TNumber = purchaseOrderDto.TNumber ?? "", RequisitionerEmail = purchaseOrderDto.RequisitionerEmail ?? "", Vendor = GetVendor(purchaseOrderDto, productionDetailsForm) ?? "", PoNumber = paymentDetails?.PoNumber ?? "", AccountCode = purchaseOrderResponse?.AccountCode ?? "", ItemIdCode = purchaseOrderResponse?.ItemIdCode ?? "", GrNumbers = await GetGrNumbers(stageRevisionStatusChanged), Commodity = GetCommodity(costData.CostType, stageDetailsForm) }; return(purchaseOrder); }