mirror of
https://github.com/cubixle/ebay.git
synced 2026-04-24 21:24:47 +01:00
Add CheckCompatibility and GetItemByGroupID
This commit is contained in:
172
browse.go
172
browse.go
@@ -375,3 +375,175 @@ func (s *BrowseService) GetItem(ctx context.Context, itemID string, opts ...Opt)
|
||||
var it Item
|
||||
return it, s.client.Do(ctx, req, &it)
|
||||
}
|
||||
|
||||
// ItemsByGroup represents eBay items by group.
|
||||
type ItemsByGroup struct {
|
||||
Items []struct {
|
||||
ItemID string `json:"itemId"`
|
||||
SellerItemRevision string `json:"sellerItemRevision"`
|
||||
Title string `json:"title"`
|
||||
ShortDescription string `json:"shortDescription"`
|
||||
Price struct {
|
||||
Value string `json:"value"`
|
||||
Currency string `json:"currency"`
|
||||
} `json:"price"`
|
||||
CategoryPath string `json:"categoryPath"`
|
||||
Condition string `json:"condition"`
|
||||
ConditionID string `json:"conditionId"`
|
||||
ItemLocation struct {
|
||||
City string `json:"city"`
|
||||
Country string `json:"country"`
|
||||
} `json:"itemLocation"`
|
||||
Image struct {
|
||||
ImageURL string `json:"imageUrl"`
|
||||
} `json:"image"`
|
||||
Color string `json:"color"`
|
||||
Material string `json:"material"`
|
||||
Pattern string `json:"pattern"`
|
||||
SizeType string `json:"sizeType"`
|
||||
Brand string `json:"brand"`
|
||||
ItemEndDate time.Time `json:"itemEndDate"`
|
||||
Seller struct {
|
||||
Username string `json:"username"`
|
||||
FeedbackPercentage string `json:"feedbackPercentage"`
|
||||
FeedbackScore int `json:"feedbackScore"`
|
||||
} `json:"seller"`
|
||||
EstimatedAvailabilities []struct {
|
||||
DeliveryOptions []string `json:"deliveryOptions"`
|
||||
AvailabilityThresholdType string `json:"availabilityThresholdType"`
|
||||
AvailabilityThreshold int `json:"availabilityThreshold"`
|
||||
EstimatedAvailabilityStatus string `json:"estimatedAvailabilityStatus"`
|
||||
EstimatedSoldQuantity int `json:"estimatedSoldQuantity"`
|
||||
} `json:"estimatedAvailabilities"`
|
||||
ShippingOptions []struct {
|
||||
ShippingServiceCode string `json:"shippingServiceCode"`
|
||||
TrademarkSymbol string `json:"trademarkSymbol,omitempty"`
|
||||
ShippingCarrierCode string `json:"shippingCarrierCode,omitempty"`
|
||||
Type string `json:"type"`
|
||||
ShippingCost struct {
|
||||
Value string `json:"value"`
|
||||
Currency string `json:"currency"`
|
||||
} `json:"shippingCost"`
|
||||
QuantityUsedForEstimate int `json:"quantityUsedForEstimate"`
|
||||
MinEstimatedDeliveryDate time.Time `json:"minEstimatedDeliveryDate"`
|
||||
MaxEstimatedDeliveryDate time.Time `json:"maxEstimatedDeliveryDate"`
|
||||
ShipToLocationUsedForEstimate struct {
|
||||
Country string `json:"country"`
|
||||
} `json:"shipToLocationUsedForEstimate"`
|
||||
AdditionalShippingCostPerUnit struct {
|
||||
Value string `json:"value"`
|
||||
Currency string `json:"currency"`
|
||||
} `json:"additionalShippingCostPerUnit"`
|
||||
ShippingCostType string `json:"shippingCostType"`
|
||||
} `json:"shippingOptions"`
|
||||
ShipToLocations struct {
|
||||
RegionIncluded []struct {
|
||||
RegionName string `json:"regionName"`
|
||||
RegionType string `json:"regionType"`
|
||||
} `json:"regionIncluded"`
|
||||
RegionExcluded []struct {
|
||||
RegionName string `json:"regionName"`
|
||||
RegionType string `json:"regionType"`
|
||||
} `json:"regionExcluded"`
|
||||
} `json:"shipToLocations"`
|
||||
ReturnTerms struct {
|
||||
ReturnsAccepted bool `json:"returnsAccepted"`
|
||||
RefundMethod string `json:"refundMethod"`
|
||||
ReturnMethod string `json:"returnMethod"`
|
||||
ReturnShippingCostPayer string `json:"returnShippingCostPayer"`
|
||||
ReturnPeriod struct {
|
||||
Value int `json:"value"`
|
||||
Unit string `json:"unit"`
|
||||
} `json:"returnPeriod"`
|
||||
} `json:"returnTerms"`
|
||||
LocalizedAspects []struct {
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
} `json:"localizedAspects"`
|
||||
TopRatedBuyingExperience bool `json:"topRatedBuyingExperience"`
|
||||
BuyingOptions []string `json:"buyingOptions"`
|
||||
PrimaryItemGroup struct {
|
||||
ItemGroupID string `json:"itemGroupId"`
|
||||
ItemGroupType string `json:"itemGroupType"`
|
||||
ItemGroupHref string `json:"itemGroupHref"`
|
||||
ItemGroupTitle string `json:"itemGroupTitle"`
|
||||
ItemGroupImage struct {
|
||||
ImageURL string `json:"imageUrl"`
|
||||
} `json:"itemGroupImage"`
|
||||
ItemGroupAdditionalImages []struct {
|
||||
ImageURL string `json:"imageUrl"`
|
||||
} `json:"itemGroupAdditionalImages"`
|
||||
} `json:"primaryItemGroup"`
|
||||
EnabledForGuestCheckout bool `json:"enabledForGuestCheckout"`
|
||||
AdultOnly bool `json:"adultOnly"`
|
||||
CategoryID string `json:"categoryId"`
|
||||
} `json:"items"`
|
||||
CommonDescriptions []struct {
|
||||
Description string `json:"description"`
|
||||
ItemIds []string `json:"itemIds"`
|
||||
} `json:"commonDescriptions"`
|
||||
}
|
||||
|
||||
// GetItemByGroupID retrieves the details of the individual items in an item group.
|
||||
//
|
||||
// eBay API docs: https://developer.ebay.com/api-docs/buy/browse/resources/item/methods/getItemsByItemGroup
|
||||
func (s *BrowseService) GetItemByGroupID(ctx context.Context, groupID string, opts ...Opt) (ItemsByGroup, error) {
|
||||
u := fmt.Sprintf("buy/browse/v1/item/get_items_by_item_group?item_group_id=%s", groupID)
|
||||
req, err := s.client.NewRequest(http.MethodGet, u, nil, opts...)
|
||||
if err != nil {
|
||||
return ItemsByGroup{}, err
|
||||
}
|
||||
var it ItemsByGroup
|
||||
return it, s.client.Do(ctx, req, &it)
|
||||
}
|
||||
|
||||
// CompatibilityProperty represents a product property.
|
||||
type CompatibilityProperty struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// Compatibility represents an item compatibility.
|
||||
type Compatibility struct {
|
||||
CompatibilityStatus string `json:"compatibilityStatus"`
|
||||
Warnings []struct {
|
||||
Category string `json:"category"`
|
||||
Domain string `json:"domain"`
|
||||
ErrorID int `json:"errorId"`
|
||||
InputRefIds []string `json:"inputRefIds"`
|
||||
LongMessage string `json:"longMessage"`
|
||||
Message string `json:"message"`
|
||||
OutputRefIds []string `json:"outputRefIds"`
|
||||
Parameters []struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
} `json:"parameters"`
|
||||
Subdomain string `json:"subdomain"`
|
||||
} `json:"warnings"`
|
||||
}
|
||||
|
||||
// Valid values for the "compatibilityStatus" compatibility field.
|
||||
const (
|
||||
BrowseCheckComoatibilityCompatible = "COMPATIBLE"
|
||||
BrowseCheckComoatibilityNotCompatible = "NOT_COMPATIBLE"
|
||||
BrowseCheckComoatibilityUndertermined = "UNDETERMINED"
|
||||
)
|
||||
|
||||
// CheckCompatibility checks a product is compatible with the specified item.
|
||||
//
|
||||
// eBay API docs: https://developer.ebay.com/api-docs/buy/browse/resources/item/methods/checkCompatibility
|
||||
func (s *BrowseService) CheckCompatibility(ctx context.Context, itemID, marketplaceID string, properties []CompatibilityProperty, opts ...Opt) (Compatibility, error) {
|
||||
type payload struct {
|
||||
CompatibilityProperties []CompatibilityProperty `json:"compatibilityProperties"`
|
||||
}
|
||||
pl := payload{properties}
|
||||
u := fmt.Sprintf("buy/browse/v1/item/%s/check_compatibility", itemID)
|
||||
opts = append(opts, OptBuyMarketplace(marketplaceID))
|
||||
req, err := s.client.NewRequest(http.MethodPost, u, &pl, opts...)
|
||||
if err != nil {
|
||||
return Compatibility{}, err
|
||||
}
|
||||
var c Compatibility
|
||||
return c, s.client.Do(ctx, req, &c)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package ebay_test
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -70,3 +71,46 @@ func TestGettItem(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "PRODUCT", item.ItemID)
|
||||
}
|
||||
|
||||
func TestGetItemByGroupID(t *testing.T) {
|
||||
client, mux, teardown := setup(t)
|
||||
defer teardown()
|
||||
|
||||
mux.HandleFunc("/buy/browse/v1/item/get_items_by_item_group", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Fatalf("expected GET method, got: %s", r.Method)
|
||||
}
|
||||
fmt.Fprintf(w, `{"items": [{"itemId": "%s"}]}`, r.URL.Query().Get("item_group_id"))
|
||||
})
|
||||
|
||||
it, err := client.Buy.Browse.GetItemByGroupID(context.Background(), "151915076499")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "151915076499", it.Items[0].ItemID)
|
||||
}
|
||||
|
||||
func TestCheckCompatibility(t *testing.T) {
|
||||
client, mux, teardown := setup(t)
|
||||
defer teardown()
|
||||
|
||||
mux.HandleFunc("/buy/browse/v1/item/v1|202117468662|0/check_compatibility", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
t.Fatalf("expected POST method, got: %s", r.Method)
|
||||
}
|
||||
assert.Equal(t, ebay.BuyMarketplaceUSA, r.Header.Get("X-EBAY-C-MARKETPLACE-ID"))
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
}
|
||||
assert.Equal(t, `{"compatibilityProperties":[{"name":"0","value":"1"},{"name":"2","value":"3"}]}
|
||||
`, string(body))
|
||||
fmt.Fprintf(w, `{"compatibilityStatus": "NOT_COMPATIBLE", "warnings": [{"category" : "category"}]}`)
|
||||
})
|
||||
compatibilityProperties := []ebay.CompatibilityProperty{
|
||||
{Name: "0", Value: "1"},
|
||||
{Name: "2", Value: "3"},
|
||||
}
|
||||
compatibility, err := client.Buy.Browse.CheckCompatibility(context.Background(), "v1|202117468662|0", ebay.BuyMarketplaceUSA, compatibilityProperties)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "NOT_COMPATIBLE", compatibility.CompatibilityStatus)
|
||||
assert.Equal(t, "category", compatibility.Warnings[0].Category)
|
||||
}
|
||||
|
||||
17
ebay.go
17
ebay.go
@@ -14,9 +14,10 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// eBay URLs.
|
||||
const (
|
||||
baseURL = "https://api.ebay.com/"
|
||||
sandboxBaseURL = "https://api.sandbox.ebay.com/"
|
||||
BaseURL = "https://api.ebay.com/"
|
||||
SandboxBaseURL = "https://api.sandbox.ebay.com/"
|
||||
)
|
||||
|
||||
// Some eBay API scopes.
|
||||
@@ -47,13 +48,13 @@ type Client struct {
|
||||
// NewClient returns a new eBay API client.
|
||||
// If a nil httpClient is provided, http.DefaultClient will be used.
|
||||
func NewClient(httpclient *http.Client) *Client {
|
||||
return newClient(httpclient, baseURL)
|
||||
return newClient(httpclient, BaseURL)
|
||||
}
|
||||
|
||||
// NewSandboxClient returns a new eBay sandbox API client.
|
||||
// If a nil httpClient is provided, http.DefaultClient will be used.
|
||||
func NewSandboxClient(httpclient *http.Client) *Client {
|
||||
return newClient(httpclient, sandboxBaseURL)
|
||||
return newClient(httpclient, SandboxBaseURL)
|
||||
}
|
||||
|
||||
// NewCustomClient returns a new custom eBay API client.
|
||||
@@ -118,12 +119,13 @@ func (c *Client) NewRequest(method, url string, body interface{}, opts ...Opt) (
|
||||
|
||||
// Do sends an API request and stores the JSON decoded value into v.
|
||||
func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) error {
|
||||
dump, _ := httputil.DumpRequest(req, true)
|
||||
resp, err := c.client.Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if err := CheckResponse(req, resp); err != nil {
|
||||
if err := CheckResponse(req, resp, string(dump)); err != nil {
|
||||
return err
|
||||
}
|
||||
if v == nil {
|
||||
@@ -165,12 +167,11 @@ func (e *ErrorData) Error() string {
|
||||
}
|
||||
|
||||
// CheckResponse checks the API response for errors, and returns them if present.
|
||||
func CheckResponse(req *http.Request, resp *http.Response) error {
|
||||
func CheckResponse(req *http.Request, resp *http.Response, dump string) error {
|
||||
if s := resp.StatusCode; 200 <= s && s < 300 {
|
||||
return nil
|
||||
}
|
||||
dump, _ := httputil.DumpRequest(req, true)
|
||||
errorData := &ErrorData{response: resp, requestDump: string(dump)}
|
||||
errorData := &ErrorData{response: resp, requestDump: dump}
|
||||
_ = json.NewDecoder(resp.Body).Decode(errorData)
|
||||
return errorData
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ func TestNewRequest(t *testing.T) {
|
||||
|
||||
func TestCheckResponseNoError(t *testing.T) {
|
||||
resp := &http.Response{StatusCode: 200}
|
||||
assert.Nil(t, ebay.CheckResponse(&http.Request{}, resp))
|
||||
assert.Nil(t, ebay.CheckResponse(&http.Request{}, resp, ""))
|
||||
}
|
||||
|
||||
func TestCheckResponse(t *testing.T) {
|
||||
@@ -67,7 +67,7 @@ func TestCheckResponse(t *testing.T) {
|
||||
]
|
||||
}`
|
||||
resp := &http.Response{StatusCode: 400, Body: ioutil.NopCloser(bytes.NewBufferString(body))}
|
||||
err, ok := ebay.CheckResponse(&http.Request{URL: &url.URL{}}, resp).(*ebay.ErrorData)
|
||||
err, ok := ebay.CheckResponse(&http.Request{URL: &url.URL{}}, resp, "").(*ebay.ErrorData)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, 1, len(err.Errors))
|
||||
assert.Equal(t, 15008, err.Errors[0].ErrorID)
|
||||
|
||||
4
offer.go
4
offer.go
@@ -120,8 +120,6 @@ const (
|
||||
//
|
||||
// eBay API docs: https://developer.ebay.com/api-docs/buy/offer/resources/bidding/methods/placeProxyBid
|
||||
func (s *OfferService) PlaceProxyBid(ctx context.Context, itemID, marketplaceID, maxAmount, currency string, userConsentAdultOnlyItem bool, opts ...Opt) (ProxyBid, error) {
|
||||
u := fmt.Sprintf("buy/offer/v1_beta/bidding/%s/place_proxy_bid", itemID)
|
||||
opts = append(opts, OptBuyMarketplace(marketplaceID))
|
||||
type userConsent struct {
|
||||
AdultOnlyItem bool `json:"adultOnlyItem,omitempty"`
|
||||
}
|
||||
@@ -139,6 +137,8 @@ func (s *OfferService) PlaceProxyBid(ctx context.Context, itemID, marketplaceID,
|
||||
if userConsentAdultOnlyItem {
|
||||
pl.UserConsent = &userConsent{userConsentAdultOnlyItem}
|
||||
}
|
||||
u := fmt.Sprintf("buy/offer/v1_beta/bidding/%s/place_proxy_bid", itemID)
|
||||
opts = append(opts, OptBuyMarketplace(marketplaceID))
|
||||
req, err := s.client.NewRequest(http.MethodPost, u, &pl, opts...)
|
||||
if err != nil {
|
||||
return ProxyBid{}, err
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/jybp/ebay"
|
||||
@@ -43,23 +42,17 @@ func TestPlaceProxyBid(t *testing.T) {
|
||||
if r.Method != "POST" {
|
||||
t.Fatalf("expected POST method, got: %s", r.Method)
|
||||
}
|
||||
marketplaceID := r.Header.Get("X-EBAY-C-MARKETPLACE-ID")
|
||||
assert.Equal(t, ebay.BuyMarketplaceUSA, r.Header.Get("X-EBAY-C-MARKETPLACE-ID"))
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
escapedBody := strconv.Quote(string(body))
|
||||
escapedBody = escapedBody[1 : len(escapedBody)-1]
|
||||
fmt.Fprintf(w, `{"proxyBidId": "%s_%s"}`, escapedBody, marketplaceID)
|
||||
assert.Equal(t, `{"maxAmount":{"currency":"USD","value":"1.23"},"userConsent":{"adultOnlyItem":true}}
|
||||
`, string(body))
|
||||
fmt.Fprintf(w, `{"proxyBidId": "123"}`)
|
||||
})
|
||||
|
||||
bid, err := client.Buy.Offer.PlaceProxyBid(context.Background(), "v1|202117468662|0", ebay.BuyMarketplaceUSA, "1.23", "USD", false)
|
||||
bid, err := client.Buy.Offer.PlaceProxyBid(context.Background(), "v1|202117468662|0", ebay.BuyMarketplaceUSA, "1.23", "USD", true)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "{\"maxAmount\":{\"currency\":\"USD\",\"value\":\"1.23\"}}\n_EBAY_US", bid.ProxyBidID)
|
||||
|
||||
bid, err = client.Buy.Offer.PlaceProxyBid(context.Background(), "v1|202117468662|0", ebay.BuyMarketplaceUSA, "1.23", "USD", true)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "{\"maxAmount\":{\"currency\":\"USD\",\"value\":\"1.23\"},\"userConsent\":{\"adultOnlyItem\":true}}\n_EBAY_US", bid.ProxyBidID)
|
||||
assert.Equal(t, `123`, bid.ProxyBidID)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -137,26 +136,5 @@ func TestAuction(t *testing.T) {
|
||||
if err != nil && !ebay.IsError(err, ebay.ErrGetBiddingNoBiddingActivity) {
|
||||
t.Fatalf("Expected error code %d, got %+v.", ebay.ErrGetBiddingNoBiddingActivity, err)
|
||||
}
|
||||
|
||||
var bidValue, bidCurrency string
|
||||
if len(bid.SuggestedBidAmounts) > 0 {
|
||||
bidValue = bid.SuggestedBidAmounts[0].Value
|
||||
bidCurrency = bid.SuggestedBidAmounts[0].Currency
|
||||
} else {
|
||||
bidValue = it.CurrentBidPrice.Value
|
||||
v, err := strconv.ParseFloat(bidValue, 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
v += 2
|
||||
bidValue = fmt.Sprintf("%.2f", v)
|
||||
bidCurrency = it.CurrentBidPrice.Currency
|
||||
}
|
||||
|
||||
_, err = client.Buy.Offer.PlaceProxyBid(ctx, it.ItemID, ebay.BuyMarketplaceUSA, bidValue, bidCurrency, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Logf("Successfully bid %+v.", bid.SuggestedBidAmounts[0])
|
||||
t.Logf("bidding: %+v", bid)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user