Skip to content

lee2nd/e-commerce-ERP-system-streamlit-app

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

86 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

title 電商平台 ERP & 報表系統
emoji 📊
colorFrom blue
colorTo purple
sdk streamlit
sdk_version 1.54.0
app_file app.py
pinned false

📊 電商平台 ERP & 報表系統

一站式電商進銷存管理系統,整合蝦皮、露天、官網 (EasyStore)、MO店等多平台訂單資料,提供即時庫存追蹤、營收報表與數據分析。

📋 專案簡介

經營多平台電商最痛苦的是什麼?每天打開 4 個後台、下載 4 份報表、手動對帳到眼花。

這套系統解決的核心問題:

  • 多平台訂單整合:一鍵匯入蝦皮、露天、官網、MO店訂單,自動轉換格式
  • 即時庫存追蹤:入庫、出庫、組合商品自動扣庫,庫存異常一目瞭然
  • 成本與利潤計算:自動計算商品成本、平台手續費、物流費用、淨利
  • 日報表 / 月報表:退貨、未取貨、部份退貨等複雜情境全自動處理
  • 數據圖表分析:營收趨勢、平台佔比、單品銷售排行,輔助經營決策

🛠️ 技術堆疊 (Tech Stack)

類別 技術
語言 Python 3.10+
前端框架 Streamlit
資料處理 Pandas, NumPy
視覺化 Plotly
檔案格式 Excel (openpyxl)
部署平台 Hugging Face Spaces / Streamlit Community Cloud

📸 系統截圖

首頁 日報表 數據圖表
首頁 日報表 數據圖表
單品銷售查詢 銷售排行
單品銷售查詢 銷售排行

🚀 環境建置指南

1. clone 專案

git clone https://github.com/lee2nd/e-commerce-ERP-system-streamlit-app.git
cd e-commerce-ERP-system-streamlit-app

2. 建立虛擬環境並啟動

python -m venv .venv

# Windows
.venv\Scripts\activate

# macOS / Linux
source .venv/bin/activate

3. 安裝依賴套件

pip install -r requirements.txt

4. 執行應用程式

streamlit run app.py

應用程式將在 http://localhost:8501 啟動。

5. 部署至 Hugging Face Spaces

  1. Fork 本專案至你的 GitHub
  2. Hugging Face Spaces 建立新 Space
  3. 選擇 Streamlit SDK,連結你的 GitHub repo
  4. 等待自動部署完成

📝 更新日誌

3/1 & 3/7 完成項目

  1. 刪除雅虎平台,新增 mo 店 / easystore
  2. 刪除分類 A/B 報表,統一合併為一個報表
    • 入庫人可以刪掉
    • 出庫的出庫人可刪除 column
    • 導出日報表不分 AB
  3. 新增商品明細的「主貨號」和「貨號」
    • 入庫多一欄主貨號(概念等同目前原本的貨號)
    • 新的貨號可以參考蝦皮
    • 對照表依照「貨號」自動匹配商品
  4. 對齊最新的 columns
  5. 解決實際環境 data 存下路徑的問題,用 Streamlit 的 Manage App 去觀察(目前 app 重開,資料就會洗掉了)

3/15 完成項目

  1. 名稱統一改 MO 店
  2. 入庫合併同商品同日期的資料
  3. 入庫設定 user 可以刪除資料
  4. 對照表:入庫品名用貨號去自動匹配,不由人工輸入
    • 入庫品名若未匹配到,標註「未匹配」
    • 出庫若未匹配到,直接沿用原報表名稱
    • 庫存明細若未匹配到,則不納入計算
  5. 庫存平均成本根據入庫平均成本連動變動
  6. 庫存明細的規格預設按照尺碼大小排序:XS>S>M>L>XL>2XL>3XL>4XL>5XL

