Esempio n. 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);
        }
Esempio n. 2
0
        public void PgPurchaseOrderResponse_When_TotalAmountIsNull_Should_HaveValidSchema()
        {
            // Arrange
            var pgPurchaseOrder = new PgPurchaseOrderResponse
            {
                AccountCode    = "TestAccountCode",
                ItemIdCode     = "ItemIdCode",
                PoNumber       = "PONumber",
                Comments       = "Comments",
                Type           = "Type",
                GlAccount      = "GLAccountCode",
                GrDate         = DateTime.Parse("2017-08-09T11:26:45.345Z"),
                GrNumber       = "GR number",
                ApproverEmail  = "Email address of approver here",
                IoNumberOwner  = "Internal order number owner",
                PoDate         = DateTime.Parse("2017-08-30T11:26:45.345Z"),
                Requisition    = "Requisition",
                ApprovalStatus = "Approved",
                TotalAmount    = null
            };
            var serialized = JsonConvert.SerializeObject(pgPurchaseOrder, Formatting.None, SerializerSettings);

            // Act
            var jobject = JObject.Parse(serialized);

            // Assert
            jobject.IsValid(_schema, out IList <string> errors).Should().BeTrue(GetSchemaValidationAssertionReason(errors));
        }
Esempio n. 3
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;
            }
        }
        public async Task Consume_whenUpdatedAndStatusApprovedAndPendingApproval_shouldApproveTheCost()
        {
            // Arrange
            var activityType   = ActivityTypes.Updated;
            var approvalStatus = ApprovalStatuses.Approved;
            var requisition    = "requisitionId";

            var purchaseOrderResponse = new PurchaseOrderResponse
            {
                ActivityType = activityType,
                CostNumber   = CostNumber,
                ClientName   = BuType.Pg.ToString(),
                Payload      = JObject.Parse(JsonConvert.SerializeObject(new PgPurchaseOrderResponse
                {
                    ApprovalStatus = approvalStatus
                }))
            };
            var operationResponse = new ApprovalServiceActionResult
            {
                Success = true
            };
            var dbPurchaseOrderResponse = new PgPurchaseOrderResponse()
            {
                Requisition = requisition,
            };
            var dbPaymentDetails = new PgPaymentDetails()
            {
                Requisition = requisition,
            };

            var cost = _efContext.Cost.Find(_costId);

            cost.Status = CostStageRevisionStatus.PendingBrandApproval;
            _efContext.Cost.Update(cost);
            await _efContext.SaveChangesAsync();

            _customDataServiceMock.Setup(cds => cds.GetCustomData <PgPurchaseOrderResponse>(It.IsAny <Guid>(), It.IsAny <string>())).Returns(Task.FromResult(dbPurchaseOrderResponse));
            _customDataServiceMock.Setup(cds => cds.GetCustomData <PgPaymentDetails>(It.IsAny <Guid>(), It.IsAny <string>())).Returns(Task.FromResult(dbPaymentDetails));
            _customDataServiceMock.Setup(cds => cds.Save(It.IsAny <Guid>(), It.IsAny <string>(), It.IsAny <object>(), It.IsAny <UserIdentity>())).Returns(Task.FromResult(new CustomObjectData()));
            _approvalServiceMock.Setup(a => a.Approve(It.IsAny <Guid>(), It.IsAny <UserIdentity>(), BuType.Pg, SourceSystem.Coupa)).Returns(Task.FromResult(operationResponse));
            _emailNotificationServiceMock.Setup(em => em.CostHasBeenApproved(It.IsAny <Guid>(), It.IsAny <Guid>(), It.IsAny <string>())).Returns(Task.FromResult(true));

            // Act
            await _consumer.Consume(purchaseOrderResponse);

            // Assert
            _approvalServiceMock.Verify(s => s.Approve(It.IsAny <Guid>(), It.IsAny <UserIdentity>(), BuType.Pg, SourceSystem.Coupa), Times.Once);
            _emailNotificationServiceMock.Verify(em => em.CostHasBeenApproved(It.IsAny <Guid>(), It.IsAny <Guid>(), It.IsAny <string>()), Times.Once);

            Assert.AreEqual(requisition, dbPurchaseOrderResponse.Requisition);
            Assert.AreEqual(requisition, dbPaymentDetails.Requisition);
        }
        public async Task Consume_whenUpdatedAndStatusRejected_shouldRejectTheCost()
        {
            // Arrange
            var activityType   = ActivityTypes.Updated;
            var approvalStatus = ApprovalStatuses.Rejected;

            var purchaseOrderResponse = new PurchaseOrderResponse
            {
                ActivityType = activityType,
                CostNumber   = CostNumber,
                ClientName   = BuType.Pg.ToString(),
                Payload      = JObject.Parse(JsonConvert.SerializeObject(new PgPurchaseOrderResponse
                {
                    ApprovalStatus = approvalStatus
                }))
            };
            var operationResponse = new ApprovalServiceActionResult()
            {
                Success = true
            };
            var dbPurchaseOrderResponse = new PgPurchaseOrderResponse()
            {
                Requisition = "requisitionId",
            };
            var dbPaymentDetails = new PgPaymentDetails()
            {
                Requisition = "requisitionId",
            };

            _customDataServiceMock.Setup(cds => cds.GetCustomData <PgPurchaseOrderResponse>(It.IsAny <Guid>(), It.IsAny <string>())).Returns(Task.FromResult(dbPurchaseOrderResponse));
            _customDataServiceMock.Setup(cds => cds.GetCustomData <PgPaymentDetails>(It.IsAny <Guid>(), It.IsAny <string>())).Returns(Task.FromResult(dbPaymentDetails));
            _customDataServiceMock.Setup(cds => cds.Save(It.IsAny <Guid>(), It.IsAny <string>(), It.IsAny <object>(), It.IsAny <UserIdentity>())).Returns(Task.FromResult(new CustomObjectData()));
            _approvalServiceMock.Setup(a => a.Reject(It.IsAny <Guid>(), It.IsAny <UserIdentity>(), BuType.Pg, It.IsAny <string>(), It.IsAny <SourceSystem>())).Returns(Task.FromResult(operationResponse));
            _emailNotificationServiceMock.Setup(em => em.CostHasBeenRejected(It.IsAny <Guid>(), It.IsAny <Guid>(), It.IsAny <string>(), It.IsAny <string>())).Returns(Task.FromResult(true));

            // Act
            await _consumer.Consume(purchaseOrderResponse);

            // Assert
            _approvalServiceMock.Verify(s => s.Reject(It.IsAny <Guid>(), It.IsAny <UserIdentity>(), BuType.Pg, It.IsAny <string>(), It.IsAny <SourceSystem>()), Times.Once);
            _emailNotificationServiceMock.Verify(em => em.CostHasBeenRejected(It.IsAny <Guid>(), It.IsAny <Guid>(), It.IsAny <string>(), It.IsAny <string>()), Times.Once);
            _customDataServiceMock.Verify(cds => cds.GetCustomData <PgPurchaseOrderResponse>(It.IsAny <Guid>(), It.IsAny <string>()), Times.Once);
            _customDataServiceMock.Verify(cds => cds.GetCustomData <PgPaymentDetails>(It.IsAny <Guid>(), It.IsAny <string>()), Times.Once);

            Assert.IsNull(dbPurchaseOrderResponse.Requisition);
            Assert.IsNull(dbPaymentDetails.Requisition);
        }
