diff --git a/person.go b/person.go new file mode 100644 index 0000000000..53fda9dc40 --- /dev/null +++ b/person.go @@ -0,0 +1,114 @@ +package stripe + +import "encoding/json" + +// RelationshipParams is used to set the relationship between an acount and a person. +type RelationshipParams struct { + Controller *bool `form:"controller"` + Director *bool `form:"director"` + Email *string `form:"email"` + Owner *bool `form:"owner"` + PercentOwnership *float64 `form:"percent_ownership"` + Phone *string `form:"phone"` + Representative *bool `form:"representative"` + Title *string `form:"title"` +} + +// PersonParams is the set of parameters that can be used when creating or updating a person. +// For more details see https://stripe.com/docs/api#create_person. +type PersonParams struct { + Params `form:"*"` + Account *string `form:"-"` // Included in URL + Address *AccountAddressParams `form:"address"` + AddressKana *AccountAddressParams `form:"address_kana"` + AddressKanji *AccountAddressParams `form:"address_kanji"` + DOB *DOBParams `form:"dob"` + FirstName *string `form:"first_name"` + FirstNameKana *string `form:"first_name_kana"` + FirstNameKanji *string `form:"first_name_kanji"` + Gender *string `form:"gender"` + LastName *string `form:"last_name"` + LastNameKana *string `form:"last_name_kana"` + LastNameKanji *string `form:"last_name_kanji"` + MaidenName *string `form:"maiden_name"` + PersonalIDNumber *string `form:"personal_id_number"` + Relationship *RelationshipParams `form:"relationship"` + SSNLast4 *string `form:"ssn_last_4"` +} + +// PersonListParams is the set of parameters that can be used when listing persons. +// For more detail see https://stripe.com/docs/api#list_persons. +type PersonListParams struct { + ListParams `form:"*"` + Account *string `form:"-"` // Included in URL + Director *bool `form:"director"` + Executive *bool `form:"executive"` + Owner *bool `form:"owner"` +} + +// Relationship represents extra information needed for a Person. +type Relationship struct { + Controller bool `json:"controller"` + Director bool `json:"director"` + Email string `json:"email"` + Owner bool `json:"owner"` + PercentOwnership float64 `json:"percent_ownership"` + Phone string `json:"phone"` + Representative bool `json:"representative"` + Title string `json:"title"` +} + +// Relationship represents the relationship between a Person and an Account. +type Requirements struct { + CurrentlyDue []string `json:"currently_due"` + EventuallyDue []string `json:"eventually_due"` + PastDue []string `json:"past_due"` +} + +// Person is the resource representing a Stripe person. +// For more details see https://stripe.com/docs/api#persons. +type Person struct { + Account string `json:"account"` + Address *AccountAddress `json:"address"` + AddressKana *AccountAddress `json:"address_kana"` + AddressKanji *AccountAddress `json:"address_kanji"` + DOB *DOB `json:"dob"` + FirstName string `json:"first_name"` + FirstNameKana string `json:"first_name_kana"` + FirstNameKanji string `json:"first_name_kanji"` + Gender string `json:"gender"` + ID string `json:"id"` + LastName string `json:"last_name"` + LastNameKana string `json:"last_name_kana"` + LastNameKanji string `json:"last_name_kanji"` + MaidenName string `json:"maiden_name"` + Relationship *Relationship `json:"relationship"` + Requirements *Requirements `json:"requirements"` + SSNLast4Provided bool `json:"ssn_last_4_provided"` + Verification *IdentityVerification `json:"verification"` +} + +// PersonList is a list of persons as retrieved from a list endpoint. +type PersonList struct { + ListMeta + Data []*Person `json:"data"` +} + +// UnmarshalJSON handles deserialization of a Person. +// This custom unmarshaling is needed because the resulting +// property may be an id or the full struct if it was expanded. +func (c *Person) UnmarshalJSON(data []byte) error { + if id, ok := ParseID(data); ok { + c.ID = id + return nil + } + + type person Person + var v person + if err := json.Unmarshal(data, &v); err != nil { + return err + } + + *c = Person(v) + return nil +} diff --git a/person/client.go b/person/client.go new file mode 100644 index 0000000000..30ad3f0c38 --- /dev/null +++ b/person/client.go @@ -0,0 +1,111 @@ +// Package person provides the /accounts/persons APIs +package person + +import ( + "fmt" + "net/http" + + stripe "github.com/stripe/stripe-go" + "github.com/stripe/stripe-go/form" +) + +// Client is used to invoke /accounts/persons APIs. +type Client struct { + B stripe.Backend + Key string +} + +// New creates a new account person. +func New(params *stripe.PersonParams) (*stripe.Person, error) { + return getC().New(params) +} + +// New creates a new account person. +func (c Client) New(params *stripe.PersonParams) (*stripe.Person, error) { + path := stripe.FormatURLPath("/accounts/%s/persons", stripe.StringValue(params.Account)) + person := &stripe.Person{} + err := c.B.Call(http.MethodPost, path, c.Key, params, person) + return person, err +} + +// Get returns the details of a account person. +func Get(id string, params *stripe.PersonParams) (*stripe.Person, error) { + return getC().Get(id, params) +} + +// Get returns the details of a account person. +func (c Client) Get(id string, params *stripe.PersonParams) (*stripe.Person, error) { + if params == nil { + return nil, fmt.Errorf("params cannot be nil, and params.Account must be set") + } + + path := stripe.FormatURLPath("/accounts/%s/persons/%s", + stripe.StringValue(params.Account), id) + person := &stripe.Person{} + err := c.B.Call(http.MethodGet, path, c.Key, params, person) + return person, err +} + +// Update updates a account person's properties. +func Update(id string, params *stripe.PersonParams) (*stripe.Person, error) { + return getC().Update(id, params) +} + +// Update updates a account person's properties. +func (c Client) Update(id string, params *stripe.PersonParams) (*stripe.Person, error) { + path := stripe.FormatURLPath("/accounts/%s/persons/%s", + stripe.StringValue(params.Account), id) + person := &stripe.Person{} + err := c.B.Call(http.MethodPost, path, c.Key, params, person) + return person, err +} + +// Del removes a person. +func Del(id string, params *stripe.PersonParams) (*stripe.Person, error) { + return getC().Del(id, params) +} + +// Del removes a person. +func (c Client) Del(id string, params *stripe.PersonParams) (*stripe.Person, error) { + path := stripe.FormatURLPath("/accounts/%s/persons/%s", + stripe.StringValue(params.Account), id) + person := &stripe.Person{} + err := c.B.Call(http.MethodDelete, path, c.Key, params, person) + return person, err +} + +// List returns a list of account persons. +func List(params *stripe.PersonListParams) *Iter { + return getC().List(params) +} + +// List returns a list of account persons. +func (c Client) List(listParams *stripe.PersonListParams) *Iter { + path := stripe.FormatURLPath("/accounts/%s/persons", stripe.StringValue(listParams.Account)) + + return &Iter{stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListMeta, error) { + list := &stripe.PersonList{} + err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list) + + ret := make([]interface{}, len(list.Data)) + for i, v := range list.Data { + ret[i] = v + } + + return ret, list.ListMeta, err + })} +} + +// Iter is an iterator for account persons. +type Iter struct { + *stripe.Iter +} + +// Person returns the account person which the iterator is currently pointing to. +func (i *Iter) Person() *stripe.Person { + return i.Current().(*stripe.Person) +} + +func getC() Client { + return Client{stripe.GetBackend(stripe.APIBackend), stripe.Key} +} diff --git a/person/client_test.go b/person/client_test.go new file mode 100644 index 0000000000..8f1056bd84 --- /dev/null +++ b/person/client_test.go @@ -0,0 +1,58 @@ +package person + +import ( + "testing" + + assert "github.com/stretchr/testify/require" + stripe "github.com/stripe/stripe-go" + _ "github.com/stripe/stripe-go/testing" +) + +func TestPersonDel(t *testing.T) { + person, err := Del("person_123", &stripe.PersonParams{ + Account: stripe.String("acct_123"), + }) + assert.Nil(t, err) + assert.NotNil(t, person) +} + +func TestPersonGet(t *testing.T) { + person, err := Get("person_123", &stripe.PersonParams{ + Account: stripe.String("acct_123"), + }) + assert.Nil(t, err) + assert.NotNil(t, person) +} + +func TestPersonList(t *testing.T) { + i := List(&stripe.PersonListParams{ + Account: stripe.String("acct_123"), + Owner: stripe.Bool(true), + }) + + // Verify that we can get at least one person + assert.True(t, i.Next()) + assert.Nil(t, i.Err()) + assert.NotNil(t, i.Person()) +} + +func TestPersonNew(t *testing.T) { + person, err := New(&stripe.PersonParams{ + Account: stripe.String("acct_123"), + FirstName: stripe.String("John"), + Relationship: &stripe.RelationshipParams{ + Owner: stripe.Bool(true), + }, + }) + assert.Nil(t, err) + assert.NotNil(t, person) +} + +func TestPersonUpdate(t *testing.T) { + person, err := Update("person_123", &stripe.PersonParams{ + Account: stripe.String("acct_123"), + FirstName: stripe.String("John"), + }) + assert.Nil(t, err) + assert.NotNil(t, person) +} diff --git a/person_test.go b/person_test.go new file mode 100644 index 0000000000..1eb70be7fa --- /dev/null +++ b/person_test.go @@ -0,0 +1,29 @@ +package stripe + +import ( + "encoding/json" + "testing" + + assert "github.com/stretchr/testify/require" +) + +func TestPerson_UnmarshalJSON(t *testing.T) { + // Unmarshals from a JSON string + { + var v Person + err := json.Unmarshal([]byte(`"person_123"`), &v) + assert.NoError(t, err) + assert.Equal(t, "person_123", v.ID) + } + + // Unmarshals from a JSON object + { + v := Person{ID: "person_123"} + data, err := json.Marshal(&v) + assert.NoError(t, err) + + err = json.Unmarshal(data, &v) + assert.NoError(t, err) + assert.Equal(t, "person_123", v.ID) + } +}