Shopline訂單轉換筆記

這裡的範例是用匯出的excel檔進行轉換動作

import pandas as pd
import json
import numpy as np
import re
import os
import tkinter as tk
from tkinter import filedialog

# **開啟 UI 讓使用者選擇 xls 檔案**
root = tk.Tk()
root.withdraw()  # 隱藏主視窗
xls_file_path = filedialog.askopenfilename(title="選擇 XLS 檔案", filetypes=[("Excel 檔案", "*.xls;*.xlsx")])

if not xls_file_path:
    print("❌ 未選擇檔案,程式結束")
    exit()

# **取得檔案名稱與路徑**
file_dir, file_name = os.path.split(xls_file_path)
file_base_name, _ = os.path.splitext(file_name)

# **設定輸出檔案名稱**
json_output_path = os.path.join(file_dir, f"{file_base_name}.json")
excel_output_path = os.path.join(file_dir, f"{file_base_name}_output.xlsx")

# **讀取 XLS**
df = pd.read_excel(xls_file_path, dtype=str)  # 讀取時強制為字串

# **讀取 plist.json(同目錄)**
plist_json_path = os.path.join(file_dir, "plist.json")
if os.path.exists(plist_json_path):
    with open(plist_json_path, "r", encoding="utf-8") as f:
        plist_data = json.load(f)
    product_price_map = {str(item["產品編號"]): str(item.get("建議售價", "0")) for item in plist_data}
else:
    print("⚠️ 找不到 plist.json,跳過商品價格填補")
    product_price_map = {}

# **清理異常字元**
def clean_text(value):
    if isinstance(value, str):
        value = value.strip()
        value = re.sub(r"[\x00-\x1F\x7F-\x9F]", "", value)
        value = value.replace("\n", " ").replace("\r", " ")
        value = value.replace('"', "'")
    return str(value)  # 確保返回字串

df = df.map(lambda x: clean_text(str(x)) if pd.notna(x) else "")

# **補充「商品結帳價」**
for index, row in df.iterrows():
    if row["商品結帳價"] == "":
        product_id = row["商品貨號"]
        if product_id in product_price_map:
            df.at[index, "商品結帳價"] = product_price_map[product_id]

# **建立 JSON**
order_dict = {}

for _, row in df.iterrows():
    order_id = row["訂單號碼"]

    # **如果該訂單號碼不存在,先存入第一列的所有欄位**
    if order_id not in order_dict:
        order_dict[order_id] = {
            "order_info": row.to_dict(),
            "products": [],
            "order_total": 0
        }

    # **移除商品貨號為空的商品**
    product_id = row["商品貨號"]
    if product_id == "":
        continue

    quantity = int(row["數量"]) if row["數量"].isdigit() else 1
    price = float(row["商品結帳價"]) if row["商品結帳價"].replace('.', '', 1).isdigit() else 0
    total_price = price * quantity

    product_info = {
        "商品貨號": product_id,
        "商品結帳價": str(price),
        "商品名稱": row["商品名稱"] if row["商品名稱"] else row["選項"],
        "數量": str(quantity)
    }

    order_dict[order_id]["products"].append(product_info)
    order_dict[order_id]["order_total"] += total_price

# **加入 "折扣" 產品**
for order_id, data in order_dict.items():
    payment_total = float(data["order_info"].get("付款總金額", "0") or "0")
    discount_value = payment_total - data["order_total"]

    discount_product = {
        "商品貨號": "P00-000-00",
        "商品結帳價": str(discount_value),
        "商品名稱": "折扣",
        "數量": "1"
    }
    data["products"].append(discount_product)

# **移除 order_total 欄位**
for order_id in order_dict:
    del order_dict[order_id]["order_total"]

# **儲存 JSON**
with open(json_output_path, "w", encoding="utf-8") as f:
    json.dump(order_dict, f, ensure_ascii=False, indent=4)

# **轉換為 Excel**
order_list = []
for order_id, data in order_dict.items():
    order_info = data["order_info"]
    for product in data["products"]:
        combined_data = {**order_info, **product}  # 先帶入 order_info,再覆蓋 products 內的欄位
        order_list.append(combined_data)

# **轉換成 DataFrame**
order_df = pd.DataFrame(order_list)

# **儲存 Excel**
order_df.to_excel(excel_output_path, index=False)

print(f"✅ JSON 轉換完成,已儲存至 {json_output_path}")
print(f"✅ Excel 轉換完成,已儲存至 {excel_output_path}")

說明一下,P00-000-00是進銷中折扣的商品貨號

plist.json格式 (商品的資料庫)

[

    {

        "產品編號": "P01-001-01",

        "品名規格": "商品1",

        "(類別名稱)": "分類1",

        "條碼編號": "55122124121",

        "建議售價": "1300"

    }

]

由於Shopline的組合商品,匯出的欄位會是
商品組合 SKU空值 總金額
商品1 SKU
商品2 SKU
(商品1和2伴隨者一堆空值)

因此我才用Python來解套

這裡的使用邏輯,就是如果商品的SKU沒有值,那麼就使用plist.json去撈金額

撈完商品金額後,在商品那裡會把 SKU空值的項目移掉

最後我會用訂單的總金額去扣除所有商品的售價x數量,生成一個折扣 P00-000-00

執行python後會自動存成json及xlsx兩種格式

大概的發想這是這樣,由於我們是用訂單總金額去扣,所以不用去管點數折扣及運費

更進階一點可以用api寫python去拉,會更省事

瀏覽次數:35