3/21 完成項目

  1. 入庫貨號重複防呆(貨號相同但品名/規格不同)

    • Excel 上傳:檔案內部或與現有資料有貨號衝突時,顯示衝突明細並封鎖匯入按鈕
    • 網頁手動新增:若新增的貨號與現有資料品名/規格不符,顯示衝突明細並阻止新增
  2. 庫存明細排序修正

    • 排序邏輯改為:主貨號 → 顏色(規格去掉尺碼的部分)→ 尺碼大小
    • 例如 HFE03002:黑色M > 黑色L > 黑色XL > 米咖色M > 米咖色L > 米咖色XL
  3. 新增「組合貨號」功能

    • 匯入資料新增第三個分頁「🔗 組合貨號」,支援新增/刪除/清除組合貨號
    • 組合貨號由多組原料貨號 × 數量組成,例如:YGK03002-RDL30-RR-DIY = YGJ03002-RDL×30 + YGK03002-RR×1
    • 資料存在 data/data_dev/組合貨號.xlsx(欄位:組合貨號、原料貨號、原料數量)
    • 庫存明細:出庫中的組合貨號會自動展開為原料貨號扣庫存
    • 對照表:組合貨號自動匹配,入庫品名顯示為「組合:原料A×數量+原料B×數量」
    • 導出出庫:組合貨號在出庫映射中正確識別,不再標為未匹配
    • 日報表:組合貨號成本 = 各原料成本 × 原料數量之總和
  4. 日報表改為 data_editor 可編輯

    • 欄位設定:日期(DateColumn)、訂單狀態(SelectboxColumn 下拉)、金額欄位(NumberColumn 格式化)
    • 訂單編號、平台欄位設為唯讀
    • 新增「💾 儲存修改」按鈕,將手動修改寫回 Excel
    • 重新產生日報表時,以「訂單編號 + 日期」為 key,保留已存在的手動修改,只新增全新訂單
  5. 日報表訂單狀態邏輯微調

    • 蝦皮
      • 遺失賠償:不成立原因 含「遺失」關鍵字 → 狀態=遺失賠償,計算同已完成
      • 退貨:退貨 / 退款狀態 非空 → 狀態=退貨
      • 其他不成立原因(無「遺失」)→ 跳過(取消/無效訂單)
    • 露天交易狀況 含「已領取退貨」→ 狀態=未取貨
    • 官網:Remark 含「cancel / 取消訂購」→ 未取貨;Financial Status 含「refund」→ 退貨
    • 未取貨訂單:只計實際運費為成本,折扣優惠、商品成本、手續費等一律歸零
  6. 未匹配標記寫入備註欄位

    • 重新產生日報表時,若該訂單所有商品均未在入庫中匹配到,備註欄自動填入「未匹配」
    • 日報表頁面新增「未匹配篩選」radio(全部 / 未匹配 / 已匹配)
    • 舊資料自動補寫:頁面載入時檢查备註空白且商品名稱空或商品成本=0 的列,自動回填「未匹配」並存檔
  7. 露天手續費計算修正

    • 成交手續費:單價 × 數量 × 3%,四捨五入,最低 1 元,最高 400 元
    • 其他服務費:單價 × 數量 × 5%,四捨五入,最低 1 元,最高 300 元
    • 金流與系統處理費:(結帳總金額 + 露天折扣碼金額) × 1.5%,四捨五入,最低 1 元,無上限

3/22 完成項目

  1. 日報表修改成本後,總成本與淨利自動重算

    • 點擊「💾 儲存修改」後,自動依公式重算篩選範圍內所有列的總成本與淨利
    • 總成本 = 商品成本+折扣優惠+未取貨/退貨運費+成交手續費+其他服務費+金流與系統處理費+發票處理費+其他費用
    • 淨利 = 訂單金額 − 總成本
  2. 入庫分批上傳資料保留修正

    • 原本第二次上傳會整份覆蓋,舊資料消失
    • 修正為以「貨號 + 入庫日期」為 PK,已存在則保留舊資料,只新增未出現過的列
    • 匯入成功後顯示實際新增筆數
  3. 未匹配判斷邏輯勘誤

    • 未匹配的唯一依據:貨號在入庫中找不到(備註 欄位含「未匹配」)
    • 移除舊邏輯中用 商品成本 == 0 判斷未匹配的錯誤(退貨訂單商品成本為 0 是正確的,不應標為未匹配)
    • 頁面載入時自動修正:退貨/未取貨且商品名稱有值的列,若被誤標「未匹配」會自動清除
  4. 導出出庫新增匹配狀態欄位與篩選

    • 匹配狀態 欄位顯示「已匹配」或「未匹配」
    • 新增 Radio 篩選器(全部 / 已匹配 / 未匹配)
    • 欄位順序調整:平台 移至最後一欄