Esempio n. 6
0
        private async Task <bool> HasCostBeenApproved(Cost cost, PgPurchaseOrderResponse payload)
        {
            // If TotalAmount in incoming messaage is the same as current cost total amount consider const as "Approved"
            var costStageRevisionId = cost.LatestCostStageRevisionId.Value;

            var totalAmountInApplicableCurrency = 0m;
            var paymentAmount = await _pgPaymentService.GetPaymentAmount(costStageRevisionId, false);

            if (paymentAmount != null)
            {
                var rateMultiplier = cost.ExchangeRate ?? 1m;

                totalAmountInApplicableCurrency = (paymentAmount.TotalCostAmount ?? 0) / rateMultiplier;
            }
            return(payload.TotalAmount.HasValue &&
                   Math.Round(totalAmountInApplicableCurrency, 2) == Math.Round(payload.TotalAmount.Value, 2));
        }
Esempio n. 7
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);
        }
        private PgPurchaseOrder.LongTextField GetLongTextField(CostStageRevisionStatusChanged stageRevisionStatusChanged,
                                                               PgPurchaseOrderDTO purchaseOrderDto, PgStageDetailsForm stageDetailsForm, PgPurchaseOrderResponse purchaseOrderResponse,
                                                               decimal paymentAmount, string currencyCode, CostType costType)
        {
            var longText = new PgPurchaseOrder.LongTextField();

            switch (stageRevisionStatusChanged.Status)
            {
            case CostStageRevisionStatus.PendingBrandApproval:
                longText.VN.AddRange(new[] {
                    "Purchase order does not authorize committing funds without approved EPCAT sheet.",
                    "The services within this Purchase Order can only be ordered from 3rd parties after EPCAT approval."
                });
                var productionTypeIfProductionCost = stageDetailsForm.ProductionType != null ? $"{stageDetailsForm.ProductionType.Key} " : "";
                longText.BN.Add($"{purchaseOrderDto.CostStageRevisionName} APPROVED {costType} {productionTypeIfProductionCost}{purchaseOrderResponse?.PoNumber}".TrimEnd());

                longText.AN.Add($"{_appSettings.FrontendUrl.TrimEnd('/')}/#/cost/{stageRevisionStatusChanged.AggregateId}/review");
                break;

            case CostStageRevisionStatus.PendingCancellation:
                longText.VN.Add("PROJECT CANCELLED. PLEASE CANCEL PO AND REQUEST CN FOR ANY AMOUNTS PAID");
                longText.BN.Add($"PROJECT CANCELLED. PLEASE CANCEL PO {purchaseOrderResponse?.PoNumber} AND REQUEST CN FOR ANY AMOUNTS PAID");
                break;

            case CostStageRevisionStatus.Approved:
                if (purchaseOrderDto.CostStageRevisionKey == CostStages.FinalActual.ToString() || purchaseOrderDto.CostStageRevisionKey == CostStages.FinalActualRevision.ToString())
                {
                    //ADC-2412
                    //Strange issue when the payment amount looks something like -1560.00000000000000000000000000002
                    paymentAmount = Math.Round(paymentAmount, 2);
                    // Get calculated credit amount
                    if (paymentAmount < 0)
                    {
                        longText.BN.Add($"A credit note of { paymentAmount } {currencyCode} is needed, please update PO accordingly.");
                    }
                }
                break;
            }
            return(longText);
        }