-
Notifications
You must be signed in to change notification settings - Fork 0
/
bigcommerce-products.py
386 lines (365 loc) · 15.1 KB
/
bigcommerce-products.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
# ---
# name: bigcommerce-products
# deployed: true
# config: index
# title: BigCommerce Products
# description: Returns a list of products for a BigCommerce Store
# params:
# - name: properties
# type: array
# description: The properties to return, given as a string or array; defaults to all properties; see "Returns" for available properties
# required: false
# - name: filter
# type: array
# description: Search query to determine the rows to return, given as a string or array
# required: false
# returns:
# - name: id
# type: integer
# description: ID of the product
# - name: name
# type: string
# description: The product name
# - name: type
# type: string
# description: The product type
# - name: sku
# type: string
# description: User defined product code/stock keeping unit (SKU)
# - name: description
# type: string
# description: The product description, which can include HTML formatting
# - name: weight
# type: number
# description: Weight of the product, which can be used when calculating shipping costs
# - name: width
# type: number
# description: Width of the product, which can be used when calculating shipping costs
# - name: depth
# type: number
# description: Depth of the product, which can be used when calculating shipping costs
# - name: height
# type: number
# description: Height of the product, which can be used when calculating shipping costs
# - name: price
# type: number
# description: The price of the product
# - name: cost_price
# type: number
# description: The cost price of the product
# - name: retail_price
# type: number
# description: The retail cost of the product
# - name: sale_price
# type: number
# description: If entered, the sale price will be used instead of value in the price field when calculating the product’s cost
# - name: map_price
# type: number
# description: Minimum advertised price
# - name: calculated_price
# type: number
# description: The price of the product as seen on the storefront
# - name: tax_class_id
# type: integer
# description: The ID of the tax class applied to the product
# - name: product_tax_code
# type: string
# description: AvaTax System tax codes
# - name: categories
# type: string
# description: An comma-delimited list of IDs for the categories to which this product belongs
# - name: brand_id
# type: integer
# description: The brand id
# - name: option_set_id
# type: integer
# description: Indicates that the product is in an Option Set (legacy V2 concept)
# - name: option_set_display
# type: string
# description: Legacy template setting which controls if the option set shows up to the side of or below the product image and description
# - name: inventory_level
# type: integer
# description: Current inventory level of the product
# - name: inventory_warning_level
# type: integer
# description: Inventory warning level for the product
# - name: inventory_tracking
# type: string
# description: The type of inventory tracking for the product
# - name: reviews_rating_sum
# type: integer
# description: The total rating for the product
# - name: reviews_count
# type: integer
# description: The number of times the product has been rated
# - name: view_count
# type: integer
# description: The number of times the product has been viewed
# - name: total_sold
# type: integer
# description: The total quantity of this product sold
# - name: fixed_cost_shipping_price
# type: number
# description: A fixed shipping cost for the product
# - name: is_free_shipping
# type: boolean
# description: Flag used to indicate whether the product has free shipping
# - name: is_visible
# type: boolean
# description: Flag to determine whether the product should be displayed to customers browsing the store
# - name: is_featured
# type: boolean
# description: Flag to determine whether the product should be included in the featured products panel when viewing the store
# - name: related_products
# type: string
# description: An comma-delimited list of IDs for the related products
# - name: warranty
# type: string
# description: Warranty information displayed on the product page
# - name: bin_picking_number
# type: string
# description: The BIN picking number for the product
# - name: layout_file
# type: string
# description: The layout template file used to render this product category
# - name: upc
# type: string
# description: The product UPC code, which is used in feeds for shopping comparison sites and external channel integrations
# - name: mpn
# type: string
# description: Manufacturer Part Numbe
# - name: gtin
# type: string
# description: Global Trade Item Numbe
# - name: search_keywords
# type: string
# description: A comma-separated list of keywords that can be used to locate the product when searching the store
# - name: availability
# type: string
# description: Availability of the product
# - name: availability_description
# type: string
# description: Availability text displayed on the checkout page, under the product title
# - name: gift_wrapping_options_type
# type: string
# description: Type of gift-wrapping options
# - name: gift_wrapping_options_list
# type: string
# description: A comma-delimited list of gift-wrapping option IDs
# - name: sort_order
# type: integer
# description: Priority to give this product when included in product lists on category pages and in search results
# - name: condition
# type: string
# description: The product condition
# - name: is_condition_shown
# type: boolean
# description: Flag used to determine whether the product condition is shown to the customer on the product page
# - name: order_quantity_minimum
# type: integer
# description: The minimum quantity an order must contain, to be eligible to purchase this product
# - name: order_quantity_maximum
# type: integer
# description: The maximum quantity an order can contain when purchasing the product
# - name: page_title
# type: string
# description: Custom title for the product page
# - name: meta_keywords
# type: string
# description: A comma-delimited list of custom meta keywords for the product page
# - name: meta_description
# type: string
# description: Custom meta description for the product page
# - name: preorder_release_date
# type: string
# description: Pre-order release date
# - name: preorder_message
# type: string
# description: Custom expected-date message to display on the product page
# - name: is_preorder_only
# type: boolean
# description: If set to true then on the preorder release date the preorder status will automatically be removed
# - name: is_price_hidden
# type: boolean
# description: False by default, indicating that this product’s price should be shown on the product page
# - name: price_hidden_label
# type: string
# description: If is_price_hidden is true, the value of price_hidden_label is displayed instead of the price
# - name: url
# type: string
# description: Category URL on the storefront
# - name: custom_url
# type: string
# description: The custom URL for the category on the storefront
# - name: base_variant_id
# type: integer
# description: The unique identifier of the base variant associated with a simple product
# - name: open_graph_type
# type: string
# description: Type of product, defaults to product
# - name: open_graph_title
# type: string
# description: Title of the product, if not specified the product name will be used instead
# - name: open_graph_description
# type: string
# description: Description to use for the product, if not specified then the meta_description will be used instead
# - name: open_graph_use_meta_description
# type: boolean
# description: Flag to determine if product description or open graph description is used
# - name: open_graph_use_product_name
# type: boolean
# description: Flag to determine if product name or open graph name is used
# - name: open_graph_use_image
# type: boolean
# description: Flag to determine if product image or open graph image is used
# - name: date_created
# type: string
# description: The date on which the product was created
# - name: date_modified
# type: string
# description: The date on which the product was modified
# examples:
# - '"*"'
# - '"id, name, sku, description, price"'
# - '"", "coffeemaker"'
# - '"id, sku, search_keywords, meta_keywords", "search_keywords:jar"'
# ---
import json
import urllib
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
from collections import OrderedDict
# main function entry point
def flexio_handler(flex):
flex.output.content_type = 'application/x-ndjson'
for data in get_data(flex.vars):
flex.output.write(data)
def get_data(params):
# get the api key from the variable input
store_hash = dict(params).get('bigcommerce_store_hash')
client_id = dict(params).get('bigcommerce_client_id')
access_token = dict(params).get('bigcommerce_access_token')
# example store:
# https://bigcommerce.github.io/storefront-api-examples/html-bootstrap-vanillajs/
# https://buybutton.store/shop-all/
# products api:
# https://developer.bigcommerce.com/api-reference/store-management/catalog/products/getproducts
headers = {
'X-Auth-Client': client_id,
'X-Auth-Token': access_token
}
url = 'https://api.bigcommerce.com/stores/' + store_hash + '/v3/catalog/products'
page_size = 250
page_idx = 1
while True:
url_query_params = {'limit': page_size, 'page': page_idx}
url_query_str = urllib.parse.urlencode(url_query_params)
page_url = url + '?' + url_query_str
response = requests_retry_session().get(page_url, headers=headers)
response.raise_for_status()
content = response.json()
data = content.get('data')
if len(data) == 0:
break
buffer = ''
for item in data:
item = get_item_info(item)
buffer = buffer + json.dumps(item, default=to_string) + "\n"
yield buffer
page_idx = page_idx + 1
def requests_retry_session(
retries=3,
backoff_factor=0.3,
status_forcelist=(429, 500, 502, 503, 504),
session=None,
):
session = session or requests.Session()
retry = Retry(
total=retries,
read=retries,
connect=retries,
backoff_factor=backoff_factor,
status_forcelist=status_forcelist,
)
adapter = HTTPAdapter(max_retries=retry)
session.mount('http://', adapter)
session.mount('https://', adapter)
return session
def to_string(value):
if isinstance(value, (date, datetime)):
return value.isoformat()
if isinstance(value, (Decimal)):
return str(value)
return value
def get_item_info(item):
info = OrderedDict()
info['id'] = item.get('id')
info['name'] = item.get('name')
info['type'] = item.get('type')
info['sku'] = item.get('sku')
info['description'] = item.get('description')
info['weight'] = item.get('weight')
info['width'] = item.get('width')
info['depth'] = item.get('depth')
info['height'] = item.get('height')
info['price'] = item.get('price')
info['cost_price'] = item.get('cost_price')
info['retail_price'] = item.get('retail_price')
info['sale_price'] = item.get('sale_price')
info['map_price'] = item.get('map_price')
info['calculated_price'] = item.get('calculated_price')
info['tax_class_id'] = item.get('tax_class_id')
info['product_tax_code'] = item.get('product_tax_code')
info['categories'] = ', '.join([str(i) for i in item.get('categories',[])]) # convert to comma-delimited string
info['brand_id'] = item.get('brand_id')
info['option_set_id'] = item.get('option_set_id')
info['option_set_display'] = item.get('option_set_display')
info['inventory_level'] = item.get('inventory_level')
info['inventory_warning_level'] = item.get('inventory_warning_level')
info['inventory_tracking'] = item.get('inventory_tracking')
info['reviews_rating_sum'] = item.get('reviews_rating_sum')
info['reviews_count'] = item.get('reviews_count')
info['view_count'] = item.get('view_count')
info['total_sold'] = item.get('total_sold')
info['fixed_cost_shipping_price'] = item.get('fixed_cost_shipping_price')
info['is_free_shipping'] = item.get('is_free_shipping')
info['is_visible'] = item.get('is_visible')
info['is_featured'] = item.get('is_featured')
info['related_products'] = ', '.join([str(i) for i in item.get('related_products',[])]) # convert to comma-delimited string
info['warranty'] = item.get('warranty')
info['bin_picking_number'] = item.get('bin_picking_number')
info['layout_file'] = item.get('layout_file')
info['upc'] = item.get('upc')
info['mpn'] = item.get('mpn')
info['gtin'] = item.get('gtin')
info['search_keywords'] = item.get('search_keywords')
info['availability'] = item.get('availability')
info['availability_description'] = item.get('availability_description')
info['gift_wrapping_options_type'] = item.get('gift_wrapping_options_type')
info['gift_wrapping_options_list'] = ', '.join([str(i) for i in item.get('gift_wrapping_options_list',[])]) # convert to comma-delimited string
info['sort_order'] = item.get('sort_order')
info['condition'] = item.get('condition')
info['is_condition_shown'] = item.get('is_condition_shown')
info['order_quantity_minimum'] = item.get('order_quantity_minimum')
info['order_quantity_maximum'] = item.get('order_quantity_maximum')
info['page_title'] = item.get('page_title')
info['meta_keywords'] = ', '.join([i for i in item.get('meta_keywords',[])]) # convert to comma-delimited string
info['meta_description'] = item.get('meta_description')
info['preorder_release_date'] = item.get('preorder_release_date')
info['preorder_message'] = item.get('preorder_message')
info['is_preorder_only'] = item.get('is_preorder_only')
info['is_price_hidden'] = item.get('is_price_hidden')
info['price_hidden_label'] = item.get('price_hidden_label')
info['url'] = item.get('url')
info['custom_url'] = item.get('custom_url',{}).get('url','') # get url part of object
info['base_variant_id'] = item.get('base_variant_id')
info['open_graph_type'] = item.get('open_graph_type')
info['open_graph_title'] = item.get('open_graph_title')
info['open_graph_description'] = item.get('open_graph_description')
info['open_graph_use_meta_description'] = item.get('open_graph_use_meta_description')
info['open_graph_use_product_name'] = item.get('open_graph_use_product_name')
info['open_graph_use_image'] = item.get('open_graph_use_image')
info['date_created'] = item.get('date_created')
info['date_modified'] = item.get('date_modified')
return info