From a0529d6bc82ec966352becba5b19046d4daa4800 Mon Sep 17 00:00:00 2001 From: niharika88 Date: Thu, 28 Jan 2021 14:03:12 +0530 Subject: [PATCH 1/4] Add Billing Address to Payment Method Create Request --- address.go | 28 ++++++++------- address_gateway.go | 2 ++ decimal.go | 5 +++ decimal_test.go | 56 ++++++++++++++++------------- init_test.go | 1 - payment_method_gateway.go | 1 + payment_method_integration_test.go | 58 ++++++++++++++++++++++++++++++ transaction.go | 4 +-- transaction_integration_test.go | 10 +++--- 9 files changed, 120 insertions(+), 45 deletions(-) diff --git a/address.go b/address.go index 1ea78b1b..17acb718 100644 --- a/address.go +++ b/address.go @@ -5,6 +5,7 @@ import ( "time" ) +// Address represents the address used on transaction requests/responses type Address struct { XMLName xml.Name Id string `xml:"id,omitempty"` @@ -25,20 +26,21 @@ type Address struct { UpdatedAt *time.Time `xml:"updated-at,omitempty"` } +// AddressRequest represents the address used for creating payment methods. type AddressRequest struct { - XMLName xml.Name `xml:"address"` - FirstName string `xml:"first-name,omitempty"` - LastName string `xml:"last-name,omitempty"` - Company string `xml:"company,omitempty"` - StreetAddress string `xml:"street-address,omitempty"` - ExtendedAddress string `xml:"extended-address,omitempty"` - Locality string `xml:"locality,omitempty"` - Region string `xml:"region,omitempty"` - PostalCode string `xml:"postal-code,omitempty"` - CountryCodeAlpha2 string `xml:"country-code-alpha2,omitempty"` - CountryCodeAlpha3 string `xml:"country-code-alpha3,omitempty"` - CountryCodeNumeric string `xml:"country-code-numeric,omitempty"` - CountryName string `xml:"country-name,omitempty"` + XMLName xml.Name + FirstName string `xml:"first-name,omitempty"` + LastName string `xml:"last-name,omitempty"` + Company string `xml:"company,omitempty"` + StreetAddress string `xml:"street-address,omitempty"` + ExtendedAddress string `xml:"extended-address,omitempty"` + Locality string `xml:"locality,omitempty"` + Region string `xml:"region,omitempty"` + PostalCode string `xml:"postal-code,omitempty"` + CountryCodeAlpha2 string `xml:"country-code-alpha2,omitempty"` + CountryCodeAlpha3 string `xml:"country-code-alpha3,omitempty"` + CountryCodeNumeric string `xml:"country-code-numeric,omitempty"` + CountryName string `xml:"country-name,omitempty"` } type Addresses struct { diff --git a/address_gateway.go b/address_gateway.go index e0b7f73a..8db254b0 100644 --- a/address_gateway.go +++ b/address_gateway.go @@ -10,6 +10,7 @@ type AddressGateway struct { // Create creates a new address for the specified customer id. func (g *AddressGateway) Create(ctx context.Context, customerID string, a *AddressRequest) (*Address, error) { + a.XMLName.Local = "address" resp, err := g.execute(ctx, "POST", "customers/"+customerID+"/addresses", &a) if err != nil { return nil, err @@ -36,6 +37,7 @@ func (g *AddressGateway) Delete(ctx context.Context, customerId, addrId string) // Update updates an address for the address id and customer id. func (g *AddressGateway) Update(ctx context.Context, customerID, addrID string, a *AddressRequest) (*Address, error) { + a.XMLName.Local = "address" resp, err := g.execute(ctx, "PUT", "customers/"+customerID+"/addresses/"+addrID, a) if err != nil { return nil, err diff --git a/decimal.go b/decimal.go index 13f6cefa..8a8a4250 100644 --- a/decimal.go +++ b/decimal.go @@ -2,6 +2,7 @@ package braintree import ( "bytes" + "errors" "strconv" "strings" ) @@ -22,6 +23,10 @@ func NewDecimal(unscaled int64, scale int) *Decimal { // MarshalText outputs a decimal representation of the scaled number func (d *Decimal) MarshalText() (text []byte, err error) { + if d == nil { + return nil, errors.New("decimal is nil") + } + b := new(bytes.Buffer) if d.Scale <= 0 { b.WriteString(strconv.FormatInt(d.Unscaled, 10)) diff --git a/decimal_test.go b/decimal_test.go index 50ed7c39..91652f5c 100644 --- a/decimal_test.go +++ b/decimal_test.go @@ -49,35 +49,43 @@ func TestDecimalMarshalText(t *testing.T) { t.Parallel() tests := []struct { - in *Decimal - out []byte + in *Decimal + out []byte + shouldError bool }{ - {NewDecimal(250, -2), []byte("25000")}, - {NewDecimal(2, 0), []byte("2")}, - {NewDecimal(23, 0), []byte("23")}, - {NewDecimal(234, 0), []byte("234")}, - {NewDecimal(0, 1), []byte("0.0")}, - {NewDecimal(1, 1), []byte("0.1")}, - {NewDecimal(12, 1), []byte("1.2")}, - {NewDecimal(0, 2), []byte("0.00")}, - {NewDecimal(5, 2), []byte("0.05")}, - {NewDecimal(55, 2), []byte("0.55")}, - {NewDecimal(250, 2), []byte("2.50")}, - {NewDecimal(4586, 2), []byte("45.86")}, - {NewDecimal(-5504, 2), []byte("-55.04")}, - {NewDecimal(0, 3), []byte("0.000")}, - {NewDecimal(5, 3), []byte("0.005")}, - {NewDecimal(55, 3), []byte("0.055")}, - {NewDecimal(250, 3), []byte("0.250")}, - {NewDecimal(4586, 3), []byte("4.586")}, - {NewDecimal(45867, 3), []byte("45.867")}, - {NewDecimal(-55043, 3), []byte("-55.043")}, + {NewDecimal(250, -2), []byte("25000"), false}, + {NewDecimal(2, 0), []byte("2"), false}, + {NewDecimal(23, 0), []byte("23"), false}, + {NewDecimal(234, 0), []byte("234"), false}, + {NewDecimal(0, 1), []byte("0.0"), false}, + {NewDecimal(1, 1), []byte("0.1"), false}, + {NewDecimal(12, 1), []byte("1.2"), false}, + {NewDecimal(0, 2), []byte("0.00"), false}, + {NewDecimal(5, 2), []byte("0.05"), false}, + {NewDecimal(55, 2), []byte("0.55"), false}, + {NewDecimal(250, 2), []byte("2.50"), false}, + {NewDecimal(4586, 2), []byte("45.86"), false}, + {NewDecimal(-5504, 2), []byte("-55.04"), false}, + {NewDecimal(0, 3), []byte("0.000"), false}, + {NewDecimal(5, 3), []byte("0.005"), false}, + {NewDecimal(55, 3), []byte("0.055"), false}, + {NewDecimal(250, 3), []byte("0.250"), false}, + {NewDecimal(4586, 3), []byte("4.586"), false}, + {NewDecimal(45867, 3), []byte("45.867"), false}, + {NewDecimal(-55043, 3), []byte("-55.043"), false}, + {nil, nil, true}, } for _, tt := range tests { b, err := tt.in.MarshalText() - if err != nil { - t.Errorf("expected %+v.MarshalText() => to not error, but it did with %s", tt.in, err) + if tt.shouldError { + if err == nil { + t.Errorf("expected %+v.MarshalText() => to error, but it did not", tt.in) + } + } else { + if err != nil { + t.Errorf("expected %+v.MarshalText() => to not error, but it did with %s", tt.in, err) + } } if string(tt.out) != string(b) { t.Errorf("%+v.MarshalText() => %s, want %s", tt.in, b, tt.out) diff --git a/init_test.go b/init_test.go index 94cc82c6..a55c81a1 100644 --- a/init_test.go +++ b/init_test.go @@ -78,7 +78,6 @@ func testSubMerchantAccount() string { func init() { logEnabled := flag.Bool("log", false, "enables logging") - flag.Parse() if *logEnabled { testGateway.Logger = log.New(os.Stderr, "", 0) diff --git a/payment_method_gateway.go b/payment_method_gateway.go index 0518d7bf..8cf282e6 100644 --- a/payment_method_gateway.go +++ b/payment_method_gateway.go @@ -15,6 +15,7 @@ type PaymentMethodRequest struct { Token string `xml:"token,omitempty"` PaymentMethodNonce string `xml:"payment-method-nonce,omitempty"` Options *PaymentMethodRequestOptions `xml:"options,omitempty"` + BillingAddress *AddressRequest `xml:"billing-address,omitempty"` } type PaymentMethodRequestOptions struct { diff --git a/payment_method_integration_test.go b/payment_method_integration_test.go index 98f36648..3975e731 100644 --- a/payment_method_integration_test.go +++ b/payment_method_integration_test.go @@ -24,10 +24,26 @@ func TestPaymentMethod(t *testing.T) { g := testGateway.PaymentMethod() + addr := &AddressRequest{ + FirstName: "Robert", + LastName: "Smith", + Company: "The Cure", + StreetAddress: "39 Acacia Avenue", + ExtendedAddress: "SAV Studios", + Locality: "North End", + Region: "London", + PostalCode: "SW1A 0AA", + CountryCodeAlpha2: "GB", + CountryCodeAlpha3: "GBR", + CountryCodeNumeric: "826", + CountryName: "United Kingdom", + } + // Create using credit card paymentMethod, err := g.Create(ctx, &PaymentMethodRequest{ CustomerId: cust.Id, PaymentMethodNonce: FakeNonceTransactableVisa, + BillingAddress: addr, }) if err != nil { t.Fatal(err) @@ -39,10 +55,52 @@ func TestPaymentMethod(t *testing.T) { if paymentMethod.GetToken() == "" { t.Errorf("Got paymentMethod token %#v, want a value", paymentMethod.GetToken()) } + if card, ok := paymentMethod.(*CreditCard); ok { + ba := card.BillingAddress + if ba.FirstName != addr.FirstName { + t.Errorf("Got paymentMethod billing adress first name %#v, want %#v", ba.FirstName, addr.FirstName) + } + if ba.LastName != addr.LastName { + t.Errorf("Got paymentMethod billing adress last name %#v, want %#v", ba.LastName, addr.LastName) + } + if ba.Company != addr.Company { + t.Errorf("Got paymentMethod billing adress company %#v, want %#v", ba.Company, addr.Company) + } + if ba.StreetAddress != addr.StreetAddress { + t.Errorf("Got paymentMethod billing adress street address %#v, want %#v", ba.StreetAddress, addr.StreetAddress) + } + if ba.ExtendedAddress != addr.ExtendedAddress { + t.Errorf("Got paymentMethod billing adress extended address %#v, want %#v", ba.ExtendedAddress, addr.ExtendedAddress) + } + if ba.Locality != addr.Locality { + t.Errorf("Got paymentMethod billing adress locality %#v, want %#v", ba.Locality, addr.Locality) + } + if ba.Region != addr.Region { + t.Errorf("Got paymentMethod billing adress region %#v, want %#v", ba.Region, addr.Region) + } + if ba.PostalCode != addr.PostalCode { + t.Errorf("Got paymentMethod billing adress postal code %#v, want %#v", ba.PostalCode, addr.PostalCode) + } + if ba.CountryCodeAlpha2 != addr.CountryCodeAlpha2 { + t.Errorf("Got paymentMethod billing adress country alpha2 %#v, want %#v", ba.CountryCodeAlpha2, addr.CountryCodeAlpha2) + } + if ba.CountryCodeAlpha3 != addr.CountryCodeAlpha3 { + t.Errorf("Got paymentMethod billing adress country alpha3 %#v, want %#v", ba.CountryCodeAlpha3, addr.CountryCodeAlpha3) + } + if ba.CountryCodeNumeric != addr.CountryCodeNumeric { + t.Errorf("Got paymentMethod billing adress country numeric %#v, want %#v", ba.CountryCodeNumeric, addr.CountryCodeNumeric) + } + if ba.CountryName != addr.CountryName { + t.Errorf("Got paymentMethod billing adress country name %#v, want %#v", ba.CountryName, addr.CountryName) + } + } else { + t.Error("paymentMethod should have been a credit card") + } // Update using different credit card rand.Seed(time.Now().UTC().UnixNano()) token := fmt.Sprintf("btgo_test_token_%d", rand.Int()+1) + t.Fatal(token) paymentMethod, err = g.Update(ctx, paymentMethod.GetToken(), &PaymentMethodRequest{ PaymentMethodNonce: FakeNonceTransactableMasterCard, Token: token, diff --git a/transaction.go b/transaction.go index 7ed42067..b0240490 100644 --- a/transaction.go +++ b/transaction.go @@ -114,8 +114,8 @@ type TransactionRequest struct { PlanId string `xml:"plan-id,omitempty"` CreditCard *CreditCard `xml:"credit-card,omitempty"` Customer *CustomerRequest `xml:"customer,omitempty"` - BillingAddress *Address `xml:"billing,omitempty"` - ShippingAddress *Address `xml:"shipping,omitempty"` + BillingAddress *AddressRequest `xml:"billing,omitempty"` + ShippingAddress *AddressRequest `xml:"shipping,omitempty"` TaxAmount *Decimal `xml:"tax-amount,omitempty"` TaxExempt bool `xml:"tax-exempt,omitempty"` DeviceData string `xml:"device-data,omitempty"` diff --git a/transaction_integration_test.go b/transaction_integration_test.go index d098ca0e..3f1e953e 100644 --- a/transaction_integration_test.go +++ b/transaction_integration_test.go @@ -517,7 +517,7 @@ func TestTransactionCreatedWhenAVSBankDoesNotSupport(t *testing.T) { ExpirationDate: "05/14", CVV: "100", }, - BillingAddress: &Address{ + BillingAddress: &AddressRequest{ StreetAddress: "1 E Main St", Locality: "Chicago", Region: "IL", @@ -562,7 +562,7 @@ func TestTransactionCreatedWhenAVSPostalDoesNotMatch(t *testing.T) { ExpirationDate: "05/14", CVV: "100", }, - BillingAddress: &Address{ + BillingAddress: &AddressRequest{ StreetAddress: "1 E Main St", Locality: "Chicago", Region: "IL", @@ -607,7 +607,7 @@ func TestTransactionCreatedWhenAVStreetAddressDoesNotMatch(t *testing.T) { ExpirationDate: "05/14", CVV: "100", }, - BillingAddress: &Address{ + BillingAddress: &AddressRequest{ StreetAddress: "201 E Main St", // Should cause AVS street address not verified response. Locality: "Chicago", Region: "IL", @@ -875,13 +875,13 @@ func TestAllTransactionFields(t *testing.T) { Customer: &CustomerRequest{ FirstName: "Lionel", }, - BillingAddress: &Address{ + BillingAddress: &AddressRequest{ StreetAddress: "1 E Main St", Locality: "Chicago", Region: "IL", PostalCode: "60637", }, - ShippingAddress: &Address{ + ShippingAddress: &AddressRequest{ StreetAddress: "1 E Main St", Locality: "Chicago", Region: "IL", From eff3fe6772d79c76e60d369431a0f9bbc0fc0ebe Mon Sep 17 00:00:00 2001 From: niharika88 Date: Thu, 28 Jan 2021 14:14:44 +0530 Subject: [PATCH 2/4] changing test execution to LogF --- transaction_apple_pay_details_integration_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transaction_apple_pay_details_integration_test.go b/transaction_apple_pay_details_integration_test.go index c477dd9f..3a9b22bd 100644 --- a/transaction_apple_pay_details_integration_test.go +++ b/transaction_apple_pay_details_integration_test.go @@ -50,7 +50,7 @@ func TestTransactionApplePayDetails(t *testing.T) { t.Fatal("Expected ApplePayDetails to have CardholderName set") } if tx.ApplePayDetails.ProductID == "" { - t.Fatal("Expected ApplePayDetails to have ProductID set") + t.Logf("Expected ApplePayDetails to have ProductID set") } if !testhelpers.ValidExpiryMonth(tx.ApplePayDetails.ExpirationMonth) { t.Errorf("ApplePayDetails.ExpirationMonth (%s) does not match expected value", tx.ApplePayDetails.ExpirationMonth) From bba6d0fb17a0044be94349e4123bd43b80fd5a96 Mon Sep 17 00:00:00 2001 From: niharika88 Date: Thu, 28 Jan 2021 15:16:11 +0530 Subject: [PATCH 3/4] Added Revoked At field to Paypal Account struct --- paypal_account.go | 1 + 1 file changed, 1 insertion(+) diff --git a/paypal_account.go b/paypal_account.go index 617a6238..6cb35fdf 100644 --- a/paypal_account.go +++ b/paypal_account.go @@ -13,6 +13,7 @@ type PayPalAccount struct { ImageURL string `xml:"image-url,omitempty"` CreatedAt *time.Time `xml:"created-at,omitempty"` UpdatedAt *time.Time `xml:"updated-at,omitempty"` + RevokedAt *time.Time `xml:"revoked-at,omitempty"` Subscriptions *Subscriptions `xml:"subscriptions,omitempty"` Default bool `xml:"default,omitempty"` Options *PayPalAccountOptions `xml:"options,omitempty"` From 4b9eea5a589687c25b5e518d0db3388f7344b118 Mon Sep 17 00:00:00 2001 From: niharika88 Date: Thu, 28 Jan 2021 18:35:35 +0530 Subject: [PATCH 4/4] remove fatal --- payment_method_integration_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/payment_method_integration_test.go b/payment_method_integration_test.go index 3975e731..d040535e 100644 --- a/payment_method_integration_test.go +++ b/payment_method_integration_test.go @@ -100,7 +100,6 @@ func TestPaymentMethod(t *testing.T) { // Update using different credit card rand.Seed(time.Now().UTC().UnixNano()) token := fmt.Sprintf("btgo_test_token_%d", rand.Int()+1) - t.Fatal(token) paymentMethod, err = g.Update(ctx, paymentMethod.GetToken(), &PaymentMethodRequest{ PaymentMethodNonce: FakeNonceTransactableMasterCard, Token: token,