public void Setup()
        {
            // oc
            _oc = Substitute.For <IOrderCloudClient>();
            _oc.IntegrationEvents.GetWorksheetAsync <HSOrderWorksheet>(OrderDirection.Incoming, mockOrderID)
            .Returns(Task.FromResult(new HSOrderWorksheet {
                Order = new Models.HSOrder {
                    ID = mockOrderID
                }
            }));
            _oc.Payments.CreateAsync <HSPayment>(OrderDirection.Incoming, mockOrderID, Arg.Any <HSPayment>())
            .Returns(Task.FromResult(PaymentMocks.CCPayment(creditcard1, 20)));

            // orderCalcc
            _orderCalc = Substitute.For <IOrderCalcService>();
            _orderCalc.GetCreditCardTotal(Arg.Any <HSOrderWorksheet>())
            .Returns(20);

            // ccCommand
            _ccCommand = Substitute.For <ICreditCardCommand>();
            _ccCommand.VoidTransactionAsync(Arg.Any <HSPayment>(), Arg.Any <HSOrder>(), mockUserToken)
            .Returns(Task.FromResult(0));

            _sut = new PaymentCommand(_oc, _orderCalc, _ccCommand);
        }
        public async Task should_handle_same_cc_same_amount()
        {
            // do nothing, payment doesn't need updating

            // Arrange
            var mockedCreditCardTotal = 50;
            var existing = PaymentMocks.PaymentList(PaymentMocks.CCPayment(creditcard1, 50, mockCCPaymentID));

            _oc.Payments.ListAsync <HSPayment>(OrderDirection.Incoming, mockOrderID)
            .Returns(Task.FromResult(existing));
            var requested = PaymentMocks.Payments(PaymentMocks.CCPayment(creditcard1));

            _orderCalc.GetCreditCardTotal(Arg.Any <HSOrderWorksheet>())
            .Returns(mockedCreditCardTotal);

            // Act
            var result = await _sut.SavePayments(mockOrderID, requested, mockUserToken);

            // Assert
            await _oc.Payments.DidNotReceive().DeleteAsync(OrderDirection.Incoming, mockOrderID, Arg.Any <string>());

            await _ccCommand.DidNotReceive().VoidTransactionAsync(Arg.Any <HSPayment>(), Arg.Any <HSOrder>(), mockUserToken);

            await _oc.Payments.DidNotReceive().CreateAsync <HSPayment>(Arg.Any <OrderDirection>(), mockOrderID, Arg.Any <HSPayment>(), mockUserToken);

            await _oc.Payments.DidNotReceive().PatchAsync <HSPayment>(Arg.Any <OrderDirection>(), mockOrderID, Arg.Any <string>(), Arg.Any <PartialPayment>());
        }
        public async Task should_handle_different_cc_different_amount()
        {
            // if the credit card has changed we need to delete the payment
            // but should void the existing authorization before that

            // Arrange
            var mockedCreditCardTotal = 50;
            var existing = PaymentMocks.PaymentList(PaymentMocks.CCPayment(creditcard1, 40, mockCCPaymentID));

            _oc.Payments.ListAsync <HSPayment>(OrderDirection.Incoming, mockOrderID)
            .Returns(Task.FromResult(existing));
            var requested = PaymentMocks.Payments(PaymentMocks.CCPayment(creditcard2));

            _orderCalc.GetCreditCardTotal(Arg.Any <HSOrderWorksheet>())
            .Returns(mockedCreditCardTotal);

            // Act
            var result = await _sut.SavePayments(mockOrderID, requested, mockUserToken);

            // Assert
            await _oc.Payments.Received().DeleteAsync(OrderDirection.Incoming, mockOrderID, mockCCPaymentID);

            await _ccCommand.Received().VoidTransactionAsync(Arg.Is <HSPayment>(p => p.ID == mockCCPaymentID), Arg.Is <HSOrder>(o => o.ID == mockOrderID), mockUserToken);

            await _oc.Payments.Received().CreateAsync <HSPayment>(OrderDirection.Outgoing, mockOrderID, Arg.Is <HSPayment>(p => p.CreditCardID == creditcard2 && p.Amount == mockedCreditCardTotal && p.Accepted == false), mockUserToken);
        }
        public async Task should_handle_same_cc_different_amount()
        {
            // if the credit card hasn't changed but the amount has
            // then we should void any existing transactions if necessary and update the payment

            // Arrange
            var mockedCreditCardTotal = 30;
            var existing = PaymentMocks.PaymentList(PaymentMocks.CCPayment(creditcard1, 20));

            _oc.Payments.ListAsync <HSPayment>(OrderDirection.Incoming, mockOrderID)
            .Returns(Task.FromResult(existing));
            var requested = PaymentMocks.Payments(PaymentMocks.CCPayment(creditcard1));

            _orderCalc.GetCreditCardTotal(Arg.Any <HSOrderWorksheet>())
            .Returns(mockedCreditCardTotal);

            // Act
            var result = await _sut.SavePayments(mockOrderID, requested, mockUserToken);

            // Assert
            await _oc.Payments.DidNotReceive().DeleteAsync(OrderDirection.Incoming, mockOrderID, Arg.Any <string>());

            await _ccCommand.Received().VoidTransactionAsync(Arg.Is <HSPayment>(p => p.ID == mockCCPaymentID), Arg.Is <HSOrder>(o => o.ID == mockOrderID), mockUserToken);

            await _oc.Payments.Received().PatchAsync <HSPayment>(OrderDirection.Incoming, mockOrderID, mockCCPaymentID, Arg.Is <PartialPayment>(p => p.Amount == mockedCreditCardTotal && p.Accepted == false));
        }
