import os, requests
from collections import defaultdict
from itertools import combinations
STORE = os.environ["SHOPIFY_STORE"]
TOKEN = os.environ["SHOPIFY_ACCESS_TOKEN"]
MV = os.environ["MAVERA_API_KEY"]
SH = f"https://{STORE}.myshopify.com/admin/api/2024-10/graphql.json"
SH_H = {"X-Shopify-Access-Token": TOKEN, "Content-Type": "application/json"}
MB = "https://app.mavera.io/api/v1"
MH = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}
QUERY = """query ($cursor: String) {
orders(first: 250, after: $cursor) {
edges { node { lineItems(first: 20) { edges { node { title originalUnitPriceSet { shopMoney { amount } } } } } } }
pageInfo { hasNextPage endCursor }
}
}"""
orders, cursor = [], None
while True:
resp = requests.post(SH, json={"query": QUERY, "variables": {"cursor": cursor} if cursor else {}}, headers=SH_H)
resp.raise_for_status(); data = resp.json()["data"]["orders"]
for e in data["edges"]:
items = [li["node"] for li in e["node"]["lineItems"]["edges"]]
if len(items) >= 2: orders.append(items)
if not data["pageInfo"]["hasNextPage"]: break
cursor = data["pageInfo"]["endCursor"]
print(f"Analyzed {len(orders)} multi-item orders")
counts, prices = defaultdict(int), defaultdict(list)
for items in orders:
titles = sorted(set(i["title"] for i in items))
pm = {i["title"]: float(i["originalUnitPriceSet"]["shopMoney"]["amount"]) for i in items}
for a, b in combinations(titles, 2):
counts[(a, b)] += 1
prices[(a, b)].append(pm.get(a, 0) + pm.get(b, 0))
bundles = [{"products": list(p), "count": c, "bundle_price": round(sum(prices[p])/len(prices[p])*0.9, 2)}
for p, c in sorted(counts.items(), key=lambda x: -x[1])[:10] if c >= 5]
for b in bundles[:5]:
print(f" {b['products'][0]} + {b['products'][1]}: {b['count']}x → ${b['bundle_price']}")
descs = [f"Bundle {i+1}: {b['products'][0]} + {b['products'][1]} at ${b['bundle_price']} (10% off)" for i, b in enumerate(bundles[:5])]
fg = requests.post(f"{MB}/focus-groups", json={
"name": "Shopify Bundle Validation",
"questions": [f"Would you buy '{bundles[0]['products'][0]}' + '{bundles[0]['products'][1]}' at ${bundles[0]['bundle_price']}?", "Which bundle is most appealing?", "What discount makes a bundle irresistible?", "Mix-and-match or curated sets?"],
"context": "Testing bundle concepts from purchase data.\n\n" + "\n".join(descs),
}, headers=MH)
fg.raise_for_status(); result = fg.json()
print(f"\nFocus group: {result['id']}")
for r in result.get("responses", []):
print(f" Q: {r['question']}\n A: {r['answer'][:200]}\n")