python-amazon-sp-api 1.9.18__py3-none-any.whl → 2.0.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. {python_amazon_sp_api-1.9.18.data → python_amazon_sp_api-2.0.7.data}/scripts/make_endpoint +2 -2
  2. {python_amazon_sp_api-1.9.18.dist-info → python_amazon_sp_api-2.0.7.dist-info}/METADATA +46 -23
  3. python_amazon_sp_api-2.0.7.dist-info/RECORD +251 -0
  4. {python_amazon_sp_api-1.9.18.dist-info → python_amazon_sp_api-2.0.7.dist-info}/WHEEL +1 -1
  5. {python_amazon_sp_api-1.9.18.dist-info → python_amazon_sp_api-2.0.7.dist-info}/top_level.txt +0 -1
  6. sp_api/__version__.py +1 -1
  7. sp_api/api/__init__.py +18 -1
  8. sp_api/api/application_integrations/application_integrations.py +118 -0
  9. sp_api/api/application_management/application_management.py +2 -1
  10. sp_api/api/catalog/catalog.py +3 -4
  11. sp_api/api/catalog_items/catalog_items.py +3 -6
  12. sp_api/api/customer_feedback/customer_feedback.py +110 -0
  13. sp_api/api/data_kiosk/data_kiosk.py +5 -6
  14. sp_api/api/easy_ship/easy_ship.py +190 -0
  15. sp_api/api/external_fulfillment/external_fulfillment.py +706 -0
  16. sp_api/api/feeds/feeds.py +11 -8
  17. sp_api/api/finances/finances.py +30 -4
  18. sp_api/api/fulfillment_inbound/fulfillment_inbound.py +35 -2
  19. sp_api/api/inventories/inventories.py +2 -7
  20. sp_api/api/listings_items/listings_items.py +3 -24
  21. sp_api/api/messaging/messaging.py +42 -0
  22. sp_api/api/orders/orders.py +7 -0
  23. sp_api/api/product_fees/product_fees.py +31 -74
  24. sp_api/api/products/products.py +80 -2
  25. sp_api/api/products/products_definitions.py +11 -85
  26. sp_api/api/reports/reports.py +65 -97
  27. sp_api/api/sales/sales.py +2 -2
  28. sp_api/asyncio/api/__init__.py +164 -0
  29. sp_api/asyncio/api/amazon_warehousing_and_distribu/__init__.py +9 -0
  30. sp_api/asyncio/api/amazon_warehousing_and_distribu/amazon_warehousing_and_distribu.py +130 -0
  31. sp_api/asyncio/api/aplus_content/__init__.py +5 -0
  32. sp_api/asyncio/api/aplus_content/aplus_content.py +330 -0
  33. sp_api/asyncio/api/application_integrations/__init__.py +5 -0
  34. sp_api/asyncio/api/application_integrations/application_integrations.py +119 -0
  35. sp_api/asyncio/api/application_management/__init__.py +5 -0
  36. sp_api/asyncio/api/application_management/application_management.py +36 -0
  37. sp_api/asyncio/api/authorization/__init__.py +5 -0
  38. sp_api/asyncio/api/authorization/authorization.py +54 -0
  39. sp_api/asyncio/api/catalog/__init__.py +5 -0
  40. sp_api/asyncio/api/catalog/catalog.py +111 -0
  41. sp_api/asyncio/api/catalog_items/__init__.py +6 -0
  42. sp_api/asyncio/api/catalog_items/catalog_items.py +93 -0
  43. sp_api/asyncio/api/clients/__init__.py +1 -0
  44. sp_api/asyncio/api/customer_feedback/__init__.py +5 -0
  45. sp_api/asyncio/api/customer_feedback/customer_feedback.py +111 -0
  46. sp_api/asyncio/api/data_kiosk/__init__.py +5 -0
  47. sp_api/asyncio/api/data_kiosk/data_kiosk.py +236 -0
  48. sp_api/asyncio/api/easy_ship/__init__.py +5 -0
  49. sp_api/asyncio/api/easy_ship/easy_ship.py +191 -0
  50. sp_api/asyncio/api/external_fulfillment/__init__.py +5 -0
  51. sp_api/asyncio/api/external_fulfillment/external_fulfillment.py +706 -0
  52. sp_api/asyncio/api/fba_inbound_eligibility/__init__.py +5 -0
  53. sp_api/asyncio/api/fba_inbound_eligibility/fba_inbound_eligibility.py +96 -0
  54. sp_api/asyncio/api/fba_small_and_light/__init__.py +5 -0
  55. sp_api/asyncio/api/fba_small_and_light/fba_small_and_light.py +213 -0
  56. sp_api/asyncio/api/feeds/feeds.py +260 -0
  57. sp_api/asyncio/api/finances/finances.py +100 -0
  58. sp_api/asyncio/api/fulfillment_inbound/fulfillment_inbound.py +1798 -0
  59. sp_api/asyncio/api/fulfillment_outbound/fulfillment_outbound.py +736 -0
  60. sp_api/asyncio/api/inventories/inventories.py +74 -0
  61. sp_api/asyncio/api/listings_items/__init__.py +0 -0
  62. sp_api/asyncio/api/listings_items/listings_items.py +170 -0
  63. sp_api/asyncio/api/listings_restrictions/__init__.py +0 -0
  64. sp_api/asyncio/api/listings_restrictions/listings_restrictions.py +36 -0
  65. sp_api/asyncio/api/merchant_fulfillment/__init__.py +0 -0
  66. sp_api/asyncio/api/merchant_fulfillment/merchant_fulfillment.py +384 -0
  67. sp_api/asyncio/api/messaging/__init__.py +0 -0
  68. sp_api/asyncio/api/messaging/messaging.py +511 -0
  69. sp_api/asyncio/api/models/__init__.py +4 -0
  70. sp_api/asyncio/api/notifications/__init__.py +0 -0
  71. sp_api/asyncio/api/notifications/notifications.py +295 -0
  72. sp_api/asyncio/api/orders/__init__.py +0 -0
  73. sp_api/asyncio/api/orders/orders.py +362 -0
  74. sp_api/asyncio/api/overrides/__init__.py +1 -0
  75. sp_api/asyncio/api/product_fees/__init__.py +0 -0
  76. sp_api/asyncio/api/product_fees/product_fees.py +194 -0
  77. sp_api/asyncio/api/product_type_definitions/__init__.py +0 -0
  78. sp_api/asyncio/api/product_type_definitions/product_type_definitions.py +75 -0
  79. sp_api/asyncio/api/products/__init__.py +0 -0
  80. sp_api/asyncio/api/products/products.py +405 -0
  81. sp_api/asyncio/api/products/products_definitions.py +11 -0
  82. sp_api/asyncio/api/replenishment/__init__.py +0 -0
  83. sp_api/asyncio/api/replenishment/replenishment.py +121 -0
  84. sp_api/asyncio/api/reports/__init__.py +0 -0
  85. sp_api/asyncio/api/reports/reports.py +439 -0
  86. sp_api/asyncio/api/sales/__init__.py +0 -0
  87. sp_api/asyncio/api/sales/sales.py +93 -0
  88. sp_api/asyncio/api/sellers/__init__.py +0 -0
  89. sp_api/asyncio/api/sellers/sellers.py +70 -0
  90. sp_api/asyncio/api/services/__init__.py +0 -0
  91. sp_api/asyncio/api/services/services.py +218 -0
  92. sp_api/asyncio/api/shipping/__init__.py +0 -0
  93. sp_api/asyncio/api/shipping/shipping.py +459 -0
  94. sp_api/asyncio/api/shipping/shippingV2.py +651 -0
  95. sp_api/asyncio/api/solicitations/__init__.py +0 -0
  96. sp_api/asyncio/api/solicitations/solicitations.py +78 -0
  97. sp_api/asyncio/api/supply_sources/__init__.py +0 -0
  98. sp_api/asyncio/api/supply_sources/supply_sources.py +138 -0
  99. sp_api/asyncio/api/tokens/__init__.py +0 -0
  100. sp_api/asyncio/api/tokens/tokens.py +65 -0
  101. sp_api/asyncio/api/upload/__init__.py +0 -0
  102. sp_api/asyncio/api/upload/upload.py +18 -0
  103. sp_api/asyncio/api/vendor_direct_fulfillment_inventory/__init__.py +0 -0
  104. sp_api/asyncio/api/vendor_direct_fulfillment_inventory/vendor_direct_fulfillment_inventory.py +64 -0
  105. sp_api/asyncio/api/vendor_direct_fulfillment_orders/__init__.py +0 -0
  106. sp_api/asyncio/api/vendor_direct_fulfillment_orders/vendor_direct_fulfillment_orders.py +196 -0
  107. sp_api/asyncio/api/vendor_direct_fulfillment_payments/__init__.py +0 -0
  108. sp_api/asyncio/api/vendor_direct_fulfillment_payments/vendor_direct_fulfillment_payments.py +254 -0
  109. sp_api/asyncio/api/vendor_direct_fulfillment_shipping/__init__.py +0 -0
  110. sp_api/asyncio/api/vendor_direct_fulfillment_shipping/vendor_direct_fulfillment_shipping.py +627 -0
  111. sp_api/asyncio/api/vendor_direct_fulfillment_transactions/__init__.py +0 -0
  112. sp_api/asyncio/api/vendor_direct_fulfillment_transactions/vendor_direct_fulfillment_transactions.py +43 -0
  113. sp_api/asyncio/api/vendor_invoices/__init__.py +0 -0
  114. sp_api/asyncio/api/vendor_invoices/vendor_invoices.py +295 -0
  115. sp_api/asyncio/api/vendor_orders/__init__.py +0 -0
  116. sp_api/asyncio/api/vendor_orders/vendor_orders.py +210 -0
  117. sp_api/asyncio/api/vendor_shipments/__init__.py +0 -0
  118. sp_api/asyncio/api/vendor_shipments/vendor_shipments.py +118 -0
  119. sp_api/asyncio/api/vendor_transaction_status/__init__.py +0 -0
  120. sp_api/asyncio/api/vendor_transaction_status/vendor_transaction_status.py +41 -0
  121. sp_api/asyncio/auth/__init__.py +12 -0
  122. sp_api/asyncio/auth/access_token_client.py +145 -0
  123. sp_api/asyncio/auth/exceptions.py +5 -0
  124. sp_api/asyncio/base/__init__.py +53 -0
  125. sp_api/asyncio/base/_transport_httpx.py +50 -0
  126. sp_api/asyncio/base/base_client.py +8 -0
  127. sp_api/asyncio/base/client.py +169 -0
  128. sp_api/asyncio/util/__init__.py +29 -0
  129. sp_api/asyncio/util/key_maker.py +5 -0
  130. sp_api/asyncio/util/load_all_pages.py +55 -0
  131. sp_api/asyncio/util/load_date_bound.py +53 -0
  132. sp_api/asyncio/util/retry.py +88 -0
  133. sp_api/auth/_core.py +39 -0
  134. sp_api/auth/access_token_client.py +18 -29
  135. sp_api/base/ApiResponse.py +3 -2
  136. sp_api/base/_core.py +110 -0
  137. sp_api/base/_transport_httpx.py +39 -0
  138. sp_api/base/client.py +40 -63
  139. sp_api/base/helpers.py +1 -1
  140. sp_api/base/reportTypes.py +3 -2
  141. sp_api/util/__init__.py +36 -0
  142. sp_api/util/load_all_pages.py +2 -1
  143. sp_api/util/params.py +57 -0
  144. sp_api/util/product_fees.py +40 -0
  145. sp_api/util/products_definitions.py +169 -0
  146. sp_api/util/report_document.py +154 -0
  147. python_amazon_sp_api-1.9.18.dist-info/RECORD +0 -144
  148. tests/api/finances/test_finances.py +0 -19
  149. tests/api/notifications/test_notifications.py +0 -26
  150. tests/api/orders/test_orders.py +0 -122
  151. tests/api/product_fees/product_fees.py +0 -49
  152. tests/api/reports/test_reports.py +0 -127
  153. tests/client/test_auth.py +0 -59
  154. tests/client/test_base.py +0 -163
  155. tests/client/test_credential_provider.py +0 -45
  156. tests/client/test_helpers.py +0 -142
  157. {python_amazon_sp_api-1.9.18.dist-info → python_amazon_sp_api-2.0.7.dist-info/licenses}/LICENSE +0 -0
  158. {tests → sp_api/api/application_integrations}/__init__.py +0 -0
  159. {tests/api → sp_api/api/customer_feedback}/__init__.py +0 -0
  160. {tests/api/finances → sp_api/api/easy_ship}/__init__.py +0 -0
  161. {tests/api/notifications → sp_api/api/external_fulfillment}/__init__.py +0 -0
  162. {tests/api/orders → sp_api/asyncio}/__init__.py +0 -0
  163. {tests/api/product_fees → sp_api/asyncio/api/feeds}/__init__.py +0 -0
  164. {tests/api/reports → sp_api/asyncio/api/finances}/__init__.py +0 -0
  165. {tests/api/sellers → sp_api/asyncio/api/fulfillment_inbound}/__init__.py +0 -0
  166. {tests/client → sp_api/asyncio/api/fulfillment_outbound}/__init__.py +0 -0
  167. /tests/api/sellers/test_sellers.py → /sp_api/asyncio/api/inventories/__init__.py +0 -0