示例#5
0
        public void should_throw_if_no_payments()
        {
            // Arrange
            _oc.Payments.ListAsync <HSPayment>(OrderDirection.Incoming, orderID, filters: Arg.Is <object>(f => (string)f == "Type=CreditCard"))
            .Returns(Task.FromResult(PaymentMocks.EmptyPaymentsList()));
            var payment = ValidIntegrationsPayment();

            // Act
            var ex = Assert.ThrowsAsync <OrderCloudIntegrationException>(async() => await _sut.AuthorizePayment(payment, userToken, merchantID));

            // Assert
            Assert.AreEqual("Payment.MissingCreditCardPayment", ex.ApiError.ErrorCode);
        }
示例#6
0
        public async Task should_handle_failed_auth_void()
        {
            // creates a new transaction when auth fails which
            // gives us full insight into transaction history as well as sets Accepted to false

            var paymentTotal = 30;             // credit card total is 38

            // Arrange
            var payment1transactions = new List <HSPaymentTransaction>()
            {
                new HSPaymentTransaction
                {
                    ID        = transactionID,
                    Succeeded = true,
                    Type      = "CreditCard",
                    xp        = new TransactionXP
                    {
                        CardConnectResponse = new CardConnectAuthorizationResponse
                        {
                            retref = validretref
                        }
                    }
                }
            };
            var mockedCCPayment = MockCCPayment(paymentTotal, true, payment1transactions);

            _oc.Payments.ListAsync <HSPayment>(OrderDirection.Incoming, orderID, filters: Arg.Is <object>(f => (string)f == "Type=CreditCard"))
            .Returns(PaymentMocks.PaymentList(mockedCCPayment));
            var payment = ValidIntegrationsPayment();

            _cardConnect
            .When(x => x.VoidAuthorization(Arg.Any <CardConnectVoidRequest>()))
            .Do(x => throw new CreditCardVoidException(new ApiError {
            }, new CardConnectVoidResponse {
            }));

            // Act
            var ex = Assert.ThrowsAsync <OrderCloudIntegrationException>(async() => await _sut.AuthorizePayment(payment, userToken, merchantID));

            // Assert
            Assert.AreEqual("Payment.FailedToVoidAuthorization", ex.ApiError.ErrorCode);

            // stuff that happens in catch block
            await _supportAlerts
            .Received()
            .VoidAuthorizationFailed(Arg.Any <HSPayment>(), transactionID, Arg.Any <HSOrder>(), Arg.Any <CreditCardVoidException>());

            await _oc.Payments.Received().CreateTransactionAsync(OrderDirection.Incoming, orderID, paymentID, Arg.Any <PaymentTransaction>());
        }
