Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FINCC-3466] Add Billing Address to Payment Method Create Request #1

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .githooks/prepare-commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/bin/sh

# This hook adds the JIRA ticket ID from branch name to every commit.

COMMIT_MSG_FILE=$1
COMMIT_SOURCE=$2
SHA1=$3

/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"

case "$COMMIT_SOURCE,$SHA1" in
,|template,)
/usr/bin/perl -i.bak -pe '
print "\n" . `git diff --cached --name-status -r`
if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
*) ;;
esac

# get current branch
branchName=`git rev-parse --abbrev-ref HEAD`
branchName_uc=$(echo $branchName | tr '[:lower:]' '[:upper:]')

# search JIRA issue id in a pattern such a "feature/ABC-123-description"
jiraId=$(echo $branchName_uc | /usr/bin/perl -ne '/[^\/]*\/([a-zA-Z]+-[0-9]+)/ && print $1')

# only prepare commit message if pattern matched and jiraId was found
if [ -n "$jiraId" ]; then
matches=$(head -n1 "$COMMIT_MSG_FILE" | grep -c "\[$jiraId\]")

# only add the jira ticket, if it is not already there.
if [ "$matches" = "0" ]; then # textual match, because numeric "error string" -eq 0 is true

sed -i.bak -e "1s/^/\[$jiraId\] /" "$COMMIT_MSG_FILE"
fi
fi
14 changes: 14 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
### Ticket
<!-- Ticket, issue or anything else that 1. describes the feature and 2. proves its need. -->

### Description
<!-- You can 1. describe what this pull request implements, 2. give an overview of the proposed solution, 3. add any further comments you might find important, such as why something is missing; whether there are dependencies for this to be merged. Feel free also to add demos (screenshots, videos) if you find that useful. -->

### Checklist
<!-- Tick with "x" the boxes that apply. You can also fill these out after creating the PR. -->
* [ ] I've read the [contribution guidelines](CONTRIBUTING.md)
saopayne marked this conversation as resolved.
Show resolved Hide resolved
* [ ] I've added Unit Tests if necessary.
* [ ] I've checked whether additional documentation is needed.
* [ ] I've ensured any personally identifying information is handled with the necessary care.
* [ ] I've checked if my implementation doesn't break other features.

26 changes: 26 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# How to Contribute

## Testing

The project is covered by a suite of unit tests.

## Submitting Changes

Please open a GitHub PR with a clear list of what you have done.
Please follow golang coding conventions.

Always write a clear description for the PR and mind the quality of your commits (small, descriptive and ordered commits).

#### Flow of a PR

- Contributors open a PR
- PR is reviewed, and maintainers give their +1
- Contributors merge the PR

**Big PRs will be rejected** Having multiple changes in the PR's description is a high indication that it should be broken into smaller PRs. (e.g This PR does X and Y -> PR for X and PR for Y).

## Deploying Your Changes

- **Do not** merge without our code review.
- Make sure your changes do not cause any new errors.

8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
.PHONY: hooks unit

SHELL:=/bin/bash

hooks: .git/hooks/prepare-commit-msg

.git/hooks/prepare-commit-msg: .githooks/prepare-commit-msg
mkdir -p .git/hooks
cp $< $@

test:
go test -parallel 15 -tags='unit integration' ./...

Expand Down
28 changes: 15 additions & 13 deletions address.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand All @@ -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
saopayne marked this conversation as resolved.
Show resolved Hide resolved
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 {
Expand Down
2 changes: 2 additions & 0 deletions address_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
5 changes: 5 additions & 0 deletions decimal.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package braintree

import (
"bytes"
"errors"
"strconv"
"strings"
)
Expand All @@ -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))
Expand Down
58 changes: 34 additions & 24 deletions decimal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,36 +49,46 @@ 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)
}
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
module github.com/braintree-go/braintree-go

go 1.14
1 change: 0 additions & 1 deletion init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ func testSubMerchantAccount() string {

func init() {
logEnabled := flag.Bool("log", false, "enables logging")
flag.Parse()
saopayne marked this conversation as resolved.
Show resolved Hide resolved

if *logEnabled {
testGateway.Logger = log.New(os.Stderr, "", 0)
Expand Down
1 change: 1 addition & 0 deletions payment_method_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
59 changes: 59 additions & 0 deletions payment_method_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,25 @@ func TestPaymentMethod(t *testing.T) {
g := testGateway.PaymentMethod()

// Create using credit card
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",
}

paymentMethod, err := g.Create(ctx, &PaymentMethodRequest{
CustomerId: cust.Id,
PaymentMethodNonce: FakeNonceTransactableVisa,
BillingAddress: addr,
})
if err != nil {
t.Fatal(err)
Expand All @@ -40,9 +56,52 @@ func TestPaymentMethod(t *testing.T) {
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)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why always fail here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was added during testing locally for this file. Will remove shortly.

paymentMethod, err = g.Update(ctx, paymentMethod.GetToken(), &PaymentMethodRequest{
PaymentMethodNonce: FakeNonceTransactableMasterCard,
Token: token,
Expand Down
4 changes: 2 additions & 2 deletions transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down
10 changes: 5 additions & 5 deletions transaction_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down