Skip to content

Commit b4ded07

Browse files
author
kada2004
committed
Push Streamlit APP
1 parent b137a03 commit b4ded07

3 files changed

Lines changed: 230 additions & 0 deletions

File tree

Streamlitapp/.env

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
POSTGRES_HOST=localhost
2+
POSTGRES_PORT=5432
3+
POSTGRES_DB=spark_db
4+
POSTGRES_USER=spark_user
5+
POSTGRES_PASSWORD=bunia243

Streamlitapp/app.py

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
import streamlit as st
2+
import psycopg2
3+
import pandas as pd
4+
from decouple import config
5+
from datetime import datetime
6+
import pandas
7+
8+
# Verify pandas version
9+
if not (1.4 <= float(pandas.__version__.split('.')[0]) + float(pandas.__version__.split('.')[1])/10 < 3):
10+
st.error(f"Streamlit requires pandas>=1.4.0,<3, but found pandas=={pandas.__version__}")
11+
st.stop()
12+
13+
# Database connection function
14+
def get_db_connection():
15+
try:
16+
conn = psycopg2.connect(
17+
host=config('POSTGRES_HOST', default='localhost'),
18+
port=config('POSTGRES_PORT', default='5432'),
19+
database=config('POSTGRES_DB', default='spark_db'),
20+
user=config('POSTGRES_USER', default='spark_user'),
21+
password=config('POSTGRES_PASSWORD')
22+
)
23+
return conn
24+
except Exception as e:
25+
st.error(f"Failed to connect to database: {e}")
26+
return None
27+
28+
# Fetch all customers
29+
@st.cache_data
30+
def get_customers():
31+
conn = get_db_connection()
32+
if conn is None:
33+
return []
34+
try:
35+
with conn.cursor() as cur:
36+
cur.execute("SELECT CustomerID FROM Customer ORDER BY CustomerID")
37+
customers = [row[0] for row in cur.fetchall()]
38+
conn.close()
39+
return customers
40+
except Exception as e:
41+
st.error(f"Error fetching customers: {e}")
42+
conn.close()
43+
return []
44+
45+
# Calculate total spend for a customer
46+
def get_total_spend(customer_id):
47+
conn = get_db_connection()
48+
if conn is None:
49+
return 0.0
50+
try:
51+
with conn.cursor() as cur:
52+
cur.execute("""
53+
SELECT SUM(s.Quantity * s.UnitPrice) as total_spend
54+
FROM Invoice i
55+
JOIN InvoiceStock ist ON i.InvoiceNo = ist.InvoiceNo
56+
JOIN Stock s ON ist.StockID = s.StockID
57+
WHERE i.CustomerID = %s
58+
AND i.InvoiceNo NOT LIKE 'C%%'
59+
""", (customer_id,))
60+
result = cur.fetchone()
61+
total_spend = result[0] if result[0] is not None else 0.0
62+
conn.close()
63+
return total_spend
64+
except Exception as e:
65+
st.error(f"Error calculating total spend: {e}")
66+
conn.close()
67+
return 0.0
68+
69+
# Fetch order history for a customer
70+
def get_order_history(customer_id):
71+
conn = get_db_connection()
72+
if conn is None:
73+
return pd.DataFrame()
74+
try:
75+
query = """
76+
SELECT i.InvoiceNo, i.InvoiceDate, SUM(s.Quantity * s.UnitPrice) as Amount,
77+
SUM(s.Quantity) as Quantity,
78+
STRING_AGG(s.Description, ', ') as ItemsPurchased
79+
FROM Invoice i
80+
JOIN InvoiceStock ist ON i.InvoiceNo = ist.InvoiceNo
81+
JOIN Stock s ON ist.StockID = s.StockID
82+
WHERE i.CustomerID = %s
83+
GROUP BY i.InvoiceNo, i.InvoiceDate
84+
ORDER BY i.InvoiceDate DESC
85+
"""
86+
df = pd.read_sql_query(query, conn, params=(customer_id,))
87+
conn.close()
88+
return df
89+
except Exception as e:
90+
st.error(f"Error fetching order history: {e}")
91+
conn.close()
92+
return pd.DataFrame()
93+
94+
# Fetch invoice details
95+
def get_invoice_details(invoice_no):
96+
conn = get_db_connection()
97+
if conn is None:
98+
return pd.DataFrame()
99+
try:
100+
query = """
101+
SELECT i.InvoiceNo, i.InvoiceDate, i.CustomerID, c.Country_Name,
102+
s.StockCode, s.Description, s.Quantity, s.UnitPrice,
103+
(s.Quantity * s.UnitPrice) as Total
104+
FROM Invoice i
105+
JOIN InvoiceStock ist ON i.InvoiceNo = ist.InvoiceNo
106+
JOIN Stock s ON ist.StockID = s.StockID
107+
LEFT JOIN Country c ON i.CustomerID = c.CustomerID
108+
WHERE i.InvoiceNo = %s
109+
"""
110+
df = pd.read_sql_query(query, conn, params=(invoice_no,))
111+
conn.close()
112+
return df
113+
except Exception as e:
114+
st.error(f"Error fetching invoice details: {e}")
115+
conn.close()
116+
return pd.DataFrame()
117+
118+
# Fetch returned items (invoices starting with 'C')
119+
def get_returned_items(customer_id):
120+
conn = get_db_connection()
121+
if conn is None:
122+
return pd.DataFrame()
123+
try:
124+
query = """
125+
SELECT i.InvoiceNo, i.InvoiceDate, s.StockCode, s.Description,
126+
s.Quantity, s.UnitPrice, (s.Quantity * s.UnitPrice) as Total
127+
FROM Invoice i
128+
JOIN InvoiceStock ist ON i.InvoiceNo = ist.InvoiceNo
129+
JOIN Stock s ON ist.StockID = s.StockID
130+
WHERE i.CustomerID = %s AND i.InvoiceNo LIKE 'C%%'
131+
ORDER BY i.InvoiceDate DESC
132+
"""
133+
df = pd.read_sql_query(query, conn, params=(customer_id,))
134+
conn.close()
135+
return df
136+
except Exception as e:
137+
st.error(f"Error fetching returned items: {e}")
138+
conn.close()
139+
return pd.DataFrame()
140+
141+
# Streamlit app
142+
st.title("Customer Dashboard")
143+
144+
# Sidebar for customer selection
145+
st.sidebar.header("Select Customer")
146+
customer_ids = get_customers()
147+
if not customer_ids:
148+
st.sidebar.error("No customers found. Please check database connection.")
149+
st.stop()
150+
151+
customer_id = st.sidebar.selectbox("Customer ID", customer_ids)
152+
153+
# Total Spend
154+
st.header(f"Total Spend for Customer {customer_id}")
155+
total_spend = get_total_spend(customer_id)
156+
st.metric("Total Spend (Excluding Returns)", f"£{total_spend:,.2f}")
157+
158+
# Order History
159+
st.header("Order History")
160+
order_history = get_order_history(customer_id)
161+
if not order_history.empty:
162+
st.dataframe(
163+
order_history.rename(columns={
164+
"invoiceno": "Invoice No",
165+
"invoicedate": "Date",
166+
"amount": "Amount (£)",
167+
"quantity": "Quantity",
168+
"itemspurchased": "Items Purchased"
169+
}),
170+
use_container_width=True
171+
)
172+
else:
173+
st.write("No orders found for this customer.")
174+
175+
# Query Invoice Details
176+
st.header("Query Invoice Details")
177+
invoice_nos = order_history["invoiceno"].tolist() if not order_history.empty else []
178+
selected_invoice = st.selectbox("Select Invoice No", ["Select an invoice"] + invoice_nos)
179+
if selected_invoice != "Select an invoice":
180+
invoice_details = get_invoice_details(selected_invoice)
181+
if not invoice_details.empty:
182+
st.dataframe(
183+
invoice_details.rename(columns={
184+
"invoiceno": "Invoice No",
185+
"invoicedate": "Date",
186+
"customerid": "Customer ID",
187+
"country_name": "Country",
188+
"stockcode": "Stock Code",
189+
"description": "Description",
190+
"quantity": "Quantity",
191+
"unitprice": "Unit Price (£)",
192+
"total": "Total (£)"
193+
}),
194+
use_container_width=True
195+
)
196+
else:
197+
st.write("No details found for this invoice.")
198+
199+
# Returned Items
200+
st.header("Returned Items")
201+
returned_items = get_returned_items(customer_id)
202+
if not returned_items.empty:
203+
st.dataframe(
204+
returned_items.rename(columns={
205+
"invoiceno": "Invoice No",
206+
"invoicedate": "Date",
207+
"stockcode": "Stock Code",
208+
"description": "Description",
209+
"quantity": "Quantity",
210+
"unitprice": "Unit Price (£)",
211+
"total": "Total (£)"
212+
}),
213+
use_container_width=True
214+
)
215+
else:
216+
st.write("No returned items found for this customer.")
217+
218+
# Generate Invoice Button (Placeholder)
219+
st.header("Generate Invoice")
220+
if st.button("Generate Invoice"):
221+
st.info("Invoice generation is not yet implemented. This will store invoices in blob storage and update Stock.invoice_url.")

Streamlitapp/requirements.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
streamlit==1.40.1
2+
psycopg2-binary==2.9.9
3+
pandas>=1.4.0,<3
4+
python-decouple==3.8

0 commit comments

Comments
 (0)