示例#7
0
        public async Task should_still_create_transaction_on_failed_auths()
        {
            // this gives us full insight into transaction history
            // as well as sets Accepted to false

            var paymentTotal = 38;             // credit card total is 38

            // Arrange
            var payment1transactions = new List <HSPaymentTransaction>()
            {
                new HSPaymentTransaction
                {
                    ID        = transactionID,
                    Succeeded = true,
                    xp        = new TransactionXP
                    {
                        CardConnectResponse = new CardConnectAuthorizationResponse
                        {
                            retref = validretref
                        }
                    }
                }
            };
            var mockedCCPayment = MockCCPayment(paymentTotal, false, payment1transactions);

            _oc.Payments.ListAsync <HSPayment>(OrderDirection.Incoming, orderID, filters: Arg.Is <object>(f => (string)f == "Type=CreditCard"))
            .Returns(PaymentMocks.PaymentList(mockedCCPayment));
            _oc.Payments.PatchAsync <HSPayment>(OrderDirection.Incoming, orderID, Arg.Any <string>(), Arg.Any <PartialPayment>())
            .Returns(Task.FromResult(mockedCCPayment));
            var payment = ValidIntegrationsPayment();

            _cardConnect
            .When(x => x.AuthWithoutCapture(Arg.Any <CardConnectAuthorizationRequest>()))
            .Do(x => throw new CreditCardAuthorizationException(new ApiError {
            }, new CardConnectAuthorizationResponse {
            }));

            // Act
            var ex = Assert.ThrowsAsync <OrderCloudIntegrationException>(async() => await _sut.AuthorizePayment(payment, userToken, merchantID));

            // Assert
            Assert.AreEqual("CreditCardAuth.", ex.ApiError.ErrorCode);
            await _cardConnect.Received().AuthWithoutCapture(Arg.Any <CardConnectAuthorizationRequest>());

            // stuff that happens in catch block
            await _oc.Payments.Received().PatchAsync <HSPayment>(OrderDirection.Incoming, orderID, paymentID, Arg.Is <PartialPayment>(p => p.Accepted == false && p.Amount == ccTotal));

            await _oc.Payments.Received().CreateTransactionAsync(OrderDirection.Incoming, orderID, paymentID, Arg.Any <PaymentTransaction>());
        }
示例#8
0
        public async Task should_handle_existing_po_payment()
        {
            // Arrange
            var mockedPOTotal = 20;
            var existing      = PaymentMocks.PaymentList(PaymentMocks.POPayment(40));

            _oc.Payments.ListAsync <HSPayment>(OrderDirection.Incoming, mockOrderID)
            .Returns(Task.FromResult(existing));
            var requested = PaymentMocks.Payments(PaymentMocks.POPayment());

            // Act
            var result = await _sut.SavePayments(mockOrderID, requested, mockUserToken);

            // Assert
            await _oc.Payments.Received().PatchAsync <HSPayment>(OrderDirection.Incoming, mockOrderID, mockPoPaymentID, Arg.Is <PartialPayment>(p => p.Amount == mockedPOTotal));
        }
示例#9
0
        [Test] public async Task should_handle_new_cc_payment()
        {
            // Arrange
            var mockedCreditCardTotal = 20;
            var existing = PaymentMocks.EmptyPaymentsList();

            _oc.Payments.ListAsync <HSPayment>(OrderDirection.Incoming, mockOrderID)
            .Returns(Task.FromResult(existing));
            var requested = PaymentMocks.Payments(PaymentMocks.CCPayment(creditcard1));

            // Act
            var result = await _sut.SavePayments(mockOrderID, requested, mockUserToken);

            // Assert
            await _oc.Payments.DidNotReceive().DeleteAsync(OrderDirection.Incoming, mockOrderID, Arg.Any <string>());

            await _oc.Payments.Received().CreateAsync <HSPayment>(OrderDirection.Outgoing, mockOrderID, Arg.Is <HSPayment>(p => p.ID == mockCCPaymentID && p.Type == PaymentType.CreditCard && p.Amount == mockedCreditCardTotal && p.Accepted == false), mockUserToken);
        }
示例#10
0
        public async Task should_delete_stale_payments()
        {
            // Arrange
            var mockedCreditCardTotal = 20;
            var existing = PaymentMocks.PaymentList(PaymentMocks.SpendingAccountPayment(20));

            _oc.Payments.ListAsync <HSPayment>(OrderDirection.Incoming, mockOrderID)
            .Returns(Task.FromResult(existing));
            var requested = PaymentMocks.Payments(PaymentMocks.CCPayment(creditcard1));

            // Act
            var result = await _sut.SavePayments(mockOrderID, requested, mockUserToken);

            // Assert
            await _oc.Payments.Received().DeleteAsync(OrderDirection.Incoming, mockOrderID, mockSpendingAccountID);

            await _oc.Payments.Received().CreateAsync <HSPayment>(OrderDirection.Outgoing, mockOrderID, Arg.Is <HSPayment>(p => p.ID == mockCCPaymentID && p.Type == PaymentType.CreditCard && p.Amount == mockedCreditCardTotal), mockUserToken);
        }
