import requests import xmlrpc.client from collections import defaultdict ODOO_URL = 'http://localhost:16001' ODOO_DB = 'hazard_new' ODOO_USER = 'admin' ODOO_PASS = 'admin' def get_shopify_credentials(): common = xmlrpc.client.ServerProxy(f'{ODOO_URL}/xmlrpc/2/common') uid = common.authenticate(ODOO_DB, ODOO_USER, ODOO_PASS, {}) models = xmlrpc.client.ServerProxy(f'{ODOO_URL}/xmlrpc/2/object') config_ids = models.execute_kw(ODOO_DB, uid, ODOO_PASS, 'shopify.config', 'search', [[]]) config = models.execute_kw(ODOO_DB, uid, ODOO_PASS, 'shopify.config', 'read', [config_ids[0]], {'fields': ['shop_url', 'access_token']})[0] return config.get('shop_url'), config.get('access_token') def get_collection_products(shop_url, access_token, collection_id): query = """ query getProducts($id: ID!, $cursor: String) { collection(id: $id) { products(first: 250, after: $cursor) { pageInfo { hasNextPage endCursor } edges { node { legacyResourceId } } } } } """ url = f"https://{shop_url}/admin/api/2023-10/graphql.json" headers = { 'X-Shopify-Access-Token': access_token, 'Content-Type': 'application/json', } product_ids = set() cursor = None has_next_page = True while has_next_page: variables = {"id": f"gid://shopify/Collection/{collection_id}"} if cursor: variables["cursor"] = cursor resp = requests.post(url, headers=headers, json={'query': query, 'variables': variables}) data = resp.json().get('data', {}).get('collection', {}).get('products', {}) if not data: break for edge in data.get('edges', []): product_ids.add(str(edge['node']['legacyResourceId'])) page_info = data.get('pageInfo', {}) has_next_page = page_info.get('hasNextPage', False) cursor = page_info.get('endCursor') return product_ids def get_may_orders(shop_url, access_token): url = f"https://{shop_url}/admin/api/2023-10/orders.json" headers = { 'X-Shopify-Access-Token': access_token, 'Content-Type': 'application/json', } params = { 'status': 'any', 'created_at_min': '2026-05-01T00:00:00-06:00', 'created_at_max': '2026-05-31T23:59:59-06:00', 'limit': 250 } orders = [] while url: resp = requests.get(url, headers=headers, params=params) if resp.status_code != 200: break data = resp.json() orders.extend(data.get('orders', [])) link_header = resp.headers.get('Link') url = None params = None if link_header: links = link_header.split(',') for link in links: if 'rel="next"' in link: url = link[link.find('<')+1 : link.find('>')] break return orders def main(): shop_url, access_token = get_shopify_credentials() padel_products = get_collection_products(shop_url, access_token, '487990952129') orders = get_may_orders(shop_url, access_token) sales_by_channel = defaultdict(float) items_by_channel = defaultdict(int) total_sales = 0.0 total_items = 0 for order in orders: if order.get('cancelled_at'): continue source = order.get('source_name', 'Unknown') # calculate refunds for padel products refunds_for_product = defaultdict(float) refunded_qty_for_product = defaultdict(int) for refund in order.get('refunds', []): for refund_line_item in refund.get('refund_line_items', []): line_item = refund_line_item.get('line_item', {}) product_id = str(line_item.get('product_id')) if product_id in padel_products: refunds_for_product[line_item.get('id')] += float(refund_line_item.get('subtotal', 0)) refunded_qty_for_product[line_item.get('id')] += int(refund_line_item.get('quantity', 0)) for item in order.get('line_items', []): product_id = str(item.get('product_id')) if product_id in padel_products: price = float(item.get('price', 0)) quantity = int(item.get('quantity', 0)) discount = 0.0 for d in item.get('discount_allocations', []): discount += float(d.get('amount', 0)) net_sale = (price * quantity) - discount # subtract refund for this line item line_item_id = item.get('id') if line_item_id in refunds_for_product: net_sale -= refunds_for_product[line_item_id] quantity -= refunded_qty_for_product[line_item_id] sales_by_channel[source] += net_sale items_by_channel[source] += quantity total_sales += net_sale total_items += quantity for channel in sales_by_channel: print(f"{channel}: {sales_by_channel[channel]}") if __name__ == '__main__': main()