3/25 完成項目

  1. 物流處理費(運費差額)正負號修正

    • 物流處理費作為費用計入總成本,正負方向需與成本邏輯一致
    • 官網原公式:實際運費支出 − 買家支付運費,修正為:買家支付運費 − 實際運費支出
    • 露天公式維持:實際運費支出 − 買家支付運費(已正確,不變)
  2. 導出出庫新增平台與日期範圍篩選

    • 篩選器列改為三欄:匹配狀態(Radio)、平台(下拉選單)、日期範圍(日期區間選擇器)
    • 平台選項依實際資料動態生成,預設顯示全部;日期區間預設為資料最早至最晚日期
  3. 日報表「儲存修改」時物流處理費連動重算

    • 修改「實際運費支出」後,點擊儲存時自動依平台公式重算「物流處理費(運費差額)」
    • 露天:max(0, 實際運費支出 − 買家支付運費)
    • 官網:max(0, 買家支付運費 − 實際運費支出)
  4. 官網訂單狀態判斷邏輯更新

    • 未出貨,取消訂單:Fulfillment Service 為空 且 Fulfillment Status = "Restocked" / "Unfulfilled" → 跳過不列出
    • 已出貨,退貨:Fulfillment Service 不為空 且 Refunded Amount ≠ 0 → 狀態=退貨
    • 已出貨,未取貨:Fulfillment Service 不為空 且(Fulfillment Status = "Restocked"/"Unfulfilled" 或 最後一筆 Transaction status = "Pending")→ 狀態=未取貨
    • Transaction status 以同訂單最後一列非空值為準(付款紀錄以最後一筆判定)
  5. 蝦皮部份退貨訂單拆成兩行顯示

    • 原本只顯示保留商品(有效數量),退貨商品直接略過
    • 更新後:拆為兩筆—第一筆「已完成」(保留商品,含一般費用)、第二筆「退貨」(退回商品,只計退貨運費)
    • 兩筆備註均標示「部份退貨」,可與整單退貨區分
    • 若未匹配,備註格式為「未匹配、部份退貨」,不影響現有未匹配篩選邏輯
    • 重新產生日報表時,以「訂單編號 + 日期」→「訂單編號 + 日期 + 訂單狀態」(3/25更新)為 key,保留已存在的手動修改,只新增全新訂單

3/27 完成項目

  1. 大資料量 st.dataframe 效能優化

    • utils/data_manager.py 主要 load 函式加上 @st.cache_dataload_storageload_platform_ordersload_compare_tableload_deliveryload_inventory_details),資料只在首次載入時讀檔,重新渲染不重複 I/O
    • 對應的 save / clear 函式呼叫 .clear() 確保寫入後下一次 rerun 拿到最新資料
  2. 分頁顯示(每頁 500 筆)

    • 適用頁面:匯入資料(入庫、各平台訂單)、對照表、導出出庫、庫存明細
    • 頁碼改為 st.selectbox 下拉選單,格式:「第 X 頁(共 N 頁)」
    • 搜尋 / 篩選作用於完整資料集,分頁只影響顯示範圍
  3. 全表下載

    • 各表格新增「⬇️ 下載」按鈕,下載對象為篩選後的完整資料(CSV UTF-8 BOM),非當頁切片
  4. 月報表