示例#11
0
        public async Task should_skip_auth_if_payment_valid()
        {
            // If a payment has already been accepted and is equal to the
            // order total then don't auth again

            // Arrange
            _oc.Payments.ListAsync <HSPayment>(OrderDirection.Incoming, orderID, filters: Arg.Is <object>(f => (string)f == "Type=CreditCard"))
            .Returns(Task.FromResult(PaymentMocks.PaymentList(PaymentMocks.CCPayment("creditcardid1", 38))));
            var payment = ValidIntegrationsPayment();

            // Act
            await _sut.AuthorizePayment(payment, userToken, merchantID);

            // Assert
            await _cardConnect.DidNotReceive().AuthWithCapture(Arg.Any <CardConnectAuthorizationRequest>());

            await _oc.Payments.DidNotReceive().CreateTransactionAsync(OrderDirection.Incoming, orderID, Arg.Any <string>(), Arg.Any <PaymentTransaction>());
        }
        public async Task should_handle_new_po_payment()
        {
            // Arrange
            var mockedPOTotal = 50;
            var existing      = PaymentMocks.EmptyPaymentsList();

            _oc.Payments.ListAsync <HSPayment>(OrderDirection.Incoming, mockOrderID)
            .Returns(Task.FromResult(existing));
            var requested = PaymentMocks.Payments(PaymentMocks.POPayment());

            _orderCalc.GetPurchaseOrderTotal(Arg.Any <HSOrderWorksheet>())
            .Returns(mockedPOTotal);

            // Act
            var result = await _sut.SavePayments(mockOrderID, requested, mockUserToken);

            // Assert
            await _oc.Payments.Received().CreateAsync <HSPayment>(OrderDirection.Incoming, mockOrderID, Arg.Is <HSPayment>(p => p.ID == mockPoPaymentID && p.Amount == mockedPOTotal));
        }
示例#13
0
        public async Task should_void_if_accepted_but_not_valid()
        {
            // if a payment is accepted but doesn't match order total than we need to void before authorizing again for new amount

            var paymentTotal = 30;             // credit card total is 38

            // Arrange
            var payment1transactions = new List <HSPaymentTransaction>()
            {
                new HSPaymentTransaction
                {
                    ID        = transactionID,
                    Succeeded = true,
                    Type      = "CreditCard",
                    xp        = new TransactionXP
                    {
                        CardConnectResponse = new CardConnectAuthorizationResponse
                        {
                            retref = validretref
                        }
                    }
                }
            };

            _oc.Payments.ListAsync <HSPayment>(OrderDirection.Incoming, orderID, filters: Arg.Is <object>(f => (string)f == "Type=CreditCard"))
            .Returns(PaymentMocks.PaymentList(MockCCPayment(paymentTotal, true, payment1transactions)));
            var payment = ValidIntegrationsPayment();

            // Act
            await _sut.AuthorizePayment(payment, userToken, merchantID);

            // Assert
            await _cardConnect.Received().VoidAuthorization(Arg.Is <CardConnectVoidRequest>(x => x.retref == validretref && x.merchid == merchantID && x.currency == "CAD"));

            await _oc.Payments.Received().CreateTransactionAsync(OrderDirection.Incoming, orderID, paymentID, Arg.Is <PaymentTransaction>(x => x.Amount == paymentTotal));

            await _cardConnect.Received().AuthWithoutCapture(Arg.Any <CardConnectAuthorizationRequest>());

            await _oc.Payments.Received().PatchAsync <HSPayment>(OrderDirection.Incoming, orderID, paymentID, Arg.Is <PartialPayment>(p => p.Accepted == true && p.Amount == ccTotal));

            await _oc.Payments.Received().CreateTransactionAsync(OrderDirection.Incoming, orderID, paymentID, Arg.Any <PaymentTransaction>());
        }
