| | import streamlit as st |
| | import pandas as pd |
| | import re |
| | import plotly.express as px |
| |
|
| | st.set_page_config(page_title="گزارش خرید کالا و داشبورد تصویری", layout="wide", initial_sidebar_state="expanded") |
| |
|
| | |
| | st.markdown( |
| | """ |
| | <link href="https://cdn.jsdelivr.net/gh/rastikerdar/vazirmatn@v33.003/Vazirmatn-Variable-font-face.css" rel="stylesheet" type="text/css" /> |
| | """, |
| | unsafe_allow_html=True |
| | ) |
| |
|
| | |
| | with open("src/style.css") as f: |
| | st.markdown(f"<style>{f.read()}</style>", unsafe_allow_html=True) |
| |
|
| | st.title("📊 گزارش خرید کالا و داشبورد تصویری") |
| |
|
| | |
| | with st.sidebar: |
| | st.header("تنظیمات") |
| | uploaded_file = st.file_uploader("📂 فایل اکسل Book.xlsx را بارگذاری کنید", type=["xlsx"]) |
| |
|
| | if uploaded_file is not None: |
| | df = pd.read_excel(uploaded_file) |
| |
|
| | |
| | def clean_col(col): |
| | col = str(col) |
| | col = re.sub(r'[\n\r]+', ' ', col) |
| | col = re.sub(r'[\u200c\u200f\u202a-\u202e\ufeff]', '', col) |
| | col = re.sub(r'\s+', ' ', col).strip() |
| | return col |
| |
|
| | df.columns = [clean_col(c) for c in df.columns] |
| |
|
| | |
| | qty_col = next((c for c in df.columns if re.search(r'خالص.*تعداد', c)), None) |
| | amt_col = next((c for c in df.columns if re.search(r'خالص.*مبلغ(?!.*تخفیف)', c)), None) |
| |
|
| | if not qty_col or not amt_col: |
| | st.error("❌ ستونهای مربوط به «خالص تعداد» یا «خالص مبلغ» پیدا نشدند!") |
| | st.write("📑 ستونهای موجود در فایل (بعد از تمیزکاری):") |
| | st.write(list(df.columns)) |
| | else: |
| | |
| | df[amt_col] = pd.to_numeric(df[amt_col], errors='coerce').fillna(0) |
| |
|
| | |
| | month_order = ['فروردین','اردیبهشت','خرداد','تیر','مرداد','شهریور', |
| | 'مهر','آبان','آذر','دی','بهمن','اسفند'] |
| | month_dict = { |
| | "01": "فروردین", "02": "اردیبهشت", "03": "خرداد", "04": "تیر", |
| | "05": "مرداد", "06": "شهریور", "07": "مهر", "08": "آبان", |
| | "09": "آذر", "10": "دی", "11": "بهمن", "12": "اسفند" |
| | } |
| |
|
| | df['کدماه'] = df['نام ماه'].astype(str).str[:2] |
| | df['ماه'] = df['کدماه'].map(month_dict) |
| |
|
| | |
| | grouped = df.groupby(['کد کالا','نام کالا','طرف حساب','ماه']).agg({ |
| | qty_col:'sum', amt_col:'sum' |
| | }).reset_index() |
| | pivot_qty = grouped.pivot_table( |
| | index=['کد کالا','نام کالا','طرف حساب'], |
| | columns='ماه', values=qty_col, fill_value=0 |
| | ).reindex(columns=month_order, fill_value=0) |
| | total_amount = grouped.groupby(['کد کالا','نام کالا','طرف حساب'])[amt_col].sum() |
| | pivot_qty['مجموع مبلغ خرید'] = total_amount |
| | report_customer = pivot_qty.reset_index() |
| |
|
| | tab1, tab2, tab3, tab4 = st.tabs(["گزارش مشتری", "گزارش تجمیعی تعداد", "گزارش تجمیعی مبلغ", "داشبورد تصویری"]) |
| |
|
| | with tab1: |
| | st.subheader("📋 گزارش خرید هر شخص برای هر کالا") |
| | st.dataframe(report_customer, use_container_width=True) |
| | st.download_button("⬇️ دانلود گزارش مشتری (CSV)", report_customer.to_csv(index=False, encoding='utf-8-sig'), |
| | "Sales_Report_ByCustomer.csv", "text/csv", use_container_width=True) |
| |
|
| | |
| | grouped_total = df.groupby(['کد کالا','نام کالا','ماه']).agg({qty_col:'sum', amt_col:'sum'}).reset_index() |
| | pivot_qty_total = grouped_total.pivot_table( |
| | index=['کد کالا','نام کالا'], columns='ماه', values=qty_col, fill_value=0 |
| | ).reindex(columns=month_order, fill_value=0) |
| | pivot_amt_total = grouped_total.pivot_table( |
| | index=['کد کالا','نام کالا'], columns='ماه', values=amt_col, fill_value=0 |
| | ).reindex(columns=month_order, fill_value=0) |
| |
|
| | |
| | pivot_qty_total['جمع کل تعداد'] = pivot_qty_total.sum(axis=1) |
| | pivot_amt_total['جمع کل مبلغ'] = pivot_amt_total.sum(axis=1) |
| |
|
| | with tab2: |
| | st.subheader("📦 گزارش تجمیعی تعداد فروش کل کالاها") |
| | st.dataframe(pivot_qty_total.reset_index(), use_container_width=True) |
| | st.download_button("⬇️ دانلود گزارش تجمیعی تعداد (CSV)", pivot_qty_total.reset_index().to_csv(index=False, encoding='utf-8-sig'), |
| | "Total_Quantity_Report.csv", "text/csv", use_container_width=True) |
| |
|
| | with tab3: |
| | st.subheader("💰 گزارش تجمیعی مبلغ فروش کل کالاها") |
| | st.dataframe(pivot_amt_total.reset_index(), use_container_width=True) |
| | st.download_button("⬇️ دانلود گزارش تجمیعی مبلغ (CSV)", pivot_amt_total.reset_index().to_csv(index=False, encoding='utf-8-sig'), |
| | "Total_Amount_Report.csv", "text/csv", use_container_width=True) |
| |
|
| | with tab4: |
| | st.header("📊 نمودارهای فروش") |
| |
|
| | |
| | sales_by_customer = df.groupby('طرف حساب')[amt_col].sum().sort_values(ascending=False).head(10).reset_index() |
| | sales_by_customer.columns = ['طرف حساب', 'مبلغ فروش'] |
| | fig1 = px.bar(sales_by_customer, x='طرف حساب', y='مبلغ فروش', title="🏆 برترین مشتریها", color='مبلغ فروش') |
| | st.plotly_chart(fig1, use_container_width=True) |
| |
|
| | |
| | sales_by_product = df.groupby('نام کالا')[amt_col].sum().sort_values(ascending=False).head(10).reset_index() |
| | sales_by_product.columns = ['نام کالا', 'مبلغ فروش'] |
| | fig2 = px.bar(sales_by_product, x='نام کالا', y='مبلغ فروش', title="📦 برترین کالاها", color='مبلغ فروش') |
| | st.plotly_chart(fig2, use_container_width=True) |
| |
|
| | |
| | sales_by_month = df.groupby('ماه')[amt_col].sum().reindex(month_order, fill_value=0) |
| | fig3 = px.bar(x=sales_by_month.index, y=sales_by_month.values, title="📅 فروش ماهانه", labels={'y':'مبلغ فروش', 'x':'ماه'}) |
| | st.plotly_chart(fig3, use_container_width=True) |
| |
|
| | |
| | top_5_customers = sales_by_customer.head(5) |
| | fig4 = px.pie(top_5_customers, values='مبلغ فروش', |
| | names='طرف حساب', title="🥧 سهم مشتریها از کل فروش (Top 5)") |
| | st.plotly_chart(fig4, use_container_width=True) |
| |
|
| | |
| | top_5_products = sales_by_product.head(5) |
| | fig5 = px.pie(top_5_products, values='مبلغ فروش', |
| | names='نام کالا', title="🥧 سهم کالاها از کل فروش (Top 5)") |
| | st.plotly_chart(fig5, use_container_width=True) |
| |
|
| | |
| | fig6 = px.line(sales_by_month, title="📈 روند فروش در طول سال", labels={'value':'مبلغ فروش', 'index':'ماه'}, markers=True) |
| | st.plotly_chart(fig6, use_container_width=True) |
| |
|