sp_api/api/feeds/feeds.py CHANGED
@@ -1,8 +1,9 @@
1
1
  import zlib
2
2
 
3
- import requests
3
+ import httpx
4
4
 
5
5
  from sp_api.base import Client, sp_endpoint, fill_query_params, ApiResponse
6
+ from sp_api.util import should_add_marketplace
6
7
 
7
8
 
8
9
  class Feeds(Client):
@@ -34,7 +35,7 @@ class Feeds(Client):
34
35
  ApiResponse:
35
36
  """
36
37
 
37
- add_marketplace = not "nextToken" in kwargs
38
+ add_marketplace = should_add_marketplace(kwargs, "nextToken")
38
39
  return self._request(
39
40
  kwargs.pop("path"), params=kwargs, add_marketplace=add_marketplace
40
41
  )
@@ -185,11 +186,12 @@ class Feeds(Client):
185
186
  upload_data = upload_data.encode("iso-8859-1")
186
187
  except AttributeError:
187
188
  pass
188
- upload = requests.put(
189
- response.payload.get("url"),
190
- data=upload_data,
191
- headers={"Content-Type": content_type},
192
- )
189
+ with httpx.Client() as client:
190
+ upload = client.put(
191
+ response.payload.get("url"),
192
+ content=upload_data,
193
+ headers={"Content-Type": content_type},
194
+ )
193
195
  if 200 <= upload.status_code < 300:
194
196
  return response
195
197
  from sp_api.base.exceptions import SellingApiException
@@ -240,7 +242,8 @@ class Feeds(Client):
240
242
  add_marketplace=False,
241
243
  )
242
244
  url = response.payload.get("url")
243
- doc_response = requests.get(url)
245
+ with httpx.Client() as client:
246
+ doc_response = client.get(url)
244
247
 
245
248
  encoding = (
246
249
  doc_response.encoding
@@ -1,10 +1,23 @@
1
+ import enum
2
+
1
3
  from sp_api.base import Client, Marketplaces, ApiResponse
2
4
  from sp_api.base import sp_endpoint, fill_query_params
3
5
 
6
+ class FinancesVersion(str, enum.Enum):
7
+ V_0 = "v0"
8
+ V_2024_06_19 = "2024-06-19"
9
+ LATEST = "2024-06-19"
10
+
4
11
 
5
12
  class Finances(Client):
13
+ version: FinancesVersion = FinancesVersion.V_0
14
+
15
+ def __init__(self, *args, **kwargs):
16
+ if "version" in kwargs:
17
+ self.version = kwargs.get("version", FinancesVersion.V_0)
18
+ super().__init__(*args, **{**kwargs, "version": self.version})
6
19
 
7
- @sp_endpoint("/finances/v0/orders/{}/financialEvents")
20
+ @sp_endpoint("/finances/<version>/orders/{}/financialEvents")
8
21
  def get_financial_events_for_order(self, order_id, **kwargs) -> ApiResponse:
9
22
  """
