import pandas as pd import gspread import gradio as gr from oauth2client.service_account import ServiceAccountCredentials from datetime import datetime import time # ------------------ AUTH ------------------ VALID_USERS = { "andrew@lortechnologies.com": "Pass.123", "phonnie@carfind.co.za": "Pass.123", "monique@carfind.co.za": "Pass.123" } # ------------------ GOOGLE SHEET SETUP ------------------ scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"] creds = ServiceAccountCredentials.from_json_keyfile_name("credentials.json", scope) client = gspread.authorize(creds) sheet_file = client.open("userAccess") # ------------------ RETRY LOGIC ------------------ def load_tab(sheet_name, retries=3, delay=5): for attempt in range(retries): try: df = pd.DataFrame(sheet_file.worksheet(sheet_name).get_all_records()) return df except gspread.exceptions.APIError as e: if attempt < retries - 1: time.sleep(delay) else: return pd.DataFrame([[f"โš ๏ธ API Error: {str(e)}"]], columns=["Error"]) # ------------------ HELPERS ------------------ def get_combined_orders(date_str): df_field = load_tab("Field Sales") df_ts = load_tab("TeleSales") combined = [] if not df_field.empty: df_field['Date'] = pd.to_datetime(df_field['Date'], errors='coerce') df_field['DateStr'] = df_field['Date'].dt.date.astype(str) df_field = df_field[df_field['DateStr'] == date_str.strip()] df_field['Order Value'] = pd.to_numeric(df_field['Order Value'], errors='coerce').fillna(0) df_field_orders = df_field.groupby("Rep").agg({ "Order Received": lambda x: (x == "Yes").sum(), "Order Value": "sum" }).reset_index().rename(columns={ "Order Received": "Orders Received", "Order Value": "Total Order Value" }) df_field_orders["Source"] = "Field Sales" combined.append(df_field_orders) if not df_ts.empty: df_ts['Date'] = pd.to_datetime(df_ts['Date'], errors='coerce') df_ts['DateStr'] = df_ts['Date'].dt.date.astype(str) df_ts = df_ts[df_ts['DateStr'] == date_str.strip()] df_ts['Order Value'] = pd.to_numeric(df_ts['Order Value'], errors='coerce').fillna(0) df_ts_orders = df_ts.groupby("Rep").agg({ "Order Received": lambda x: (x == "Yes").sum(), "Order Value": "sum" }).reset_index().rename(columns={ "Order Received": "Orders Received", "Order Value": "Total Order Value" }) df_ts_orders["Source"] = "TeleSales" combined.append(df_ts_orders) if combined: return pd.concat(combined, ignore_index=True) else: return pd.DataFrame([["No orders on this date"]], columns=["Message"]) # Define other helper functions similarly using load_tab... # ------------------ GRADIO APP ------------------ with gr.Blocks() as app: with gr.Row(): with gr.Column(visible=True) as login_ui: gr.Markdown("## ๐Ÿ” Login Required") email = gr.Textbox(label="Email") password = gr.Textbox(label="Password", type="password") login_btn = gr.Button("Login") login_msg = gr.Markdown("") with gr.Column(visible=False) as main_ui: gr.Markdown("## ๐Ÿ—‚๏ธ CarMat Dashboard") df_initial = load_tab("Field Sales") unique_dates = sorted(df_initial["Date"].astype(str).unique(), reverse=True) if not df_initial.empty else [] # --- Tabs --- with gr.Tab("๐Ÿ“Š Summary"): gr.Markdown("Summary content coming soon...") with gr.Tab("๐Ÿ“‚ Field Sales"): field_df = gr.Dataframe(value=load_tab("Field Sales"), label="๐Ÿ“‚ Field Sales Records", interactive=False) gr.Button("๐Ÿ”„ Refresh").click(fn=lambda: load_tab("Field Sales"), outputs=field_df) with gr.Tab("๐Ÿ“ž TeleSales"): ts_table = gr.Dataframe(value=load_tab("TeleSales"), label="๐Ÿ“ž TeleSales Summary") gr.Button("๐Ÿ”„ Refresh").click(fn=lambda: load_tab("TeleSales"), outputs=ts_table) with gr.Tab("๐Ÿ“ฆ Orders Summary"): order_date = gr.Dropdown(label="Select Date", choices=unique_dates, interactive=True) order_table = gr.Dataframe(label="๐Ÿงพ Combined Order Summary") order_date.change(fn=get_combined_orders, inputs=order_date, outputs=order_table) # Continue similarly for other tabs... def do_login(user, pw): if VALID_USERS.get(user) == pw: return gr.update(visible=False), gr.update(visible=True), "" else: return gr.update(visible=True), gr.update(visible=False), "โŒ Invalid login." login_btn.click(fn=do_login, inputs=[email, password], outputs=[login_ui, main_ui, login_msg]) app.launch()