# POS

# POS 轉檔功能

### 功能簡介

此工具用於將 POS 系統匯出的 **CSV 檔** 轉換為 **Excel（.xls）檔案**，並在轉檔過程中自動進行資料清理與補充，方便後續匯入正航系統。

### 功能特色

**支援檔案選擇介面**

- - 執行後會開啟檔案選擇視窗，選取欲轉換的 POS CSV 檔案。
    - 轉檔後檔案儲存在原檔案相同資料夾，檔名格式為：

```bash
原檔名_匯正航.xls
```

**自動補齊產品編號**

- 若「產品編號」欄位為空值，系統會自動填入固定值：

```bash
P07-005-09
```

**自動新增轉單編號**

- 根據「銷貨日期」欄位產生「轉單編號」：
    
    
    - 移除日期中的 `/`
    - 前方加上字母 `P`
    - 例如：

```
銷貨日期：2025/08/01 → 轉單編號：P20250801
```

**資料格式處理**

- 自動處理空值，避免 Excel 開啟時出錯。
- 自動清理工作表名稱，確保符合 Excel 限制（長度 ≤ 31，無非法字元）

### 使用步驟

1. 雙擊或執行 `轉檔.py`
2. 選擇 POS 匯出的 CSV 檔案
3. 等待轉換完成，在相同資料夾找到 `_匯正航.xls` 檔案
4. 將該檔案匯入正航系統

```python
import os
import re
import pandas as pd
import pyexcel as pe
from tkinter import Tk
from tkinter.filedialog import askopenfilename

INVALID_CHARS = r'[:\\/?*\[\]]'  # Excel 禁用字元
MAX_SHEET_NAME = 31

def sanitize_sheet_name(base_name: str) -> str:
    name = re.sub(INVALID_CHARS, '_', base_name)
    name = name[:MAX_SHEET_NAME].rstrip()
    return name or "Sheet1"

def read_csv_smart(path: str) -> pd.DataFrame:
    try:
        return pd.read_csv(path, encoding="utf-8-sig")
    except Exception:
        return pd.read_csv(path, encoding="cp950")

def convert_csv_to_xls(csv_path: str) -> str:
    base_no_ext = os.path.splitext(csv_path)[0]
    xls_path = f"{base_no_ext}_匯正航.xls"
    sheet_name = sanitize_sheet_name(os.path.basename(base_no_ext))

    df = read_csv_smart(csv_path)

    # 規則 1：產品編號空值補上 P07-005-09
    if "產品編號" in df.columns:
        df["產品編號"] = df["產品編號"].astype(str).replace({"nan": "", "NaN": ""}).replace(r"^\s*$", "", regex=True)
        df.loc[df["產品編號"] == "", "產品編號"] = "P07-005-09"
    else:
        print("⚠️ 找不到『產品編號』欄位，無法補值。")

    # 規則 2：新增「轉單編號」
    if "銷貨日期" in df.columns:
        date_str = df["銷貨日期"].astype(str).fillna("").str.replace("/", "", regex=False)
        df["轉單編號"] = "P" + date_str
    else:
        print("⚠️ 找不到『銷貨日期』欄位，無法產生『轉單編號』。")

    # 轉二維陣列（含表頭）
    header = df.columns.tolist()
    data = df.astype(object).where(pd.notna(df), "").values.tolist()
    array = [header] + data

    # 存成 xls
    pe.save_as(array=array, dest_file_name=xls_path, sheet_name=sheet_name)
    return xls_path

def main():
    Tk().withdraw()
    csv_path = askopenfilename(
        title="選擇要轉換的 CSV 檔案",
        filetypes=[("CSV 檔案", "*.csv"), ("所有檔案", "*.*")]
    )
    if not csv_path:
        print("未選擇檔案，程式結束。")
        return

    out_path = convert_csv_to_xls(csv_path)
    print("轉換完成！")
    print(f"來源：{csv_path}")
    print(f"輸出：{out_path}")

if __name__ == "__main__":
    main()
```