Skip to content
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
18 changes: 18 additions & 0 deletions etsy_python/v3/resources/Listing.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,24 @@ def get_listings_by_listings_ids(
)
return self.get_listings_by_listing_ids(listing_ids, includes, legacy)

def get_listings_inventory_by_listing_ids(
self, listing_ids: List[int]
) -> Union[Response, RequestException]:
endpoint = "/listings/batch/inventory"
query_params: Dict[str, Any] = {
"listing_ids": ",".join(list(map(str, listing_ids))),
}
return self.session.make_request(endpoint, query_params=query_params)

def get_listings_shipping_by_listing_ids(
self, listing_ids: List[int]
) -> Union[Response, RequestException]:
endpoint = "/listings/batch/shipping"
query_params: Dict[str, Any] = {
"listing_ids": ",".join(list(map(str, listing_ids))),
}
return self.session.make_request(endpoint, query_params=query_params)

def get_featured_listings_by_shop(
self, shop_id: int, limit: int = 25, offset: int = 0,
legacy: Optional[bool] = None,
Expand Down
172 changes: 172 additions & 0 deletions specs/baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -2673,6 +2673,16 @@
}
}
},
"409": {
"description": "There was a request conflict with the current state of the target resource. See the error message for details.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorSchema"
}
}
}
},
"500": {
"description": "The server encountered an internal error. See the error message for details.",
"content": {
Expand All @@ -2694,6 +2704,82 @@
]
}
},
"/v3/application/listings/batch/inventory": {
"get": {
"operationId": "getListingsInventoryByListingIds",
"description": "<div class=\"wt-display-flex-xs wt-align-items-center wt-mt-xs-2 wt-mb-xs-3\"><span class=\"wt-badge wt-badge--notificationPrimary wt-bg-slime-tint wt-mr-xs-2\">General Release</span><a class=\"wt-text-link\" href=\"https://github.com/etsy/open-api/discussions\" target=\"_blank\" rel=\"noopener noreferrer\">Report bug</a></div><div class=\"wt-display-flex-xs wt-align-items-center wt-mt-xs-2 wt-mb-xs-3\"><p class=\"wt-text-body-01 banner-text\">This endpoint is ready for production use.</p></div>\n\nRetrieves the inventory record for each listing referenced by listing ID. Requires the listings_r OAuth scope. Limit 100 listing IDs per request.",
"tags": [
"ShopListing Inventory"
],
"parameters": [
{
"name": "listing_ids",
"in": "query",
"description": "The list of numeric IDS for the listings in a specific Etsy shop.",
"required": true,
"schema": {
"type": "array",
"description": "The list of numeric IDS for the listings in a specific Etsy shop.",
"items": {
"type": "integer",
"format": "int64",
"minimum": 1
}
}
}
],
"responses": {
"200": {
"description": "A list of listings with their inventory records.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ShopListingsWithAssociations"
}
}
}
},
"400": {
"description": "There was a problem with the request data. See the error message for details.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorSchema"
}
}
}
},
"404": {
"description": "A resource could not be found. See the error message for details.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorSchema"
}
}
}
},
"500": {
"description": "The server encountered an internal error. See the error message for details.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorSchema"
}
}
}
}
},
"security": [
{
"api_key": [],
"oauth2": [
"listings_r"
]
}
]
}
},
"/v3/application/listings/{listing_id}/inventory/products/{product_id}": {
"get": {
"operationId": "getListingProduct",
Expand Down Expand Up @@ -3937,6 +4023,82 @@
}
}
},
"/v3/application/listings/batch/shipping": {
"get": {
"operationId": "getListingsShippingByListingIds",
"description": "<div class=\"wt-display-flex-xs wt-align-items-center wt-mt-xs-2 wt-mb-xs-3\"><span class=\"wt-badge wt-badge--notificationPrimary wt-bg-slime-tint wt-mr-xs-2\">General Release</span><a class=\"wt-text-link\" href=\"https://github.com/etsy/open-api/discussions\" target=\"_blank\" rel=\"noopener noreferrer\">Report bug</a></div><div class=\"wt-display-flex-xs wt-align-items-center wt-mt-xs-2 wt-mb-xs-3\"><p class=\"wt-text-body-01 banner-text\">This endpoint is ready for production use.</p></div>\n\nRetrieves the shipping profile for each listing referenced by listing ID. Requires the shops_r OAuth scope. Limit 100 listing IDs per request.",
"tags": [
"ShopListing"
],
"parameters": [
{
"name": "listing_ids",
"in": "query",
"description": "The list of numeric IDS for the listings in a specific Etsy shop.",
"required": true,
"schema": {
"type": "array",
"description": "The list of numeric IDS for the listings in a specific Etsy shop.",
"items": {
"type": "integer",
"format": "int64",
"minimum": 1
}
}
}
],
"responses": {
"200": {
"description": "A list of listings with their shipping profiles.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ShopListingsWithAssociations"
}
}
}
},
"400": {
"description": "There was a problem with the request data. See the error message for details.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorSchema"
}
}
}
},
"404": {
"description": "A resource could not be found. See the error message for details.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorSchema"
}
}
}
},
"500": {
"description": "The server encountered an internal error. See the error message for details.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorSchema"
}
}
}
}
},
"security": [
{
"api_key": [],
"oauth2": [
"shops_r"
]
}
]
}
},
"/v3/application/shops/{shop_id}/listings/{listing_id}/transactions": {
"get": {
"operationId": "getShopReceiptTransactionsByListing",
Expand Down Expand Up @@ -12915,6 +13077,11 @@
"type": "string",
"description": "A description string of the product for sale in the listing."
},
"rich_description": {
"type": "string",
"description": "The seller-authored HTML rich-text description of the product when the listing uses rich text; null for plain-text listings. The plain-text `description` field is always populated. This value is HTML and consumers MUST sanitize it before rendering it in any HTML context.",
"nullable": true
},
"state": {
"type": "string",
"description": "When _updating_ a listing, this value can be either `active` or `inactive`. Note: Setting a `draft` listing to `active` will also publish the listing on etsy.com and requires that the listing have an image set. Setting a `sold_out` listing to active will update the quantity to 1 and renew the listing on etsy.com.",
Expand Down Expand Up @@ -13378,6 +13545,11 @@
"type": "string",
"description": "A description string of the product for sale in the listing."
},
"rich_description": {
"type": "string",
"description": "The seller-authored HTML rich-text description of the product when the listing uses rich text; null for plain-text listings. The plain-text `description` field is always populated. This value is HTML and consumers MUST sanitize it before rendering it in any HTML context.",
"nullable": true
},
"state": {
"type": "string",
"description": "When _updating_ a listing, this value can be either `active` or `inactive`. Note: Setting a `draft` listing to `active` will also publish the listing on etsy.com and requires that the listing have an image set. Setting a `sold_out` listing to active will update the quantity to 1 and renew the listing on etsy.com.",
Expand Down
52 changes: 52 additions & 0 deletions tests/test_listing_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,58 @@ def test_legacy_forwarded_through_deprecated_alias(self, mock_session):
assert qp["legacy"] is True


class TestGetListingsInventoryByListingIds:
def test_listing_ids_joined(self, mock_session):
mock_session.make_request.return_value = Response(
200, make_shop_listing_collection()
)
resource = ListingResource(session=mock_session)

resource.get_listings_inventory_by_listing_ids([111, 222, 333])

endpoint = mock_session.make_request.call_args[0][0]
qp = mock_session.make_request.call_args[1]["query_params"]
assert endpoint == "/listings/batch/inventory"
assert qp["listing_ids"] == "111,222,333"

def test_single_listing_id(self, mock_session):
mock_session.make_request.return_value = Response(
200, make_shop_listing_collection()
)
resource = ListingResource(session=mock_session)

resource.get_listings_inventory_by_listing_ids([111])

qp = mock_session.make_request.call_args[1]["query_params"]
assert qp["listing_ids"] == "111"


class TestGetListingsShippingByListingIds:
def test_listing_ids_joined(self, mock_session):
mock_session.make_request.return_value = Response(
200, make_shop_listing_collection()
)
resource = ListingResource(session=mock_session)

resource.get_listings_shipping_by_listing_ids([111, 222, 333])

endpoint = mock_session.make_request.call_args[0][0]
qp = mock_session.make_request.call_args[1]["query_params"]
assert endpoint == "/listings/batch/shipping"
assert qp["listing_ids"] == "111,222,333"

def test_single_listing_id(self, mock_session):
mock_session.make_request.return_value = Response(
200, make_shop_listing_collection()
)
resource = ListingResource(session=mock_session)

resource.get_listings_shipping_by_listing_ids([111])

qp = mock_session.make_request.call_args[1]["query_params"]
assert qp["listing_ids"] == "111"


class TestGetFeaturedListingsByShop:
def test_basic_call(self, mock_session):
mock_session.make_request.return_value = Response(
Expand Down
Loading