10
23
  get_financial_events_for_order(self, order_id, **kwargs) -> ApiResponse
@@ -25,7 +38,7 @@ class Finances(Client):
25
38
  fill_query_params(kwargs.pop("path"), order_id), params={**kwargs}
26
39
  )
27
40
 
28
- @sp_endpoint("/finances/v0/financialEvents")
41
+ @sp_endpoint("/finances/<version>/financialEvents")
29
42
  def list_financial_events(self, **kwargs) -> ApiResponse:
30
43
  """
31
44
  list_financial_events(self, **kwargs) -> ApiResponse:
@@ -39,7 +52,7 @@ class Finances(Client):
39
52
  """
40
53
  return self._request(fill_query_params(kwargs.pop("path")), params={**kwargs})
41
54
 
42
- @sp_endpoint("/finances/v0/financialEventGroups/{}/financialEvents")
55
+ @sp_endpoint("/finances/<version>/financialEventGroups/{}/financialEvents")
43
56
  def list_financial_events_by_group_id(
44
57
  self, event_group_id, **kwargs
45
58
  ) -> ApiResponse:
@@ -58,7 +71,7 @@ class Finances(Client):
58
71
  fill_query_params(kwargs.pop("path"), event_group_id), params={**kwargs}
59
72
  )
60
73
 
