# Skill: Kết nối Excel / Power Query AN TOÀN **Áp dụng các Rule:** R6.* (tất cả), R3.5 Có **3 kênh hợp lệ** để Excel đọc dữ liệu chấm công. **KHÔNG kênh nào đụng tới thiết bị Hikvision.** Refresh = 0% lock risk. --- ## Kênh A — API Server localhost (mặc định, đã có sẵn) **Khi dùng:** lab nhỏ, 1 máy, đơn giản nhất. 1. Chạy `start_server.bat` → Flask listen tại `http://127.0.0.1:5000`. 2. Excel → Data → Get Data → From Web → URL: ``` http://127.0.0.1:5000/api/attendance ``` 3. M-code mẫu xem `create_excel.py` hoặc sheet "Hướng dẫn" trong [BaoCao_ChamCong.xlsx](../BaoCao_ChamCong.xlsx). **Ưu:** đơn giản. **Nhược:** phải chạy server trước khi Refresh. --- ## Kênh B — File export (không cần server, không cần driver) **Khi dùng:** muốn Refresh không phụ thuộc tiến trình Python. 1. Chạy `python export_for_powerquery.py` để tạo: - `data/export/attendance.xlsx` (kèm sheet `Employees`) - `data/export/attendance.csv` 2. Excel → Data → Get Data → From File → From Workbook (hoặc From Text/CSV). 3. Refresh All sẽ đọc lại file → 0% lock risk. **Tự động hoá:** đặt Windows Task Scheduler chạy `export_for_powerquery.py` mỗi 15 phút (chỉ đọc DB, không đụng thiết bị). **Ưu:** không cần process nền, không cần driver. **Nhược:** dữ liệu trễ tới 15ph. --- ## Kênh C — SQLite ODBC (Power Query query trực tiếp DB) **Khi dùng:** cần dữ liệu realtime, sẵn sàng cài driver 1 lần. ### Cài đặt 1 lần 1. Tải **SQLite ODBC Driver** (Christian Werner): http://www.ch-werner.de/sqliteodbc/ 2. Cài file `sqliteodbc_w64.exe` (64-bit) — KHÔNG cần admin nếu cài chỉ cho user. 3. Verify trong **ODBC Data Source Administrator (64-bit)** → tab Drivers → có "SQLite3 ODBC Driver". ### Tạo DSN (tuỳ chọn nhưng khuyến nghị) 1. ODBC Admin → User DSN → Add → SQLite3 ODBC Driver. 2. Data Source Name: `ChamCong`. 3. Database Name: `D:\Du_an_Cham_cong\data\attendance.db`. 4. **Sync Mode = NORMAL**. 5. ✅ **Don't Create Database** (đã tick mặc định). 6. ✅ **No TXN** — chặn driver bắt đầu transaction → kết nối thành read-only ở mức logic. Phiên bản driver hiện tại KHÔNG có checkbox "Read Only" trong GUI, `No TXN` là cách thay thế tốt nhất (R6.5). 7. Để trống các option còn lại. ### Power Query M-code ```m let Source = Odbc.DataSource("dsn=ChamCong", [HierarchicalNavigation=true]), Attendance = Source{[Name="attendance"]}[Data], Employees = Source{[Name="employees"]}[Data], // R3.7: JOIN để lấy tên NV (employee_name trong attendance đang rỗng) Joined = Table.NestedJoin(Attendance, {"employee_no"}, Employees, {"employee_no"}, "Emp", JoinKind.LeftOuter), Expanded = Table.ExpandTableColumn(Joined, "Emp", {"name"}, {"Ten_NV"}), Selected = Table.SelectColumns(Expanded, {"date","time","employee_no","Ten_NV","status"}), Renamed = Table.RenameColumns(Selected, { {"date","Ngay"},{"time","Gio"},{"employee_no","Ma_NV"},{"status","Trang_thai"} }) in Renamed ``` ### Power Query M-code (không cần DSN — dùng connection string) ```m let Source = Odbc.DataSource( "Driver={SQLite3 ODBC Driver};Database=D:\Du_an_Cham_cong\data\attendance.db;ReadOnly=1;NoTXN=1;", [HierarchicalNavigation=true] ), Attendance = Source{[Name="attendance"]}[Data] in Attendance ``` Tham số `ReadOnly=1` được driver hiểu qua connection string (không có trong GUI). `NoTXN=1` là lớp bảo vệ thứ hai. WAL mode đã enabled nên đọc-ghi song song không khoá nhau. **Lưu ý:** - Lần đầu Power Query hỏi credentials → chọn **Default or Custom** → Connect. - Excel sẽ cảnh báo "Native database query" — Run. --- ## So sánh nhanh | Tiêu chí | A (API) | B (File) | C (ODBC) | |---|---|---|---| | Cần process Python chạy | Có | Không (lúc Refresh) | Không | | Cần cài driver | Không | Không | Có (1 lần) | | Realtime | Có | Trễ tới interval export | Có | | Có thể chạy đa máy mạng LAN | Có (mở port) | Không | Không (DB local) | | Lock thiết bị Hikvision | 0% | 0% | 0% | --- ## Triển khai đa máy qua Tailscale **Máy chủ (chỗ đặt DB):** 1. Cài Tailscale. 2. Sửa `rules/project_rules.py`: `API_HOST = "0.0.0.0"`. 3. Chạy `start_server.bat`. 4. Bật Tailscale ACL cho phép `tag:office` truy cập `tcp:5000` (Admin Console). 5. Optional: `tailscale serve --https=443 http://localhost:5000` để có HTTPS. **Máy khách (Excel):** - M-code: ```m Web.Contents("http://..ts.net:5000/api/attendance") ``` Hostname xem trong app Tailscale của máy chủ. **KHÔNG dùng SMB share DB SQLite qua Tailscale** — WAL + SMB có rủi ro corrupt. ## Cấm tuyệt đối (R6.1) - Cấu hình Excel/Power Query trỏ trực tiếp `http:///ISAPI/...`. - Dùng VBA gọi thẳng device API. - Mở DB ở chế độ **read-write** từ Excel.