3/28 完成項目

  1. 有儲存修改功能的頁面顯示最後修改時間

  2. 一鍵下載所有 data / data_dev 資料 & 可上傳覆蓋

  3. 導出出庫增加「訂單編號」欄位

  4. 月報表「其他費用(一)」無法修改

    • 修正為可編輯欄位
  5. 蝦皮報表折扣優惠計入修正

    • 折扣優惠:[Q_賣家負擔優惠券][R_賣家負擔蝦幣回饋券]
    • 蝦皮報表欄位名稱近期有變動,原為 [Q_賣場優惠券][R_賣家蝦幣回饋券]
  6. 數據圖表優化

    • 修正 Arrow 序列化錯誤(年度平均訂單量欄位混合型別)
    • 圖表顏色調整:蝦皮橘色、露天藍色、官網綠色
  7. 單品銷售查詢 & 銷售排行

    • 移除 _NULL_LIKE 中的 "tbd" 判斷
  8. 程式碼清理

    • 刪除未使用的變數與函式
    • 刪除未使用的套件(xlrdbeautifulsoup4html5lib
  9. 日報表儲存後資料異常修正

    • 修正物流處理費(運費差額)重算公式與 calculators.py 不一致的問題
    • 露天:-max(0, 買家支付運費 − 實際運費支出)(≤0)
    • 官網:實際運費支出 − 買家支付運費(可正可負)
  10. 時區修正(Streamlit Cloud UTC+0 → 台灣時間 UTC+8)

    • 問題:datetime.now()pd.Timestamp.now() 在 Streamlit Cloud(UTC+0)環境下會顯示 UTC 時間,比台灣時間少 8 小時
    • 修正方式:所有產生「最後儲存時間」的呼叫改用 TZ_TAIPEI = timezone(timedelta(hours=8)),即 datetime.now(tz=TZ_TAIPEI)
    • 無需安裝額外套件(使用標準庫 datetime.timezone + datetime.timedelta
    • 影響檔案:app.pypages/1_📥_匯入資料.pypages/2_📋_對照表.pypages/3_📦_導出出庫.pypages/4_🔎_庫存明細.pypages/5_📊_日報表.pypages/6_📈_月報表.py

4/12 完成項目

效能優化(Streamlit Community Cloud 記憶體瓶頸)

  1. 數值型態降級(dtype downcast)

    • utils/data_manager.py 新增 _optimize_dtypes():int64 降為最小可用整數型態、float64 降為 float32
    • 所有 load 函式回傳前自動套用,節省記憶體
  2. 全面加入 @st.cache_data(ttl=300)

    • 原本部分 load 函式已有 cache,本次補齊所有遺漏(load_daily_reportload_combo_sku
    • TTL = 300 秒,避免長時間不重新載入
  3. Session state 大型暫存清理

    • app.py:ZIP 下載後主動清除個別檔案快取、個別檔案下載時清除 ZIP 快取
    • 避免 session_state 堆積過多 bytes 導致 OOM

功能新增 & 修正

  1. 月報表新增「營登租金」欄位

    • 手動可編輯,預設值 $1,155
    • 計入「總成本」公式
  2. 月報表新增「備註」欄位

    • 文字欄位,可輸入任意備註內容
    • 更新月報表時自動保留既有備註
  3. 數據圖表新增薪資費用、廣告費用合計趨勢線

    • 圖表新增兩條虛線:薪資費用(橘色)、廣告費用合計(紫色),掛右軸
    • 年度摘要指標新增「薪資費用」、「廣告費用合計」區塊
  4. 數據圖表「總淨利額」改從月報表取得

    • 原本從日報表直接計算(訂單金額 − 總成本),未包含月報表手動費用
    • 修正為讀取月報表的「淨利」欄位,確保與月報表一致
  5. 數據圖表「年度平均訂單量」分母修正

    • 原本固定除以 12,年中時數值偏低
    • 修正為除以「實際有訂單資料的月份數」,更準確反映月均量
    • 只有有月份的 "年度平均訂單量" 才顯示,其他的月份放 0
  6. pandas FutureWarning 修正

    • 數據圖表 頁面 pd.concat 合計列前先 .dropna(axis=1, how="all") 避免全空欄警告
  7. 修正 hover 數值出現2次問題

  8. 導出出庫:官網訂單編號修正

  • 官網原始資料使用 Order Name 欄位,但出庫取值時統一用 訂單編號,導致官網訂單編號為空
  • 修正 _get_order_data:官網改為讀取 Order Name 欄位
  1. 導出出庫:平台篩選改為多選
  • 原本為單選下拉選單(st.selectbox),改為多選(st.multiselect
  • 預設選取所有平台,可自由勾選/取消
  1. 數據圖表:年度摘要指標字體縮小
  • 總營業額等 metric 數值過長會被截斷顯示 ...
  • 注入自訂 CSS 將 metric 數值字體縮小為 1.2rem,避免溢位截斷
  1. 露天未取貨訂單運費欄位修正
  • 原本 買家支付運費平台補助運費實際運費支出物流處理費(運費差額) 在未取貨時仍帶入原值,導致總成本計算偏差
  • 修正:未取貨時以上四欄歸零,僅保留 未取貨/退貨運費 = 實際運費支出
  1. 導出出庫:平台多選全取消時顯示空表
  • 原本全部取消勾選時,篩選邏輯因空 list 判斷失效,仍顯示所有資料
  • 修正:改為無條件套用 isin(plat_filter),空 list 時正確回傳空結果
  1. 蝦皮訂單包含未匹配商品時,日報表未顯示「未匹配」
  • 問題:蝦皮訂單編號 2505283XEMY4EP 含 5 個商品(4 個已匹配、1 個未匹配),對照表及出庫正確顯示未匹配,但日報表未標註
  • 原因:日報表依訂單分組後使用 any(r["_matched"]) 判斷,只要有任一商品匹配即不標記「未匹配」
  • 修正:改為 all(r["_matched"]),只有全部商品皆匹配才算已匹配;任一商品未匹配即在備註標記「未匹配」
  • 影響範圍:_process_shopee(部份退貨/整單退貨/已完成)、_process_ruten_process_easystore
  1. 對照表及出庫未顯示未匹配,但日報表正常顯示(與 Bug 7 相反)
  • 問題:官網訂單 #114621#117136 與蝦皮訂單 250513RDPQHFS0 的商品,對照表及出庫顯示為已匹配,但日報表正確顯示未匹配
  • 原因 1(對照表 SKU 過時):auto_match_compare_table 使用 drop_duplicates(keep="first"),保留最早出現的 SKU;如平台上的 SKU 已變更(如 HME03001-GY-LTB300001-灰色-L-新標),對照表仍沿用舊 SKU(在入庫中存在),導致誤判為已匹配
  • 修正 1:改為 drop_duplicates(keep="last"),使用最新訂單的 SKU 重新比對入庫
  • 原因 2(出庫官網 ffill 跨訂單污染):_filter_easystoreRemarkFulfillment ServiceFulfillment Status 做整表 ffill(),前一筆訂單的「取消訂購」或「Restocked」狀態可能洩漏至後續訂單,導致有效訂單被錯誤過濾
  • 修正 2:改為先 ffill("Order Name"),再 groupby("Order Name").ffill() 避免跨訂單污染
  1. 露天已取消訂單仍出現在日報表與出庫中
  • 問題:露天訂單 25112338114612訂單狀態 = 「已取消」,但日報表仍列出為「已完成」,出庫也包含該筆
  • 原因:_process_ruten 僅檢查 交易狀況 欄位是否含「取消」,但此訂單的 交易狀況 = 「請於11/27前完成出貨」(不含「取消」),而 訂單狀態 = 「已取消」未被檢查
  • 修正(日報表):_process_ruten 新增 訂單狀態 欄位的「取消」關鍵字檢查
  • 修正(出庫):_filter_ruten 新增 訂單狀態 含「取消」的過濾條件
  1. 首頁新增記憶體監控
  • 顯示三項指標:本程序 RSS(MB)、佔系統記憶體(%)、佔 Cloud 上限 1 GB(%)
  • 使用量超過 80% 時顯示警告
  • 新增 psutil 依賴
  1. 程式碼清理
  • 移除未使用的變數:app.py 中的 _sys_mem日報表.py 中的 _PLAT_COLORS
  • 移除未使用的套件:requirements.txt 中的 lxml(程式碼中無任何引用)
  1. 防止 Hugging Face Spaces 閒置斷線
  • 問題:Hugging Face Spaces 負載平衡器在偵測到 WebSocket 閒置一段時間後,會強制切斷連線,導致網頁反灰或顯示斷線
  • 解法 A(Keep-alive):requirements.txt 加入 streamlit-autorefreshapp.pyset_page_config 後呼叫 st_autorefresh(interval=3 * 60 * 1000, key="keep_alive"),每 3 分鐘在背景發送訊號保持連線
  • 解法 B(停用 WebSocket 壓縮):新增 .streamlit/config.toml,設定 enableWebsocketCompression = false,避免代理伺服器誤判連線狀態
  1. UI 優化更新
  • 視覺風格升級:導入全域 CSS 樣式集(utils/styles.py),優化按鈕、卡片、標籤頁與滾動條視覺效果,透過 apply_global_styles() 套用至所有頁面。
  • 介面一致性:統一各頁面的標題層級與間距,提升操作體驗。
  • 主題配色:自定義 .streamlit/config.toml 主題配色,採用更專業的深藍(#2563EB)與簡潔白背景。
  1. 首頁新增一鍵還原與一鍵全刪功能
  • 一鍵上傳 ZIP 還原:可上傳先前下載的備份 ZIP,自動解壓並將所有 .xlsx 覆蓋還原至 data/ 目錄(本地或雲端皆支援)。
  • 一鍵刪除全部資料:刪除 data/ 目錄下所有 .xlsx 檔案;需手動輸入「確認刪除」才能啟用按鈕,防止誤操作。
  • 操作結果訊息改為就近顯示:各功能按鈕的執行結果(成功/失敗)顯示在該區塊附近,不再跳到頁面頂部。

CICD Issues

  1. 顯示隱藏的項目的 .git folder 刪掉

  2. 先把 github 上面的 data folder 最新資料下載下來,放在本地專案的 data 資料夾中(極重要)

  3. 重新初始化一個乾淨的 Git git init git add . git commit -m "Clean history without Excel files"

  4. 把分支名稱設定為 main git branch -M main

  5. 重新連上你的 GitHub git remote add origin https://github.com/lee2nd/e-commerce-ERP-system-streamlit-app.git

  6. 強制覆蓋 GitHub 上的舊紀錄 (加上 -f) git push -f origin main

  7. publish branch main 到 GitHub

資料概況

  • 存放 2~3 年的資料
  • 入庫 : 1000+
  • 蝦皮 : 5000 ~ 8000 / 每月
  • MOMO & 露天 & 官網 : 100-300 / 每月

退貨 / 取消訂單業務規則

官網

情境 日報表 庫存 / 出庫
未取貨(#144485) 需列出,未取貨/退貨運費 固定 $65 不扣庫存、不計入出庫
出貨前取消(#143166) 可直接刪除,不列出 不扣庫存、不計入出庫

蝦皮

情境 日報表 庫存 / 出庫
未取貨(260101T9JAVCHM) 可直接刪除,不列出 不扣庫存、不計入出庫
出貨前取消(260101U289VMH1) 可直接刪除,不列出 不扣庫存、不計入出庫
整單退貨(260101UQC2FXC5) 需列出,退貨運費 需列出(即使為 $0) 不扣庫存、不計入出庫
部份退貨(260101VGTQ5TTD) 需列出,退貨運費 需列出(即使為 $0);AI欄_數量與AJ欄_退貨數量的差額為實際退貨數量,無差額代表該項全退 退貨部份不扣庫存、不計入出庫;實際成交數量計入庫存與出庫。例:HME03002-ST-DN-XL 購買3退2 → 計入庫存/出庫 ×1
部份退貨(260111RDUTKB7X) 需列出,退貨運費 需列出(即使為 $0);未退貨品項的「退貨/退款狀態」欄位為空白 退貨品項不扣庫存;未退貨品項計入庫存與出庫。例:HFA02001-TN-BK-M 全退,HFF02001-SK-140G 保留 → 計入庫存/出庫 ×1

露天

情境 日報表 庫存 / 出庫
買家未取貨 需列出,未取貨/退貨運費 依該筆訂單的付款方式(D欄_付款方式)計入 不扣庫存、不計入出庫

露天運費對照:

  • 7-11 取貨 → $60
  • 全家取貨 → $60
  • OK 超商取貨 → $60
  • 萊爾富取貨 → $50
  • 中華郵政 → $65

密碼

  • MOMO: 87150737
  • 蝦皮: 030812

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors