From a62595de9bf626f0e570d118d17311439c2de351 Mon Sep 17 00:00:00 2001 From: Braintree Date: Wed, 8 Nov 2023 22:57:44 +0000 Subject: [PATCH] 5.21.0 Co-authored-by: Sara Vasquez Co-authored-by: Debra Do --- CHANGELOG.md | 7 + src/Braintree/Braintree.csproj | 9 +- src/Braintree/IndustryDataRequest.cs | 6 +- src/Braintree/MetaCheckoutCard.cs | 148 +++++++++++ src/Braintree/MetaCheckoutCardDetails.cs | 121 +++++++++ src/Braintree/MetaCheckoutToken.cs | 152 +++++++++++ src/Braintree/MetaCheckoutTokenDetails.cs | 125 +++++++++ src/Braintree/PaymentMethodOptionsRequest.cs | 6 +- src/Braintree/PaymentMethodParser.cs | 8 + src/Braintree/Properties/AssemblyInfo.cs | 4 +- src/Braintree/Test/Nonce.cs | 3 + src/Braintree/Transaction.cs | 14 + src/Braintree/UsBankAccountVerification.cs | 39 +-- src/Braintree/VenmoProfileData.cs | 16 +- src/Braintree/WebhookTestingGateway.cs | 16 +- .../PaymentMethodNonceIntegrationTest.cs | 30 +++ .../TransactionIntegrationTest.cs | 250 ++++++++++++++++++ ...sBankAccountVerificationIntegrationTest.cs | 75 +++++- .../IndustryDataRequestTest.cs | 4 + .../MetaCheckoutCardDetailsTest.cs | 79 ++++++ test/Braintree.Tests/MetaCheckoutCardTest.cs | 82 ++++++ .../MetaCheckoutTokenDetailsTest.cs | 82 ++++++ test/Braintree.Tests/MetaCheckoutTokenTest.cs | 86 ++++++ .../UsBankAccountVerificationTest.cs | 8 +- .../WebhookNotificationTest.cs | 14 + 25 files changed, 1355 insertions(+), 29 deletions(-) create mode 100644 src/Braintree/MetaCheckoutCard.cs create mode 100644 src/Braintree/MetaCheckoutCardDetails.cs create mode 100644 src/Braintree/MetaCheckoutToken.cs create mode 100644 src/Braintree/MetaCheckoutTokenDetails.cs create mode 100644 test/Braintree.Tests/MetaCheckoutCardDetailsTest.cs create mode 100644 test/Braintree.Tests/MetaCheckoutCardTest.cs create mode 100644 test/Braintree.Tests/MetaCheckoutTokenDetailsTest.cs create mode 100644 test/Braintree.Tests/MetaCheckoutTokenTest.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index cc66891c..7166636b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 5.21.0 +- Add `DateOfBirth` and `CountryCode` to `IndustryDataRequest` +- Add `BillingAddress` and `ShippingAddress` to `VenmoProfileData` +- Add `VerificationAddOns` and `AdditionalProcessorResponse` to `UsBankAccountVerification` +- Add `MetaCheckoutCard` and `MetaCheckoutToken` to payment method +- Add `MetaCheckoutCardDetails` nd `MetaCheckoutTokenDetails` to Transaction + ## 5.20.0 - Add `SUBSCRIPTIONBILLINGSKIPPED` webhook notification support - Add `implicitlyVaultedPaymentMethodToken` and `implicitlyVaultedPaymentMethodGlobalId` to `LocalPaymentDetails` diff --git a/src/Braintree/Braintree.csproj b/src/Braintree/Braintree.csproj index 91f2ef5b..19fa348f 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.20.0 + 5.21.0 Braintree net452;netstandard2.0 @@ -12,8 +12,11 @@ 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 `SUBSCRIPTIONBILLINGSKIPPED` webhook notification support - - Add `implicitlyVaultedPaymentMethodToken` and `implicitlyVaultedPaymentMethodGlobalId` to `LocalPaymentDetails` + - Add `DateOfBirth` and `CountryCode` to `IndustryDataRequest` + - Add `BillingAddress` and `ShippingAddress` to `VenmoProfileData` + - Add `VerificationAddOns` and `AdditionalProcessorResponse` to `UsBankAccountVerification` + - Add `MetaCheckoutCard` and `MetaCheckoutToken` to payment method + - Add `MetaCheckoutCardDetails` nd `MetaCheckoutTokenDetails` to Transaction https://github.com/braintree/braintree_dotnet false diff --git a/src/Braintree/IndustryDataRequest.cs b/src/Braintree/IndustryDataRequest.cs index 8c4d08eb..170521bd 100644 --- a/src/Braintree/IndustryDataRequest.cs +++ b/src/Braintree/IndustryDataRequest.cs @@ -10,7 +10,9 @@ public class IndustryDataRequest : Request public DateTime? ArrivalDate { get; set; } public string CheckInDate { get; set; } public string CheckOutDate { get; set; } + public string CountryCode { get; set; } public string CustomerCode { get; set; } + public string DateOfBirth { get; set; } public string DepartureDate { get; set; } public decimal? FareAmount { get; set; } public decimal? FeeAmount { get; set; } @@ -75,7 +77,9 @@ protected virtual RequestBuilder BuildRequest(string root) AddElement("ticket-number", TicketNumber). AddElement("issuing-carrier-code", IssuingCarrierCode). AddElement("customer-code", CustomerCode). - AddElement("property-phone", PropertyPhone); + AddElement("property-phone", PropertyPhone). + AddElement("date-of-birth", DateOfBirth). + AddElement("country-code", CountryCode); if (RoomRate != null) builder.AddElement("room-rate", RoomRate.ToString()); diff --git a/src/Braintree/MetaCheckoutCard.cs b/src/Braintree/MetaCheckoutCard.cs new file mode 100644 index 00000000..7af50105 --- /dev/null +++ b/src/Braintree/MetaCheckoutCard.cs @@ -0,0 +1,148 @@ +#pragma warning disable 1591 + +using System; +using System.Collections.Generic; + +namespace Braintree +{ + public class MetaCheckoutCard : PaymentMethod + { + public virtual string Bin { get; protected set; } + public virtual string CardholderName { get; protected set; } + public virtual CreditCardCardType CardType { get; protected set; } + public virtual CreditCardCommercial Commercial { get; protected set; } + public virtual string ContainerId { get; protected set; } + public virtual DateTime? CreatedAt { get; protected set; } + public virtual string CustomerId { get; protected set; } + public virtual CreditCardCustomerLocation CustomerLocation { get; protected set; } + public virtual CreditCardDebit Debit { get; protected set; } + public virtual CreditCardDurbinRegulated DurbinRegulated { get; protected set; } + public virtual string ExpirationMonth { get; protected set; } + public virtual string ExpirationYear { get; protected set; } + public virtual CreditCardHealthcare Healthcare { get; protected set; } + public virtual string ImageUrl { get; protected set; } + public virtual bool? IsDefault { get; protected set; } + public virtual bool? IsExpired { get; protected set; } + public virtual string LastFour { get; protected set; } + public virtual CreditCardPayroll Payroll { get; protected set; } + public virtual CreditCardPrepaid Prepaid { get; protected set; } + public virtual string Token { get; protected set; } + public virtual string UniqueNumberIdentifier { get; protected set; } + public virtual DateTime? UpdatedAt { get; protected set; } + public virtual CreditCardVerification Verification { get; protected set; } + + private string _CountryOfIssuance; + + public virtual string CountryOfIssuance + { + get + { + if (_CountryOfIssuance == "") + { + return CreditCard.CountryOfIssuanceUnknown; + } + else + { + return _CountryOfIssuance; + } + } + } + + private string _IssuingBank; + + public virtual string IssuingBank + { + get + { + if (_IssuingBank == "") + { + return CreditCard.IssuingBankUnknown; + } + else + { + return _IssuingBank; + } + } + } + + private string _ProductId; + + public virtual string ProductId + { + get + { + if (_ProductId == "") + { + return CreditCard.ProductIdUnknown; + } + else + { + return _ProductId; + } + } + } + + public virtual string ExpirationDate + { + get => ExpirationMonth + "/" + ExpirationYear; + protected set + { + if (string.IsNullOrEmpty(value)) return; + ExpirationMonth = value.Split('/')[0]; + ExpirationYear = value.Split('/')[1]; + } + } + + public string MaskedNumber => $"{Bin}******{LastFour}"; + + protected internal MetaCheckoutCard(NodeWrapper node, IBraintreeGateway gateway) + { + if (node == null) return; + + Bin = node.GetString("bin"); + CardholderName = node.GetString("cardholder-name"); + CardType = node.GetEnum("card-type", CreditCardCardType.UNRECOGNIZED); + Commercial = node.GetEnum("commercial", CreditCardCommercial.UNKNOWN); + ContainerId = node.GetString("container-id"); + CustomerId = node.GetString("customer-id"); + CustomerLocation = node.GetEnum("customer-location", CreditCardCustomerLocation.UNRECOGNIZED); + CreatedAt = node.GetDateTime("created-at"); + Debit = node.GetEnum("debit", CreditCardDebit.UNKNOWN); + DurbinRegulated = node.GetEnum("durbin-regulated", CreditCardDurbinRegulated.UNKNOWN); + ExpirationMonth = node.GetString("expiration-month"); + ExpirationYear = node.GetString("expiration-year"); + IsDefault = node.GetBoolean("default"); + IsExpired = node.GetBoolean("expired"); + LastFour = node.GetString("last-4"); + Token = node.GetString("token"); + UpdatedAt = node.GetDateTime("updated-at"); + Prepaid = node.GetEnum("prepaid", CreditCardPrepaid.UNKNOWN); + Payroll = node.GetEnum("payroll", CreditCardPayroll.UNKNOWN); + Healthcare = node.GetEnum("healthcare", CreditCardHealthcare.UNKNOWN); + UniqueNumberIdentifier = node.GetString("unique-number-identifier"); + _CountryOfIssuance = node.GetString("country-of-issuance"); + _IssuingBank = node.GetString("issuing-bank"); + _ProductId = node.GetString("product-id"); + ImageUrl = node.GetString("image-url"); + + var verificationNodes = node.GetList("verifications/verification"); + Verification = FindLatestVerification(verificationNodes, gateway); + } + + private CreditCardVerification FindLatestVerification(List verificationNodes, IBraintreeGateway gateway) { + if(verificationNodes.Count > 0) + { + verificationNodes.Sort(delegate(NodeWrapper first, NodeWrapper second) { + DateTime time1 = (DateTime)first.GetDateTime("created-at"); + DateTime time2 = (DateTime)second.GetDateTime("created-at"); + + return DateTime.Compare(time2, time1); + }); + + return new CreditCardVerification(verificationNodes[0], gateway); + } + + return null; + } + } +} diff --git a/src/Braintree/MetaCheckoutCardDetails.cs b/src/Braintree/MetaCheckoutCardDetails.cs new file mode 100644 index 00000000..95422ad6 --- /dev/null +++ b/src/Braintree/MetaCheckoutCardDetails.cs @@ -0,0 +1,121 @@ +using System; + +namespace Braintree +{ + public class MetaCheckoutCardDetails + { + public virtual string Bin { get; protected set; } + public virtual string CardholderName { get; protected set; } + public virtual CreditCardCardType CardType { get; protected set; } + public virtual CreditCardCommercial Commercial { get; protected set; } + public virtual string ContainerId { get; protected set; } + public virtual DateTime? CreatedAt { get; protected set; } + public virtual CreditCardCustomerLocation CustomerLocation { get; protected set; } + public virtual CreditCardDebit Debit { get; protected set; } + public virtual CreditCardDurbinRegulated DurbinRegulated { get; protected set; } + public virtual string ExpirationMonth { get; protected set; } + public virtual string ExpirationYear { get; protected set; } + public virtual CreditCardHealthcare Healthcare { get; protected set; } + public virtual string ImageUrl { get; protected set; } + public virtual bool? IsExpired { get; protected set; } + public virtual string LastFour { get; protected set; } + public virtual CreditCardPayroll Payroll { get; protected set; } + public virtual CreditCardPrepaid Prepaid { get; protected set; } + public virtual string Token { get; protected set; } + public virtual string UniqueNumberIdentifier { get; protected set; } + public virtual DateTime? UpdatedAt { get; protected set; } + + private string _CountryOfIssuance; + + public virtual string CountryOfIssuance + { + get + { + if (_CountryOfIssuance == "") + { + return CreditCard.CountryOfIssuanceUnknown; + } + else + { + return _CountryOfIssuance; + } + } + } + + private string _IssuingBank; + + public virtual string IssuingBank + { + get + { + if (_IssuingBank == "") + { + return CreditCard.IssuingBankUnknown; + } + else + { + return _IssuingBank; + } + } + } + + private string _ProductId; + + public virtual string ProductId + { + get + { + if (_ProductId == "") + { + return CreditCard.ProductIdUnknown; + } + else + { + return _ProductId; + } + } + } + + public virtual string ExpirationDate + { + get => ExpirationMonth + "/" + ExpirationYear; + protected set + { + if (string.IsNullOrEmpty(value)) return; + ExpirationMonth = value.Split('/')[0]; + ExpirationYear = value.Split('/')[1]; + } + } + + public string MaskedNumber => $"{Bin}******{LastFour}"; + + protected internal MetaCheckoutCardDetails(NodeWrapper node) + { + if (node == null) return; + + Bin = node.GetString("bin"); + ContainerId = node.GetString("container-id"); + CardholderName = node.GetString("cardholder-name"); + CardType = node.GetEnum("card-type", CreditCardCardType.UNRECOGNIZED); + ExpirationMonth = node.GetString("expiration-month"); + ExpirationYear = node.GetString("expiration-year"); + IsExpired = node.GetBoolean("expired"); + CustomerLocation = node.GetEnum("customer-location", CreditCardCustomerLocation.UNRECOGNIZED); + LastFour = node.GetString("last-4"); + UniqueNumberIdentifier = node.GetString("unique-number-identifier"); + Token = node.GetString("token"); + CreatedAt = node.GetDateTime("created-at"); + UpdatedAt = node.GetDateTime("updated-at"); + Prepaid = node.GetEnum("prepaid", CreditCardPrepaid.UNKNOWN); + Payroll = node.GetEnum("payroll", CreditCardPayroll.UNKNOWN); + DurbinRegulated = node.GetEnum("durbin-regulated", CreditCardDurbinRegulated.UNKNOWN); + Debit = node.GetEnum("debit", CreditCardDebit.UNKNOWN); + Commercial = node.GetEnum("commercial", CreditCardCommercial.UNKNOWN); + Healthcare = node.GetEnum("healthcare", CreditCardHealthcare.UNKNOWN); + _CountryOfIssuance = node.GetString("country-of-issuance"); + _IssuingBank = node.GetString("issuing-bank"); + _ProductId = node.GetString("product-id"); + ImageUrl = node.GetString("image-url"); + } + } +} diff --git a/src/Braintree/MetaCheckoutToken.cs b/src/Braintree/MetaCheckoutToken.cs new file mode 100644 index 00000000..b80b5580 --- /dev/null +++ b/src/Braintree/MetaCheckoutToken.cs @@ -0,0 +1,152 @@ +#pragma warning disable 1591 + +using System; +using System.Collections.Generic; + +namespace Braintree +{ + public class MetaCheckoutToken : PaymentMethod + { + public virtual string Bin { get; protected set; } + public virtual string CardholderName { get; protected set; } + public virtual CreditCardCardType CardType { get; protected set; } + public virtual CreditCardCommercial Commercial { get; protected set; } + public virtual string ContainerId { get; protected set; } + public virtual DateTime? CreatedAt { get; protected set; } + public virtual string Cryptogram { get; protected set; } + public virtual string CustomerId { get; protected set; } + public virtual CreditCardCustomerLocation CustomerLocation { get; protected set; } + public virtual CreditCardDebit Debit { get; protected set; } + public virtual CreditCardDurbinRegulated DurbinRegulated { get; protected set; } + public virtual string ECommerceIndicator { get; protected set; } + public virtual string ExpirationMonth { get; protected set; } + public virtual string ExpirationYear { get; protected set; } + public virtual string ImageUrl { get; protected set; } + public virtual bool? IsDefault { get; protected set; } + public virtual bool? IsExpired { get; protected set; } + public virtual CreditCardHealthcare Healthcare { get; protected set; } + public virtual string LastFour { get; protected set; } + public virtual string Token { get; protected set; } + public virtual DateTime? UpdatedAt { get; protected set; } + public virtual CreditCardPrepaid Prepaid { get; protected set; } + public virtual CreditCardPayroll Payroll { get; protected set; } + public virtual string UniqueNumberIdentifier { get; protected set; } + public virtual CreditCardVerification Verification { get; protected set; } + + private string _CountryOfIssuance; + + public virtual string CountryOfIssuance + { + get + { + if (_CountryOfIssuance == "") + { + return CreditCard.CountryOfIssuanceUnknown; + } + else + { + return _CountryOfIssuance; + } + } + } + + private string _IssuingBank; + + public virtual string IssuingBank + { + get + { + if (_IssuingBank == "") + { + return CreditCard.IssuingBankUnknown; + } + else + { + return _IssuingBank; + } + } + } + + private string _ProductId; + + public virtual string ProductId + { + get + { + if (_ProductId == "") + { + return CreditCard.ProductIdUnknown; + } + else + { + return _ProductId; + } + } + } + + public virtual string ExpirationDate + { + get => ExpirationMonth + "/" + ExpirationYear; + protected set + { + if (string.IsNullOrEmpty(value)) return; + ExpirationMonth = value.Split('/')[0]; + ExpirationYear = value.Split('/')[1]; + } + } + + public string MaskedNumber => $"{Bin}******{LastFour}"; + + protected internal MetaCheckoutToken(NodeWrapper node, IBraintreeGateway gateway) + { + if (node == null) return; + + Bin = node.GetString("bin"); + CardholderName = node.GetString("cardholder-name"); + CardType = node.GetEnum("card-type", CreditCardCardType.UNRECOGNIZED); + ContainerId = node.GetString("container-id"); + CustomerId = node.GetString("customer-id"); + Cryptogram = node.GetString("cryptogram"); + ECommerceIndicator = node.GetString("ecommerce-indicator"); + ExpirationMonth = node.GetString("expiration-month"); + ExpirationYear = node.GetString("expiration-year"); + IsDefault = node.GetBoolean("default"); + IsExpired = node.GetBoolean("expired"); + CustomerLocation = node.GetEnum("customer-location", CreditCardCustomerLocation.UNRECOGNIZED); + LastFour = node.GetString("last-4"); + UniqueNumberIdentifier = node.GetString("unique-number-identifier"); + Token = node.GetString("token"); + CreatedAt = node.GetDateTime("created-at"); + UpdatedAt = node.GetDateTime("updated-at"); + Prepaid = node.GetEnum("prepaid", CreditCardPrepaid.UNKNOWN); + Payroll = node.GetEnum("payroll", CreditCardPayroll.UNKNOWN); + DurbinRegulated = node.GetEnum("durbin-regulated", CreditCardDurbinRegulated.UNKNOWN); + Debit = node.GetEnum("debit", CreditCardDebit.UNKNOWN); + Commercial = node.GetEnum("commercial", CreditCardCommercial.UNKNOWN); + Healthcare = node.GetEnum("healthcare", CreditCardHealthcare.UNKNOWN); + _CountryOfIssuance = node.GetString("country-of-issuance"); + _IssuingBank = node.GetString("issuing-bank"); + _ProductId = node.GetString("product-id"); + ImageUrl = node.GetString("image-url"); + + var verificationNodes = node.GetList("verifications/verification"); + Verification = FindLatestVerification(verificationNodes, gateway); + } + + private CreditCardVerification FindLatestVerification(List verificationNodes, IBraintreeGateway gateway) { + if(verificationNodes.Count > 0) + { + verificationNodes.Sort(delegate(NodeWrapper first, NodeWrapper second) { + DateTime time1 = (DateTime)first.GetDateTime("created-at"); + DateTime time2 = (DateTime)second.GetDateTime("created-at"); + + return DateTime.Compare(time2, time1); + }); + + return new CreditCardVerification(verificationNodes[0], gateway); + } + + return null; + } + } +} diff --git a/src/Braintree/MetaCheckoutTokenDetails.cs b/src/Braintree/MetaCheckoutTokenDetails.cs new file mode 100644 index 00000000..b0441ae6 --- /dev/null +++ b/src/Braintree/MetaCheckoutTokenDetails.cs @@ -0,0 +1,125 @@ +using System; + +namespace Braintree +{ + public class MetaCheckoutTokenDetails + { + public virtual string Bin { get; protected set; } + public virtual string CardholderName { get; protected set; } + public virtual CreditCardCardType CardType { get; protected set; } + public virtual CreditCardCommercial Commercial { get; protected set; } + public virtual string ContainerId { get; protected set; } + public virtual DateTime? CreatedAt { get; protected set; } + public virtual string Cryptogram { get; protected set; } + public virtual CreditCardCustomerLocation CustomerLocation { get; protected set; } + public virtual CreditCardDebit Debit { get; protected set; } + public virtual CreditCardDurbinRegulated DurbinRegulated { get; protected set; } + public virtual string ECommerceIndicator { get; protected set; } + public virtual string ExpirationMonth { get; protected set; } + public virtual string ExpirationYear { get; protected set; } + public virtual CreditCardHealthcare Healthcare { get; protected set; } + public virtual string ImageUrl { get; protected set; } + public virtual bool? IsExpired { get; protected set; } + public virtual string LastFour { get; protected set; } + public virtual CreditCardPayroll Payroll { get; protected set; } + public virtual CreditCardPrepaid Prepaid { get; protected set; } + public virtual string Token { get; protected set; } + public virtual string UniqueNumberIdentifier { get; protected set; } + public virtual DateTime? UpdatedAt { get; protected set; } + + private string _CountryOfIssuance; + + public virtual string CountryOfIssuance + { + get + { + if (_CountryOfIssuance == "") + { + return CreditCard.CountryOfIssuanceUnknown; + } + else + { + return _CountryOfIssuance; + } + } + } + + private string _IssuingBank; + + public virtual string IssuingBank + { + get + { + if (_IssuingBank == "") + { + return CreditCard.IssuingBankUnknown; + } + else + { + return _IssuingBank; + } + } + } + + private string _ProductId; + + public virtual string ProductId + { + get + { + if (_ProductId == "") + { + return CreditCard.ProductIdUnknown; + } + else + { + return _ProductId; + } + } + } + + public virtual string ExpirationDate + { + get => ExpirationMonth + "/" + ExpirationYear; + protected set + { + if (string.IsNullOrEmpty(value)) return; + ExpirationMonth = value.Split('/')[0]; + ExpirationYear = value.Split('/')[1]; + } + } + + public string MaskedNumber => $"{Bin}******{LastFour}"; + + protected internal MetaCheckoutTokenDetails(NodeWrapper node) + { + if (node == null) return; + + Bin = node.GetString("bin"); + ContainerId = node.GetString("container-id"); + CardholderName = node.GetString("cardholder-name"); + CardType = node.GetEnum("card-type", CreditCardCardType.UNRECOGNIZED); + ExpirationMonth = node.GetString("expiration-month"); + ExpirationYear = node.GetString("expiration-year"); + Cryptogram = node.GetString("cryptogram"); + ECommerceIndicator = node.GetString("ecommerce-indicator"); + IsExpired = node.GetBoolean("expired"); + CustomerLocation = node.GetEnum("customer-location", CreditCardCustomerLocation.UNRECOGNIZED); + LastFour = node.GetString("last-4"); + UniqueNumberIdentifier = node.GetString("unique-number-identifier"); + Token = node.GetString("token"); + CreatedAt = node.GetDateTime("created-at"); + UpdatedAt = node.GetDateTime("updated-at"); + Prepaid = node.GetEnum("prepaid", CreditCardPrepaid.UNKNOWN); + Payroll = node.GetEnum("payroll", CreditCardPayroll.UNKNOWN); + DurbinRegulated = node.GetEnum("durbin-regulated", CreditCardDurbinRegulated.UNKNOWN); + Debit = node.GetEnum("debit", CreditCardDebit.UNKNOWN); + Commercial = node.GetEnum("commercial", CreditCardCommercial.UNKNOWN); + Healthcare = node.GetEnum("healthcare", CreditCardHealthcare.UNKNOWN); + _CountryOfIssuance = node.GetString("country-of-issuance"); + _IssuingBank = node.GetString("issuing-bank"); + _ProductId = node.GetString("product-id"); + ImageUrl = node.GetString("image-url"); + } + } +} diff --git a/src/Braintree/PaymentMethodOptionsRequest.cs b/src/Braintree/PaymentMethodOptionsRequest.cs index e16e3083..2d31ceeb 100644 --- a/src/Braintree/PaymentMethodOptionsRequest.cs +++ b/src/Braintree/PaymentMethodOptionsRequest.cs @@ -4,6 +4,9 @@ namespace Braintree { public class PaymentMethodOptionsRequest : Request { + public PaymentMethodOptionsPayPalRequest OptionsPayPal { get; set; } + public UsBankAccountVerificationMethod? UsBankAccountVerificationMethod { get; set; } + public VerificationAddOns? VerificationAddOns { get; set; } public bool? FailOnDuplicatePaymentMethod { get; set; } public bool? MakeDefault { get; set; } public bool? SkipAdvancedFraudChecking { get; set; } @@ -12,8 +15,6 @@ public class PaymentMethodOptionsRequest : Request public string VerificationAmount { get; set; } public string VerificationCurrencyIsoCode { get; set; } public string VerificationMerchantAccountId { get; set; } - public PaymentMethodOptionsPayPalRequest OptionsPayPal { get; set; } - public UsBankAccountVerificationMethod? UsBankAccountVerificationMethod { get; set; } public override string ToXml(string root) { @@ -34,6 +35,7 @@ protected virtual RequestBuilder BuildRequest(string root) AddElement("skip-advanced-fraud-checking", SkipAdvancedFraudChecking). AddElement("us-bank-account-verification-method", UsBankAccountVerificationMethod.GetDescription()). AddElement("verification-account-type", VerificationAccountType). + AddElement("verification-add-ons", VerificationAddOns.GetDescription()). AddElement("verification-amount", VerificationAmount). AddElement("verification-currency-iso-code", VerificationCurrencyIsoCode). AddElement("verification-merchant-account-id", VerificationMerchantAccountId). diff --git a/src/Braintree/PaymentMethodParser.cs b/src/Braintree/PaymentMethodParser.cs index 1f3ad1d4..299cd8fc 100644 --- a/src/Braintree/PaymentMethodParser.cs +++ b/src/Braintree/PaymentMethodParser.cs @@ -18,6 +18,14 @@ public static PaymentMethod ParsePaymentMethod(NodeWrapper response, IBraintreeG { return new CreditCard(response, gateway); } + else if (response.GetName() == "meta-checkout-card") + { + return new MetaCheckoutCard(response, gateway); + } + else if (response.GetName() == "meta-checkout-token") + { + return new MetaCheckoutToken(response, gateway); + } else if (response.GetName() == "paypal-account") { return new PayPalAccount(response, gateway); diff --git a/src/Braintree/Properties/AssemblyInfo.cs b/src/Braintree/Properties/AssemblyInfo.cs index 213d902d..aaf00836 100644 --- a/src/Braintree/Properties/AssemblyInfo.cs +++ b/src/Braintree/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // Build Number // Revision // -[assembly: AssemblyVersion("5.20.0.0")] -[assembly: AssemblyFileVersion("5.20.0.0")] +[assembly: AssemblyVersion("5.21.0.0")] +[assembly: AssemblyFileVersion("5.21.0.0")] diff --git a/src/Braintree/Test/Nonce.cs b/src/Braintree/Test/Nonce.cs index 2eca8500..8b7a2402 100644 --- a/src/Braintree/Test/Nonce.cs +++ b/src/Braintree/Test/Nonce.cs @@ -17,6 +17,8 @@ public class Nonce public const string GatewayRejectedTokenIssuance = "fake-token-issuance-error-venmo-account-nonce"; public const string LocalPayment = "fake-local-payment-method-nonce"; public const string LuhnInvalid = "fake-luhn-invalid-nonce"; + public const string MetaCheckoutCard = "fake-meta-checkout-card-nonce"; + public const string MetaCheckoutToken = "fake-meta-checkout-token-nonce"; public const string PayPalBillingAgreement = "fake-paypal-billing-agreement-nonce"; // NEXT_MAJOR_VERSION - no longer supported in the Gateway, remove this constant public const string PayPalFuturePayment = "fake-paypal-future-nonce"; @@ -66,6 +68,7 @@ public class Nonce public const string TransactablePrepaid = "fake-valid-prepaid-nonce"; public const string TransactableUnknownIndicators = "fake-valid-unknown-indicators-nonce"; public const string TransactableVisa = "fake-valid-visa-nonce"; + public const string UsBankAccount = "fake-us-bank-account-nonce"; public const string VenmoAccount = "fake-venmo-account-nonce"; public const string VisaCheckoutAmEx = "fake-visa-checkout-amex-nonce"; public const string VisaCheckoutDiscover = "fake-visa-checkout-discover-nonce"; diff --git a/src/Braintree/Transaction.cs b/src/Braintree/Transaction.cs index f248fa45..4657c9e8 100644 --- a/src/Braintree/Transaction.cs +++ b/src/Braintree/Transaction.cs @@ -86,6 +86,8 @@ public enum PaymentInstrumentType [Description("apple_pay_card")] APPLE_PAY_CARD, [Description("credit_card")] CREDIT_CARD, [Description("local_payment")] LOCAL_PAYMENT, + [Description("meta_checkout_card")] META_CHECKOUT_CARD, + [Description("meta_checkout_token")] META_CHECKOUT_TOKEN, [Description("paypal_account")] PAYPAL_ACCOUNT, [Description("paypal_here")] PAYPAL_HERE, [Description("samsung_pay_card")] SAMSUNG_PAY_CARD, @@ -174,6 +176,8 @@ public class Transaction public virtual VenmoAccountDetails VenmoAccountDetails { get; protected set; } public virtual SepaDirectDebitAccountDetails SepaDirectDebitAccountDetails { get; protected set; } public virtual UsBankAccountDetails UsBankAccountDetails { get; protected set; } + public virtual MetaCheckoutCardDetails MetaCheckoutCardDetails { get; protected set; } + public virtual MetaCheckoutTokenDetails MetaCheckoutTokenDetails { get; protected set; } public virtual VisaCheckoutCardDetails VisaCheckoutCardDetails { get; protected set; } public virtual SamsungPayCardDetails SamsungPayCardDetails { get; protected set; } public virtual PaymentInstrumentType PaymentInstrumentType { get; protected set; } @@ -329,6 +333,16 @@ protected internal Transaction(NodeWrapper node, IBraintreeGateway gateway) { UsBankAccountDetails = new UsBankAccountDetails(usBankAccountNode); } + var metaCheckoutCardNode = node.GetNode("meta-checkout-card"); + if (metaCheckoutCardNode != null) + { + MetaCheckoutCardDetails = new MetaCheckoutCardDetails(metaCheckoutCardNode); + } + var metaCheckoutTokenNode = node.GetNode("meta-checkout-token"); + if (metaCheckoutTokenNode != null) + { + MetaCheckoutTokenDetails = new MetaCheckoutTokenDetails(metaCheckoutTokenNode); + } var visaCheckoutNode = node.GetNode("visa-checkout-card"); if (visaCheckoutNode != null) { diff --git a/src/Braintree/UsBankAccountVerification.cs b/src/Braintree/UsBankAccountVerification.cs index eed35566..bc439bc6 100644 --- a/src/Braintree/UsBankAccountVerification.cs +++ b/src/Braintree/UsBankAccountVerification.cs @@ -9,49 +9,58 @@ public enum UsBankAccountVerificationStatus { [Description("failed")] FAILED, [Description("gateway_rejected")] GATEWAY_REJECTED, + [Description("pending")] PENDING, [Description("processor_declined")] PROCESSOR_DECLINED, [Description("unrecognized")] UNRECOGNIZED, - [Description("verified")] VERIFIED, - [Description("pending")] PENDING + [Description("verified")] VERIFIED } public enum UsBankAccountVerificationMethod { [Description("independent_check")] INDEPENDENT_CHECK, + [Description("micro_transfers")] MICRO_TRANSFERS, [Description("network_check")] NETWORK_CHECK, [Description("tokenized_check")] TOKENIZED_CHECK, - [Description("micro_transfers")] MICRO_TRANSFERS, + [Description("unrecognized")] UNRECOGNIZED + } + + public enum VerificationAddOns + { + [Description("customer_verification")] CUSTOMER_VERIFICATION, [Description("unrecognized")] UNRECOGNIZED } public class UsBankAccountVerification { - public virtual UsBankAccountVerificationMethod VerificationMethod { get; protected set; } + public virtual DateTime? CreatedAt { get; protected set; } public virtual DateTime? VerificationDeterminedAt { get; protected set; } public virtual TransactionGatewayRejectionReason? GatewayRejectionReason { get; protected set; } - public virtual string ProcessorResponseCode { get; protected set; } - public virtual string ProcessorResponseText { get; protected set; } - public virtual string MerchantAccountId { get; protected set; } + public virtual UsBankAccount UsBankAccount { get; protected set; } + public virtual UsBankAccountVerificationMethod VerificationMethod { get; protected set; } public virtual UsBankAccountVerificationStatus Status { get; protected set; } + public virtual VerificationAddOns VerificationAddOns { get; protected set; } + public virtual string AdditionalProcessorResponse { get; protected set; } public virtual string Id { get; protected set; } - public virtual UsBankAccount UsBankAccount { get; protected set; } - public virtual DateTime? CreatedAt { get; protected set; } + public virtual string MerchantAccountId { get; protected set; } + public virtual string ProcessorResponseCode { get; protected set; } + public virtual string ProcessorResponseText { get; protected set; } public UsBankAccountVerification(NodeWrapper node) { if (node == null) return; - VerificationMethod = node.GetEnum("verification-method", UsBankAccountVerificationMethod.UNRECOGNIZED); - VerificationDeterminedAt = node.GetDateTime("verification-determined-at"); + AdditionalProcessorResponse = node.GetString("additional-processor-response"); + CreatedAt = node.GetDateTime("created-at"); GatewayRejectionReason = null; + Id = node.GetString("id"); + MerchantAccountId = node.GetString("merchant-account-id"); ProcessorResponseCode = node.GetString("processor-response-code"); ProcessorResponseText = node.GetString("processor-response-text"); - MerchantAccountId = node.GetString("merchant-account-id"); Status = node.GetEnum("status", UsBankAccountVerificationStatus.UNRECOGNIZED); - Id = node.GetString("id"); - UsBankAccount = new UsBankAccount(node.GetNode("us-bank-account")); - CreatedAt = node.GetDateTime("created-at"); + VerificationAddOns = node.GetEnum("verification-add-ons", VerificationAddOns.UNRECOGNIZED); + VerificationDeterminedAt = node.GetDateTime("verification-determined-at"); + VerificationMethod = node.GetEnum("verification-method", UsBankAccountVerificationMethod.UNRECOGNIZED); } [Obsolete("Mock Use Only")] diff --git a/src/Braintree/VenmoProfileData.cs b/src/Braintree/VenmoProfileData.cs index ac168353..b829daac 100644 --- a/src/Braintree/VenmoProfileData.cs +++ b/src/Braintree/VenmoProfileData.cs @@ -4,11 +4,13 @@ namespace Braintree { public class VenmoProfileData { - public virtual string Username { get; protected set; } + public virtual Address BillingAddress { get; protected set; } + public virtual string Email { get; protected set; } public virtual string FirstName { get; protected set; } public virtual string LastName { get; protected set; } public virtual string PhoneNumber { get; protected set; } - public virtual string Email { get; protected set; } + public virtual Address ShippingAddress { get; protected set; } + public virtual string Username { get; protected set; } protected internal VenmoProfileData(NodeWrapper node) { Username = node.GetString("username"); @@ -16,6 +18,16 @@ protected internal VenmoProfileData(NodeWrapper node) { LastName = node.GetString("last-name"); PhoneNumber = node.GetString("phone-number"); Email = node.GetString("email"); + + var billingAddressNode = node.GetNode("billing-address"); + if (billingAddressNode != null) { + BillingAddress = new Address(billingAddressNode); + } + + var shippingAddressNode = node.GetNode("shipping-address"); + if (shippingAddressNode != null) { + ShippingAddress = new Address(shippingAddressNode); + } } } } diff --git a/src/Braintree/WebhookTestingGateway.cs b/src/Braintree/WebhookTestingGateway.cs index 1db34af8..ba9a1c49 100644 --- a/src/Braintree/WebhookTestingGateway.cs +++ b/src/Braintree/WebhookTestingGateway.cs @@ -650,7 +650,21 @@ private static string PaymentMethodCustomerDataUpdatedMetadataSampleXml(string i Node("last-name", "Doe"), Node("phone-number", "1231231234"), Node("email", "john.doe@paypal.com"), - Node("username", "venmo_username") + Node("username", "venmo_username"), + Node("billing-address", + Node("street-address", "billing-street-address"), + Node("extended-address", "billing-extended-address"), + Node("locality", "billing-locality"), + Node("region", "billing-region"), + Node("postal-code", "billing-code") + ), + Node("shipping-address", + Node("street-address", "shipping-street-address"), + Node("extended-address", "shipping-extended-address"), + Node("locality", "shipping-locality"), + Node("region", "shipping-region"), + Node("postal-code", "shipping-code") + ) ) ) ); diff --git a/test/Braintree.Tests.Integration/PaymentMethodNonceIntegrationTest.cs b/test/Braintree.Tests.Integration/PaymentMethodNonceIntegrationTest.cs index 2862c045..51818b25 100644 --- a/test/Braintree.Tests.Integration/PaymentMethodNonceIntegrationTest.cs +++ b/test/Braintree.Tests.Integration/PaymentMethodNonceIntegrationTest.cs @@ -93,6 +93,36 @@ public void Find_ExposesDetailsForCreditCardNonce() Assert.AreEqual(foundNonce.Details.ExpirationYear, (DateTime.Now.Year + 1).ToString()); } + [Test] + public void Find_MetaCheckoutCardNonce() + { + PaymentMethodNonce foundNonce = gateway.PaymentMethodNonce.Find(Nonce.MetaCheckoutCard); + Assert.IsNotNull(foundNonce); + Assert.AreEqual(foundNonce.Nonce, Nonce.MetaCheckoutCard); + Assert.IsNotNull(foundNonce.Details); + Assert.AreEqual(foundNonce.Details.Bin, "401288"); + Assert.AreEqual(foundNonce.Details.CardType, "Visa"); + Assert.AreEqual(foundNonce.Details.LastTwo, "81"); + Assert.AreEqual(foundNonce.Details.LastFour, "1881"); + Assert.AreEqual(foundNonce.Details.ExpirationMonth, "12"); + Assert.AreEqual(foundNonce.Details.ExpirationYear, "2024"); + } + + [Test] + public void Find_MetaCheckoutTokenNonce() + { + PaymentMethodNonce foundNonce = gateway.PaymentMethodNonce.Find(Nonce.MetaCheckoutToken); + Assert.IsNotNull(foundNonce); + Assert.AreEqual(foundNonce.Nonce, Nonce.MetaCheckoutToken); + Assert.IsNotNull(foundNonce.Details); + Assert.AreEqual(foundNonce.Details.Bin, "401288"); + Assert.AreEqual(foundNonce.Details.CardType, "Visa"); + Assert.AreEqual(foundNonce.Details.LastTwo, "81"); + Assert.AreEqual(foundNonce.Details.LastFour, "1881"); + Assert.AreEqual(foundNonce.Details.ExpirationMonth, "12"); + Assert.AreEqual(foundNonce.Details.ExpirationYear, "2024"); + } + [Test] public void Find_ExposesDetailsForSepaDirectDebitNonce() { diff --git a/test/Braintree.Tests.Integration/TransactionIntegrationTest.cs b/test/Braintree.Tests.Integration/TransactionIntegrationTest.cs index 32465de8..ae8e1b05 100644 --- a/test/Braintree.Tests.Integration/TransactionIntegrationTest.cs +++ b/test/Braintree.Tests.Integration/TransactionIntegrationTest.cs @@ -3479,6 +3479,66 @@ public void Sale_WithApplePayNonce() Assert.IsNotNull(result.Target.ApplePayDetails.IssuingBank); } + [Test] + public void Sale_WithMetaCheckoutCardNonce() + { + TransactionRequest request = new TransactionRequest + { + Amount = SandboxValues.TransactionAmount.AUTHORIZE, + PaymentMethodNonce = Nonce.MetaCheckoutCard + }; + Result result = gateway.Transaction.Sale(request); + Assert.IsTrue(result.IsSuccess()); + + Assert.AreEqual(PaymentInstrumentType.META_CHECKOUT_CARD, result.Target.PaymentInstrumentType); + Assert.IsNotNull(result.Target.MetaCheckoutCardDetails); + Assert.IsNotNull(result.Target.MetaCheckoutCardDetails.CardType); + Assert.IsNotNull(result.Target.MetaCheckoutCardDetails.ExpirationMonth); + Assert.IsNotNull(result.Target.MetaCheckoutCardDetails.ExpirationYear); + Assert.IsNotNull(result.Target.MetaCheckoutCardDetails.CardholderName); + Assert.IsNotNull(result.Target.MetaCheckoutCardDetails.LastFour); + Assert.IsNotNull(result.Target.MetaCheckoutCardDetails.ImageUrl); + Assert.IsNotNull(result.Target.MetaCheckoutCardDetails.Bin); + Assert.IsNotNull(result.Target.MetaCheckoutCardDetails.Prepaid); + Assert.IsNotNull(result.Target.MetaCheckoutCardDetails.Healthcare); + Assert.IsNotNull(result.Target.MetaCheckoutCardDetails.Debit); + Assert.IsNotNull(result.Target.MetaCheckoutCardDetails.DurbinRegulated); + Assert.IsNotNull(result.Target.MetaCheckoutCardDetails.Commercial); + Assert.IsNotNull(result.Target.MetaCheckoutCardDetails.Payroll); + Assert.IsNotNull(result.Target.MetaCheckoutCardDetails.ProductId); + } + + [Test] + public void Sale_WithMetaCheckoutTokenNonce() + { + TransactionRequest request = new TransactionRequest + { + Amount = SandboxValues.TransactionAmount.AUTHORIZE, + PaymentMethodNonce = Nonce.MetaCheckoutToken + }; + Result result = gateway.Transaction.Sale(request); + Assert.IsTrue(result.IsSuccess()); + + Assert.AreEqual(PaymentInstrumentType.META_CHECKOUT_TOKEN, result.Target.PaymentInstrumentType); + Assert.IsNotNull(result.Target.MetaCheckoutTokenDetails); + Assert.IsNotNull(result.Target.MetaCheckoutTokenDetails.CardType); + Assert.IsNotNull(result.Target.MetaCheckoutTokenDetails.Cryptogram); + Assert.IsNotNull(result.Target.MetaCheckoutTokenDetails.ECommerceIndicator); + Assert.IsNotNull(result.Target.MetaCheckoutTokenDetails.ExpirationMonth); + Assert.IsNotNull(result.Target.MetaCheckoutTokenDetails.ExpirationYear); + Assert.IsNotNull(result.Target.MetaCheckoutTokenDetails.CardholderName); + Assert.IsNotNull(result.Target.MetaCheckoutTokenDetails.LastFour); + Assert.IsNotNull(result.Target.MetaCheckoutTokenDetails.ImageUrl); + Assert.IsNotNull(result.Target.MetaCheckoutTokenDetails.Bin); + Assert.IsNotNull(result.Target.MetaCheckoutTokenDetails.Prepaid); + Assert.IsNotNull(result.Target.MetaCheckoutTokenDetails.Healthcare); + Assert.IsNotNull(result.Target.MetaCheckoutTokenDetails.Debit); + Assert.IsNotNull(result.Target.MetaCheckoutTokenDetails.DurbinRegulated); + Assert.IsNotNull(result.Target.MetaCheckoutTokenDetails.Commercial); + Assert.IsNotNull(result.Target.MetaCheckoutTokenDetails.Payroll); + Assert.IsNotNull(result.Target.MetaCheckoutTokenDetails.ProductId); + } + [Test] public void Sale_WithApplePayParams() { @@ -5032,6 +5092,8 @@ public void Sale_WithTravelFlightIndustryData_ReturnsSuccessfulResponse() RestrictedTicket = false, ArrivalDate = new DateTime(2018, 1, 1), TicketIssuerAddress = "tkt-issuer-address", + DateOfBirth = "2012-12-12", + CountryCode = "US", Legs = new IndustryDataLegRequest[] { new IndustryDataLegRequest @@ -5162,6 +5224,8 @@ public void SubmitForSettlement_WithTravelFlightIndustryDataCreditCard_ReturnsSu RestrictedTicket = false, ArrivalDate = new DateTime(2018, 1, 1), TicketIssuerAddress = "tkt-issuer-address", + DateOfBirth = "2012-12-12", + CountryCode = "US", Legs = new IndustryDataLegRequest[] { new IndustryDataLegRequest @@ -8484,6 +8548,192 @@ public void SubmitForPartialSettlement_WithAmount() Assert.AreEqual(50.00, result.Target.Amount); } + [Test] + public void SubmitForSettlement_WithTravelFlightIndustryData() + { + var request = new TransactionRequest + { + Amount = SandboxValues.TransactionAmount.AUTHORIZE, + PaymentMethodNonce = Nonce.PayPalOneTimePayment, + Options = new TransactionOptionsRequest + { + SubmitForSettlement = false + } + }; + Transaction transaction = gateway.Transaction.Sale(request).Target; + + request = new TransactionRequest + { + Amount = SandboxValues.TransactionAmount.AUTHORIZE, + Industry = new IndustryRequest + { + IndustryType = TransactionIndustryType.TRAVEL_AND_FLIGHT, + IndustryData = new IndustryDataRequest + { + PassengerFirstName = "John", + PassengerLastName = "Doe", + PassengerMiddleInitial = "M", + PassengerTitle = "Mr.", + IssuedDate = new DateTime(2018, 1, 1), + TravelAgencyName = "Expedia", + TravelAgencyCode = "12345678", + TicketNumber = "ticket-number", + IssuingCarrierCode = "AA", + CustomerCode = "customer-code", + FareAmount = 7000M, + FeeAmount = 1000M, + TaxAmount = 2000M, + RestrictedTicket = false, + ArrivalDate = new DateTime(2018, 1, 1), + TicketIssuerAddress = "tkt-issuer-address", + DateOfBirth = "2012-12-12", + CountryCode = "US", + Legs = new IndustryDataLegRequest[] + { + new IndustryDataLegRequest + { + ConjunctionTicket = "CJ0001", + ExchangeTicket = "ET0001", + CouponNumber = "1", + ServiceClass = "Y", + CarrierCode = "AA", + FareBasisCode = "W", + FlightNumber = "AA100", + DepartureDate = new DateTime(2018, 1, 2), + DepartureAirportCode = "MDW", + DepartureTime = "08:00", + ArrivalAirportCode = "ATX", + ArrivalTime = "10:00", + StopoverPermitted = false, + FareAmount = 3500M, + FeeAmount = 500M, + TaxAmount = 1000M, + EndorsementOrRestrictions = "NOT REFUNDABLE", + }, + new IndustryDataLegRequest + { + ConjunctionTicket = "CJ0002", + ExchangeTicket = "ET0002", + CouponNumber = "1", + ServiceClass = "Y", + CarrierCode = "AA", + FareBasisCode = "W", + FlightNumber = "AA200", + DepartureDate = new DateTime(2018, 1, 3), + DepartureAirportCode = "ATX", + DepartureTime = "12:00", + ArrivalAirportCode = "MDW", + ArrivalTime = "14:00", + StopoverPermitted = false, + FareAmount = 3500M, + FeeAmount = 500M, + TaxAmount = 1000M, + EndorsementOrRestrictions = "NOT REFUNDABLE", + } + } + } + } + }; + + Result result = gateway.Transaction.SubmitForSettlement(transaction.Id, request); + Assert.IsTrue(result.IsSuccess()); + Assert.AreEqual(TransactionStatus.SETTLING, result.Target.Status); + Assert.AreEqual(SandboxValues.TransactionAmount.AUTHORIZE, result.Target.Amount); + } + + [Test] + public void SubmitForPartialSettlement_WithTravelFlightIndustryData() + { + var request = new TransactionRequest + { + Amount = SandboxValues.TransactionAmount.AUTHORIZE, + PaymentMethodNonce = Nonce.PayPalOneTimePayment, + Options = new TransactionOptionsRequest + { + SubmitForSettlement = false + } + }; + Transaction transaction = gateway.Transaction.Sale(request).Target; + + request = new TransactionRequest + { + Amount = decimal.Parse("50.00"), + Industry = new IndustryRequest + { + IndustryType = TransactionIndustryType.TRAVEL_AND_FLIGHT, + IndustryData = new IndustryDataRequest + { + PassengerFirstName = "John", + PassengerLastName = "Doe", + PassengerMiddleInitial = "M", + PassengerTitle = "Mr.", + IssuedDate = new DateTime(2018, 1, 1), + TravelAgencyName = "Expedia", + TravelAgencyCode = "12345678", + TicketNumber = "ticket-number", + IssuingCarrierCode = "AA", + CustomerCode = "customer-code", + FareAmount = 7000M, + FeeAmount = 1000M, + TaxAmount = 2000M, + RestrictedTicket = false, + ArrivalDate = new DateTime(2018, 1, 1), + TicketIssuerAddress = "tkt-issuer-address", + DateOfBirth = "2012-12-12", + CountryCode = "US", + Legs = new IndustryDataLegRequest[] + { + new IndustryDataLegRequest + { + ConjunctionTicket = "CJ0001", + ExchangeTicket = "ET0001", + CouponNumber = "1", + ServiceClass = "Y", + CarrierCode = "AA", + FareBasisCode = "W", + FlightNumber = "AA100", + DepartureDate = new DateTime(2018, 1, 2), + DepartureAirportCode = "MDW", + DepartureTime = "08:00", + ArrivalAirportCode = "ATX", + ArrivalTime = "10:00", + StopoverPermitted = false, + FareAmount = 3500M, + FeeAmount = 500M, + TaxAmount = 1000M, + EndorsementOrRestrictions = "NOT REFUNDABLE", + }, + new IndustryDataLegRequest + { + ConjunctionTicket = "CJ0002", + ExchangeTicket = "ET0002", + CouponNumber = "1", + ServiceClass = "Y", + CarrierCode = "AA", + FareBasisCode = "W", + FlightNumber = "AA200", + DepartureDate = new DateTime(2018, 1, 3), + DepartureAirportCode = "ATX", + DepartureTime = "12:00", + ArrivalAirportCode = "MDW", + ArrivalTime = "14:00", + StopoverPermitted = false, + FareAmount = 3500M, + FeeAmount = 500M, + TaxAmount = 1000M, + EndorsementOrRestrictions = "NOT REFUNDABLE", + } + } + } + } + }; + + Result result = gateway.Transaction.SubmitForPartialSettlement(transaction.Id, request); + Assert.IsTrue(result.IsSuccess()); + Assert.AreEqual(TransactionStatus.SETTLING, result.Target.Status); + Assert.AreEqual(50.00, result.Target.Amount); + } + [Test] public void SubmitForPartialSettlement_WithOrderId() { diff --git a/test/Braintree.Tests.Integration/UsBankAccountVerificationIntegrationTest.cs b/test/Braintree.Tests.Integration/UsBankAccountVerificationIntegrationTest.cs index 8ce5a61d..71966bf5 100644 --- a/test/Braintree.Tests.Integration/UsBankAccountVerificationIntegrationTest.cs +++ b/test/Braintree.Tests.Integration/UsBankAccountVerificationIntegrationTest.cs @@ -1,4 +1,5 @@ using Braintree.TestUtil; +using Braintree.Test; using NUnit.Framework; using System; using System.Threading.Tasks; @@ -190,7 +191,7 @@ public void Create_ReturnsSuccessfulResponse() var request = new PaymentMethodRequest { CustomerId = customer.Target.Id, - PaymentMethodNonce = TestHelper.GenerateValidUsBankAccountNonce(gateway), + PaymentMethodNonce = Nonce.UsBankAccount, Options = new PaymentMethodOptionsRequest { VerificationMerchantAccountId = MerchantAccountIDs.US_BANK_MERCHANT_ACCOUNT_ID, @@ -211,6 +212,78 @@ public void Create_ReturnsSuccessfulResponse() Assert.NotNull(verification.VerificationDeterminedAt); } + [Test] + public void CreateWithAddOns_ReturnsSuccessfulResponse() + { + Result customer = gateway.Customer.Create(new CustomerRequest()); + Assert.IsTrue(customer.IsSuccess()); + + var request = new PaymentMethodRequest + { + CustomerId = customer.Target.Id, + PaymentMethodNonce = Nonce.UsBankAccount, + Options = new PaymentMethodOptionsRequest + { + VerificationMerchantAccountId = MerchantAccountIDs.US_BANK_MERCHANT_ACCOUNT_ID, + UsBankAccountVerificationMethod = UsBankAccountVerificationMethod.NETWORK_CHECK, + VerificationAddOns = VerificationAddOns.CUSTOMER_VERIFICATION + } + }; + + Result result = gateway.PaymentMethod.Create(request); + Assert.IsTrue(result.IsSuccess()); + UsBankAccount usBankAccount = (UsBankAccount) result.Target; + + Assert.AreEqual("0000", usBankAccount.Last4); + Assert.AreEqual("Wells Fargo", usBankAccount.BankName); + Assert.AreEqual("Dan Schulman", usBankAccount.AccountHolderName); + + Assert.IsNotNull(usBankAccount.Token); + UsBankAccountVerification verification = usBankAccount.Verifications[0]; + + Assert.AreEqual(UsBankAccountVerificationMethod.NETWORK_CHECK, verification.VerificationMethod); + Assert.AreEqual(UsBankAccountVerificationStatus.VERIFIED, verification.Status); + Assert.NotNull(verification.Id); + Assert.NotNull(verification.VerificationDeterminedAt); + Assert.AreEqual(verification.ProcessorResponseCode, "1000"); + } + + [Test] + public void Create_ReturnsAdditionalProcessorResponse() + { + Result customer = gateway.Customer.Create(new CustomerRequest()); + Assert.IsTrue(customer.IsSuccess()); + + var request = new PaymentMethodRequest + { + CustomerId = customer.Target.Id, + PaymentMethodNonce = TestHelper.GenerateValidUsBankAccountNonce(gateway, "1000000005"), + Options = new PaymentMethodOptionsRequest + { + VerificationMerchantAccountId = MerchantAccountIDs.US_BANK_MERCHANT_ACCOUNT_ID, + UsBankAccountVerificationMethod = UsBankAccountVerificationMethod.NETWORK_CHECK + } + }; + + Result result = gateway.PaymentMethod.Create(request); + Assert.IsTrue(result.IsSuccess()); + UsBankAccount usBankAccount = (UsBankAccount) result.Target; + + Assert.AreEqual("0005", usBankAccount.Last4); + Assert.AreEqual("JPMORGAN CHASE", usBankAccount.BankName); + Assert.AreEqual("Dan Schulman", usBankAccount.AccountHolderName); + + Assert.IsNotNull(usBankAccount.Token); + UsBankAccountVerification verification = usBankAccount.Verifications[0]; + + Assert.AreEqual(UsBankAccountVerificationMethod.NETWORK_CHECK, verification.VerificationMethod); + Assert.AreEqual(UsBankAccountVerificationStatus.PROCESSOR_DECLINED, verification.Status); + Assert.NotNull(verification.Id); + Assert.NotNull(verification.VerificationDeterminedAt); + Assert.AreEqual(verification.ProcessorResponseCode, "2061"); + Assert.AreEqual(verification.AdditionalProcessorResponse, "Invalid routing number"); + } + [Test] public void Create_HandlesInvalidResponse() { diff --git a/test/Braintree.Tests/IndustryDataRequestTest.cs b/test/Braintree.Tests/IndustryDataRequestTest.cs index ae3d2ee5..78e96963 100644 --- a/test/Braintree.Tests/IndustryDataRequestTest.cs +++ b/test/Braintree.Tests/IndustryDataRequestTest.cs @@ -46,6 +46,8 @@ public void ToXml_IncludesAllProperties() RestrictedTicket = false, ArrivalDate = new DateTime(2018, 1, 1), TicketIssuerAddress = "tkt-issuer-address", + DateOfBirth = "2012-12-12", + CountryCode = "US", Legs = new IndustryDataLegRequest[] { new IndustryDataLegRequest @@ -74,6 +76,8 @@ public void ToXml_IncludesAllProperties() Assert.IsTrue(request.ToXml().Contains("2018-01-01 00:00:00Z")); Assert.IsTrue(request.ToXml().Contains("tkt-issuer-address")); + Assert.IsTrue(request.ToXml().Contains("US")); + Assert.IsTrue(request.ToXml().Contains("2012-12-12")); } } } diff --git a/test/Braintree.Tests/MetaCheckoutCardDetailsTest.cs b/test/Braintree.Tests/MetaCheckoutCardDetailsTest.cs new file mode 100644 index 00000000..bde2498b --- /dev/null +++ b/test/Braintree.Tests/MetaCheckoutCardDetailsTest.cs @@ -0,0 +1,79 @@ +using Braintree.Exceptions; +using Newtonsoft.Json; +using NUnit.Framework; +using System; +using System.Globalization; +using System.Text; +using System.Xml; + +namespace Braintree.Tests +{ + [TestFixture] + public class MetaCheckoutCardDetailsTest + { + private BraintreeGateway gateway; + + [SetUp] + public void Setup() + { + gateway = new BraintreeGateway + { + Environment = Environment.DEVELOPMENT, + MerchantId = "integration_merchant_id", + PublicKey = "integration_public_key", + PrivateKey = "integration_private_key" + }; + } + + [Test] + public void ConstructFromXMLResponse() + { + StringBuilder builder = new StringBuilder(); + builder.Append(""); + builder.Append(""); + builder.Append("a-bin"); + builder.Append("Cardholder"); + builder.Append("Visa"); + builder.Append("11"); + builder.Append("2024"); + builder.Append("US"); + builder.Append("false"); + builder.Append("false"); + builder.Append("1234"); + builder.Append("token1"); + builder.Append("2023-05-05T21:28:37Z"); + builder.Append("2023-05-05T21:28:37Z"); + builder.Append("NO"); + builder.Append("NO"); + builder.Append("NO"); + builder.Append("NO"); + builder.Append("NO"); + builder.Append("a-container-id" ); + builder.Append("1234"); + builder.Append(""); + + XmlDocument doc = new XmlDocument(); + doc.LoadXml(builder.ToString()); + + MetaCheckoutCardDetails details = new MetaCheckoutCardDetails(new NodeWrapper(doc).GetNode("transaction")); + + Assert.AreEqual("a-bin", details.Bin); + Assert.AreEqual("Cardholder", details.CardholderName); + Assert.AreEqual("Visa", details.CardType.GetDescription()); + Assert.AreEqual("11", details.ExpirationMonth); + Assert.AreEqual("2024", details.ExpirationYear); + Assert.AreEqual("us", details.CustomerLocation.GetDescription()); + Assert.AreEqual(false, details.IsExpired); + Assert.AreEqual("1234", details.UniqueNumberIdentifier); + Assert.AreEqual("token1", details.Token); + Assert.AreEqual("No", details.Prepaid.GetDescription()); + Assert.AreEqual("No", details.Payroll.GetDescription()); + Assert.AreEqual("No", details.Commercial.GetDescription()); + Assert.AreEqual("No", details.Healthcare.GetDescription()); + Assert.AreEqual(DateTime.Parse("2023-05-05T21:28:37Z"), details.CreatedAt); + Assert.AreEqual(DateTime.Parse("2023-05-05T21:28:37Z"), details.UpdatedAt); + Assert.AreEqual("a-container-id", details.ContainerId); + Assert.AreEqual("1234", details.LastFour); + } + } +} diff --git a/test/Braintree.Tests/MetaCheckoutCardTest.cs b/test/Braintree.Tests/MetaCheckoutCardTest.cs new file mode 100644 index 00000000..3019a38e --- /dev/null +++ b/test/Braintree.Tests/MetaCheckoutCardTest.cs @@ -0,0 +1,82 @@ +using Braintree.Exceptions; +using Newtonsoft.Json; +using NUnit.Framework; +using System; +using System.Globalization; +using System.Text; +using System.Xml; + +namespace Braintree.Tests +{ + [TestFixture] + public class MetaCheckoutCardTest + { + private BraintreeGateway gateway; + + [SetUp] + public void Setup() + { + gateway = new BraintreeGateway + { + Environment = Environment.DEVELOPMENT, + MerchantId = "integration_merchant_id", + PublicKey = "integration_public_key", + PrivateKey = "integration_private_key" + }; + } + + [Test] + public void ConstructFromXMLResponse() + { + StringBuilder builder = new StringBuilder(); + builder.Append(""); + builder.Append(""); + builder.Append("a-bin"); + builder.Append("Cardholder"); + builder.Append("Visa"); + builder.Append("customer-id"); + builder.Append("11"); + builder.Append("2024"); + builder.Append("US"); + builder.Append("false"); + builder.Append("false"); + builder.Append("1234"); + builder.Append("token1"); + builder.Append("2023-05-05T21:28:37Z"); + builder.Append("2023-05-05T21:28:37Z"); + builder.Append("NO"); + builder.Append("NO"); + builder.Append("NO"); + builder.Append("NO"); + builder.Append("NO"); + builder.Append("a-container-id" ); + builder.Append("1234"); + builder.Append(""); + + XmlDocument doc = new XmlDocument(); + doc.LoadXml(builder.ToString()); + + MetaCheckoutCard card = new MetaCheckoutCard(new NodeWrapper(doc).GetNode("payment-method"), gateway); + + Assert.AreEqual("a-bin", card.Bin); + Assert.AreEqual("Cardholder", card.CardholderName); + Assert.AreEqual("Visa", card.CardType.GetDescription()); + Assert.AreEqual("customer-id", card.CustomerId); + Assert.AreEqual("11", card.ExpirationMonth); + Assert.AreEqual("2024", card.ExpirationYear); + Assert.AreEqual("us", card.CustomerLocation.GetDescription()); + Assert.AreEqual(false, card.IsDefault); + Assert.AreEqual(false, card.IsExpired); + Assert.AreEqual("1234", card.UniqueNumberIdentifier); + Assert.AreEqual("token1", card.Token); + Assert.AreEqual("No", card.Prepaid.GetDescription()); + Assert.AreEqual("No", card.Payroll.GetDescription()); + Assert.AreEqual("No", card.Commercial.GetDescription()); + Assert.AreEqual("No", card.Healthcare.GetDescription()); + Assert.AreEqual(DateTime.Parse("2023-05-05T21:28:37Z"), card.CreatedAt); + Assert.AreEqual(DateTime.Parse("2023-05-05T21:28:37Z"), card.UpdatedAt); + Assert.AreEqual("a-container-id", card.ContainerId); + Assert.AreEqual("1234", card.LastFour); + } + } +} diff --git a/test/Braintree.Tests/MetaCheckoutTokenDetailsTest.cs b/test/Braintree.Tests/MetaCheckoutTokenDetailsTest.cs new file mode 100644 index 00000000..ba0690fa --- /dev/null +++ b/test/Braintree.Tests/MetaCheckoutTokenDetailsTest.cs @@ -0,0 +1,82 @@ +using Braintree.Exceptions; +using Newtonsoft.Json; +using NUnit.Framework; +using System; +using System.Globalization; +using System.Text; +using System.Xml; + +namespace Braintree.Tests +{ + [TestFixture] + public class MetaCheckoutTokenDetailsTest + { + private BraintreeGateway gateway; + + [SetUp] + public void Setup() + { + gateway = new BraintreeGateway + { + Environment = Environment.DEVELOPMENT, + MerchantId = "integration_merchant_id", + PublicKey = "integration_public_key", + PrivateKey = "integration_private_key" + }; + } + + [Test] + public void ConstructFromXMLResponse() + { + StringBuilder builder = new StringBuilder(); + builder.Append(""); + builder.Append(""); + builder.Append("a-bin"); + builder.Append("Cardholder"); + builder.Append("Visa"); + builder.Append("11"); + builder.Append("2024"); + builder.Append("US"); + builder.Append("false"); + builder.Append("1234"); + builder.Append("token1"); + builder.Append("2023-05-05T21:28:37Z"); + builder.Append("2023-05-05T21:28:37Z"); + builder.Append("NO"); + builder.Append("NO"); + builder.Append("NO"); + builder.Append("NO"); + builder.Append("NO"); + builder.Append("a-container-id" ); + builder.Append("1234"); + builder.Append("AlhlvxmN2ZKuAAESNFZ4GoABFA=="); + builder.Append("07"); + builder.Append(""); + + XmlDocument doc = new XmlDocument(); + doc.LoadXml(builder.ToString()); + + MetaCheckoutTokenDetails details = new MetaCheckoutTokenDetails(new NodeWrapper(doc).GetNode("transaction")); + + Assert.AreEqual("a-bin", details.Bin); + Assert.AreEqual("Cardholder", details.CardholderName); + Assert.AreEqual("Visa", details.CardType.GetDescription()); + Assert.AreEqual("11", details.ExpirationMonth); + Assert.AreEqual("2024", details.ExpirationYear); + Assert.AreEqual("us", details.CustomerLocation.GetDescription()); + Assert.AreEqual(false, details.IsExpired); + Assert.AreEqual("1234", details.UniqueNumberIdentifier); + Assert.AreEqual("token1", details.Token); + Assert.AreEqual("No", details.Prepaid.GetDescription()); + Assert.AreEqual("No", details.Payroll.GetDescription()); + Assert.AreEqual("No", details.Commercial.GetDescription()); + Assert.AreEqual("No", details.Healthcare.GetDescription()); + Assert.AreEqual(DateTime.Parse("2023-05-05T21:28:37Z"), details.CreatedAt); + Assert.AreEqual(DateTime.Parse("2023-05-05T21:28:37Z"), details.UpdatedAt); + Assert.AreEqual("a-container-id", details.ContainerId); + Assert.AreEqual("1234", details.LastFour); + Assert.AreEqual("AlhlvxmN2ZKuAAESNFZ4GoABFA==", details.Cryptogram); + Assert.AreEqual("07", details.ECommerceIndicator); + } + } +} diff --git a/test/Braintree.Tests/MetaCheckoutTokenTest.cs b/test/Braintree.Tests/MetaCheckoutTokenTest.cs new file mode 100644 index 00000000..e1149e3d --- /dev/null +++ b/test/Braintree.Tests/MetaCheckoutTokenTest.cs @@ -0,0 +1,86 @@ +using Braintree.Exceptions; +using Newtonsoft.Json; +using NUnit.Framework; +using System; +using System.Globalization; +using System.Text; +using System.Xml; + +namespace Braintree.Tests +{ + [TestFixture] + public class MetaCheckoutTokenTest + { + private BraintreeGateway gateway; + + [SetUp] + public void Setup() + { + gateway = new BraintreeGateway + { + Environment = Environment.DEVELOPMENT, + MerchantId = "integration_merchant_id", + PublicKey = "integration_public_key", + PrivateKey = "integration_private_key" + }; + } + + [Test] + public void ConstructFromXMLResponse() + { + StringBuilder builder = new StringBuilder(); + builder.Append(""); + builder.Append(""); + builder.Append("a-bin"); + builder.Append("Cardholder"); + builder.Append("Visa"); + builder.Append("customer-id"); + builder.Append("11"); + builder.Append("2024"); + builder.Append("US"); + builder.Append("false"); + builder.Append("false"); + builder.Append("1234"); + builder.Append("token1"); + builder.Append("2023-05-05T21:28:37Z"); + builder.Append("2023-05-05T21:28:37Z"); + builder.Append("NO"); + builder.Append("NO"); + builder.Append("NO"); + builder.Append("NO"); + builder.Append("NO"); + builder.Append("a-container-id" ); + builder.Append("1234"); + builder.Append("AlhlvxmN2ZKuAAESNFZ4GoABFA=="); + builder.Append("07"); + builder.Append(""); + + XmlDocument doc = new XmlDocument(); + doc.LoadXml(builder.ToString()); + + MetaCheckoutToken card = new MetaCheckoutToken(new NodeWrapper(doc).GetNode("payment-method"), gateway); + + Assert.AreEqual("a-bin", card.Bin); + Assert.AreEqual("Cardholder", card.CardholderName); + Assert.AreEqual("Visa", card.CardType.GetDescription()); + Assert.AreEqual("customer-id", card.CustomerId); + Assert.AreEqual("11", card.ExpirationMonth); + Assert.AreEqual("2024", card.ExpirationYear); + Assert.AreEqual("us", card.CustomerLocation.GetDescription()); + Assert.AreEqual(false, card.IsDefault); + Assert.AreEqual(false, card.IsExpired); + Assert.AreEqual("1234", card.UniqueNumberIdentifier); + Assert.AreEqual("token1", card.Token); + Assert.AreEqual("No", card.Prepaid.GetDescription()); + Assert.AreEqual("No", card.Payroll.GetDescription()); + Assert.AreEqual("No", card.Commercial.GetDescription()); + Assert.AreEqual("No", card.Healthcare.GetDescription()); + Assert.AreEqual(DateTime.Parse("2023-05-05T21:28:37Z"), card.CreatedAt); + Assert.AreEqual(DateTime.Parse("2023-05-05T21:28:37Z"), card.UpdatedAt); + Assert.AreEqual("a-container-id", card.ContainerId); + Assert.AreEqual("1234", card.LastFour); + Assert.AreEqual("AlhlvxmN2ZKuAAESNFZ4GoABFA==", card.Cryptogram); + Assert.AreEqual("07", card.ECommerceIndicator); + } + } +} diff --git a/test/Braintree.Tests/UsBankAccountVerificationTest.cs b/test/Braintree.Tests/UsBankAccountVerificationTest.cs index 9ed30e7b..6ce68628 100644 --- a/test/Braintree.Tests/UsBankAccountVerificationTest.cs +++ b/test/Braintree.Tests/UsBankAccountVerificationTest.cs @@ -28,9 +28,11 @@ public void ConstructFromResponse() builder.Append(""); builder.Append(""); builder.Append(" "); - builder.Append(" independent_check"); + builder.Append(" network_check"); + builder.Append(" customer_verification"); builder.Append(" processor_declined"); builder.Append(" 2000"); + builder.Append(" Invalid routing number"); builder.Append(" Do Not Honor"); builder.Append(" "); builder.Append(""); @@ -42,10 +44,12 @@ public void ConstructFromResponse() new NodeWrapper(doc).GetNode("//verification") ); - Assert.AreEqual(UsBankAccountVerificationMethod.INDEPENDENT_CHECK, verification.VerificationMethod); + Assert.AreEqual(UsBankAccountVerificationMethod.NETWORK_CHECK, verification.VerificationMethod); + Assert.AreEqual(VerificationAddOns.CUSTOMER_VERIFICATION, verification.VerificationAddOns); Assert.AreEqual(UsBankAccountVerificationStatus.PROCESSOR_DECLINED, verification.Status); Assert.AreEqual("2000", verification.ProcessorResponseCode); Assert.AreEqual("Do Not Honor", verification.ProcessorResponseText); + Assert.AreEqual("Invalid routing number", verification.AdditionalProcessorResponse); } [Test] diff --git a/test/Braintree.Tests/WebhookNotificationTest.cs b/test/Braintree.Tests/WebhookNotificationTest.cs index 8847f7c9..204b0786 100644 --- a/test/Braintree.Tests/WebhookNotificationTest.cs +++ b/test/Braintree.Tests/WebhookNotificationTest.cs @@ -786,6 +786,20 @@ public void SampleNotification_ReturnsAPaymentMethodCustomerDataUpdatedMetadata( Assert.AreEqual("venmo_username", profileData.Username); Assert.AreEqual("1231231234", profileData.PhoneNumber); Assert.AreEqual("john.doe@paypal.com", profileData.Email); + + Assert.NotNull(profileData.BillingAddress); + Assert.AreEqual("billing-street-address", profileData.BillingAddress.StreetAddress); + Assert.AreEqual("billing-extended-address", profileData.BillingAddress.ExtendedAddress); + Assert.AreEqual("billing-locality", profileData.BillingAddress.Locality); + Assert.AreEqual("billing-region", profileData.BillingAddress.Region); + Assert.AreEqual("billing-code", profileData.BillingAddress.PostalCode); + + Assert.NotNull(profileData.ShippingAddress); + Assert.AreEqual("shipping-street-address", profileData.ShippingAddress.StreetAddress); + Assert.AreEqual("shipping-extended-address", profileData.ShippingAddress.ExtendedAddress); + Assert.AreEqual("shipping-locality", profileData.ShippingAddress.Locality); + Assert.AreEqual("shipping-region", profileData.ShippingAddress.Region); + Assert.AreEqual("shipping-code", profileData.ShippingAddress.PostalCode); } } }