61
- @sp_endpoint("/finances/v0/financialEventGroups")
74
+ @sp_endpoint("/finances/<version>/financialEventGroups")
62
75
  def list_financial_event_groups(self, **kwargs) -> ApiResponse:
63
76
  """
64
77
  list_financial_event_groups(self, **kwargs) -> ApiResponse:
@@ -71,3 +84,16 @@ class Finances(Client):
71
84
 
72
85
  """
73
86
  return self._request(kwargs.pop("path"), params={**kwargs})
87
+
88
+ @sp_endpoint("/finances/<version>/transactions")
89
+ def list_transactions(self, **kwargs) -> ApiResponse:
90
+ """
91
+ list_transactions(self, **kwargs) -> ApiResponse:
92
+
93
+ Args:
94
+ **kwargs:
95
+
96
+ Returns: ApiResponse
97
+ """
98
+
99
+ return self._request(kwargs.pop("path"), params={**kwargs})
@@ -4,6 +4,7 @@ from sp_api.base import Client, Marketplaces, ApiResponse
4
4
  from sp_api.base import sp_endpoint, fill_query_params
5
5
 
6
6
  import urllib.parse
7
+ from sp_api.util import ensure_csv
7
8
 
8
9
 
9
10
  class FulfillmentInboundVersion(str, enum.Enum):
@@ -197,6 +198,39 @@ class FulfillmentInbound(Client):
197
198
  fill_query_params(kwargs.pop("path"), shipment_id), data={**data, **kwargs}
198
199
  )
199
200
 