示例#14
0
        public async Task should_handle_existing_voids_us()
        {
            // same as should_handle_existing_voids but handle usd merchant

            var paymentTotal = 30;             // credit card total is 38

            // Arrange
            var payment1transactions = new List <HSPaymentTransaction>()
            {
                new HSPaymentTransaction
                {
                    ID        = "authattempt1",
                    Succeeded = true,
                    Type      = "CreditCard",
                    xp        = new TransactionXP
                    {
                        CardConnectResponse = new CardConnectAuthorizationResponse
                        {
                            retref = "retref1"
                        }
                    }
                },
                new HSPaymentTransaction
                {
                    ID        = "voidattempt1",
                    Succeeded = true,
                    Type      = "CreditCardVoidAuthorization",
                    xp        = new TransactionXP
                    {
                        CardConnectResponse = new CardConnectAuthorizationResponse
                        {
                            retref = "retref2"
                        }
                    }
                },
                new HSPaymentTransaction
                {
                    ID        = "authattempt2",
                    Type      = "CreditCard",
                    Succeeded = true,
                    xp        = new TransactionXP
                    {
                        CardConnectResponse = new CardConnectAuthorizationResponse
                        {
                            retref = "retref3"
                        }
                    }
                }
            };

            _settings.CardConnectSettings.UsdMerchantID = merchantID;
            _settings.CardConnectSettings.CadMerchantID = "somethingelse";
            _hsExchangeRates.GetCurrencyForUser(userToken)
            .Returns(Task.FromResult(CurrencySymbol.USD));
            _oc.Payments.ListAsync <HSPayment>(OrderDirection.Incoming, orderID, filters: Arg.Is <object>(f => (string)f == "Type=CreditCard"))
            .Returns(PaymentMocks.PaymentList(MockCCPayment(paymentTotal, true, payment1transactions)));
            var payment = ValidIntegrationsPayment();

            // Act
            await _sut.AuthorizePayment(payment, userToken, merchantID);

            // Assert
            await _cardConnect.Received().VoidAuthorization(Arg.Is <CardConnectVoidRequest>(x => x.retref == "retref3" && x.merchid == merchantID && x.currency == "USD"));

            await _oc.Payments.Received().CreateTransactionAsync(OrderDirection.Incoming, orderID, paymentID, Arg.Is <PaymentTransaction>(x => x.Amount == paymentTotal));

            await _cardConnect.Received().AuthWithoutCapture(Arg.Any <CardConnectAuthorizationRequest>());

            await _oc.Payments.Received().PatchAsync <HSPayment>(OrderDirection.Incoming, orderID, paymentID, Arg.Is <PartialPayment>(p => p.Accepted == true && p.Amount == ccTotal));

            await _oc.Payments.Received().CreateTransactionAsync(OrderDirection.Incoming, orderID, paymentID, Arg.Any <PaymentTransaction>());
        }
示例#15
0
        public async Task should_handle_existing_voids()
        {
            // in a scenario where a void has already been processed on the payment
            // we want to make sure to only try to void the last successful transaction of type "CreditCard"

            var paymentTotal = 30;             // credit card total is 38

            // Arrange
            var payment1transactions = new List <HSPaymentTransaction>()
            {
                new HSPaymentTransaction
                {
                    ID        = "authattempt1",
                    Succeeded = true,
                    Type      = "CreditCard",
                    xp        = new TransactionXP
                    {
                        CardConnectResponse = new CardConnectAuthorizationResponse
                        {
                            retref = "retref1"
                        }
                    }
                },
                new HSPaymentTransaction
                {
                    ID        = "voidattempt1",
                    Succeeded = true,
                    Type      = "CreditCardVoidAuthorization",
                    xp        = new TransactionXP
                    {
                        CardConnectResponse = new CardConnectAuthorizationResponse
                        {
                            retref = "retref2"
                        }
                    }
                },
                new HSPaymentTransaction
                {
                    ID        = "authattempt2",
                    Type      = "CreditCard",
                    Succeeded = true,
                    xp        = new TransactionXP
                    {
                        CardConnectResponse = new CardConnectAuthorizationResponse
                        {
                            retref = "retref3"
                        }
                    }
                }
            };

            _oc.Payments.ListAsync <HSPayment>(OrderDirection.Incoming, orderID, filters: Arg.Is <object>(f => (string)f == "Type=CreditCard"))
            .Returns(PaymentMocks.PaymentList(MockCCPayment(paymentTotal, true, payment1transactions)));
            var payment = ValidIntegrationsPayment();

            // Act
            await _sut.AuthorizePayment(payment, userToken, merchantID);

            // Assert
            await _cardConnect.Received().VoidAuthorization(Arg.Is <CardConnectVoidRequest>(x => x.retref == "retref3" && x.merchid == merchantID && x.currency == "CAD"));

            await _oc.Payments.Received().CreateTransactionAsync(OrderDirection.Incoming, orderID, paymentID, Arg.Is <PaymentTransaction>(x => x.Amount == paymentTotal));

            await _cardConnect.Received().AuthWithoutCapture(Arg.Any <CardConnectAuthorizationRequest>());

            await _oc.Payments.Received().PatchAsync <HSPayment>(OrderDirection.Incoming, orderID, paymentID, Arg.Is <PartialPayment>(p => p.Accepted == true && p.Amount == ccTotal));

            await _oc.Payments.Received().CreateTransactionAsync(OrderDirection.Incoming, orderID, paymentID, Arg.Any <PaymentTransaction>());
        }