瑪黑
📖 簡介
此程式用於處理 瑪黑家居平台的訂單檔案(Excel 或 CSV),自動完成 SKU 轉換、溫層判斷、預交貨日設定、分錄備註生成與新轉單編號產生,輸出可直接使用的新訂單檔案。
🛠 功能特色
-
預交貨日設定
-
啟動程式時輸入加幾天(預設 1),自動計算新預交貨日。
-
-
SKU 對應轉換
-
根據
sku_ma.json對照表,將「瑪黑家居新版商品編號」轉換為新 SKU。 -
自動計算新數量與新進價。
-
-
溫層判斷
-
使用
plist.json溫層資料:-
若同一訂單所有品項均為常溫 → 設為常溫
-
否則 → 設為冷凍。
-
-
-
分錄備註
-
自動生成「收件人地址前三字 + 收件人姓名」。
-
若同一轉單編號有多筆 → 僅保留首筆,其餘備註清空。
-
-
新轉單編號生成
-
格式:
MYYYYMMDD001 -
每日流水號遞增,記錄於
sku_transfer_log.json,避免重複。
-
-
輸出檔案
-
檔名格式:
-
原始檔名_SKU轉換_YYYYMMDD_HHMMSS.xls
📂 必要檔案
-
輸入檔案
-
瑪黑訂單 Excel 或 CSV
-
-
SKU 對照表
-
\\nas-lianruey\office\sku\sku_ma.json
-
-
溫層資料
-
\\nas-lianruey\office\sku\plist.json
-
-
轉單紀錄檔
-
\\nas-lianruey\office\sku\app\sku_transfer_log.json
-
📐 新增欄位
輸出檔案中會自動新增:
-
新SKU
-
新數量
-
新進價
-
新預交貨日
-
溫層
-
分錄備註
-
新轉單編號
⚙️ 操作流程
-
執行程式。
-
輸入「預交貨日加幾天」(若不輸入,預設為 1)。
-
選取訂單檔案(Excel 或 CSV)。
-
程式自動完成 SKU 轉換、溫層判斷、分錄備註生成、新轉單編號產生。
-
完成後在原目錄輸出新檔案。
✅ 輸出結果
-
已完成 SKU 轉換、預交貨日設定、溫層判斷、分錄備註、新轉單編號生成。
-
新檔案可直接用於出貨或後續系統匯入。
⚙️ 程式原始碼
import os
import json
import pyexcel as pe
import requests
import re
from tkinter import Tk, filedialog, simpledialog
from datetime import datetime, timedelta
from collections import defaultdict, OrderedDict
# 關閉 tkinter 主視窗
root = Tk()
root.withdraw()
# 詢問加幾天,預設為1
days_to_add = simpledialog.askinteger("預交貨日設定", "請輸入要加幾天(預設為1)", initialvalue=1)
if not days_to_add:
days_to_add = 1
# 選取檔案(支援 Excel 與 CSV)
file_path = filedialog.askopenfilename(
title="選擇 Excel 或 CSV 檔案",
filetypes=[("Excel/CSV Files", "*.xls *.xlsx *.csv")]
)
if not file_path:
print("❌ 未選擇檔案,程式結束。")
exit()
# SKU 對照表
sku_json_path = r"\\nas-lianruey\office\sku\sku_ma.json"
if not os.path.isfile(sku_json_path):
print(f"❌ 找不到 SKU 對照表檔案:{sku_json_path}")
exit()
with open(sku_json_path, "r", encoding="utf-8") as f:
sku_map = json.load(f)
# 溫層資料
plist_url = r'\\nas-lianruey\office\sku\plist.json'
try:
with open(plist_url, "r", encoding="utf-8") as f:
temp_data = json.load(f)
except FileNotFoundError:
print(f"❌ 找不到溫層資料檔案:{plist_url}")
exit()
except json.JSONDecodeError as e:
print(f"❌ 無法解析溫層資料檔案:{e}")
exit()
sku_temp_map = {}
for item in temp_data:
sku = item.get("sku")
temp = item.get("temp", "").strip() or "冷凍"
if sku:
sku_temp_map[sku] = temp
# 讀取資料
ext = os.path.splitext(file_path)[1].lower()
if ext == ".csv":
records = pe.get_array(file_name=file_path, encoding="utf-8-sig")
else:
records = pe.get_array(file_name=file_path)
next_date = (datetime.today() + timedelta(days=days_to_add)).strftime("%Y%m%d")
header = records[0]
# 欄位定位與轉單欄位建立
try:
order_index = header.index("訂單編號")
item_index = header.index("瑪黑家居新版商品編號")
qty_index = header.index("數量")
address_index = header.index("收件人地址")
name_index = header.index("收件人姓名")
if "轉單編號" not in header:
header.append("轉單編號")
for i in range(1, len(records)):
order_id = str(records[i][order_index])
mo_id = order_id[:12] if len(order_id) >= 12 else order_id
records[i].append(mo_id)
header = records[0]
except ValueError as e:
print("❌ 缺少必要欄位:", e)
exit()
# 新欄位
header += ["新SKU", "新數量", "新進價", "新預交貨日", "溫層", "分錄備註", "新轉單編號"]
# 新轉單編號 log 處理
log_file_path = r"\\nas-lianruey\office\sku\app\sku_transfer_log.json"
if os.path.exists(log_file_path):
with open(log_file_path, "r", encoding="utf-8") as f:
transfer_log = json.load(f)
else:
transfer_log = {}
today_key = datetime.today().strftime("%Y%m%d")
today_prefix = f"M{today_key}"
start_seq = transfer_log.get(today_key, 0) + 1
transfer_seq_counter = start_seq
transfer_id_map = OrderedDict()
# 主處理流程
new_records = [header]
temp_by_order = defaultdict(list)
for row in records[1:]:
row = row + [""] * (len(header) - 7 - len(row))
product_id = str(row[item_index])
try:
order_qty = int(row[qty_index])
except (ValueError, TypeError):
order_qty = 1
transfer_id = row[header.index("轉單編號")]
if transfer_id not in transfer_id_map:
transfer_id_map[transfer_id] = f"{today_prefix}{transfer_seq_counter:03d}"
transfer_seq_counter += 1
address = str(row[address_index])
address_cleaned = re.sub(r"[0-9\s]", "", address)[:3]
name = str(row[name_index])
remark = address_cleaned + name
if product_id in sku_map:
for sku in sku_map[product_id]:
try:
new_qty = int(sku["新數量"]) * order_qty
except (ValueError, TypeError):
new_qty = sku["新數量"]
new_sku = sku["新SKU"]
temp_value = sku_temp_map.get(new_sku, "冷凍")
temp_by_order[transfer_id].append(temp_value)
new_row = row + [new_sku, new_qty, sku["新進價"], next_date, temp_value, remark, transfer_id_map[transfer_id]]
new_records.append(new_row)
else:
temp_by_order[transfer_id].append("冷凍")
new_records.append(row + ["", "", "", next_date, "冷凍", remark, transfer_id_map[transfer_id]])
# 清除重複備註、整合溫層
final_records = [new_records[0]]
temp_index = header.index("溫層")
transfer_index = header.index("轉單編號")
remark_index = header.index("分錄備註")
seen_transfer_ids = set()
for row in new_records[1:]:
transfer_id = row[transfer_index]
row[temp_index] = "常溫" if all(t == "常溫" for t in temp_by_order[transfer_id]) else "冷凍"
if transfer_id in seen_transfer_ids:
row[remark_index] = ""
else:
seen_transfer_ids.add(transfer_id)
final_records.append(row)
# 更新 log
transfer_log[today_key] = transfer_seq_counter - 1
with open(log_file_path, "w", encoding="utf-8") as f:
json.dump(transfer_log, f, ensure_ascii=False, indent=2)
# 儲存檔案
base_dir = os.path.dirname(file_path)
name_part, ext_part = os.path.splitext(os.path.basename(file_path))
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
new_filename = f"{name_part}_SKU轉換_{timestamp}.xls"
new_path = os.path.join(base_dir, new_filename)
pe.save_as(array=final_records, dest_file_name=new_path)
print(f"✅ SKU轉換、預交貨日、溫層與分錄備註、新轉單編號處理完成,檔案儲存為:{new_path}")
No comments to display
No comments to display