diff --git a/product.go b/product.go index e3835fc5b0..5c3230e20f 100644 --- a/product.go +++ b/product.go @@ -2,6 +2,10 @@ package stripe import "encoding/json" +// ProductParams is the set of parameters that can be used +// when creating or updating a product. +// For more details, see https://stripe.com/docs/api#create_product +// and https://stripe.com/docs/api#update_product. type ProductParams struct { Params ID string @@ -10,9 +14,13 @@ type ProductParams struct { Caption string Desc string Attrs []string + Images []string + URL string Shippable *bool } +// Product is the resource representing a Stripe product. +// For more details see https://stripe.com/docs/api#products. type Product struct { ID string `json:"id"` Created int64 `json:"created"` @@ -24,15 +32,23 @@ type Product struct { Desc string `json:"description"` Attrs []string `json:"attributes"` Shippable bool `json:"shippable"` + Images []string `json:"images"` Meta map[string]string `json:"metdata"` + URL string `json:"url"` Skus *SKUList `json:"skus"` } +// ProductListParams is the set of parameters that can be used when +// listing products. For more details, see: +// https://stripe.com/docs/api#list_products. type ProductListParams struct { ListParams Created int64 } +// UnmarshalJSON handles deserialization of a Product. +// This custom unmarshaling is needed because the resulting +// property may be an id or the full struct if it was expanded. func (p *Product) UnmarshalJSON(data []byte) error { type product Product var pr product diff --git a/product/client.go b/product/client.go index 7af6a7c559..6807fa1a9f 100644 --- a/product/client.go +++ b/product/client.go @@ -13,10 +13,14 @@ type Client struct { Key string } +// New POSTs a new product. +// For more details see https://stripe.com/docs/api#create_product. func New(params *stripe.ProductParams) (*stripe.Product, error) { return getC().New(params) } +// New POSTs a new product. +// For more details see https://stripe.com/docs/api#create_product. func (c Client) New(params *stripe.ProductParams) (*stripe.Product, error) { var body *url.Values var commonParams *stripe.Params @@ -32,17 +36,31 @@ func (c Client) New(params *stripe.ProductParams) (*stripe.Product, error) { if params.ID != "" { body.Add("id", params.ID) } + if params.Active != nil { body.Add("active", strconv.FormatBool(*(params.Active))) } + if params.Caption != "" { body.Add("caption", params.Caption) } + if len(params.Attrs) > 0 { for _, v := range params.Attrs { body.Add("attributes[]", v) } } + + if len(params.Images) > 0 { + for _, v := range params.Images { + body.Add("images[]", v) + } + } + + if len(params.URL) > 0 { + body.Add("url", params.URL) + } + if params.Shippable != nil { body.Add("shippable", strconv.FormatBool(*(params.Shippable))) } @@ -56,6 +74,52 @@ func (c Client) New(params *stripe.ProductParams) (*stripe.Product, error) { return p, err } +// Update updates a product's properties. +// For more details see https://stripe.com/docs/api#update_product. +func Update(id string, params *stripe.ProductParams) (*stripe.Product, error) { + return getC().Update(id, params) +} + +// Update updates a product's properties. +// For more details see https://stripe.com/docs/api#update_product. +func (c Client) Update(id string, params *stripe.ProductParams) (*stripe.Product, error) { + var body *url.Values + var commonParams *stripe.Params + + if params != nil { + body = &url.Values{} + + if len(params.Name) > 0 { + body.Add("name", params.Name) + } + + if len(params.Desc) > 0 { + body.Add("description", params.Desc) + } + + if params.Active != nil { + body.Add("active", strconv.FormatBool(*(params.Active))) + } + + if len(params.Images) > 0 { + for _, v := range params.Images { + body.Add("images[]", v) + } + } + + if len(params.URL) > 0 { + body.Add("url", params.URL) + } + + params.AppendTo(body) + } + + p := &stripe.Product{} + err := c.B.Call("POST", "/products/"+id, c.Key, body, commonParams, p) + + return p, err +} + // Get returns the details of an product // For more details see https://stripe.com/docs/api#retrieve_product. func Get(id string) (*stripe.Product, error) { diff --git a/product/client_test.go b/product/client_test.go index b09dd4422e..c05b82d874 100644 --- a/product/client_test.go +++ b/product/client_test.go @@ -4,6 +4,7 @@ import ( "fmt" "math/rand" "testing" + "time" stripe "github.com/stripe-internal/stripe-go" . "github.com/stripe-internal/stripe-go/utils" @@ -11,6 +12,7 @@ import ( func init() { stripe.Key = GetTestKey() + rand.Seed(time.Now().UTC().UnixNano()) } func TestProduct(t *testing.T) { @@ -23,6 +25,7 @@ func TestProduct(t *testing.T) { Desc: "This is a description", Caption: "This is a caption", Attrs: []string{"attr1", "attr2"}, + URL: "http://example.com", Shippable: &shippable, }) @@ -57,6 +60,10 @@ func TestProduct(t *testing.T) { if p.Desc != "This is a description" { t.Errorf("Description is invalid: %v", p.Desc) } + + if p.URL != "http://example.com" { + t.Errorf("URL is invalid: %v", p.URL) + } } func TestProductWithCustomID(t *testing.T) { @@ -76,6 +83,27 @@ func TestProductWithCustomID(t *testing.T) { } } +func TestProductUpdate(t *testing.T) { + randID := fmt.Sprintf("TEST-PRODUCT-%v", randSeq(16)) + p, err := New(&stripe.ProductParams{ + ID: randID, + Name: "Test product name", + Desc: "Test description", + }) + if err != nil { + t.Fatalf("%+v", err) + } + p, err = Update(p.ID, &stripe.ProductParams{ + Desc: "new description", + }) + if err != nil { + t.Fatalf("%+v", err) + } + if p.Desc != "new description" { + t.Errorf("Invalid description: %v", p.Desc) + } +} + // h/t: http://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-golang func randSeq(n int) string { letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")