# 瑪黑

## 📖 簡介

此程式用於處理 **瑪黑家居平台的訂單檔案（Excel 或 CSV）**，自動完成 SKU 轉換、溫層判斷、預交貨日設定、分錄備註生成與新轉單編號產生，輸出可直接使用的新訂單檔案。

---

## 🛠 功能特色

1. **預交貨日設定**
    
    
    - 啟動程式時輸入加幾天（預設 1），自動計算新預交貨日。
2. **SKU 對應轉換**
    
    
    - 根據 `sku_ma.json` 對照表，將「瑪黑家居新版商品編號」轉換為新 SKU。
    - 自動計算新數量與新進價。
3. **溫層判斷**
    
    
    - 使用 `plist.json` 溫層資料：
        
        
        - 若同一訂單所有品項均為常溫 → 設為常溫
        - 否則 → 設為冷凍。
4. **分錄備註**
    
    
    - 自動生成「收件人地址前三字 + 收件人姓名」。
    - 若同一轉單編號有多筆 → 僅保留首筆，其餘備註清空。
5. **新轉單編號生成**
    
    
    - 格式：`MYYYYMMDD001`
    - 每日流水號遞增，記錄於 `sku_transfer_log.json`，避免重複。
6. **輸出檔案**
    
    
    - 檔名格式：

```python
原始檔名_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. 執行程式。
2. 輸入「預交貨日加幾天」（若不輸入，預設為 1）。
3. 選取訂單檔案（Excel 或 CSV）。
4. 程式自動完成 SKU 轉換、溫層判斷、分錄備註生成、新轉單編號產生。
5. 完成後在原目錄輸出新檔案。

---

## ✅ 輸出結果

- 已完成 **SKU 轉換**、**預交貨日設定**、**溫層判斷**、**分錄備註**、**新轉單編號生成**。
- 新檔案可直接用於出貨或後續系統匯入。

## ⚙️ 程式原始碼

```python
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}")

```