愛合購

📖 簡介 

 此程式用於處理 愛合購 (i) 平台的訂單檔案（Excel 或 CSV） ，自動進行 SKU 轉換、溫層判斷、預交貨日設定、分錄備註與新轉單編號生成，並輸出新的檔案，方便後續出貨與系統匯入。 

 

 🛠 功能特色 

 

 

 預交貨日設定 

 

 

 啟動程式時可輸入「加幾天」（預設 1），自動計算新預交貨日。 

 

 

 

 

 SKU 對應轉換 

 

 

 依據 sku_i.json 對照表，將「原廠商品編號」轉換為新 SKU，並計算新數量與新進價。 

 

 

 

 

 溫層判斷 

 

 

 使用 plist.json 判斷商品溫層： 

 

 

 若同一訂單商品全為常溫 → 統一為「常溫」 

 

 

 否則 → 判定為「冷凍」 

 

 

 

 

 特殊商品 P11-000-05 → 固定為「常溫」。 

 

 

 

 

 分錄備註產生 

 

 

 取「收貨地址前三字 + 收件人姓名」，並去除特殊符號。 

 

 

 若同一訂單多筆，僅保留首筆備註，其餘清空。 

 

 

 

 

 新轉單編號生成 

 

 

 格式： IYYYYMMDD001 

 

 

 每日流水號遞增，並記錄於 sku_transfer_log.json ，避免重複。 

 

 

 

 

 輸出檔案 

 

 

 輸出檔命名格式： 

 

 

 

 

 原始檔名_SKU轉換_YYYYMMDD_HHMMSS.xls 

 📂 必要檔案 

 

 

 輸入檔案 

 

 

 愛合購 訂單 Excel / CSV 

 

 

 

 

 SKU 對照表 

 

 

 \\nas-lianruey\office\sku\sku_i.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_i.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)

# 刪除前3列，只留表頭與資料

if len(records) > 3:

 records = records[3:]

# 預交貨日

next_date = (datetime.today() + timedelta(days=days_to_add)).strftime("%Y%m%d")

# 讀取 log 紀錄：新轉單編號流水號

log_file_path = r"\\nas-lianruey\office\sku\app\sku_transfer_log.json"

if os.path.isfile(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")

prefix = f"I{today_key}"

start_seq = transfer_log.get(today_key, 0) + 1

transfer_seq_counter = start_seq

transfer_id_map = OrderedDict()

# 找出欄位位置

header = records[0]

try:

 order_index = header.index("訂單編號")

 item_index = header.index("原廠商品編號")

 qty_index = header.index("數量")

 price_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 = "I" + order_id[:7] if len(order_id) >= 7 else "I" + order_id

 records[i].append(mo_id)

 header = records[0]

except ValueError as e:

 print("❌ 缺少必要欄位：", e)

 exit()

# 加入新欄位

header += ["新SKU", "新數量", "新進價", "新預交貨日", "溫層", "分錄備註", "新轉單編號"]

# 處理資料列

new_records = [header]

temp_by_order = defaultdict(list)

transfer_index = header.index("轉單編號")

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

 mo_id = row[transfer_index]

 # 建立新轉單編號

 if mo_id not in transfer_id_map:

 transfer_id_map[mo_id] = f"{prefix}{transfer_seq_counter:03d}"

 transfer_seq_counter += 1

 # 分錄備註

 address = str(row[address_index])

 address_clean = re.sub(r"[0-9\s]", "", address)[:3]

 recipient = str(row[name_index])

 raw_remark = address_clean + recipient

 remark = re.sub(r"[^\u4e00-\u9fffA-Za-z0-9]", "", raw_remark)

 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"]

 new_temp = sku_temp_map.get(new_sku, "冷凍")

 if new_sku == "P11-000-05":

 new_temp = "常溫"

 temp_by_order[mo_id].append(new_temp)

 new_row = row + [new_sku, new_qty, sku["新進價"], next_date, new_temp, remark, transfer_id_map[mo_id]]

 new_records.append(new_row)

 else:

 default_temp = "冷凍"

 temp_by_order[mo_id].append(default_temp)

 new_row = row + [

 product_id,

 order_qty,

 row[price_index] if price_index < len(row) else "",

 next_date,

 default_temp,

 remark,

 transfer_id_map[mo_id]

 ]

 new_records.append(new_row)

# 統一溫層與清除重複備註

final_records = [new_records[0]]

temp_col_index = header.index("溫層")

remark_col_index = header.index("分錄備註")

sku_col_index = header.index("新SKU")

seen_transfer_ids = set()

for row in new_records[1:]:

 mo_id = row[transfer_index]

 sku = row[sku_col_index]

 if sku == "P11-000-05":

 row[temp_col_index] = "常溫"

 else:

 row[temp_col_index] = "常溫" if all(t == "常溫" for t in temp_by_order[mo_id]) else "冷凍"

 if mo_id in seen_transfer_ids:

 row[remark_col_index] = ""

 else:

 seen_transfer_ids.add(mo_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}")