コード例 #1
0
        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);
        }
コード例 #2
0
        public async Task Consume(PurchaseOrderResponse message)
        {
            var cost = await _efContext.Cost
                       .AsNoTracking()
                       .FirstOrDefaultAsync(c => c.CostNumber == message.CostNumber);

            if (cost == null)
            {
                throw new XmgException($"Could't find the cost with Cost Number {message.CostNumber}")
                      {
                          ClientName = message.ClientName
                      };
            }

            try
            {
                var payload = JsonConvert.DeserializeObject <PgPurchaseOrderResponse>(message.Payload.ToString());

                var adminUser = await _efContext.CostUser.FirstOrDefaultAsync(u => u.Email == ApprovalMemberModel.BrandApprovalUserEmail);

                var adminUserIdentity = new SystemAdminUserIdentity(adminUser);
                await _efContext.InTransactionAsync(async() =>
                {
                    await SaveResponse(payload, cost, adminUserIdentity);

                    await ActionOnCost(message, payload, cost, adminUserIdentity);

                    if (payload.ApprovalStatus == ApprovalStatuses.Approved ||
                        // ADC-1731
                        (payload.ApprovalStatus == ApprovalStatuses.AwaitingDecisionInCost &&
                         ApprovalRequired(cost) && await HasCostBeenApproved(cost, payload)))
                    {
                        // payload details are required in the email so the response needs to be saved before we can send the email
                        await _emailNotificationService.CostHasBeenApproved(cost.Id, adminUserIdentity.Id, ApprovalType.Brand.ToString());
                    }
                },
                                                    () => _eventService.SendAllPendingAsync());
            }
            catch (Exception ex)
            {
                var messageJson = JsonConvert.SerializeObject(message);
                throw new XmgException($"Failed to consume response message: {messageJson} from Coupa {ex}", ex);
            }
        }
コード例 #3
0
        private async Task <PgPaymentDetails> UpdatePaymentDetails(
            Guid costStageRevisionId,
            PgPurchaseOrderResponse purchaseOrderData,
            SystemAdminUserIdentity adminUser)
        {
            var paymentDetails = await _customDataService
                                 .GetCustomData <PgPaymentDetails>(costStageRevisionId, CustomObjectDataKeys.PgPaymentDetails)
                                 ?? new PgPaymentDetails();

            _mapper.Map(purchaseOrderData, paymentDetails);
            if (string.Compare(purchaseOrderData.ApprovalStatus, ApprovalStatuses.Rejected, StringComparison.OrdinalIgnoreCase) == 0)
            {
                //null requisition ID should be allowed here
                paymentDetails.Requisition = purchaseOrderData.Requisition;
            }

            await _customDataService.Save(costStageRevisionId, CustomObjectDataKeys.PgPaymentDetails, paymentDetails, adminUser);

            return(paymentDetails);
        }
        public async Task Handle_ErrorMessageFromXmg_ShouldRejectCost(ResponseErrorType errorType)
        {
            // Arrange
            var cost = MockCost();

            var payload = new { errorMessages = new[] { new { type = ((int)errorType).ToString(), message = "Error messages" } } };

            var message = new PurchaseOrderErrorResponse
            {
                ActivityType   = "Error",
                ClientName     = BuType.Pg.ToString(),
                EventTimeStamp = DateTime.Now,
                CostNumber     = cost.CostNumber,
                Payload        = JObject.Parse(JsonConvert.SerializeObject(payload))
            };
            var response = new ApprovalServiceActionResult {
                Success = true, ApprovalType = "Brand"
            };

            var costUser = new CostUser {
                GdamUserId = "alsjdnaljsdn"
            };
            var adminUser = new CostUser {
                Email = ApprovalMemberModel.BrandApprovalUserEmail
            };
            var adminUserIdentity = new SystemAdminUserIdentity(adminUser);

            var costUserSetMock = _efContextMock.MockAsyncQueryable(new List <CostUser> {
                costUser, adminUser
            }.AsQueryable(), context => context.CostUser);

            costUserSetMock.Setup(u => u.FindAsync(It.IsAny <Guid>())).ReturnsAsync(costUser);

            _approvalServiceMock.Setup(a => a.Reject(cost.Id, adminUserIdentity, BuType.Pg, "Error messages", SourceSystem.Coupa)).ReturnsAsync(response);

            // Act
            await _handler.Handle(message);

            // Assert
            _approvalServiceMock.Verify(s => s.Reject(cost.Id, adminUserIdentity, BuType.Pg, "Error messages", SourceSystem.Coupa));
        }