201
+ @sp_endpoint(
202
+ "/inbound/fba/<version>/inboundPlans/{}/shipments/{}/name", method="PUT"
203
+ )
204
+ def update_shipment_name(self, inboundPlanId, shipmentId, **kwargs):
205
+ """
206
+ update_shipment_name(self, inboundPlanId, shipmentId, **kwargs) -> ApiResponse
207
+
208
+ Updates the name of an existing shipment.
209
+
210
+ **Usage Plan:**
211
+
212
+ | Rate (requests per second) | Burst |
213
+ | ---- | ---- |
214
+ | 2 | 30 |
215
+
216
+ The `x-amzn-RateLimit-Limit` response header returns the usage plan rate limits that were applied to the requested operation, when available. The table above indicates the default rate and burst values for this operation. Selling partners whose business demands require higher throughput may see higher rate and burst values than those shown here. For more information, refer to [Usage Plans and Rate Limits in the Selling Partner API](https://developer-docs.amazon.com/sp-api/docs/usage-plans-and-rate-limits-in-the-sp-api).
217
+
218
+ Args:
219
+
220
+ inboundPlanId:string | * REQUIRED Identifier to an inbound plan.
221
+
222
+ shipmentId:string | * REQUIRED Identifier to a shipment. A shipment contains the boxes and units being inbounded.
223
+
224
+ body: | * REQUIRED {'name': {'description': 'A human-readable name to update the shipment name to.'}, 'type': 'string'}
225
+
226
+ Returns:
227
+ ApiResponse:
228
+ """
229
+ return self._request(
230
+ fill_query_params(kwargs.pop("path"), inboundPlanId, shipmentId),
231
+ data=kwargs,
232
+ )
233
+
200
234
  @sp_endpoint("/fba/inbound/<version>/shipments/{}/preorder")
201
235
  def preorder(self, shipment_id, **kwargs):
202
236
  """
@@ -456,8 +490,7 @@ class FulfillmentInbound(Client):
456
490
  Returns:
457
491
  ApiResponse
458
492
  """
459
- if not isinstance(shipment_id_list, str):
460
- shipment_id_list = ",".join(shipment_id_list)
493
+ shipment_id_list = ensure_csv(shipment_id_list)
461
494
  return self.get_shipments(
462
495
  QueryType="SHIPMENT", ShipmentIdList=shipment_id_list, **kwargs
463
496
  )
@@ -1,8 +1,8 @@
1
- from collections import abc
2
1
  import urllib
3
2
 
4
3
  from sp_api.base import Client, Marketplaces, sp_endpoint, ApiResponse
5
4
  from sp_api.base.InventoryEnums import InventoryGranularity
5
+ from sp_api.util import normalize_csv_param
6
6
 
7
7
 
8
8
  class Inventories(Client):
@@ -68,11 +68,6 @@ class Inventories(Client):
68
68
  "granularityId": kwargs.get("granularityId", self.marketplace_id),
69
69
  }
70
70
  )
71
- if (
72
- "sellerSkus" in kwargs
73
- and isinstance(kwargs.get("sellerSkus"), abc.Iterable)
74
- and not isinstance(kwargs.get("sellerSkus"), str)
75
- ):
76
- kwargs.update({"sellerSkus": ",".join(kwargs.get("sellerSkus"))})
71
+ normalize_csv_param(kwargs, "sellerSkus")
77
72
 
78
73
  return self._request(kwargs.pop("path"), params=kwargs)
@@ -1,5 +1,3 @@
1
- from collections import abc
2
-
3
1
  from sp_api.base import (
4
2
  Client,
5
3
  sp_endpoint,
@@ -7,6 +5,7 @@ from sp_api.base import (
7
5
  ApiResponse,
8
6
  IncludedData,
9
7
  )
8
+ from sp_api.util import normalize_included_data
10
9
 
11
10
 
12
11
  class ListingsItems(Client):
@@ -65,17 +64,7 @@ class ListingsItems(Client):
65
64
  Returns:
66
65
  ApiResponse:
67
66
  """
68
- if (
69
- kwargs.get("includedData")
70
- and isinstance(kwargs.get("includedData"), abc.Iterable)
71
- and not isinstance(kwargs.get("includedData"), str)
72
- ):
73
- kwargs["includedData"] = ",".join(
74
- [
75
- x.value if isinstance(x, IncludedData) else x
76
- for x in kwargs["includedData"]
77
- ]
78
- )
67
+ normalize_included_data(kwargs, enum_cls=IncludedData)
79
68
 
80
69
  return self._request(
81
70
  fill_query_params(kwargs.pop("path"), sellerId, sku), params=kwargs
@@ -101,17 +90,7 @@ class ListingsItems(Client):
101
90
  Returns:
102
91
  ApiResponse:
103
92
  """
104
- if (
105
- kwargs.get("includedData")
106
- and isinstance(kwargs.get("includedData"), abc.Iterable)
107
- and not isinstance(kwargs.get("includedData"), str)
108
- ):
109
- kwargs["includedData"] = ",".join(
110
- [
111
- x.value if isinstance(x, IncludedData) else x
112
- for x in kwargs["includedData"]
113
- ]
114
- )
93
+ normalize_included_data(kwargs, enum_cls=IncludedData)
115
94
 
116
95
  return self._request(
117
96
  fill_query_params(kwargs.pop("path"), sellerId), params=kwargs
@@ -466,3 +466,45 @@ class Messaging(Client):
466
466
  "method": kwargs.pop("method"),
467
467
  },
468
468
  )
