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
1 change: 1 addition & 0 deletions etsy_python/v3/enums/Listing.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class Includes(Enum):
INVENTORY = "Inventory"
VIDEOS = "Videos"
PERSONALIZATION = "Personalization"
BUYER_PRICE = "BuyerPrice"


class InventoryIncludes(Enum):
Expand Down
8 changes: 8 additions & 0 deletions etsy_python/v3/resources/Listing.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ def find_all_listings_active(
shop_location: Optional[str] = None,
is_safe: Optional[bool] = None,
legacy: Optional[bool] = None,
buyer_country: Optional[str] = None,
currency: Optional[str] = None,
) -> Union[Response, RequestException]:
endpoint = "/listings/active"
query_params: Dict[str, Any] = {
Expand All @@ -106,6 +108,8 @@ def find_all_listings_active(
"shop_location": shop_location,
"is_safe": is_safe,
"legacy": legacy,
"buyer_country": buyer_country,
"currency": currency,
}
return self.session.make_request(endpoint, query_params=query_params)

Expand Down Expand Up @@ -135,6 +139,8 @@ def get_listings_by_listing_ids(
listing_ids: List[int],
includes: Optional[List[Includes]] = None,
legacy: Optional[bool] = None,
buyer_country: Optional[str] = None,
currency: Optional[str] = None,
) -> Union[Response, RequestException]:
endpoint = "/listings/batch"
query_params: Dict[str, Any] = {
Expand All @@ -143,6 +149,8 @@ def get_listings_by_listing_ids(
if includes is not None
else None,
"legacy": legacy,
"buyer_country": buyer_country,
"currency": currency,
}
return self.session.make_request(endpoint, query_params=query_params)

Expand Down
171 changes: 150 additions & 21 deletions specs/baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,8 @@
"Translations",
"Inventory",
"Videos",
"Personalization"
"Personalization",
"BuyerPrice"
]
},
"default": null
Expand Down Expand Up @@ -961,7 +962,8 @@
"Translations",
"Inventory",
"Videos",
"Personalization"
"Personalization",
"BuyerPrice"
]
},
"default": null
Expand Down Expand Up @@ -1657,6 +1659,29 @@
"type": "boolean",
"description": "When true, filters out mature/adult content from search results."
}
},
{
"name": "currency",
"in": "query",
"description": "The ISO 4217 alphabetic currency code (e.g., EUR, MXN) for price conversion. If provided, the listing price will be converted to this currency.",
"required": false,
"schema": {
"type": "string",
"description": "The ISO 4217 alphabetic currency code (e.g., EUR, MXN) for price conversion. If provided, the listing price will be converted to this currency.",
"default": null
}
},
{
"name": "buyer_country",
"in": "query",
"description": "The ISO 3166-1 alpha-2 country code (e.g., DE, MX). Filters results to listings that ship to this country.",
"required": false,
"schema": {
"type": "string",
"description": "The ISO 3166-1 alpha-2 country code (e.g., DE, MX). Filters results to listings that ship to this country.",
"format": "ISO 3166-1 alpha-2",
"default": null
}
}
],
"responses": {
Expand Down Expand Up @@ -2884,7 +2909,8 @@
"Translations",
"Inventory",
"Videos",
"Personalization"
"Personalization",
"BuyerPrice"
]
},
"default": null
Expand All @@ -2899,6 +2925,29 @@
"type": "boolean",
"description": "This parameter needed to enable new parameters and response values related to processing profiles."
}
},
{
"name": "currency",
"in": "query",
"description": "The ISO 4217 alphabetic currency code (e.g., EUR, MXN) for price conversion. If provided, the listing price will be converted to this currency.",
"required": false,
"schema": {
"type": "string",
"description": "The ISO 4217 alphabetic currency code (e.g., EUR, MXN) for price conversion. If provided, the listing price will be converted to this currency.",
"default": null
}
},
{
"name": "buyer_country",
"in": "query",
"description": "The ISO 3166-1 alpha-2 country code (e.g., GB, DE). Used for buyer-facing price calculations (VAT, inclusive shipping). Does not filter listings.",
"required": false,
"schema": {
"type": "string",
"description": "The ISO 3166-1 alpha-2 country code (e.g., GB, DE). Used for buyer-facing price calculations (VAT, inclusive shipping). Does not filter listings.",
"format": "ISO 3166-1 alpha-2",
"default": null
}
}
],
"responses": {
Expand Down Expand Up @@ -8188,15 +8237,7 @@
}
}
}
},
"security": [
{
"api_key": [],
"oauth2": [
"shops_r"
]
}
]
}
}
},
"/v3/application/shops/{shop_id}/policies/return/{return_policy_id}": {
Expand Down Expand Up @@ -8369,15 +8410,7 @@
}
}
}
},
"security": [
{
"api_key": [],
"oauth2": [
"shops_r"
]
}
]
}
},
"put": {
"operationId": "updateShopReturnPolicy",
Expand Down Expand Up @@ -12941,6 +12974,15 @@
}
]
},
"converted_price": {
"description": "The listing price converted to the currency requested via the currency parameter. Only present when the currency parameter is provided. Null if the conversion rate is unavailable.",
"oneOf": [
{
"$ref": "#/components/schemas/Money"
}
],
"nullable": true
},
"taxonomy_id": {
"type": "integer",
"description": "The numerical taxonomy ID of the listing. See [SellerTaxonomy](/documentation/reference#tag/SellerTaxonomy) and [BuyerTaxonomy](/documentation/reference#tag/BuyerTaxonomy) for more information.",
Expand Down Expand Up @@ -13388,6 +13430,15 @@
}
]
},
"converted_price": {
"description": "The listing price converted to the currency requested via the currency parameter. Only present when the currency parameter is provided. Null if the conversion rate is unavailable.",
"oneOf": [
{
"$ref": "#/components/schemas/Money"
}
],
"nullable": true
},
"taxonomy_id": {
"type": "integer",
"description": "The numerical taxonomy ID of the listing. See [SellerTaxonomy](/documentation/reference#tag/SellerTaxonomy) and [BuyerTaxonomy](/documentation/reference#tag/BuyerTaxonomy) for more information.",
Expand Down Expand Up @@ -13504,6 +13555,15 @@
}
],
"nullable": true
},
"buyer_price": {
"description": "The buyer-facing price for a listing, including VAT, inclusive shipping (UK), and active promotions. Requires buyer_country parameter. Shows base_price, shipping_cost, original_price (display price), and discounted_price if a promotion is active. Currently only supported on the /listings/batch endpoint.",
"oneOf": [
{
"$ref": "#/components/schemas/ListingBuyerPrice"
}
],
"nullable": true
}
}
},
Expand Down Expand Up @@ -14581,6 +14641,75 @@
}
}
},
"ListingBuyerPrice": {
"type": "object",
"x-resource-id": "ListingBuyerPrice",
"description": "The buyer-facing price for a listing, including VAT, inclusive shipping (UK), and active promotions.",
"properties": {
"base_price": {
"description": "The pre-discount listing price with VAT applied, excluding shipping. When a promotion is active, this is the price before the discount is applied.",
"oneOf": [
{
"$ref": "#/components/schemas/Money"
}
]
},
"shipping_cost": {
"description": "The shipping cost with VAT applied. Only present for UK buyers.",
"oneOf": [
{
"$ref": "#/components/schemas/Money"
}
],
"nullable": true
},
"original_price": {
"description": "The all-in display price (base + shipping for UK). This is the price to show to the buyer.",
"oneOf": [
{
"$ref": "#/components/schemas/Money"
}
]
},
"discounted_price": {
"description": "The sale price (all-in). Null if no active promotion.",
"oneOf": [
{
"$ref": "#/components/schemas/Money"
}
],
"nullable": true
},
"discount_amount": {
"description": "The discount amount as money (original_price - discounted_price). Null if no active promotion.",
"oneOf": [
{
"$ref": "#/components/schemas/Money"
}
],
"nullable": true
},
"discount_percentage": {
"type": "integer",
"description": "The discount percentage (e.g. 20 for 20% off). Null if no active promotion or if the promotion is a fixed-amount discount.",
"nullable": true
},
"has_discount": {
"type": "boolean",
"description": "Whether an active promotion applies to this listing."
},
"discount_start_epoch": {
"type": "integer",
"description": "The start timestamp of the active promotion. Null if no active promotion.",
"nullable": true
},
"discount_end_epoch": {
"type": "integer",
"description": "The end timestamp of the active promotion. Null if no active promotion.",
"nullable": true
}
}
},
"ListingImages": {
"type": "object",
"x-resource-id": "ListingImages",
Expand Down
50 changes: 50 additions & 0 deletions tests/test_listing_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,30 @@ def test_is_safe_defaults_to_none(self, mock_session):
qp = mock_session.make_request.call_args[1]["query_params"]
assert qp["is_safe"] is None

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

resource.find_all_listings_active(buyer_country="DE", currency="EUR")

qp = mock_session.make_request.call_args[1]["query_params"]
assert qp["buyer_country"] == "DE"
assert qp["currency"] == "EUR"

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

resource.find_all_listings_active()

qp = mock_session.make_request.call_args[1]["query_params"]
assert qp["buyer_country"] is None
assert qp["currency"] is None


class TestFindAllActiveListingsByShop:
def test_basic_call(self, mock_session):
Expand Down Expand Up @@ -234,6 +258,32 @@ def test_legacy_defaults_to_none(self, mock_session):
qp = mock_session.make_request.call_args[1]["query_params"]
assert qp["legacy"] is None

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

resource.get_listings_by_listing_ids(
[111, 222], buyer_country="GB", currency="GBP"
)

qp = mock_session.make_request.call_args[1]["query_params"]
assert qp["buyer_country"] == "GB"
assert qp["currency"] == "GBP"

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

resource.get_listings_by_listing_ids([111])

qp = mock_session.make_request.call_args[1]["query_params"]
assert qp["buyer_country"] is None
assert qp["currency"] is None


class TestGetListingsByListingsIds:
def test_listing_ids_joined(self, mock_session):
Expand Down
Loading