コード例 #5
0
        private async Task Reject(PurchaseOrderResponse message, PurchaseOrderErrorMessage errorMessage)
        {
            var adminUser = await _efContext.CostUser.FirstOrDefaultAsync(u => u.Email == ApprovalMemberModel.BrandApprovalUserEmail);

            var adminUserIdentity = new SystemAdminUserIdentity(adminUser);
            var cost = await _efContext.Cost.SingleAsync(c => c.CostNumber == message.CostNumber);

            var result = await _approvalService.Reject(cost.Id, adminUserIdentity, GetBuType(message.ClientName), errorMessage.Message, SourceSystem.Coupa);

            if (!result.Success)
            {
                await OnTechnicalError(message.CostNumber, $"Failed to reject cost due to error! {result.Messages}");
            }
            else
            {
                var error = $"Cost {message.CostNumber} rejected due to : {errorMessage.Type.GetStringValue()} {errorMessage.Message}";
                _logger.Information(error);

                await _emailNotificationService.CostHasBeenRejected(
                    cost.Id, adminUser.Id, ApprovalType.Brand.ToString(), error);
            }
        }
コード例 #6
0
        private async Task ActionOnCost(PurchaseOrderResponse message, PgPurchaseOrderResponse payload, Cost cost, SystemAdminUserIdentity adminUser)
        {
            var adminUserId = adminUser.Id;

            OperationResponse response;

            switch (message.ActivityType)
            {
            case ActivityTypes.Updated:
                switch (payload.ApprovalStatus)
                {
                case ApprovalStatuses.Approved:
                    if (ApprovalRequired(cost))
                    {
                        await ApproveCost(cost.Id, adminUser);
                    }
                    break;

                case ApprovalStatuses.Rejected:
                    message.Payload.TryGetValue(nameof(PgPurchaseOrderResponse.Comments), StringComparison.OrdinalIgnoreCase, out var commentsToken);
                    var comments = commentsToken != null?commentsToken.ToObject <string>() : string.Empty;

                    response = await _approvalService.Reject(cost.Id, adminUser, BuType.Pg, comments, SourceSystem.Coupa);

                    if (response.Success)
                    {
                        await _emailNotificationService.CostHasBeenRejected(cost.Id, adminUserId, ApprovalType.Brand.ToString(), comments);
                    }

                    break;

                // ADC-1731 Dealing with COUPA's limitations
                case ApprovalStatuses.AwaitingDecisionInCost:
                    if (ApprovalRequired(cost) && await HasCostBeenApproved(cost, payload))
                    {
                        await ApproveCost(cost.Id, adminUser);
                    }
                    break;
                }
                break;

            case ActivityTypes.Cancelled:
                response = await _costActionService.CompleteCancel(cost.Id, BuType.Pg);

                if (response.Success)
                {
                    await _emailNotificationService.CostHasBeenCancelled(cost.Id);
                }

                break;

            case ActivityTypes.Recalled:
                await _costActionService.CompleteRecall(cost.Id, adminUser);

                break;
            }
        }
