Skip to content

Commit

Permalink
Added CustomerAddressService (bold-commerce#26)
Browse files Browse the repository at this point in the history
- CRUD for Customer Addresses without having to go through
CustomerService
  • Loading branch information
gordcurrie authored and andrewhoff committed Oct 26, 2018
1 parent 949a2dc commit e714274
Show file tree
Hide file tree
Showing 5 changed files with 300 additions and 0 deletions.
70 changes: 70 additions & 0 deletions customer_address.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
package goshopify

import "fmt"

const customerAddressResourceName = "customer-addresses"

// CustomerAddressService is an interface for interfacing with the customer address endpoints
// of the Shopify API.
// See: https://help.shopify.com/en/api/reference/customers/customer_address
type CustomerAddressService interface {
List(int, interface{}) ([]CustomerAddress, error)
Get(int, int, interface{}) (*CustomerAddress, error)
Create(int, CustomerAddress) (*CustomerAddress, error)
Update(int, CustomerAddress) (*CustomerAddress, error)
Delete(int, int) error
}

// CustomerAddressServiceOp handles communication with the customer address related methods of
// the Shopify API.
type CustomerAddressServiceOp struct {
client *Client
}

// CustomerAddress represents a Shopify customer address
type CustomerAddress struct {
ID int `json:"id,omitempty"`
Expand All @@ -20,3 +41,52 @@ type CustomerAddress struct {
CountryName string `json:"country_name"`
Default bool `json:"default"`
}

// CustomerAddressResoruce represents the result from the addresses/X.json endpoint
type CustomerAddressResource struct {
Address *CustomerAddress `json:"customer_address"`
}

// CustomerAddressResoruce represents the result from the customers/X/addresses.json endpoint
type CustomerAddressesResource struct {
Addresses []CustomerAddress `json:"addresses"`
}

// List addresses
func (s *CustomerAddressServiceOp) List(customerID int, options interface{}) ([]CustomerAddress, error) {
path := fmt.Sprintf("%s/%d/addresses.json", customersBasePath, customerID)
resource := new(CustomerAddressesResource)
err := s.client.Get(path, resource, options)
return resource.Addresses, err
}

// Get address
func (s *CustomerAddressServiceOp) Get(customerID, addressID int, options interface{}) (*CustomerAddress, error) {
path := fmt.Sprintf("%s/%d/addresses/%d.json", customersBasePath, customerID, addressID)
resource := new(CustomerAddressResource)
err := s.client.Get(path, resource, options)
return resource.Address, err
}

// Create a new address for given customer
func (s *CustomerAddressServiceOp) Create(customerID int, address CustomerAddress) (*CustomerAddress, error) {
path := fmt.Sprintf("%s/%d/addresses.json", customersBasePath, customerID)
wrappedData := CustomerAddressResource{Address: &address}
resource := new(CustomerAddressResource)
err := s.client.Post(path, wrappedData, resource)
return resource.Address, err
}

// Create a new address for given customer
func (s *CustomerAddressServiceOp) Update(customerID int, address CustomerAddress) (*CustomerAddress, error) {
path := fmt.Sprintf("%s/%d/addresses/%d.json", customersBasePath, customerID, address.ID)
wrappedData := CustomerAddressResource{Address: &address}
resource := new(CustomerAddressResource)
err := s.client.Put(path, wrappedData, resource)
return resource.Address, err
}

// Delete an existing address
func (s *CustomerAddressServiceOp) Delete(customerID, addressID int) error {
return s.client.Delete(fmt.Sprintf("%s/%d/addresses/%d.json", customersBasePath, customerID, addressID))
}
165 changes: 165 additions & 0 deletions customer_address_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package goshopify

import (
"testing"

httpmock "gopkg.in/jarcoal/httpmock.v1"
)

func verifyAddress(t *testing.T, address CustomerAddress) {
expectedID := 1
if address.ID != expectedID {
t.Errorf("CustomerAddress.ID returned %+v, expected %+v", address.ID, expectedID)
}

expectedCustomerID := 1
if address.CustomerID != expectedCustomerID {
t.Errorf("CustomerAddress.CustomerID returned %+v, expected %+v", address.CustomerID, expectedCustomerID)
}

expectedFirstName := "Test"
if address.FirstName != expectedFirstName {
t.Errorf("CustomerAddress.FirstName returned %+v, expected %+v", address.FirstName, expectedFirstName)
}

expectedLastName := "Citizen"
if address.LastName != expectedLastName {
t.Errorf("CustomerAddress.LastName returned %+v, expected %+v", address.LastName, expectedLastName)
}

expectedCompany := "TestCo"
if address.Company != expectedCompany {
t.Errorf("CustomerAddress.Company returned %+v, expected %+v", address.Company, expectedCompany)
}

expectedAddress1 := "1 Smith St"
if address.Address1 != expectedAddress1 {
t.Errorf("CustomerAddress.Address1 returned %+v, expected %+v", address.Address1, expectedAddress1)
}

expectedAddress2 := ""
if address.Address2 != expectedAddress2 {
t.Errorf("CustomerAddress.Address2 returned %+v, expected %+v", address.Address2, expectedAddress2)
}

expectedCity := "BRISBANE"
if address.City != expectedCity {
t.Errorf("CustomerAddress.City returned %+v, expected %+v", address.City, expectedCity)
}

expectedProvince := "Queensland"
if address.Province != expectedProvince {
t.Errorf("CustomerAddress.Province returned %+v, expected %+v", address.Province, expectedProvince)
}

expectedCountry := "Australia"
if address.Country != expectedCountry {
t.Errorf("CustomerAddress.Country returned %+v, expected %+v", address.Country, expectedCountry)
}

expectedZip := "4000"
if address.Zip != expectedZip {
t.Errorf("CustomerAddress.Zip returned %+v, expected %+v", address.Zip, expectedZip)
}

expectedPhone := "1111 111 111"
if address.Phone != expectedPhone {
t.Errorf("CustomerAddress.Phone returned %+v, expected %+v", address.Phone, expectedPhone)
}

expectedName := "Test Citizen"
if address.Name != expectedName {
t.Errorf("CustomerAddress.Name returned %+v, expected %+v", address.Name, expectedName)
}

expectedProvinceCode := "QLD"
if address.ProvinceCode != expectedProvinceCode {
t.Errorf("CustomerAddress.ProvinceCode returned %+v, expected %+v", address.ProvinceCode, expectedProvinceCode)
}

expectedCountryCode := "AU"
if address.CountryCode != expectedCountryCode {
t.Errorf("CustomerAddress.CountryCode returned %+v, expected %+v", address.CountryCode, expectedCountryCode)
}

expectedCountryName := "Australia"
if address.CountryName != expectedCountryName {
t.Errorf("CustomerAddress.CountryName returned %+v, expected %+v", address.CountryName, expectedCountryName)
}

expectedDefault := true
if address.Default != expectedDefault {
t.Errorf("CustomerAddress.Default returned %+v, expected %+v", address.Default, expectedDefault)
}
}

func TestList(t *testing.T) {
setup()
defer teardown()

httpmock.RegisterResponder("GET", "https://fooshop.myshopify.com/admin/customers/1/addresses.json", httpmock.NewBytesResponder(200, loadFixture("customer_addresses.json")))

addresses, err := client.CustomerAddress.List(1, nil)
if err != nil {
t.Errorf("CustomerAddress.List returned error: %v", err)
}

if len(addresses) != 2 {
t.Errorf("CustomerAddress.List got %v addresses, expected 2", len(addresses))
}
verifyAddress(t, addresses[0])
}

func TestGet(t *testing.T) {
setup()
defer teardown()

httpmock.RegisterResponder("GET", "https://fooshop.myshopify.com/admin/customers/1/addresses/1.json", httpmock.NewBytesResponder(200, loadFixture("customer_address.json")))

address, err := client.CustomerAddress.Get(1, 1, nil)
if err != nil {
t.Errorf("CustomerAddress.Get returned error: %v", err)
}

verifyAddress(t, *address)
}

func TestCreate(t *testing.T) {
setup()
defer teardown()

httpmock.RegisterResponder("POST", "https://fooshop.myshopify.com/admin/customers/1/addresses.json", httpmock.NewBytesResponder(200, loadFixture("customer_address.json")))

address, err := client.CustomerAddress.Create(1, CustomerAddress{})
if err != nil {
t.Errorf("CustomerAddress.Create returned error: %v", err)
}

verifyAddress(t, *address)
}

func TestUpdate(t *testing.T) {
setup()
defer teardown()

httpmock.RegisterResponder("PUT", "https://fooshop.myshopify.com/admin/customers/1/addresses/1.json", httpmock.NewBytesResponder(200, loadFixture("customer_address.json")))

address, err := client.CustomerAddress.Update(1, CustomerAddress{ID: 1})
if err != nil {
t.Errorf("CustomerAddress.Update returned error: %v", err)
}

verifyAddress(t, *address)
}

func TestDelete(t *testing.T) {
setup()
defer teardown()

httpmock.RegisterResponder("DELETE", "https://fooshop.myshopify.com/admin/customers/1/addresses/1.json", httpmock.NewStringResponder(200, "{}"))

err := client.CustomerAddress.Delete(1, 1)
if err != nil {
t.Errorf("CustomerAddress.Update returned error: %v", err)
}
}
21 changes: 21 additions & 0 deletions fixtures/customer_address.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"customer_address": {
"address1": "1 Smith St",
"address2": null,
"city": "BRISBANE",
"company": "TestCo",
"country": "Australia",
"country_code": "AU",
"country_name": "Australia",
"customer_id": 1,
"default": true,
"first_name": "Test",
"id": 1,
"last_name": "Citizen",
"name": "Test Citizen",
"phone": "1111 111 111",
"province": "Queensland",
"province_code": "QLD",
"zip": "4000"
}
}
42 changes: 42 additions & 0 deletions fixtures/customer_addresses.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"addresses": [
{
"address1": "1 Smith St",
"address2": null,
"city": "BRISBANE",
"company": "TestCo",
"country": "Australia",
"country_code": "AU",
"country_name": "Australia",
"customer_id": 1,
"default": true,
"first_name": "Test",
"id": 1,
"last_name": "Citizen",
"name": "Test Citizen",
"phone": "1111 111 111",
"province": "Queensland",
"province_code": "QLD",
"zip": "4000"
},
{
"address1": "2 Smith St",
"address2": null,
"city": "BRISBANE",
"company": null,
"country": "Australia",
"country_code": "AU",
"country_name": "Australia",
"customer_id": 1,
"default": true,
"first_name": "Test",
"id": 2,
"last_name": "Citizen",
"name": "Test Citizen",
"phone": "2222 222 222",
"province": "Queensland",
"province_code": "QLD",
"zip": "4000"
}
]
}
2 changes: 2 additions & 0 deletions goshopify.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ type Client struct {
CustomCollection CustomCollectionService
SmartCollection SmartCollectionService
Customer CustomerService
CustomerAddress CustomerAddressService
Order OrderService
Shop ShopService
Webhook WebhookService
Expand Down Expand Up @@ -187,6 +188,7 @@ func NewClient(app App, shopName, token string) *Client {
c.CustomCollection = &CustomCollectionServiceOp{client: c}
c.SmartCollection = &SmartCollectionServiceOp{client: c}
c.Customer = &CustomerServiceOp{client: c}
c.CustomerAddress = &CustomerAddressServiceOp{client: c}
c.Order = &OrderServiceOp{client: c}
c.Shop = &ShopServiceOp{client: c}
c.Webhook = &WebhookServiceOp{client: c}
Expand Down

0 comments on commit e714274

Please sign in to comment.