Source code for parsons.shopify.shopify

from datetime import datetime, timedelta
import re

from parsons.etl.table import Table
from parsons.utilities import check_env
from parsons.utilities.api_connector import APIConnector


[docs]class Shopify(object): """ Instantiate the Shopify class `Args:` subdomain: str The Shopify subdomain (e.g. ``myorg`` for myorg.myshopify.com) Not required if ``SHOPIFY_SUBDOMAIN`` env variable set. password: str The Shopify account password. Not required if ``SHOPIFY_PASSWORD`` env variable set. api_key: str The Shopify account API key. Not required if ``SHOPIFY_API_KEY`` env variable set. api_version: str The Shopify API version. Not required if ``SHOPIFY_API_VERSION`` env variable set. access_token: str The Shopify access token. Not required if ``SHOPIFY_ACCESS_TOKEN`` env variable set. If argument or env variable is set, password and api_key are ignored. `Returns:` Shopify Class """ def __init__( self, subdomain=None, password=None, api_key=None, api_version=None, access_token=None, ): self.subdomain = check_env.check("SHOPIFY_SUBDOMAIN", subdomain) self.access_token = check_env.check("SHOPIFY_ACCESS_TOKEN", access_token, optional=True) self.password = check_env.check("SHOPIFY_PASSWORD", password, optional=True) self.api_key = check_env.check("SHOPIFY_API_KEY", api_key, optional=True) self.api_version = check_env.check("SHOPIFY_API_VERSION", api_version) self.base_url = "https://%s.myshopify.com/admin/api/%s/" % ( self.subdomain, self.api_version, ) if self.access_token is None and (self.password is None or self.api_key is None): raise KeyError("Must set either access_token or both api_key and password.") if self.access_token is not None: self.client = APIConnector( self.base_url, headers={"X-Shopify-Access-Token": access_token} ) else: self.client = APIConnector(self.base_url, auth=(self.api_key, self.password))
[docs] def get_count(self, query_date=None, since_id=None, table_name=None): """ Get the count of rows in a table. `Args:` query_date: str Filter query by a date that rows were created. This filter is ignored if value is None. since_id: str Filter query by a minimum ID. This filter is ignored if value is None. table_name: str The name of the Shopify table to query. `Returns:` int """ return ( self.client.request(self.get_query_url(query_date, since_id, table_name), "GET") .json() .get("count", 0) )
[docs] def get_orders(self, query_date=None, since_id=None, completed=True): """ Get Shopify orders. `Args:` query_date: str Filter query by a date that rows were created. Format: yyyy-mm-dd. This filter is ignored if value is None. since_id: str Filter query by a minimum ID. This filter is ignored if value is None. completed: bool True if only getting completed orders, False otherwise. `Returns:` Table Class """ orders = [] def _append_orders(url): nonlocal orders if completed: url += "&financial_status=paid" res = self.client.request(url, "GET") cur_orders = res.json().get("orders", []) # Flatten orders to non-complex types for order in cur_orders: keys_to_add = {} keys_to_delete = [] for key1 in order: if isinstance(order[key1], dict): for key2 in order[key1]: keys_to_add[key1 + "_" + key2] = order[key1][key2] keys_to_delete.append(key1) elif key1 == "note_attributes": for note in order[key1]: keys_to_add[key1 + "_" + note["name"]] = note["value"] order.update(keys_to_add) for key in keys_to_delete: del order[key] orders += cur_orders return res res = _append_orders(self.get_query_url(query_date, since_id, "orders", False)) # Get next page while res.headers.get("Link"): link = re.split("; |, ", res.headers.get("Link")) if len(link) and link[len(link) - 1] == 'rel="next"': res = _append_orders(link[len(link) - 2][1:-1]) else: break return Table(orders)
[docs] def get_query_url(self, query_date=None, since_id=None, table_name=None, count=True): """ Get the URL of a Shopify API request `Args:` query_date: str Filter query by a date that rows were created. Format: yyyy-mm-dd. This filter is ignored if value is None. since_id: str Filter query by a minimum ID. This filter is ignored if value is None. table_name: str The name of the Shopify table to query. count: bool True if refund should be included in Table, False otherwise. `Returns:` str """ filters = "limit=250&status=any" if count: table = table_name + "/count.json" else: table = table_name + ".json" if query_date: # Specific date if provided query_date = datetime.strptime(query_date, "%Y-%m-%d") max_date = query_date + timedelta(days=1) filters += "&created_at_min={}&created_at_max={}".format( query_date.isoformat(), max_date.isoformat() ) elif since_id: # Since ID if provided filters += "&since_id=%s" % since_id return self.base_url + "%s?%s" % (table, filters)
[docs] def graphql(self, query): """ Make GraphQL request. Reference: https://shopify.dev/api/admin-graphql `Args:` query: str GraphQL query. `Returns:` dict """ return ( self.client.request(self.base_url + "graphql.json", "POST", json={"query": query}) .json() .get("data") )
[docs] @classmethod def load_to_table( cls, subdomain=None, password=None, api_key=None, api_version=None, query_date=None, since_id=None, completed=True, ): """ Fast classmethod so you can get the data all at once: tabledata = Shopify.load_to_table(subdomain='myorg', password='abc123', api_key='abc123', api_version='2020-10', query_date='2020-10-20', since_id='8414', completed=True) This instantiates the class and makes the appropriate query type to Shopify's orders table based on which arguments are supplied. `Args:` subdomain: str The Shopify subdomain (e.g. ``myorg`` for myorg.myshopify.com). password: str The Shopify account password. api_key: str The Shopify account API key. api_version: str The Shopify API version. query_date: str Filter query by a date that rows were created. Format: yyyy-mm-dd. This filter is ignored if value is None. since_id: str Filter query by a minimum ID. This filter is ignored if value is None. completed: bool True if only getting completed orders, False otherwise. value as value `Returns:` Table Class """ return cls(subdomain, password, api_key, api_version).get_orders( query_date, since_id, completed )