|
|
| |
| |
| |
| import gradio as gr |
| import sqlite3, os, datetime, pandas as pd, time |
| from shutil import copyfile |
|
|
| ADMIN_PIN = os.environ.get("FEVICOL_ADMIN_PIN", "FEVI-ADMIN-123") |
| OWNER_EMAIL = os.environ.get("FEVICOL_OWNER_EMAIL", "").lower() |
|
|
| DATA_DIR = os.path.join(os.path.dirname(__file__), "data") |
| os.makedirs(DATA_DIR, exist_ok=True) |
| DB_PATH = os.path.join(DATA_DIR, "fevicol_creatorhub.db") |
| LOGO_PATH = os.path.join(DATA_DIR, "logo.png") |
|
|
| DEFAULT_TAGLINE = "India’s makers, united by Fevicol." |
| DEFAULT_MISSION = "Empower customers, designers, carpenters, and dealers to collaborate and deliver quality interiors faster." |
|
|
| |
| def init_db(): |
| con = sqlite3.connect(DB_PATH); cur = con.cursor() |
| cur.execute("""CREATE TABLE IF NOT EXISTS users( |
| id INTEGER PRIMARY KEY AUTOINCREMENT, |
| email TEXT UNIQUE, password TEXT, name TEXT, role TEXT, city TEXT, is_verified INTEGER DEFAULT 0 |
| );""") |
| cur.execute("""CREATE TABLE IF NOT EXISTS products( |
| id INTEGER PRIMARY KEY AUTOINCREMENT, |
| name TEXT NOT NULL, brand TEXT, price REAL NOT NULL, description TEXT, created_at TEXT |
| );""") |
| cur.execute("""CREATE TABLE IF NOT EXISTS orders( |
| id INTEGER PRIMARY KEY AUTOINCREMENT, |
| user_id INTEGER, total REAL, address TEXT, delivery_option TEXT, delivery_fee REAL, |
| payment_method TEXT, payment_status TEXT, status TEXT, created_at TEXT |
| );""") |
| cur.execute("""CREATE TABLE IF NOT EXISTS order_items( |
| id INTEGER PRIMARY KEY AUTOINCREMENT, |
| order_id INTEGER, product_id INTEGER, product_name TEXT, unit_price REAL, qty INTEGER, subtotal REAL |
| );""") |
| cur.execute("""CREATE TABLE IF NOT EXISTS settings( |
| key TEXT PRIMARY KEY, value TEXT |
| );""") |
| con.commit(); con.close() |
|
|
| def migrate_products_table(): |
| con = sqlite3.connect(DB_PATH); cur = con.cursor() |
| cur.execute("PRAGMA table_info(products)") |
| cols = {c[1] for c in cur.fetchall()} |
| alters = [] |
| if "category" not in cols: alters.append("ADD COLUMN category TEXT") |
| if "mrp" not in cols: alters.append("ADD COLUMN mrp REAL") |
| if "sale_price" not in cols: alters.append("ADD COLUMN sale_price REAL") |
| if "unit" not in cols: alters.append("ADD COLUMN unit TEXT") |
| if "stock" not in cols: alters.append("ADD COLUMN stock INTEGER DEFAULT 0") |
| if "hsn" not in cols: alters.append("ADD COLUMN hsn TEXT") |
| if "gst" not in cols: alters.append("ADD COLUMN gst REAL") |
| if "image_path" not in cols: alters.append("ADD COLUMN image_path TEXT") |
| for stmt in alters: |
| try: cur.execute(f"ALTER TABLE products {stmt}") |
| except Exception: pass |
| con.commit(); con.close() |
|
|
| init_db(); migrate_products_table() |
|
|
| |
| def get_setting(key): |
| con = sqlite3.connect(DB_PATH); cur = con.cursor() |
| cur.execute("SELECT value FROM settings WHERE key=?", (key,)); row = cur.fetchone() |
| con.close(); return row[0] if row else None |
|
|
| def set_setting(key, val): |
| con = sqlite3.connect(DB_PATH); cur = con.cursor() |
| cur.execute("INSERT INTO settings(key,value) VALUES(?,?) ON CONFLICT(key) DO UPDATE SET value=excluded.value", (key, val)) |
| con.commit(); con.close() |
|
|
| if get_setting("tagline") is None: set_setting("tagline", DEFAULT_TAGLINE) |
| if get_setting("mission") is None: set_setting("mission", DEFAULT_MISSION) |
|
|
| |
| def get_logo_path(): |
| return LOGO_PATH if os.path.exists(LOGO_PATH) else None |
|
|
| def about_md(): |
| return f"""### Welcome to Fevicol CreatorHub |
| {get_setting("tagline") or DEFAULT_TAGLINE} |
| |
| **Mission:** {get_setting("mission") or DEFAULT_MISSION} |
| |
| **What you can do here** |
| - Browse & buy Fevicol/Pidilite products |
| - Dealers can add SKUs with images and pricing |
| - Customers can add to cart and place orders |
| - Orders are tracked in “My Orders” |
| """ |
|
|
| |
| def signup(email, password, name, role, city): |
| if not email or not password: return None, "Enter email & password." |
| con = sqlite3.connect(DB_PATH); cur = con.cursor() |
| try: |
| cur.execute("INSERT INTO users(email,password,name,role,city,is_verified) VALUES(?,?,?,?,?,0)", |
| (email.lower().strip(), password, name or "", role, city or "")) |
| con.commit() |
| user = {"id": cur.lastrowid, "email": email.lower().strip(), "name": name or "", "role": role, "city": city or "", "is_verified": 0} |
| return user, f"Account created for {email}." |
| except sqlite3.IntegrityError: |
| return None, "Email already exists." |
| finally: |
| con.close() |
|
|
| def login(email, password): |
| con = sqlite3.connect(DB_PATH); cur = con.cursor() |
| cur.execute("SELECT id,email,name,role,city,is_verified FROM users WHERE email=? AND password=?", (email.lower().strip(), password)) |
| row = cur.fetchone(); con.close() |
| if not row: return None, "Invalid credentials." |
| user = {"id": row[0], "email": row[1], "name": row[2], "role": row[3], "city": row[4], "is_verified": row[5] or 0} |
| badge = " ✔ Fevicol Certified" if user["is_verified"] else "" |
| return user, f"Logged in as {row[1]} ({row[3]}){badge}." |
|
|
| |
| def verify_user(email, pin, value): |
| if pin != ADMIN_PIN: return "Invalid admin PIN." |
| con = sqlite3.connect(DB_PATH); cur = con.cursor() |
| cur.execute("UPDATE users SET is_verified=? WHERE email=?", (1 if value else 0, email.lower().strip())) |
| con.commit(); con.close() |
| return ("✅ Verified " if value else "❎ Unverified ") + email.lower().strip() |
|
|
| |
| DEMO_PRODUCTS = [ |
| {"name":"Fevicol MR 200g","brand":"Fevicol","price":95,"description":"White adhesive 200g","category":"Adhesives","unit":"200g","mrp":95,"sale_price":90,"stock":50,"hsn":"3506","gst":18}, |
| {"name":"Fevicol SH 1kg","brand":"Fevicol","price":300,"description":"Woodworking adhesive 1kg","category":"Adhesives","unit":"1kg","mrp":310,"sale_price":299,"stock":40,"hsn":"3506","gst":18}, |
| {"name":"Dr. Fixit LW+ 200ml","brand":"Dr. Fixit","price":190,"description":"Waterproofing additive 200ml","category":"Construction","unit":"200ml","mrp":199,"sale_price":190,"stock":60,"hsn":"3824","gst":18}, |
| {"name":"M-Seal Phataphat 25g","brand":"M-Seal","price":35,"description":"Quick setting epoxy 25g","category":"Quick Fix","unit":"25g","mrp":35,"sale_price":35,"stock":150,"hsn":"3506","gst":18}, |
| ] |
| def seed_demo(pin): |
| if pin != ADMIN_PIN: return "Invalid admin PIN." |
| return _seed_products(DEMO_PRODUCTS) |
|
|
| |
| FEVICOL_PRODUCTS = [ |
| {"name":"Fevicol MR 50g","brand":"Fevicol","price":20,"description":"MR white adhesive 50g","category":"Adhesives","unit":"50g","mrp":20,"sale_price":20,"stock":200,"hsn":"3506","gst":18}, |
| {"name":"Fevicol MR 100g","brand":"Fevicol","price":52,"description":"MR white adhesive 100g","category":"Adhesives","unit":"100g","mrp":52,"sale_price":52,"stock":150,"hsn":"3506","gst":18}, |
| {"name":"Fevicol MR 200g","brand":"Fevicol","price":95,"description":"MR white adhesive 200g","category":"Adhesives","unit":"200g","mrp":95,"sale_price":95,"stock":120,"hsn":"3506","gst":18}, |
| {"name":"Fevicol MR 1kg","brand":"Fevicol","price":273,"description":"MR white adhesive 1kg","category":"Adhesives","unit":"1kg","mrp":273,"sale_price":273,"stock":80,"hsn":"3506","gst":18}, |
| {"name":"Fevicol SH 1kg","brand":"Fevicol","price":299,"description":"SH synthetic resin adhesive 1kg","category":"Adhesives","unit":"1kg","mrp":310,"sale_price":299,"stock":90,"hsn":"3506","gst":18}, |
| {"name":"Fevicol Marine 1kg","brand":"Fevicol","price":304,"description":"Water-resistant adhesive 1kg","category":"Waterproof","unit":"1kg","mrp":304,"sale_price":304,"stock":70,"hsn":"3506","gst":18}, |
| {"name":"Fevicol HeatX 500g","brand":"Fevicol","price":146,"description":"Heatproof fast-setting adhesive 500g","category":"Heatproof","unit":"500g","mrp":146,"sale_price":146,"stock":100,"hsn":"3506","gst":18}, |
| {"name":"Fevicol Ezee Spray 383g","brand":"Fevicol","price":599,"description":"Ezee spray adhesive 383g","category":"Spray Adhesive","unit":"383g","mrp":599,"sale_price":599,"stock":60,"hsn":"3506","gst":18}, |
| {"name":"Fevicol SR 998 Multipurpose 1kg","brand":"Fevicol","price":132,"description":"Synthetic rubber adhesive SR 998","category":"Industrial","unit":"1kg","mrp":132,"sale_price":132,"stock":65,"hsn":"3506","gst":18}, |
| {"name":"Fevicol DDL 500g","brand":"Fevicol","price":792,"description":"Synthetic resin adhesive DDL 500g","category":"Adhesives","unit":"500g","mrp":792,"sale_price":792,"stock":40,"hsn":"3506","gst":18}, |
| {"name":"Fevicol Allfix 20ml","brand":"Fevicol","price":50,"description":"Allfix clear adhesive 20ml","category":"Quick Fix","unit":"20ml","mrp":50,"sale_price":50,"stock":180,"hsn":"3506","gst":18}, |
| {"name":"Fevicol Homefix 15g","brand":"Fevicol","price":74,"description":"Homefix DIY adhesive 15g","category":"DIY","unit":"15g","mrp":74,"sale_price":74,"stock":160,"hsn":"3506","gst":18}, |
| ] |
|
|
| def _seed_products(items): |
| con = sqlite3.connect(DB_PATH); cur = con.cursor() |
| added = 0 |
| for p in items: |
| cur.execute("SELECT COUNT(1) FROM products WHERE name=? AND brand=?", (p["name"], p["brand"])) |
| if cur.fetchone()[0] == 0: |
| cur.execute("""INSERT INTO products |
| (name,brand,price,description,created_at,category,mrp,sale_price,unit,stock,hsn,gst,image_path) |
| VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)""", |
| (p["name"], p["brand"], float(p["price"]), p.get("description",""), |
| datetime.datetime.utcnow().isoformat(), p.get("category",""), p.get("mrp",p["price"]), |
| p.get("sale_price",p["price"]), p.get("unit",""), int(p.get("stock",0)), p.get("hsn",""), float(p.get("gst",0)), "")) |
| added += 1 |
| con.commit(); con.close() |
| return f"Added {added} item(s)." |
|
|
| def seed_fevicol_products(pin): |
| if pin != ADMIN_PIN: return "Invalid admin PIN." |
| return "Real Fevicol catalog: " + _seed_products(FEVICOL_PRODUCTS) |
|
|
| |
| DELIVERY_OPTIONS = {"Pickup (₹0)":0.0,"Standard 5–7 days (₹99)":99.0,"Express 2–3 days (₹199)":199.0} |
| PAYMENT_METHODS = ["COD (Cash on Delivery)", "UPI (Simulated)"] |
|
|
| def distinct_categories(): |
| con = sqlite3.connect(DB_PATH); cur = con.cursor() |
| try: |
| cur.execute("SELECT DISTINCT IFNULL(category,'') FROM products ORDER BY 1") |
| cats = [r[0] for r in cur.fetchall() if r and r[0] is not None] |
| except Exception: |
| cats = [] |
| con.close() |
| return ["All"] + [c for c in cats if c.strip()] |
|
|
| def list_products_extended(category="All", query=""): |
| con = sqlite3.connect(DB_PATH); cur = con.cursor() |
| sql = ("SELECT id,name,brand,IFNULL(category,''),IFNULL(unit,'')," |
| "IFNULL(mrp,price),IFNULL(sale_price,price),price,IFNULL(stock,0)," |
| "IFNULL(hsn,''),IFNULL(gst,0),IFNULL(description,''),IFNULL(image_path,'') FROM products") |
| conds=[]; params=[] |
| if category!="All": |
| conds.append("IFNULL(category,'')=?"); params.append(category) |
| if query.strip(): |
| q=f"%{query.strip().lower()}%"; conds.append("(LOWER(name) LIKE ? OR LOWER(brand) LIKE ? OR LOWER(description) LIKE ?)"); params+= [q,q,q] |
| if conds: sql+=" WHERE "+" AND ".join(conds) |
| sql+=" ORDER BY id DESC" |
| cur.execute(sql, params); rows=cur.fetchall(); con.close() |
| df = pd.DataFrame(rows, columns=["ID","Name","Brand","Category","Unit","MRP","Price","Base_Price","Stock","HSN","GST%","Description","Image_Path"]) |
| gallery=[]; |
| for r in rows: |
| img=r[12] |
| if img and os.path.exists(img): |
| gallery.append((img, f"{r[1]} – ₹{r[6] or r[7]} ({r[4]})")) |
| return df, gallery |
|
|
| def add_product(name, brand, price, description, user, category="", mrp="", sale_price="", unit="", stock="0", hsn="", gst="0", image_file=None): |
| if not user: return "Please log in first." |
| if user["role"] != "dealer": return "Only dealers can add products." |
| try: |
| base_price = float(price) if price not in (None, "") else None |
| mrp_val = float(mrp) if mrp not in (None, "") else base_price |
| sale_val = float(sale_price) if sale_price not in (None, "") else base_price |
| stock_val = int(stock) if str(stock).strip() else 0 |
| gst_val = float(gst) if str(gst).strip() else 0.0 |
| except: |
| return "Enter valid numeric values for price/mrp/sale_price/stock/gst." |
| if not name or base_price is None: |
| return "Name and base price are required." |
| con = sqlite3.connect(DB_PATH); cur = con.cursor() |
| cur.execute("""INSERT INTO products(name,brand,price,description,created_at,category,mrp,sale_price,unit,stock,hsn,gst,image_path) |
| VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)""", |
| (name.strip(), brand or "", base_price, description or "", datetime.datetime.utcnow().isoformat(), |
| category or "", mrp_val, sale_val, unit or "", stock_val, hsn or "", gst_val, "")) |
| pid = cur.lastrowid |
| img_path="" |
| if image_file and os.path.exists(image_file): |
| ext=os.path.splitext(image_file)[1].lower() |
| if ext not in [".png",".jpg",".jpeg",".webp"]: ext=".png" |
| img_dir=os.path.join(DATA_DIR,"product_images"); os.makedirs(img_dir, exist_ok=True) |
| img_path=os.path.join(img_dir, f"prod_{pid}_{int(time.time())}{ext}") |
| try: copyfile(image_file, img_path) |
| except Exception: img_path="" |
| if img_path: |
| cur.execute("UPDATE products SET image_path=? WHERE id=?", (img_path, pid)) |
| con.commit(); con.close() |
| return f"Product added (ID: {pid})." |
|
|
| def add_to_cart(pid_text, qty, cart): |
| if not str(pid_text).strip().isdigit(): return cart, "Enter a valid Product ID.", None |
| try: qty=int(qty) |
| except: qty=0 |
| if qty<=0: return cart, "Enter a valid quantity.", None |
| pid=int(pid_text) |
| con=sqlite3.connect(DB_PATH); cur=con.cursor() |
| cur.execute("SELECT id,name,IFNULL(sale_price,price) FROM products WHERE id=?", (pid,)) |
| row=cur.fetchone(); con.close() |
| if not row: return cart, "Product not found.", None |
| cart=(cart or []) + [ {"product_id": row[0], "name": row[1], "unit_price": float(row[2] or 0), "qty": qty} ] |
| df,total=_cart_df(cart); return cart, "Added to cart.", f"Items: {len(cart)} | Total: ₹{total:.2f}" |
|
|
| def _cart_df(cart): |
| if not cart: return pd.DataFrame(columns=["Product_ID","Name","Unit_Price","Qty","Subtotal"]), 0.0 |
| rows=[]; total=0.0 |
| for it in cart: |
| sub=it["unit_price"]*it["qty"]; total+=sub |
| rows.append([it["product_id"], it["name"], it["unit_price"], it["qty"], sub]) |
| return pd.DataFrame(rows, columns=["Product_ID","Name","Unit_Price","Qty","Subtotal"]), total |
|
|
| def checkout(address, delivery_label, payment_method, user, cart): |
| if not user: return "Please login first." |
| if not cart: return "Your cart is empty." |
| if not address: return "Address is required." |
| if delivery_label not in DELIVERY_OPTIONS: return "Choose delivery option." |
| if payment_method not in PAYMENT_METHODS: return "Choose payment method." |
| df, subtotal = _cart_df(cart) |
| fee = DELIVERY_OPTIONS[delivery_label]; total=float(subtotal+fee) |
| pay_status = "paid" if payment_method=="UPI (Simulated)" else "pending" |
|
|
| con=sqlite3.connect(DB_PATH); cur=con.cursor() |
| |
| for _, r in df.iterrows(): |
| cur.execute("SELECT IFNULL(stock,0) FROM products WHERE id=?", (int(r["Product_ID"]),)) |
| stock=cur.fetchone(); stock_val=int(stock[0]) if stock else 0 |
| if int(r["Qty"])>stock_val: |
| con.close(); return f"Stock insufficient for ID {int(r['Product_ID'])}: need {int(r['Qty'])}, have {stock_val}." |
| |
| cur.execute("""INSERT INTO orders(user_id,total,address,delivery_option,delivery_fee,payment_method,payment_status,status,created_at) |
| VALUES(?,?,?,?,?,?,?,?,?)""", |
| (user["id"], total, address, delivery_label, fee, payment_method, pay_status, "processing", |
| datetime.datetime.utcnow().isoformat())) |
| order_id=cur.lastrowid |
| for _, r in df.iterrows(): |
| cur.execute("""INSERT INTO order_items(order_id,product_id,product_name,unit_price,qty,subtotal) |
| VALUES(?,?,?,?,?,?)""", |
| (order_id, int(r["Product_ID"]), str(r["Name"]), float(r["Unit_Price"]), int(r["Qty"]), float(r["Subtotal"]))) |
| cur.execute("UPDATE products SET stock = IFNULL(stock,0) - ? WHERE id=?", (int(r["Qty"]), int(r["Product_ID"]))) |
| con.commit(); con.close() |
| return f"Order #{order_id} placed! Payment: {pay_status.upper()} | Total: ₹{total:.2f}" |
|
|
| def my_orders(user): |
| if not user: return pd.DataFrame(columns=["Order_ID","Total","Payment","Status","Created","Delivery","Address"]) |
| con=sqlite3.connect(DB_PATH); cur=con.cursor() |
| cur.execute("""SELECT id,total,payment_status,status,created_at,delivery_option,address |
| FROM orders WHERE user_id=? ORDER BY id DESC""",(user["id"],)) |
| rows=cur.fetchall(); con.close() |
| return pd.DataFrame(rows, columns=["Order_ID","Total","Payment","Status","Created","Delivery","Address"]) |
|
|
| |
| with gr.Blocks(title="Fevicol CreatorHub") as demo: |
| user_state = gr.State(None) |
| cart_state = gr.State([]) |
|
|
| gr.Markdown("## 🧱 Fevicol CreatorHub — Projects • Products • Orders") |
|
|
| |
| with gr.Tab("Home / About"): |
| logo = gr.Image(label="Logo", type="filepath", value=get_logo_path(), interactive=False) |
| md = gr.Markdown(about_md()) |
| gr.Button("Reload").click(lambda: (get_logo_path(), about_md()), None, [logo, md]) |
|
|
| |
| with gr.Tab("Admin"): |
| gr.Markdown("### Verify users (✔), manage branding, seed products") |
| pin = gr.Textbox(label="Admin PIN", type="password") |
| email = gr.Textbox(label="User Email") |
| with gr.Row(): |
| btn_v = gr.Button("Verify") |
| btn_u = gr.Button("Unverify") |
| msg = gr.Textbox(label="Status", interactive=False) |
| btn_v.click(lambda e,p: verify_user(e,p,True), [email,pin], [msg]) |
| btn_u.click(lambda e,p: verify_user(e,p,False), [email,pin], [msg]) |
|
|
| gr.Markdown("---") |
| tg = gr.Textbox(label="Tagline", value=(get_setting("tagline") or DEFAULT_TAGLINE)) |
| ms = gr.Textbox(label="Mission Statement", value=(get_setting("mission") or DEFAULT_MISSION), lines=3) |
| up = gr.Image(label="Upload Logo", type="filepath", sources=["upload"], interactive=True) |
| outb = gr.Textbox(label="Branding Result", interactive=False) |
| def save_brand(pin, tg, ms, file): |
| if pin != ADMIN_PIN: return "Invalid admin PIN.", get_logo_path(), about_md() |
| set_setting("tagline", tg or DEFAULT_TAGLINE); set_setting("mission", ms or DEFAULT_MISSION) |
| if file and os.path.exists(file): |
| try: copyfile(file, LOGO_PATH) |
| except Exception as e: return f"Saved (logo copy failed: {e})", get_logo_path(), about_md() |
| return "Branding saved.", get_logo_path(), about_md() |
| gr.Button("Save Branding").click(save_brand, [pin, tg, ms, up], [outb, logo, md]) |
|
|
| gr.Markdown("---") |
| out_seed_demo = gr.Textbox(label="Demo Seed Result", interactive=False) |
| gr.Button("Load Demo Products").click(lambda p: seed_demo(p), [pin], [out_seed_demo]) |
|
|
| out_seed_real = gr.Textbox(label="Real Fevicol Seed Result", interactive=False) |
| gr.Button("Load Real Fevicol Products").click(lambda p: seed_fevicol_products(p), [pin], [out_seed_real]) |
|
|
| |
| with gr.Tab("Login / Sign Up"): |
| with gr.Row(): |
| with gr.Column(): |
| e1=gr.Textbox(label="Email"); p1=gr.Textbox(label="Password", type="password") |
| n1=gr.Textbox(label="Name"); r1=gr.Dropdown(["customer","designer","carpenter","dealer"], value="customer", label="Role") |
| c1=gr.Textbox(label="City") |
| out_s=gr.Textbox(label="Message", interactive=False) |
| def _s(e,p,n,r,c): u,m=signup(e,p,n,r,c); return u,m |
| gr.Button("Sign Up").click(_s, [e1,p1,n1,r1,c1], [user_state,out_s]) |
| with gr.Column(): |
| e2=gr.Textbox(label="Email"); p2=gr.Textbox(label="Password", type="password") |
| out_l = gr.Textbox(label="Message", interactive=False) |
| who = gr.Textbox(label="Current User", interactive=False) |
| def _l(e,p): |
| u,m=login(e,p); badge=" ✔ Fevicol Certified" if (u and u.get("is_verified")) else "" |
| return m, u, ((u['email']+" ("+u['role']+")"+badge) if u else "") |
| gr.Button("Login").click(_l, [e2,p2], [out_l, user_state, who]) |
|
|
| |
| with gr.Tab("Products & Orders"): |
| gr.Markdown("**Browse Catalog**") |
| with gr.Row(): |
| cat = gr.Dropdown(choices=distinct_categories(), value="All", label="Category") |
| q = gr.Textbox(label="Search") |
| btn = gr.Button("Apply") |
| gallery = gr.Gallery(label="Images", show_label=True) |
| dfp = gr.Dataframe(interactive=False) |
| def _load(cat,q): df,gal = list_products_extended(cat,q); return gal, df |
| btn.click(_load, [cat,q], [gallery, dfp]) |
| demo.load(_load, [cat,q], [gallery, dfp]) |
|
|
| gr.Markdown("### Add to Cart") |
| with gr.Row(): |
| pid = gr.Textbox(label="Product ID") |
| qty = gr.Textbox(label="Qty", value="1") |
| add_msg = gr.Textbox(label="Cart Status", interactive=False) |
| cart_summary = gr.Textbox(label="Cart Summary", interactive=False) |
| def _add(pid, qty_str, cart): |
| try: qv=int(qty_str) |
| except: qv=0 |
| cart,msg,summary = add_to_cart(pid, qv, cart) |
| return cart, msg, summary |
| gr.Button("Add").click(_add, [pid, qty, cart_state], [cart_state, add_msg, cart_summary]) |
|
|
| gr.Markdown("### Cart & Checkout") |
| deliv = gr.Dropdown(list(DELIVERY_OPTIONS.keys()), value="Pickup (₹0)", label="Delivery Option") |
| cart_df = gr.Dataframe(interactive=False); cart_tot = gr.Markdown() |
| def _view(cart, dlab): |
| df, total = _cart_df(cart or []); fee = DELIVERY_OPTIONS.get(dlab or "Pickup (₹0)", 0.0) |
| return df, f"Subtotal ₹{total:.2f} + Delivery ₹{fee:.2f} = **Grand Total ₹{(total+fee):.2f}**" |
| gr.Button("View Cart").click(_view, [cart_state, deliv], [cart_df, cart_tot]) |
|
|
| addr = gr.Textbox(label="Delivery Address") |
| pay = gr.Dropdown(PAYMENT_METHODS, value="COD (Cash on Delivery)", label="Payment Method") |
| out_co = gr.Textbox(label="Order Status", interactive=False) |
| def _checkout(address, dopt, pm, user, cart): |
| msg = checkout(address, dopt, pm, user, cart) |
| return ([], msg) if msg.startswith("Order #") else (cart, msg) |
| gr.Button("Place Order").click(_checkout, [addr, deliv, pay, user_state, cart_state], [cart_state, out_co]) |
|
|
| gr.Markdown("---") |
| gr.Markdown("### Dealer: Add Product") |
| with gr.Row(): |
| pn = gr.Textbox(label="Name") |
| pb = gr.Textbox(label="Brand", value="Fevicol") |
| pc = gr.Textbox(label="Category", placeholder="Adhesives / Construction / Craft / Tools") |
| with gr.Row(): |
| pmrp = gr.Textbox(label="MRP ₹") |
| psale = gr.Textbox(label="Sale Price ₹ (shown)") |
| pbase = gr.Textbox(label="Base Price ₹ (fallback)", value="0") |
| punit = gr.Textbox(label="Unit", placeholder="200g, 1kg, 500ml") |
| with gr.Row(): |
| pstock = gr.Textbox(label="Stock Qty", value="10") |
| phsn = gr.Textbox(label="HSN") |
| pgst = gr.Textbox(label="GST %", value="18") |
| pd = gr.Textbox(label="Description") |
| pimg = gr.Image(label="Image", type="filepath", sources=["upload"], interactive=True) |
| out_ap = gr.Textbox(label="Status", interactive=False) |
| def _dealer_add(user, name, brand, cat, mrp, sale, base, unit, stock, hsn, gst, desc, img): |
| price_to_store = base if base not in (None,"") else (sale if sale not in (None,"") else mrp) |
| return add_product(name, brand, price_to_store, desc, user, category=cat, mrp=mrp, sale_price=sale, unit=unit, stock=stock, hsn=hsn, gst=gst, image_file=img) |
| gr.Button("Save Product").click(_dealer_add, [user_state,pn,pb,pc,pmrp,psale,pbase,punit,pstock,phsn,pgst,pd,pimg], [out_ap]) |
|
|
| |
| with gr.Tab("My Orders"): |
| out = gr.Dataframe(interactive=False) |
| gr.Button("Refresh My Orders").click(my_orders, [user_state], [out]) |
|
|
| demo = demo |
| demo.launch() |
|
|