diff --git a/CHANGELOG.md b/CHANGELOG.md index 634dc226..e5c570fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 5.9.0 +- Add `LocalPaymentExpired` and `LocalPaymentFunded` webhook notification support + ## 5.8.0 - Add error code `TRANSACTION_TAX_AMOUNT_IS_REQUIRED_FOR_AIB_SWEDISH` for attribute `tax_amount` in `transaction` key for AIB:Domestic Transactions in Sweden - Add `ExchangeRateQuoteId` to `TransactionRequest` diff --git a/src/Braintree/Braintree.csproj b/src/Braintree/Braintree.csproj index 7bd6aca2..07372251 100644 --- a/src/Braintree/Braintree.csproj +++ b/src/Braintree/Braintree.csproj @@ -4,7 +4,7 @@ Braintree Client Library Copyright © Braintree, a division of PayPal, Inc. 2021 - 5.8.0 + 5.9.0 Braintree net452;netstandard2.0 @@ -12,22 +12,7 @@ Braintree braintree;paypal;venmo;intenational;payments;gateway;currencies;money;visa;mastercard;bitcoin;maestro;apple pay;android pay;amex;jcb;diners club;discover;american express - - Add error code `TRANSACTION_TAX_AMOUNT_IS_REQUIRED_FOR_AIB_SWEDISH` for attribute `tax_amount` in `transaction` key for AIB Domestic Transactions in Sweden - - Add `ExchangeRateQuoteId` to `TransactionRequest` - - Add `EXCHANGE_RATE_QUOTE_ID_IS_TOO_LONG` to `ValidationErrorCode` - - Add the following fields to `AndroidPayCard` and `ApplePayCard` - - `Commercial` - - `Debit` - - `DurbinRegulated` - - `Healthcare` - - `Payroll` - - `Prepaid` - - `ProductId` - - `CountryOfIssuance` - - `IssuingBank` - - Add the following fields to `PaypalDetails` - - `TaxId` - - `TaxIdType` + - Add `LocalPaymentExpired` and `LocalPaymentFunded` webhook notification support https://github.com/braintree/braintree_dotnet false diff --git a/src/Braintree/LocalPaymentExpired.cs b/src/Braintree/LocalPaymentExpired.cs new file mode 100644 index 00000000..8b6c85b9 --- /dev/null +++ b/src/Braintree/LocalPaymentExpired.cs @@ -0,0 +1,19 @@ +using System; + +namespace Braintree +{ + public class LocalPaymentExpired + { + public virtual string PaymentId { get; protected set; } + public virtual string PaymentContextId { get; protected set; } + + protected internal LocalPaymentExpired(NodeWrapper node, IBraintreeGateway gateway) + { + PaymentId = node.GetString("payment-id"); + PaymentContextId = node.GetString("payment-context-id"); + } + + [Obsolete("Mock Use Only")] + protected internal LocalPaymentExpired() { } + } +} diff --git a/src/Braintree/LocalPaymentFunded.cs b/src/Braintree/LocalPaymentFunded.cs new file mode 100644 index 00000000..3c40dcc7 --- /dev/null +++ b/src/Braintree/LocalPaymentFunded.cs @@ -0,0 +1,26 @@ +using System; + +namespace Braintree +{ + public class LocalPaymentFunded + { + public virtual string PaymentId { get; protected set; } + public virtual string PaymentContextId { get; protected set; } + public virtual Transaction Transaction { get; protected set; } + + protected internal LocalPaymentFunded(NodeWrapper node, IBraintreeGateway gateway) + { + PaymentId = node.GetString("payment-id"); + PaymentContextId = node.GetString("payment-context-id"); + + var transactionNode = node.GetNode("transaction"); + if (transactionNode != null) + { + Transaction = new Transaction(transactionNode, gateway); + } + } + + [Obsolete("Mock Use Only")] + protected internal LocalPaymentFunded() { } + } +} diff --git a/src/Braintree/Properties/AssemblyInfo.cs b/src/Braintree/Properties/AssemblyInfo.cs index c32d708a..bfe3f7b2 100644 --- a/src/Braintree/Properties/AssemblyInfo.cs +++ b/src/Braintree/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // Build Number // Revision // -[assembly: AssemblyVersion("5.8.0.0")] -[assembly: AssemblyFileVersion("5.8.0.0")] +[assembly: AssemblyVersion("5.9.0.0")] +[assembly: AssemblyFileVersion("5.9.0.0")] diff --git a/src/Braintree/WebhookNotification.cs b/src/Braintree/WebhookNotification.cs index 4d8ddfa4..2900765a 100644 --- a/src/Braintree/WebhookNotification.cs +++ b/src/Braintree/WebhookNotification.cs @@ -22,6 +22,8 @@ public enum WebhookKind [Description("grantor_updated_granted_payment_method")] GRANTOR_UPDATED_GRANTED_PAYMENT_METHOD, [Description("granted_payment_method_revoked")] GRANTED_PAYMENT_METHOD_REVOKED, [Description("local_payment_completed")] LOCAL_PAYMENT_COMPLETED, + [Description("local_payment_expired")] LOCAL_PAYMENT_EXPIRED, + [Description("local_payment_funded")] LOCAL_PAYMENT_FUNDED, [Description("local_payment_reversed")] LOCAL_PAYMENT_REVERSED, [Description("oauth_access_revoked")] OAUTH_ACCESS_REVOKED, [Description("partner_merchant_connected")] PARTNER_MERCHANT_CONNECTED, @@ -56,6 +58,8 @@ public class WebhookNotification public virtual WebhookKind Kind { get; protected set; } public virtual MerchantAccount MerchantAccount { get; protected set; } public virtual LocalPaymentCompleted LocalPaymentCompleted { get; protected set; } + public virtual LocalPaymentExpired LocalPaymentExpired { get; protected set; } + public virtual LocalPaymentFunded LocalPaymentFunded { get; protected set; } public virtual LocalPaymentReversed LocalPaymentReversed { get; protected set; } public virtual PartnerMerchant PartnerMerchant { get; protected set; } public virtual string Message { get; protected set; } @@ -158,6 +162,16 @@ public WebhookNotification(NodeWrapper node, IBraintreeGateway gateway) LocalPaymentCompleted = new LocalPaymentCompleted(WrapperNode.GetNode("local-payment"), gateway); } + if (WrapperNode.GetNode("local-payment-expired") != null) + { + LocalPaymentExpired = new LocalPaymentExpired(WrapperNode.GetNode("local-payment-expired"), gateway); + } + + if (WrapperNode.GetNode("local-payment-funded") != null) + { + LocalPaymentFunded = new LocalPaymentFunded(WrapperNode.GetNode("local-payment-funded"), gateway); + } + if (WrapperNode.GetNode("local-payment-reversed") != null) { LocalPaymentReversed = new LocalPaymentReversed(WrapperNode.GetNode("local-payment-reversed"), gateway); diff --git a/src/Braintree/WebhookTestingGateway.cs b/src/Braintree/WebhookTestingGateway.cs index d9acf92a..bf422cdf 100644 --- a/src/Braintree/WebhookTestingGateway.cs +++ b/src/Braintree/WebhookTestingGateway.cs @@ -100,6 +100,10 @@ private string SubjectSampleXml(WebhookKind kind, string id) return GrantedPaymentMethodRevokedSampleXml(id); } else if (kind == WebhookKind.LOCAL_PAYMENT_COMPLETED) { return LocalPaymentCompletedSampleXml(); + } else if (kind == WebhookKind.LOCAL_PAYMENT_EXPIRED) { + return LocalPaymentExpiredSampleXml(); + } else if (kind == WebhookKind.LOCAL_PAYMENT_FUNDED) { + return LocalPaymentFundedSampleXml(); } else if (kind == WebhookKind.LOCAL_PAYMENT_REVERSED) { return LocalPaymentReversedSampleXml(); } else { @@ -535,7 +539,7 @@ private static string PaymentMethodRevokedByCustomerSampleXml(string id) { Node("limited-use-order-id", NIL_TRUE, ""), NodeAttr("revoked-at", TYPE_DATE_TIME, "2019-01-02T12:00:00Z") ); - } + } private static string GrantedPaymentMethodRevokedSampleXml(string id) { return Node("venmo-account", @@ -567,6 +571,26 @@ private static string LocalPaymentCompletedSampleXml() { ); } + private static string LocalPaymentExpiredSampleXml() { + return Node("local-payment-expired", + Node("payment-id", "a-payment-id"), + Node("payment-context-id", "a-payment-context-id") + ); + } + + private static string LocalPaymentFundedSampleXml() { + return Node("local-payment-funded", + Node("payment-id", "a-payment-id"), + Node("payment-context-id", "a-payment-context-id"), + Node("transaction", + Node("id", "1"), + Node("status", "settled"), + Node("amount", "10.00"), + Node("order-id", "order1234") + ) + ); + } + private static string LocalPaymentReversedSampleXml() { return Node("local-payment-reversed", Node("payment-id", "a-payment-id") diff --git a/test/Braintree.Tests.Integration/PaymentMethodNonceIntegrationTest.cs b/test/Braintree.Tests.Integration/PaymentMethodNonceIntegrationTest.cs index 40a60a1e..6bc320ae 100644 --- a/test/Braintree.Tests.Integration/PaymentMethodNonceIntegrationTest.cs +++ b/test/Braintree.Tests.Integration/PaymentMethodNonceIntegrationTest.cs @@ -109,15 +109,7 @@ public void Find_ExposesDetailsForVenmoNonce() [Test] public void Find_ExposesThreeDSecureInfo() { - BraintreeService service = new BraintreeService(gateway.Configuration); - CreditCardRequest creditCardRequest = new CreditCardRequest - { - Number = SandboxValues.CreditCardNumber.VISA, - ExpirationMonth = "05", - ExpirationYear = "2020" - }; - string nonce = TestHelper.Generate3DSNonce(service, creditCardRequest); - + string nonce = "fake-three-d-secure-visa-full-authentication-nonce"; PaymentMethodNonce foundNonce = gateway.PaymentMethodNonce.Find(nonce); ThreeDSecureInfo info = foundNonce.ThreeDSecureInfo; @@ -127,10 +119,10 @@ public void Find_ExposesThreeDSecureInfo() Assert.AreEqual("authenticate_successful", info.Status); Assert.IsTrue(info.LiabilityShifted); Assert.IsTrue(info.LiabilityShiftPossible); - Assert.AreEqual("test_cavv", info.Cavv); - Assert.AreEqual("test_eci", info.EciFlag); + Assert.AreEqual("cavv_value", info.Cavv); + Assert.AreEqual("05", info.EciFlag); Assert.AreEqual("1.0.2", info.ThreeDSecureVersion); - Assert.AreEqual("test_xid", info.Xid); + Assert.AreEqual("xid_value", info.Xid); Assert.IsNotNull(info.ThreeDSecureAuthenticationId); Assert.IsNotNull(info.Authentication); Assert.IsNotNull(info.Lookup); diff --git a/test/Braintree.Tests/WebhookNotificationTest.cs b/test/Braintree.Tests/WebhookNotificationTest.cs index 323d8a65..522f6ee6 100644 --- a/test/Braintree.Tests/WebhookNotificationTest.cs +++ b/test/Braintree.Tests/WebhookNotificationTest.cs @@ -661,6 +661,40 @@ public void SampleNotification_ReturnsANotificationForLocalPaymentCompleted() Assert.NotNull(localPayment.Transaction); } + [Test] + public void SampleNotification_ReturnsANotificationForLocalPaymentExpired() + { + Dictionary sampleNotification = gateway.WebhookTesting.SampleNotification(WebhookKind.LOCAL_PAYMENT_EXPIRED, "my_id"); + + WebhookNotification notification = gateway.WebhookNotification.Parse(sampleNotification["bt_signature"], sampleNotification["bt_payload"]); + + Assert.AreEqual(WebhookKind.LOCAL_PAYMENT_EXPIRED, notification.Kind); + LocalPaymentExpired localPayment = notification.LocalPaymentExpired; + + Assert.AreEqual("a-payment-id", localPayment.PaymentId); + Assert.AreEqual("a-payment-context-id", localPayment.PaymentContextId); + } + + [Test] + public void SampleNotification_ReturnsANotificationForLocalPaymentFunded() + { + Dictionary sampleNotification = gateway.WebhookTesting.SampleNotification(WebhookKind.LOCAL_PAYMENT_FUNDED, "my_id"); + + WebhookNotification notification = gateway.WebhookNotification.Parse(sampleNotification["bt_signature"], sampleNotification["bt_payload"]); + + Assert.AreEqual(WebhookKind.LOCAL_PAYMENT_FUNDED, notification.Kind); + + LocalPaymentFunded localPayment = notification.LocalPaymentFunded; + Assert.AreEqual("a-payment-id", localPayment.PaymentId); + Assert.AreEqual("a-payment-context-id", localPayment.PaymentContextId); + + Transaction transaction = localPayment.Transaction; + Assert.NotNull(transaction); + Assert.AreEqual("1", transaction.Id); + Assert.AreEqual(TransactionStatus.SETTLED, transaction.Status); + Assert.AreEqual("order1234", transaction.OrderId); + } + [Test] public void SampleNotification_ReturnsANotificationForLocalPaymentReversed() {