469
+
470
+ @sp_endpoint("/messaging/v1/orders/{}/messages/invoice", method="POST")
471
+ def send_invoice(self, order_id, **kwargs) -> ApiResponse:
472
+ """
473
+ send_invoice(self, order_id, **kwargs) -> ApiResponse
474
+
475
+ Sends a message providing the buyer an invoice
476
+
477
+ **Usage Plan:**
478
+
479
+ ====================================== ==============
480
+ Rate (requests per second) Burst
481
+ ====================================== ==============
482
+ 1 5
483
+ ====================================== ==============
484
+
485
+ For more information, see "Usage Plans and Rate Limits" in the Selling Partner API documentation.
486
+
487
+ Args:
488
+ order_id:string | * REQUIRED An Amazon order identifier. This specifies the order for which a message is sent.
489
+ body: {
490
+ "attachments": [
491
+ {
492
+ "uploadDestinationId": "string",
493
+ "fileName": "string"
494
+ }
495
+ ]
496
+ }
497
+
498
+
499
+ Returns:
500
+ ApiResponse:
501
+ """
502
+
503
+ return self._request(
504
+ fill_query_params(kwargs.pop("path"), order_id),
505
+ data=kwargs.pop("body"),
506
+ params={
507
+ "marketplaceIds": self.marketplace_id,
508
+ "method": kwargs.pop("method"),
509
+ },
510
+ )
@@ -1,5 +1,6 @@
1
1
  from sp_api.base import sp_endpoint, fill_query_params, ApiResponse, deprecated
2
2
  from sp_api.base import Client, Marketplaces
3
+ from sp_api.util import normalize_csv_param
3
4
 
4
5
 
5
6
  class Orders(Client):
@@ -53,6 +54,12 @@ class Orders(Client):
53
54
 
54
55
 
55
56
  """
57
+ normalize_csv_param(kwargs, "OrderStatuses")
58
+ normalize_csv_param(kwargs, "MarketplaceIds")
59
+ normalize_csv_param(kwargs, "FulfillmentChannels")
60
+ normalize_csv_param(kwargs, "PaymentMethods")
61
+ normalize_csv_param(kwargs, "AmazonOrderIds")
62
+
56
63
  if "RestrictedResources" in kwargs:
57
64
  return self._access_restricted(kwargs)
58
65
  return self._request(kwargs.pop("path"), params={**kwargs})
@@ -3,6 +3,7 @@ from urllib.parse import quote_plus
3
3
 
4
4
  from sp_api.base.helpers import sp_endpoint, fill_query_params
5
5
  from sp_api.base import Client, ApiResponse
6
+ from sp_api.util.product_fees import create_fees_body
6
7
 
7
8
 
8
9
  class ProductFees(Client):
@@ -63,15 +64,15 @@ class ProductFees(Client):
63
64
  seller_sku = quote_plus(seller_sku)
64
65
 
65
66
  kwargs.update(
66
- self._create_body(
67
- price,
68
- shipping_price,
69
- currency,
70
- is_fba,
71
- seller_sku,
72
- points,
73
- marketplace_id,
74
- optional_fulfillment_program,
67
+ create_fees_body(
68
+ price=price,
69
+ shipping_price=shipping_price,
70
+ currency=currency,
71
+ is_fba=is_fba,
72
+ identifier=seller_sku,
73
+ points=points,
74
+ marketplace_id=marketplace_id or self.marketplace_id,
75
+ optional_fulfillment_program=optional_fulfillment_program,
75
76
  )
76
77
  )
77
78
  return self._request(
@@ -124,15 +125,15 @@ class ProductFees(Client):
124
125
 
125
126
  """