コード例 #7
0
        public async Task UpdateLedgerMaterialCodes(Guid costStageRevisionId)
        {
            var costStageRevision = await _efContext.CostStageRevision
                                    .Include(csr => csr.StageDetails)
                                    .Include(csr => csr.ExpectedAssets)
                                    .Include(csr => csr.CostStage)
                                    .ThenInclude(cs => cs.Cost)
                                    .FirstOrDefaultAsync(csr => csr.Id == costStageRevisionId);

            var costType = costStageRevision.CostStage.Cost.CostType.ToString();

            var multipleOvalTypesOption = await _efContext.DictionaryEntry
                                          .Where(d => d.Dictionary.Name == Constants.DictionaryNames.OvalType && d.Key == MultipleOptions)
                                          .FirstAsync();

            var multipleMediaTypesOption = await _efContext.DictionaryEntry
                                           .Where(d => d.Dictionary.Name == Constants.DictionaryNames.MediaType && d.Key == MultipleOptions)
                                           .FirstAsync();

            var stageDetailsForm = JsonConvert.DeserializeObject <PgStageDetailsForm>(costStageRevision.StageDetails.Data);

            // Eligible for Production cost
            var  contentTypeId    = stageDetailsForm.ContentType?.Id;
            var  productionTypeId = stageDetailsForm.ProductionType?.Id;
            var  expectedAssets   = costStageRevision.ExpectedAssets;
            Guid?mediaTypeId      = null;
            Guid?ovalTypeId       = null;

            var mediaTypeIds = expectedAssets.Where(a => a.MediaTypeId != null).Select(a => a.MediaTypeId).Distinct().ToArray();

            if (mediaTypeIds.Length > 0)
            {
                mediaTypeId = mediaTypeIds.Length == 1 ? mediaTypeIds[0] : multipleMediaTypesOption.Id;
            }
            var ovalTypeIds = expectedAssets.Where(a => a.OvalTypeId != null).Select(a => a.OvalTypeId).Distinct().ToArray();

            if (ovalTypeIds.Length > 0)
            {
                ovalTypeId = ovalTypeIds.Length == 1 ? ovalTypeIds[0] : multipleOvalTypesOption.Id;
            }

            // Eligible for Usage/Buyout cost
            var usageTypeId = stageDetailsForm.UsageType?.Id;

            var ledgerMaterialCode = await _efContext.PgLedgerMaterialCode
                                     .OrderBy(c => c.ProductionTypeId)
                                     .FirstOrDefaultAsync(c =>
                                                          (c.CostType == costType &&
                                                           c.ContentTypeId == contentTypeId &&
                                                           c.ProductionTypeId == productionTypeId &&
                                                           c.MediaTypeId == mediaTypeId &&
                                                           c.OvalId == ovalTypeId &&
                                                           c.UsageTypeId == usageTypeId
                                                          )
                                                          ||
                                                          //Default values needed for AIPE
                                                          (costType == CostType.Production.ToString() &&
                                                           c.ContentTypeId == contentTypeId &&
                                                           c.ProductionTypeId == null &&
                                                           c.MediaTypeId == null &&
                                                           c.OvalId == null &&
                                                           c.UsageTypeId == null
                                                          )
                                                          ||
                                                          (c.CostType == CostType.Trafficking.ToString() &&
                                                           costType == CostType.Trafficking.ToString())
                                                          );

            var mgCode = ledgerMaterialCode?.MaterialGroupCode;
            var glCode = ledgerMaterialCode?.GeneralLedgerCode;

            var codeModel = new PgLedgerMaterialCodeModel {
                GlCode = glCode, MgCode = mgCode
            };

            var adminUser = await _efContext.CostUser.FirstOrDefaultAsync(u => u.Email == ApprovalMemberModel.BrandApprovalUserEmail);

            var adminUserIdentity = new SystemAdminUserIdentity(adminUser);
            await _customDataService.Save(costStageRevisionId, CustomObjectDataKeys.PgMaterialLedgerCodes, codeModel, adminUserIdentity);
        }