126
127
  kwargs.update(
127
- self._create_body(
128
- price,
129
- shipping_price,
130
- currency,
131
- is_fba,
132
- asin,
133
- points,
134
- marketplace_id,
135
- optional_fulfillment_program,
128
+ create_fees_body(
129
+ price=price,
130
+ shipping_price=shipping_price,
131
+ currency=currency,
132
+ is_fba=is_fba,
133
+ identifier=asin,
134
+ points=points,
135
+ marketplace_id=marketplace_id or self.marketplace_id,
136
+ optional_fulfillment_program=optional_fulfillment_program,
136
137
  )
137
138
  )
138
139
  return self._request(fill_query_params(kwargs.pop("path"), asin), data=kwargs)
@@ -166,7 +167,18 @@ class ProductFees(Client):
166
167
  marketplace_id: str | Defaults to self.marketplace_id
167
168
  optional_fulfillment_program:
168
169
  """
169
- data = [dict(**self._create_body(**er)) for er in estimate_requests]
170
+ data = []
171
+ for estimate in estimate_requests:
172
+ estimate_payload = dict(estimate)
173
+ marketplace_id = estimate_payload.pop("marketplace_id", None)
174
+ data.append(
175
+ dict(
176
+ **create_fees_body(
177
+ marketplace_id=marketplace_id or self.marketplace_id,
178
+ **estimate_payload,
179
+ )
180
+ )
181
+ )
170
182
  return self._request(
171
183
  "/products/fees/v0/feesEstimate",
172
184
  data=data,
@@ -174,61 +186,6 @@ class ProductFees(Client):
174
186
  wrap_list=True,
175
187
  )
176
188
 
177
- def _create_body(
178
- self,
179
- price,
180
- shipping_price=None,
181
- currency="USD",
182
- is_fba=False,
183
- identifier=None,
184
- points: dict = None,
185
- marketplace_id: str = None,
186
- optional_fulfillment_program: str = None,
187
- id_type=None,
188
- id_value=None,
189
- ):
190
- """
191
- Create request body
192
-
193
- Args:
194
- price:
195
- shipping_price:
196
- currency:
197
- is_fba:
198
- identifier:
199
- points:
200
-
201
- Returns:
202
-
203
- """
204
- body = {
205
- "FeesEstimateRequest": {
206
- "Identifier": identifier or str(price),
207
- "PriceToEstimateFees": {
208
- "ListingPrice": {"Amount": price, "CurrencyCode": currency},
209
- "Shipping": (
210
- {"Amount": shipping_price, "CurrencyCode": currency}
211
- if shipping_price
212
- else None
213
- ),
214
- "Points": points or None,
215
- },
216
- "IsAmazonFulfilled": is_fba,
217
- "OptionalFulfillmentProgram": (
218
- optional_fulfillment_program
219
- if is_fba is True and optional_fulfillment_program
220
- else None
221
- ),
222
- "MarketplaceId": marketplace_id or self.marketplace_id,
223
- }
224
- }
225
-
226
- if id_type and id_value:
227
- body["IdType"] = id_type
228
- body["IdValue"] = id_value
229
-
230
- return body
231
-
232
189
  def _add_marketplaces(self, data):
233
190
  # MarketplaceID is a property of the body's FeesEstimateRequest for this section, and does
234
191
  # not need to be added. Additionally, Client._add_marketplaces will fail as it assumes
@@ -2,14 +2,19 @@ from typing import Optional, List, Dict, Union
2
2
 
3
3
  from sp_api.base import ApiResponse, Client, fill_query_params, sp_endpoint
4
4
  from sp_api.api.products.products_definitions import (
5
+ GetCompetitiveSummaryBatch,
6
+ GetFeaturedOfferExpectedPriceBatch,
5
7
  GetItemOffersBatchRequest,
6
8
  GetListingOffersBatchRequest,
7
9
  )
10
+ from sp_api.util import ensure_csv
8
11
 
9
12
 
10
13
  class Products(Client):
11
14
  """
12
- :link: https://github.com/amzn/selling-partner-api-docs/blob/main/references/product-pricing-api/productPricingV0.md
15
+ :links:
16
+ https://github.com/amzn/selling-partner-api-docs/blob/main/references/product-pricing-api/productPricingV0.md
17
+ https://developer-docs.amazon.com/sp-api/docs/product-pricing-api-v2022-05-01-reference
13
18
  """
14
19
 
15
20
  @sp_endpoint("/products/pricing/v0/price", method="GET")
@@ -300,11 +305,84 @@ class Products(Client):
300
305
  add_marketplace=False,
301
306
  )
302
307
 
308
+ @sp_endpoint('/batches/products/pricing/2022-05-01/offer/featuredOfferExpectedPrice', method='POST')
309
+ def get_featured_offer_expected_price_batch(self, requests_: Optional[
310
+ Union[List[Dict], GetFeaturedOfferExpectedPriceBatch]], **kwargs) -> ApiResponse:
311
+ """
312
+ get_featured_offer_expected_price_batch(self, **kwargs) -> ApiResponse
313
+
314
+ Returns the set of responses that correspond to the batched list of up to 40 requests defined in the request
315
+ body. The response for each successful (HTTP status code 200) request in the set includes the computed listing
316
+ price at or below which a seller can expect to become the featured offer (before applicable promotions).
317
+ This is called the featured offer expected price (FOEP). Featured offer is not guaranteed, because competing
318
+ offers may change, and different offers may be featured based on other factors, including fulfillment
319
+ capabilities to a specific customer. The response to an unsuccessful request includes the available error text.
320
+
321
+ **Usage Plan:**
322
+
323
+ ====================================== ==============
324
+ Rate (requests per second) Burst
325
+ ====================================== ==============
326
+ .033 1
327
+ ====================================== ==============
328
+
329
+ Args:
330
+ requests_: [dict] The request associated with the getFeaturedOfferExpectedPriceBatch API call.
331
+
332
+ Returns:
333
+ ApiResponse:
334
+ """
335
+ if isinstance(requests_, GetFeaturedOfferExpectedPriceBatch):
336
+ get_featured_offer_expected_price_batch_request = requests_.to_dict()
337
+ else:
338
+ get_featured_offer_expected_price_batch_request = {"requests": requests_}
339
+
340
+ return self._request(
341
+ kwargs.pop('path'),
342
+ data=get_featured_offer_expected_price_batch_request,
343
+ params={**kwargs},
344
+ add_marketplace=False
345
+ )
346
+
347
+ @sp_endpoint('/batches/products/pricing/2022-05-01/items/competitiveSummary', method='POST')
348
+ def get_competitive_summary_batch(self, requests_: Optional[Union[List[Dict], GetCompetitiveSummaryBatch]], **kwargs) -> ApiResponse:
349
+ """
350
+ get_competitive_summary(self, **kwargs) -> ApiResponse
351
+
352
+ Returns the competitive summary response including featured buying options for the ASIN and `marketplaceId` combination.
353
+
354
+ **Usage Plan:**
355
+
356
+ ====================================== ==============
357
+ Rate (requests per second) Burst
358
+ ====================================== ==============
359
+ .033 1
360
+ ====================================== ==============
361
+
362
+ Args:
363
+ requests_: The request associated with the getCompetitiveSummary API call.
364
+
365
+ Returns:
366
+ ApiResponse:
367
+ """
368
+ if isinstance(requests_, GetCompetitiveSummaryBatch):
369
+ get_competitive_summary_batch_request = requests_.to_dict()
370
+ else:
371
+ get_competitive_summary_batch_request = {"requests": requests_}
372
+
373
+ return self._request(
374
+ kwargs.pop('path'),
375
+ data=get_competitive_summary_batch_request,
376
+ params={**kwargs},
377
+ add_marketplace=False
378
+ )
379
+
303
380
  def _create_get_pricing_request(self, item_list, item_type, **kwargs):
381
+ items_csv = ensure_csv(item_list)
304
382
  return self._request(
305
383
  kwargs.pop("path"),
306
384
  params={
307
- **{f"{item_type}s": ",".join(item_list)},
385
+ **{f"{item_type}s": items_csv},
308
386
  "ItemType": item_type,
309
387
  **(
310
388
  {"ItemCondition": kwargs.pop("ItemCondition")}
@@ -1,85 +1,11 @@
1
- from typing import Optional, List, Dict, Union
2
- from dataclasses import dataclass, asdict
3
-
4
-
5
- @dataclass
6
- class ItemOffersRequest:
7
- """Implements definition: https://developer-docs.amazon.com/sp-api/docs/product-pricing-api-v0-reference
8
- #itemoffersrequest"""
9
-
10
- uri: str
11
- method: str
12
- MarketplaceId: str
13
- ItemCondition: str = None
14
- CustomerType: str = None
15
- headers: Dict = None
16
-
17
-
18
- @dataclass
19
- class GetItemOffersBatchRequest:
20
- """Implements definition: https://developer-docs.amazon.com/sp-api/docs/product-pricing-api-v0-reference
21
- #getitemoffersbatchrequest"""
22
-
23
- requests: Optional[List[Union[ItemOffersRequest, Dict]]] = None
24
-
25
- def __post_init__(self):
26
- self.requests = self.parse_requests(self.requests)
27
-
28
- def to_dict(self):
29
- return asdict(self)
30
-
31
- @staticmethod
32
- def parse_requests(requests) -> List[ItemOffersRequest]:
33
- parsed_requestes = []
34
-
35
- for request in requests:
36
- if isinstance(request, Dict):
37
- request = ItemOffersRequest(**request)
38
-
39
- if not isinstance(request, ItemOffersRequest):
40
- raise TypeError
41
-
42
- parsed_requestes.append(request)
43
-
44
- return parsed_requestes
45
-
46
-
47
- @dataclass
48
- class ListingOffersRequest:
49
- """Implements definition: https://developer-docs.amazon.com/sp-api/docs/product-pricing-api-v0-reference
50
- #listingoffersrequest"""
51
-
52
- uri: str
53
- MarketplaceId: str
54
- ItemCondition: str
55
- method: str = "GET"
56
- CustomerType: str = "Consumer"
57
-
58
-
59
- @dataclass
60
- class GetListingOffersBatchRequest:
61
- """Implements definition: https://developer-docs.amazon.com/sp-api/docs/product-pricing-api-v0-reference
62
- #getlistingoffersbatchrequest"""
63
-
64
- requests: Optional[List[Union[ListingOffersRequest, Dict]]] = None
65
-
66
- def __post_init__(self):
67
- self.requests = self.parse_requests(self.requests)
68
-
69
- def to_dict(self):
70
- return asdict(self)
71
-
72
- @staticmethod
73
- def parse_requests(requests) -> List[ListingOffersRequest]:
74
- parsed_requestes = []
75
-
76
- for request in requests:
77
- if isinstance(request, Dict):
78
- request = ListingOffersRequest(**request)
79
-
80
- if not isinstance(request, ListingOffersRequest):
81
- raise TypeError
82
-
83
- parsed_requestes.append(request)
84
-
85
- return parsed_requestes
1
+ from sp_api.util.products_definitions import (
2
+ CompetitiveSummaryIncludedData,
3
+ ItemOffersRequest,
4
+ GetItemOffersBatchRequest,
5
+ ListingOffersRequest,
6
+ GetListingOffersBatchRequest,
7
+ FeaturedOfferExpectedPriceRequest,
8
+ GetFeaturedOfferExpectedPriceBatch,
9
+ CompetitiveSummaryRequest,
10
+ GetCompetitiveSummaryBatch,
11
+ )