📘 LHB Margin Loan Process — คู่มือการใช้งานโปรแกรม
สารบัญ
- บทนำ
- โครงสร้างโปรเจค
- ความต้องการของระบบ
- การติดตั้งและตั้งค่า
- การกำหนดค่า (Configuration)
- ภาพรวม Pipeline การทำงาน
- รายละเอียดแต่ละ Flow
- 7.1 Download Flow
- 7.2 Input File Flow
- 7.3 Manual Mapping File Flow
- 7.4 Backup Origin Files Flow
- 7.5 Master Template Date Check Flow
- 7.6 Create Master Template Flow
- 7.7 Copy COL_STOCK Flow
- 7.8 Create Temp Public Company Flow
- 7.9 Manual Mapping Update Flow
- 7.10 Fuzzy Symbol Flow
- 7.11 Update Manual Mapping from Temp Flow
- 7.12 Summary Master Flow
- 7.13 Master Template Flow
- 7.14 Pledged Update Master Flow
- 7.15 SET API Update Flow
- 7.16 Combine Listed Company Flow
- 7.17 Summary Output Flow
- Utility Modules
- การทำงานกับ Prefect
- การ Build เป็น .exe ด้วย PyInstaller
- การแก้ไขปัญหา (Troubleshooting)
1. บทนำ
LHB Margin Loan Process เป็นระบบประมวลผลข้อมูลอัตโนมัติสำหรับกระบวนการ Margin Loan ของธนาคาร โดยมีหน้าที่หลักในการ:
- ดาวน์โหลดข้อมูลบริษัทจดทะเบียนและข้อมูล Margin Loan จากตลาดหลักทรัพย์แห่งประเทศไทย (SET)
- รวมรวมและจัดเตรียมข้อมูลจากหลายแหล่งเข้าด้วยกัน
- สร้าง Master Template สำหรับการวิเคราะห์ Margin Loan
- ทำการ Matching สัญลักษณ์หลักทรัพย์ (Symbol) ด้วยเทคนิค Fuzzy Matching
- อัปเดตข้อมูลต่าง ๆ เช่น Free Float, AmtShares, %Margin Loan, RegisShares
- ส่งออกไฟล์ผลลัพธ์ไปยังปลายทางที่กำหนด
โปรแกรมรองรับการทำงาน 3 สภาพแวดล้อม: Dev, UAT, Prod และสามารถทำงานร่วมกับ Prefect สำหรับการจัดการ Workflow หรือรันแบบ Standalone ได้
2. โครงสร้างโปรเจค
LHB-MarginLoan4/
│
├── main.py # จุดเริ่มต้นโปรแกรม (Entry Point)
├── main.spec # PyInstaller spec สำหรับ build .exe
├── requirements.txt # รายการ dependencies
├── Instruction.md # เอกสารคู่มือนี้
├── debug_parse_date.py # สคริปต์ debug การ parse วันที่
├── test_nas_connection.py # ทดสอบการเชื่อมต่อ NAS
├── test_nas_fromAI.py # ทดสอบการเชื่อมต่อ NAS (AI-generated)
│
├── config/
│ └── settings.py # การตั้งค่าและโหลด config จาก Excel
│
├── flows/ # Flow layer (Business Logic Orchestration)
│ ├── download_flow.py
│ ├── input_file_flow.py
│ ├── manual_mapping_file_flow.py
│ ├── backup_origin_files_flow.py
│ ├── master_template_date_check_flow.py
│ ├── create_master_template_flow.py
│ ├── copy_col_stock_flow.py
│ ├── create_temp_public_company_flow.py
│ ├── manual_mapping_flow.py
│ ├── fuzzy_symbol_flow.py
│ ├── update_manual_mapping_from_temp_flow.py
│ ├── summary_master_flow.py
│ ├── master_template_flow.py
│ ├── pledged_update_master_flow.py
│ ├── set_api_update_flow.py
│ ├── combine_listed_company_flow.py
│ ├── summary_output_flow.py # (ถูกคอมเม้นไว้ใน main.py แล้ว)
│ └── enhanced_summary_output_flow.py # (ตัวใหม่ที่ใช้งานจริง)
│
├── tasks/ # Task layer (Implementation Logic)
│ ├── helper_tasks.py
│ ├── download_tasks.py
│ ├── input_file_tasks.py
│ ├── manual_mapping_tasks.py
│ ├── excel_tasks.py
│ ├── copy_tasks.py
│ ├── public_company_tasks.py
│ ├── fuzzy_symbol_tasks.py
│ ├── update_manual_mapping_from_temp_tasks.py
│ ├── summary_master_tasks.py
│ ├── master_excel_tasks.py
│ ├── pledged_update_master_tasks.py
│ ├── set_api_update_tasks.py
│ ├── combine_listed_company_tasks.py
│ ├── master_template_date_check_tasks.py
│ ├── summary_output_tasks.py # (ถูกคอมเม้นไว้ใน main.py แล้ว)
│ └── enhanced_summary_output_tasks.py # (ตัวใหม่ที่ใช้งานจริง)
│
├── utils/ # Utility layer (Reusable Helpers)
│ ├── logger.py
│ ├── credential_utils.py
│ ├── date_utils.py
│ ├── download_utils.py
│ ├── excel_utils.py
│ ├── excel_copy_utils.py
│ ├── master_excel_helper.py
│ ├── summary_master_utils.py
│ ├── master_template_date_check_utils.py
│ ├── public_company_utils.py
│ ├── pledged_update_master_utils.py
│ ├── set_api_utils.py
│ └── ...
│
├── Original MIS/ # ตัวอย่างไฟล์ข้อมูลต้นฉบับ
│
└── build/ # Build output (PyInstaller)
สถาปัตยกรรม 3-Layer
โปรแกรมออกแบบเป็น 3 ชั้น (Layered Architecture):
┌─────────────────────────────────────┐
│ flows/ (Flow Layer) │ ← จัดลำดับการทำงาน, Orchestration
├─────────────────────────────────────┤
│ tasks/ (Task Layer) │ ← ตรรกะทางธุรกิจ, Implementation
├─────────────────────────────────────┤
│ utils/ (Utility Layer) │ ← ฟังก์ชันช่วยเหลือ, Reusable
└─────────────────────────────────────┘
3. ความต้องการของระบบ
3.1 ซอฟต์แวร์ที่ต้องติดตั้ง
| รายการ | รายละเอียด |
|---|---|
| Python | 3.10+ (แนะนำ 3.12) |
| Google Chrome | สำหรับ Playwright ใช้ดาวน์โหลดไฟล์ |
| Windows OS | รองรับ Windows 10/11 |
3.2 Python Packages
ดูจาก requirements.txt:
prefect # Workflow orchestration (optional)
requests # HTTP requests
python-dateutil # Date manipulation
openpyxl # Excel (.xlsx) file handling
pandas # Data manipulation
urllib3 # HTTP client
xlrd # Excel (.xls) file handling
lxml # XML/HTML parsing
html5lib # HTML parsing
beautifulsoup4 # HTML/XML parsing
keyring # Windows Credential Manager access
pyinstaller # Build .exe (development only)
playwright # Browser automation for downloads
rapidfuzz # Fuzzy string matching
3.3 โครงสร้างโฟลเดอร์ที่ต้องการ
โปรแกรมต้องการโฟลเดอร์ดังต่อไปนี้ (ค่าอ่านจาก ConfigPy.xlsx):
| โฟลเดอร์ | หน้าที่ |
|---|---|
Input_Path |
ตำแหน่งไฟล์นำเข้าจากระบบภายนอก |
Download_Path |
เก็บไฟล์ที่ดาวน์โหลดจาก SET |
DataInput_Path |
เก็บไฟล์นำเข้าที่คัดลอกมาพร้อมประมวลผล |
DataOutput_Path |
เก็บไฟล์ผลลัพธ์ |
TemplateInput_Path |
ปลายทางส่งออกไฟล์ไปยังระบบอื่น |
Temp_Path |
เก็บไฟล์ชั่วคราวระหว่างประมวลผล |
BackupInput_Path |
เก็บ backup ไฟล์ต้นฉบับ |
PythonLogs_Path |
เก็บ log files |
4. การติดตั้งและตั้งค่า
4.1 ติดตั้ง Dependencies
pip install -r requirements.txt
pip install playwright
playwright install chromium
4.2 การตั้งค่าไฟล์ Environment
สร้างไฟล์ D:\Script\LHB173_UW_Data_Margin_Loan\Environment.txt โดยมีเนื้อหาเป็น:
Dev
หรือ
UAT
หรือ
Prod
4.3 การตั้งค่า ConfigPy.xlsx
สร้างไฟล์ D:\Script\LHB173_UW_Data_Margin_Loan\ConfigPy.xlsx โดยมีโครงสร้าง:
| Name | Value_Dev | Value_UAT | Value_Prod |
|---|---|---|---|
| Input_Path | \\server\share\Input |
... | ... |
| Python_Path | D:\Python |
... | ... |
| PythonExe_Path | C:\Python312\python.exe |
... | ... |
| PythonLogs_Path | D:\Python\logs |
... | ... |
| Download_Path | D:\Python\download |
... | ... |
| DataInput_Path | D:\Python\dataInput |
... | ... |
| DataOutput_Path | D:\Python\dataOutput |
... | ... |
| TemplateInput_Path | \\server\share\Template |
... | ... |
| Temp_Path | D:\Python\temp |
... | ... |
| BackupInput_Path | D:\Python\backup |
... | ... |
| Chrome64Exe_Path | C:\Program Files\Google\Chrome\Application\chrome.exe |
... | ... |
| Chrome32Exe_Path | C:\Program Files (x86)\Google\Chrome\Application\chrome.exe |
... | ... |
| InputName_FileName | COL_STOCK_Public_Company_20260517.xlsx |
... | ... |
| InputSheet_SheetName | Sheet1 |
... | ... |
| ListedSET_FileName | listedCompanies.xlsx |
... | ... |
| ManualMapping_FileName | Manual_Mapping.xlsx |
... | ... |
| MasterTemplate_FileName | Master_Template.xlsx |
... | ... |
| NotFoundLog_FileName | not_found.log |
... | ... |
| ActivityLog_FileName | activity.log |
... | ... |
| MarginLoanProcessingLog_FileName | marginLoanProcessing.log |
... | ... |
| PlaywrightHeadless_Variable | TRUE |
... | ... |
| ManualTargetDate_Variable | (ว่างหรือ YYYYMM) | ... | ... |
| TargetDateStr_Variable | ManualTargetDate_Variable |
... | ... |
| RequestTimeOut_Variable | 30 |
... | ... |
| VerifySSL_Variable | TRUE |
... | ... |
| WIN_ServiceName | LHB173_MarginLoan |
... | ... |
| WIN_Username | rpadi01 |
... | ... |
| UsePrefect_Variable | FALSE |
... | ... |
| RetryConfig_Variable | 2 |
... | ... |
| RetryDelaySeconds_Variable | 10 |
... | ... |
4.4 การตั้งค่า Windows Credential Manager
สำหรับการเข้าถึง Network Path (UNC Path) ที่ต้องใช้รหัสผ่าน:
- เปิด Credential Manager ใน Windows
- เลือก Windows Credentials
- คลิก Add a generic credential
- ตั้งค่า:
- Network address:
LHB173_MarginLoan(หรือค่าที่ตั้งใน WIN_ServiceName) - User name:
rpadi01(หรือค่าที่ตั้งใน WIN_Username) - Password: รหัสผ่านสำหรับเข้าถึง Network Path
5. การกำหนดค่า (Configuration)
5.1 settings.py — กลไกการโหลด Config
ไฟล์ config/settings.py ทำหน้าที่:
- อ่าน Environment จากไฟล์
D:\Script\LHB173_UW_Data_Margin_Loan\Environment.txt - โหลด ConfigPy.xlsx จาก
D:\Script\LHB173_UW_Data_Margin_Loan\ConfigPy.xlsxและเลือกคอลัมน์ตาม Environment (Value_Dev / Value_UAT / Value_Prod) - ตั้งค่าตัวแปรทั่วโลก ที่ flows/tasks/utils ใช้ร่วมกัน
- รองรับการอ้างอิงค่า (Value Resolution): ถ้า value ใน Excel เป็นชื่อ key อื่น จะ resolve ไปยังค่าของ key นั้น (ใช้สำหรับ TargetDateStr_Variable)
5.2 ตัวแปรสำคัญใน settings.py
| ตัวแปร | รายละเอียด |
|---|---|
CONFIG_ROOT |
Path หลักสำหรับไฟล์ตั้งค่า D:\Script\LHB173_UW_Data_Margin_Loan |
ENVIRONMENT_FILE |
Path เต็มของ Environment.txt |
CONFIG_EXCEL_FILE |
Path เต็มของ ConfigPy.xlsx |
BASE_PATH |
Project Root Path (auto-detect สำหรับ Python / PyInstaller) |
CURRENT_ENV |
ค่า Environment ปัจจุบัน (DEV / UAT / PROD) |
INPUT_PATH |
Path ต้นทางของไฟล์นำเข้า (จาก ConfigPy) |
PYTHON_PATH |
Path สำหรับ Python runtime |
PYTHON_LOGS_PATH |
Path สำหรับเก็บ log files |
DOWNLOAD_PATH |
Path สำหรับเก็บไฟล์ที่ดาวน์โหลด |
DATA_INPUT_PATH |
Path สำหรับเก็บไฟล์ที่คัดลอกมาประมวลผล |
DATA_OUTPUT_PATH |
Path สำหรับไฟล์ผลลัพธ์ |
TEMPLATE_INPUT_PATH |
Path ปลายทางส่งออกไฟล์ |
TEMP_PATH |
Path สำหรับไฟล์ชั่วคราว |
BACKUP_INPUT_PATH |
Path สำหรับ backup ไฟล์ต้นฉบับ |
CHROME_PATH |
Path ของ Chrome executable (64-bit ก่อน, fallback 32-bit) |
INPUT_FILE_NAME |
ชื่อไฟล์ Input จาก ConfigPy (InputName_FileName) |
INPUT_SHEET_NAME |
ชื่อ Sheet ในไฟล์ Input (InputSheet_SheetName) |
LISTED_SET_FILE_NAME |
ชื่อไฟล์ Listed Companies |
MANUAL_MAPPING_FILE_NAME |
ชื่อไฟล์ Manual Mapping |
MASTER_TEMPLATE_FILE_NAME |
ชื่อไฟล์ Master Template |
NOT_FOUND_LOG_FILE_NAME |
ชื่อไฟล์ not_found.log |
ACTIVITY_LOG_FILE_NAME |
ชื่อไฟล์ activity.log |
MARGIN_LOAN_PROCESSING_LOG_FILE_NAME |
ชื่อไฟล์ marginLoanProcessing.log |
INPUT_FILE |
Path เต็มของไฟล์ Input ที่ DataInput_Path |
LISTED_SET_FILE |
Path เต็มของไฟล์ Listed Companies ที่ DataInput_Path |
MANUAL_MAPPING_FILE |
Path เต็มของ Manual Mapping ที่ DataInput_Path |
MASTER_TEMPLATE_FILE |
Path เต็มของ Master_Template.xlsx ที่ DataOutput_Path |
LISTED_COMPANY_FILE |
Path เต็มของ listedCompanies.xlsx ที่ DataOutput_Path |
MANUAL_MAPPING_OUTPUT_FILE |
Path เต็มของ Manual Mapping ที่ DataOutput_Path (สำหรับส่งออก) |
TEMP_PUBLIC_COMPANY_FILE |
Path ไฟล์ temp _tempLHBPublicCompany.xlsx ที่ Temp_Path |
LOG_FILE |
Path เต็มของ activity.log |
NOT_FOUND_LOG_FILE |
Path เต็มของ not_found.log |
MARGIN_LOAN_PROCESSING_LOG_FILE |
Path เต็มของ marginLoanProcessing.log |
MARGIN_LOAN_FILE_PATTERN |
Pattern สำหรับค้นหาไฟล์ Margin Loan: *Securities_Pledged_MarginAccounts_en.xlsx |
INPUT_FILE_AUTO_PATTERN |
Pattern สำหรับค้นหาไฟล์ Input ใน DataInput (ค่าเดียวกับ INPUT_FILE_NAME) |
TARGET_DATE_STR |
วันที่เป้าหมาย (Manual หรือ Auto Detect) |
MANUAL_TARGET_DATE |
วันที่กำหนดเองจาก ConfigPy (YYYYMM) |
PLAYWRIGHT_HEADLESS |
เปิด/ปิดโหมด Headless ของ Playwright |
USE_PREFECT |
เปิด/ปิดการทำงานผ่าน Prefect |
WIN_SERVICE_NAME / WIN_USERNAME |
สำหรับ Windows Credential Manager |
REQUEST_TIMEOUT |
Timeout สำหรับ HTTP requests |
VERIFY_SSL |
เปิด/ปิด SSL verification |
RETRY_COUNT / RETRY_DELAY_SECONDS |
จำนวนครั้งและระยะห่างในการ retry |
5.3 กลไก Target Date (date_utils.py)
ระบบมีกลไกการกำหนดวันที่ทำงาน 3 ระดับในฟังก์ชัน get_final_run_date():
- Auto Detect: สแกนหาไฟล์ที่ตรงกับ
INPUT_FILE_AUTO_PATTERNในDATA_INPUT_PATHและดึงตัวเลข 6-8 หลักจากชื่อไฟล์ (ใช้ 6 ตัวแรกเป็น YYYYMM) - Manual: ถ้าไม่เจอไฟล์ จะใช้ค่า
TARGET_DATE_STRจาก ConfigPy (รูปแบบ YYYYMM) - Default: ถ้าไม่มีทั้งคู่ ใช้วันที่ปัจจุบัน (ตั้งวันที่ 1 ของเดือน)
ฟังก์ชัน get_marginloan_url() ใช้ get_final_run_date() เพื่อสร้าง URL ดาวน์โหลด Margin Loan: ใช้เดือนปัจจุบันสำหรับ folder path และเดือนก่อนหน้าสำหรับชื่อไฟล์
5.4 กลไก Resolve Config Value
settings.py มีฟังก์ชัน _resolve_config_value() ที่รองรับการอ้างอิง key อื่น:
- ถ้า TargetDateStr_Variable = "ManualTargetDate_Variable" ระบบจะ resolve ไปยังค่าของ ManualTargetDate_Variable
- กรณีนี้ใช้สำหรับให้ TargetDateStr อ้างอิงไปยัง ManualTargetDate ได้โดยไม่ต้องกำหนดค่าซ้ำ
6. ภาพรวม Pipeline การทำงาน
Pipeline ประกอบด้วย 17 ขั้นตอน เรียงตามลำดับการทำงานใน main.py:
1. set_marginloan_download_flow() ← ดาวน์โหลดข้อมูลจาก SET
2. input_file_flow(INPUT_PATH) ← ค้นหา/คัดลอก Input File
3. manual_mapping_file_flow(TEMPLATE_INPUT_PATH) ← ค้นหา/คัดลอก Manual Mapping
4. backup_origin_files_flow() ← Backup ไฟล์ต้นฉบับ
5. master_template_date_check_flow() ← ตรวจสอบวันที่ตัดสินใจโหมดเขียน
6. create_master_template_flow() ← สร้าง/โหลด Master Template
7. copy_col_stock_flow() ← คัดลอกข้อมูล COL_STOCK
8. create_temp_public_company_flow() ← สร้าง Temp Public Company
9. manual_mapping_update_flow() ← อัปเดต Temp ด้วย Manual Mapping
10. fuzzy_symbol_flow() ← Fuzzy Match Symbol
11. update_manual_mapping_from_temp_flow() ← อัปเดต Manual Mapping
12. summary_master_template_flow() ← สรุปข้อมูลลง Master Template
13. master_template_flow() ← คัดลอกข้อมูลไปยัง sheets อื่น
14. pledged_update_master_flow() ← อัปเดต %Free Float, AmtShares, %Margin Loan
15. set_api_regis_shares_flow() ← อัปเดต RegisShares จาก SET API
16. combine_listed_company_flow() ← รวมไฟล์ Listed Companies
17. enhanced_summary_output_flow() ← ตรวจสอบและคัดลอกผลลัพธ์ (รองรับ Append)
การตัดสินใจโหมดการเขียน (Write Mode)
ขั้นตอนที่ 5 (master_template_date_check_flow) จะตัดสินใจโหมดการเขียนข้อมูลลง Master Template โดยใช้ Shared State (ตัวแปร global _WRITE_MODE, _REPORT_DATE) ที่ flows ถัดไปสามารถอ่านได้:
| โหมด | ความหมาย | เมื่อไร |
|---|---|---|
overwrite |
เขียนทับทั้งหมด | Master Template ยังไม่มีข้อมูล หรือ Report Date เท่ากับข้อมูลที่มี |
overwrite_specific |
ลบข้อมูลวันที่ตรงกันแล้วเขียนใหม่ | Report Date มีอยู่แล้วใน Master |
append |
ต่อท้าย | Report Date ใหม่กว่า Max Date ใน Master |
7. รายละเอียดแต่ละ Flow
7.1 Download Flow
ไฟล์: flows/download_flow.py → tasks/download_tasks.py
วัตถุประสงค์: ดาวน์โหลดข้อมูลบริษัทจดทะเบียนและข้อมูล Margin Loan จาก SET
ขั้นตอนการทำงาน:
- ดาวน์โหลดบริษัทจดทะเบียนภาษาไทย
- URL:
https://www.set.or.th/dat/eod/listedcompany/static/listedCompanies_th_TH.xls -
บันทึก:
{Download_Path}/listedCompanies_th_TH.xls -
ดาวน์โหลดบริษัทจดทะเบียนภาษาอังกฤษ
- URL:
https://www.set.or.th/dat/eod/listedcompany/static/listedCompanies_en_US.xls -
บันทึก:
{Download_Path}/listedCompanies_en_US.xls -
ดาวน์โหลดไฟล์ Margin Loan
- สร้าง URL แบบไดนามิกโดยใช้
get_marginloan_url()ในutils/date_utils.py - รูปแบบ URL:
https://www.set.or.th/services/download?url=https://media.set.or.th/set/Documents/{year}/{month}/{yyyymm}_Securities_Pledged_MarginAccounts_en.xlsx&name={yyyymm}_Securities_Pledged_MarginAccounts_en - บันทึก:
{Download_Path}/{yyyymm}_Securities_Pledged_MarginAccounts_en.xlsx - มี 2 โหมดการทำงาน ขึ้นอยู่กับค่า
ManualTargetDate_Variableใน ConfigPy.xlsx:
#### โหมด 1: ManualTargetDate_Variable != None (มีค่าที่กำหนด)
- ทำงานตาม Logic เดิม — ดาวน์โหลดเฉพาะไฟล์ของเดือนที่คำนวณได้เท่านั้น
- ไม่มีการ Retry ย้อนหลัง
#### โหมด 2: ManualTargetDate_Variable = None (ไม่มีค่าหรือว่าง)
- เริ่มต้นดาวน์โหลดไฟล์ล่าสุดตามวันที่คำนวณได้จาก get_final_run_date()
- ถ้าดาวน์โหลดไม่สำเร็จ → Log แจ้งเตือน → ลบไฟล์ที่ไม่สมบูรณ์ทิ้ง → ถอยไปดาวน์โหลดเดือนก่อนหน้า
- ถอยไปเรื่อยๆ สูงสุด 12 เดือน จนกว่าจะเจอไฟล์ที่ดาวน์โหลดสำเร็จ
- ถ้าเจอไฟล์ → ใช้ไฟล์นั้น (ไฟล์ล่าสุดที่หาได้)
- ถ้าครบ 12 เดือนแล้วยังไม่เจอ → throw Exception
ตัวอย่างการทำงานโหมด 2:
พยายามดาวน์โหลด 202606_Securities_Pledged_MarginAccounts_en.xlsx → ❌ ไม่เจอ
→ Log: "Download Failed, retrying previous month: 202605"
พยายามดาวน์โหลด 202605_Securities_Pledged_MarginAccounts_en.xlsx → ❌ ไม่เจอ
→ Log: "Download Failed, retrying previous month: 202604"
พยายามดาวน์โหลด 202604_Securities_Pledged_MarginAccounts_en.xlsx → ✅ เจอ!
→ ใช้ไฟล์ 202604_Securities_Pledged_MarginAccounts_en.xlsx
เทคนิคการดาวน์โหลด:
- ใช้ Playwright (browser automation) เพื่อเลียนแบบการดาวน์โหลดจากเว็บเบราว์เซอร์จริง
- Session Management: เข้า https://www.set.or.th/th/home ก่อนเพื่อสร้าง Session Cookies
- Human-like Behavior: มีการหน่วงเวลาแบบสุ่มระหว่างขั้นตอน (2-8 วินาที)
- Anti-detection: ตั้งค่า User-Agent, viewport, locale และปิด webdriver flag
- Download Handling: ใช้ expect_download() + wait_until="commit" เพื่อป้องกัน "Download is starting" exception
7.2 Input File Flow
ไฟล์: flows/input_file_flow.py → tasks/input_file_tasks.py
วัตถุประสงค์: ค้นหาและคัดลอกไฟล์ Input (COL_STOCK_Public_Company) จากต้นทางไปยัง DataInput
Parameters: รับ input_path: Path (INPUT_PATH จาก settings)
ขั้นตอนการทำงาน:
- ค้นหาไฟล์
{input_path}/{INPUT_FILE_NAME}สูงสุด 3 ครั้ง (retry) - ถ้าไม่พบและ path เป็น UNC → ดึง credential จาก Windows Credential Manager → เชื่อมต่อด้วย
net use→ ค้นหาอีกครั้ง - ถ้าพบ → คัดลอกไปยัง
{DataInput_Path}/{INPUT_FILE_NAME} - ถ้าไม่พบครบ 3 ครั้ง → raise
FileNotFoundError("No input data found for report generation.")
Retry Logic: - จำนวนครั้ง: 3 ครั้ง - ระยะห่าง: 300 วินาที (5 นาที) ระหว่างครั้ง
7.3 Manual Mapping File Flow
ไฟล์: flows/manual_mapping_file_flow.py
วัตถุประสงค์: ค้นหาและคัดลอกไฟล์ Manual Mapping (Manual_Mapping.xlsx) จากต้นทางไปยัง DataInput
Parameters: รับ input_path: Path (TEMPLATE_INPUT_PATH จาก settings)
การทำงาน: คล้ายกับ Input File Flow แต่ค้นหาไฟล์ Manual_Mapping.xlsx แทน
7.4 Backup Origin Files Flow
ไฟล์: flows/backup_origin_files_flow.py → tasks/input_file_tasks.py (ฟังก์ชัน backup_input_files)
วัตถุประสงค์: สำรองข้อมูลไฟล์ต้นฉบับก่อนเริ่มประมวลผล
ไฟล์ที่ Backup:
1. {Input_Path}/{InputName_FileName}
2. {TemplateInput_Path}/listedCompanies.xlsx
3. {TemplateInput_Path}/Manual_Mapping.xlsx
4. {TemplateInput_Path}/Master_Template.xlsx
รูปแบบการ Backup:
- สร้างโฟลเดอร์: {BackupInput_Path}/{YYYYMMDD_HHmmss}/
- คัดลอกไฟล์ที่มีอยู่เท่านั้น (ไฟล์ไหนไม่มีจะข้ามไป)
7.5 Master Template Date Check Flow
ไฟล์: flows/master_template_date_check_flow.py → tasks/master_template_date_check_tasks.py
วัตถุประสงค์: ตรวจสอบวันที่และตัดสินใจโหมดการเขียนข้อมูลก่อนเริ่มประมวลผล โดยใช้ Shared State (Module-level variables)
ขั้นตอน:
- ล้าง Shared State (clear_shared_state) — ล้าง
_WRITE_MODEและ_REPORT_DATE - อ่าน Report Date จากไฟล์
*Securities_Pledged_MarginAccounts_en.xlsxใน Download_Path โดยค้นหาข้อความ "For the month ending" และ extract วันที่ด้วย regex(\d{1,2}\s+[A-Za-z]+\s+\d{4})แล้วแปลงเป็น DD/MM/YYYY - อ่าน Max Date จากทุก sheet ใน Master_Template:
- Column F (index 6) สำหรับ: Data-OS, Data-Limit, Data-%Free float, Data-AmtShares, Data-%Margin Loan, Data-RegisShares
- Column AV (index 48) สำหรับ: Data-COL_STOCK
- ตัดสินใจโหมด:
- Master Template ยังไม่มีข้อมูล →
overwrite - Report Date > Max Date →
append - Report Date <= Max Date →
overwrite_specific - ถ้าเป็น
overwrite_specific: ลบแถวที่มีวันที่ตรงกับ Report Date ออกจากทุก sheets ใน Master Template แล้วเปลี่ยนโหมดเป็นappend - ตั้งค่า Shared State:
set_write_mode(mode)และset_report_date(report_date)สำหรับ Flow ถัดไป
ฟังก์ชันใน Shared State:
| ฟังก์ชัน | รายละเอียด |
|---------|-----------|
| get_write_mode() | อ่านโหมดการเขียน |
| get_report_date() | อ่าน Report Date |
| set_write_mode(mode) | ตั้งค่าโหมดการเขียน |
| set_report_date(date_str) | ตั้งค่า Report Date |
| clear_shared_state() | ล้างค่า shared state |
7.6 Create Master Template Flow
ไฟล์: flows/create_master_template_flow.py → tasks/excel_tasks.py
วัตถุประสงค์: สร้าง Master_Template.xlsx ใหม่หรือโหลดไฟล์เดิม
การทำงาน:
- เช็ค Write Mode จาก Shared State (
get_write_mode()) - ถ้าเป็น
overwriteหรือไฟล์ไม่มีอยู่ → สร้าง Workbook ใหม่ - ถ้าเป็น
appendและไฟล์มีอยู่แล้ว → โหลดไฟล์เดิม (ตรวจสอบว่าครบ 7 sheets) - สร้าง 7 Sheets:
| Sheet Name | Columns |
|---|---|
Data-OS |
Customer Name (Thai), Customer Name (Eng), Segment, Symbol, OS, Date |
Data-Limit |
Customer Name (Thai), Customer Name (Eng), Segment, Symbol, Limit, Date |
Data-%Free float |
Customer Name (Thai), Customer Name (Eng), Segment, Symbol, %Free float, Date |
Data-AmtShares |
Customer Name (Thai), Customer Name (Eng), Segment, Symbol, AmtShares, Date |
Data-%Margin Loan |
Customer Name (Thai), Customer Name (Eng), Segment, Symbol, %Margin Loan, Date |
Data-RegisShares |
Customer Name (Thai), Customer Name (Eng), Segment, Symbol, RegisShares, Date |
Data-COL_STOCK |
48 Columns (ดู Appendix B) |
7.7 Copy COL_STOCK Flow
ไฟล์: flows/copy_col_stock_flow.py → tasks/copy_tasks.py
วัตถุประสงค์: คัดลอกข้อมูลจากไฟล์ Input (COL_STOCK_Public_Company) ไปยัง Sheet Data-COL_STOCK ใน Master Template
ขั้นตอน:
- สแกนหาไฟล์ต้นทาง ใน DataInput_Path ด้วย Pattern
INPUT_FILE_AUTO_PATTERN(ค่าเดียวกับ INPUT_FILE_NAME) - กรองข้อมูล ด้วย Include/Exclude list ของ BPADSC (Column U, index 20):
- Include: ธนาคารพาณิชย์ไทยเพื่อรายย่อย, ธนาคารพาณิชย์จดทะเบียนในประเทศ, ธนาคารพาณิชย์ที่เป็นบริษัทลูกของธนาคารต่างประเทศ, นิติบุคคลอื่นๆ ตามกฎหมายต่างประเทศ, บ.หลักทรัพย์จัดการกองทุนรวม (บ.มหาชนจำกัด), บริษัทจำกัด, บริษัทบริหารสินทรัพย์ (บริษัทมหาชนจำกัด), บริษัทประกันชีวิต (บริษัทมหาชนจำกัด), บริษัทมหาชน จำกัด, บริษัทหลักทรัพย์ (บริษัทมหาชนจำกัด), รัฐวิสาหกิจในรูปแบบบริษัทจำกัด, ลิสซิ่ง (บริษัทมหาชนจำกัด), สถาบันการเงินอื่น (บริษัทมหาชนจำกัด)
- Exclude: บ.หลักทรัพย์จัดการกองทุนรวม (บริษัทจำกัด), บริษัทบริหารสินทรัพย์กรุงเทพพาณิชย์ จำกัด, บริษัทประกันชีวิต (บริษัทจำกัด), บริษัทหลักทรัพย์ (บริษัทจำกัด), สถาบันไม่มีวัตถุประสงค์หากำไร(เสียภาษี), สถาบันไม่มีวัตถุประสงค์หากำไร(ยกเว้นภาษี), สถาบันการเงินอื่น (บริษัทจำกัด), สาขาธนาคารต่างประเทศ, ห้างหุ้นส่วนจำกัด, องค์การของรัฐ
- อ่าน Report Date จาก Shared State (
get_report_date()) หรือ fallback อ่านจากไฟล์ Margin Loan - เขียนข้อมูล ตาม Write Mode (overwrite = เขียนที่ row 2, append = ต่อท้าย)
- เขียนวันที่ ที่ Column AV (column 48) ทุกแถว
7.8 Create Temp Public Company Flow
ไฟล์: flows/create_temp_public_company_flow.py → tasks/public_company_tasks.py
วัตถุประสงค์: สร้างไฟล์ชั่วคราว _tempLHBPublicCompany.xlsx สำหรับใช้ในขั้นตอนถัดไป
โครงสร้างไฟล์ Temp (11 Columns A-K):
| Column | Header | ที่มา |
|---|---|---|
| A | Symbol | จาก Listed Companies (EN) |
| B | CompanyUS | จาก Listed Companies (EN) |
| C | CompanyTH | จาก Listed Companies (TH) |
| D | CIF_Key | จาก Master Template → Data-COL_STOCK (Column A) |
| E | CusNameTh | จาก Master Template → Data-COL_STOCK (Column D) |
| F | CusNameEn | จาก Master Template → Data-COL_STOCK (Column E) |
| G | Segment | จาก Master Template → Data-COL_STOCK (Column V, index 21) |
| H | SUM_CBAL(OS) | จาก Master Template → Data-COL_STOCK (Column AF, index 31) |
| I | SUM_A1IMLMTE(LIMIT) | จาก Master Template → Data-COL_STOCK (Column AC, index 28) |
| J | ResultSymbol | (เตรียมไว้สำหรับ Fuzzy Match) |
| K | FuzzyScore | (เตรียมไว้สำหรับ Fuzzy Match) |
วิธีการสร้าง:
1. อ่าน Listed Companies จากไฟล์ที่ดาวน์โหลด (TH และ EN) ด้วย pandas.read_html()
2. คัดลอก Symbol, CompanyUS, CompanyTH
3. อ่านข้อมูลจาก Master Template → Data-COL_STOCK (กรองเฉพาะ Report Date ปัจจุบันเท่านั้น)
4. Header style: สีเขียว (C6E0B4), Font Tahoma, ขนาด 10
5. บันทึกไฟล์ที่ Temp_Path
7.9 Manual Mapping Update Flow
ไฟล์: flows/manual_mapping_flow.py → tasks/manual_mapping_tasks.py
วัตถุประสงค์: อัปเดตข้อมูลใน Temp Public Company ด้วยข้อมูลจาก Manual Mapping
ขั้นตอน:
- โหลด Manual Mapping (
Manual_Mapping.xlsx) → DataFrame ด้วย pandas - กรองข้อมูล:
- ลบแถวที่ Correct_Symbol เป็น "Non-listed", ว่างเปล่า, หรือ "nan"
- ลบแถวที่ CIF ว่างเปล่าหรือ "nan"
- สร้าง CIF Map: CIF → {CustomerName_TH, CustomerName_EN, Correct_Symbol}
- อัปเดต Temp File: ใช้ CIF_Key (จาก Temp) จับคู่กับ CIF (จาก Manual Mapping) แล้วเขียน:
- CustomerName_TH → CusNameTh
- CustomerName_EN → CusNameEn
- Correct_Symbol → ResultSymbol
- รายงานสถิติ: จำนวน CIF ที่ match / ไม่ match / จำนวน rows ที่อัปเดต
7.10 Fuzzy Symbol Flow
ไฟล์: flows/fuzzy_symbol_flow.py → tasks/fuzzy_symbol_tasks.py
วัตถุประสงค์: ทำการจับคู่ชื่อบริษัท (Customer Name) กับ Symbol ใน Listed Companies โดยใช้เทคนิค Fuzzy String Matching
ข้อมูลที่เขียนใน Temp File (Columns J-O):
| Column | Header | รายละเอียด |
|---|---|---|
| J | ResultSymbol | Symbol ที่ Match (ถ้ามี Manual Mapping อยู่แล้ว → เก็บไว้ ไม่เขียนทับ) |
| K | Fuzzy Score | คะแนนความเหมือน |
| L | MatchedCompanyUS | ชื่อบริษัทที่ Match |
| M | SourceCustomerName | ชื่อลูกค้าต้นทาง |
| N | MatchRemark | หมายเหตุการ Match |
| O | SuggestSymbol | Symbol แนะนำ (ถ้ามี Manual Mapping แล้ว) |
7.10.1 การ Normalize ชื่อบริษัท
- แปลงเป็นตัวพิมพ์ใหญ่ทั้งหมด
- แทนที่
&→AND - จัดการคำที่เว้นวรรค (เช่น
PUBLICCOMPANY→PUBLIC COMPANY) - ลบเครื่องหมายพิเศษ
. , ( ) / _ - - ลบคำทั่วไป: PUBLIC, COMPANY, CO, LIMITED, LTD, PCL, PLC
- จัดการตัวอักษรเว้นวรรค (เช่น
P U B L I C→PUBLIC)
7.10.2 การคำนวณคะแนน (Primary Score)
ใช้ rapidfuzz library:
- WRatio: Weighted Ratio
- Token Sort Ratio: เรียง token แล้วเปรียบเทียบ
- Token Set Ratio: ใช้ intersection ของ token sets
- กรณีชื่อสั้น/ตัวย่อ: ใช้เฉพาะ WRatio และ Token Sort Ratio
7.10.3 การตรวจสอบความขัดแย้ง (Conflict Detection)
| ประเภท | คำอธิบาย |
|---|---|
| Brand Conflict | Brand token ตัวแรกไม่ตรงกัน (เช่น SCB vs KBANK) |
| Short Name Conflict | ชื่อสั้น (< 4 ตัวอักษร) หรือ token เดียว |
| Parent-Child Conflict | ชื่อบริษัทเหมือนกันแต่มีคำต่อท้ายต่างกัน (เช่น SCB → SCB LEASING) |
7.10.4 การตัดสินใจ (Decision Logic)
| คะแนน | การดำเนินการ |
|---|---|
| >= 95 | Accept ทันที |
| 90-94.99 | Second Pass: ตรวจสอบ trimmed first 6 characters > 95 → Accept มิฉะนั้น Reject |
| < 90 | Reject |
| Brand Conflict → ตรวจสอบ Trimmed First6 > 95 → Override มิฉะนั้น Skip | |
| Short Name → ตรวจสอบ Trimmed First6 > 95 → Approve มิฉะนั้น Skip (ถ้า score < 98) | |
| Parent-Child Conflict → Skip เสมอ |
7.10.5 สีของ Remark
| สี | ความหมาย |
|---|---|
| 🔵 น้ำเงิน | Exact Normalized Match |
| 🟢 เขียว | Matched (คะแนน >= 92) |
| 🟠 ส้ม | ต้องตรวจสอบเพิ่มเติม (Second Pass, Short Name, Brand Override) |
| 🔴 แดง | Conflict ที่ถูก Skip หรือ Reject, หรือ First5 Score < 98 |
หมายเหตุ: ถ้ามี Manual Mapping อยู่แล้ว จะไม่เขียนทับ ResultSymbol (Column J) แต่จะเก็บ Symbol ที่ Match ไว้ที่ SuggestSymbol (Column O) แทน
7.11 Update Manual Mapping from Temp Flow
ไฟล์: flows/update_manual_mapping_from_temp_flow.py → tasks/update_manual_mapping_from_temp_tasks.py
วัตถุประสงค์: คัดลอกข้อมูลจาก Temp Public Company กลับไปยัง Manual Mapping สำหรับรายการที่ ResultSymbol ว่าง (ไม่สามารถ Match Symbol ได้)
ขั้นตอน:
- คัดลอก Manual Mapping จาก DataInput ไปยัง DataOutput (ด้วย
shutil.copy2()เพื่อป้องกันแก้ไขไฟล์ต้นทาง) - ตรวจสอบ Temp File: เฉพาะแถวที่ ResultSymbol ว่าง
- Update หรือ Append ใน Manual Mapping:
- ถ้า CIF มีอยู่แล้ว → Update ข้อมูล
- ถ้า CIF ยังไม่มี → Append แถวใหม่
- ใส่ Remark: "ระบบตรวจพบว่ามีการแปรสภาพ" (ตัวอักษรสีแดง) ทุกกรณี
7.12 Summary Master Flow
ไฟล์: flows/summary_master_flow.py → tasks/summary_master_tasks.py
วัตถุประสงค์: สรุปข้อมูลจาก Temp Public Company ไปยัง Master Template (Sheet Data-OS และ Data-Limit)
ขั้นตอน:
- โหลด Temp File และ Master Template
- อ่าน Write Mode และ Report Date จาก Shared State
- สร้าง Symbol Master: แมป Symbol → {company_th, company_us} จาก Temp File Columns A-C
- กำหนด start_row ตาม Write Mode:
overwrite: row 2overwrite_specific: ใช้find_first_row_by_date()เพื่อหาแถวแรกที่มี Report Date ตรงกันappend:max_row + 1- วนลูปข้อมูล ใน Temp File:
- อ่าน Symbol จาก ResultSymbol (Column J)
- ถ้า Symbol มีใน Symbol Master และ ResultSymbol ไม่ว่าง → เขียนข้อมูล
- เขียนข้อมูลลง Data-OS (Column H: SUM_CBAL) และ Data-Limit (Column I: SUM_A1IMLMTE)
7.13 Master Template Flow
ไฟล์: flows/master_template_flow.py → tasks/master_excel_tasks.py
วัตถุประสงค์: คัดลอกข้อมูลจาก Data-OS ไปยัง sheets อื่นใน Master Template (Data-%Free float, Data-AmtShares, Data-%Margin Loan, Data-RegisShares)
Column Mapping:
Data-OS Column A (Customer Name Thai) → Target Column A
Data-OS Column B (Customer Name Eng) → Target Column B
Data-OS Column C (Segment) → Target Column C
Data-OS Column D (Symbol) → Target Column D
Data-OS Column F (Date) → Target Column F
การตัดสินใจตาม Write Mode:
- overwrite: เขียนทับทั้งหมดตั้งแต่ row 2
- append / overwrite_specific: กรองเฉพาะแถวที่ Date ตรงกับ Report Date แล้วต่อท้ายข้อมูลเดิม
7.14 Pledged Update Master Flow
ไฟล์: flows/pledged_update_master_flow.py → tasks/pledged_update_master_tasks.py
วัตถุประสงค์: อัปเดตข้อมูล 3 รายการใน Master Template โดยอ่านจากไฟล์ Margin Loan ที่ดาวน์โหลดมา
3 งานที่ทำ:
| งาน | Target Sheet | Source Column |
|---|---|---|
| 1. Update %Free Float | Data-%Free float |
Column E (index 5) |
| 2. Update AmtShare | Data-AmtShares |
Column C (index 3) |
| 3. Update %Margin Loan | Data-%Margin Loan |
Column D (index 4) |
การทำงาน: 1. ค้นหาไฟล์ Margin Loan ล่าสุดใน Download_Path 2. อ่าน Symbol (Column B) และค่าจาก Source Column → สร้าง Map (เริ่มจาก Row 10) 3. อ่าน Report Date จาก Shared State 4. กรองเฉพาะแถวที่ Date (Column F) ตรงกับ Report Date เท่านั้น 5. Match กับ Symbol ใน Master Template (Column D) → เขียนค่าลง Column E 6. ถ้าไม่พบ Symbol → ใส่ค่า 0
7.15 SET API Update Flow
ไฟล์: flows/set_api_update_flow.py → tasks/set_api_update_tasks.py
วัตถุประสงค์: อัปเดตค่า RegisShares ใน Master Template โดยการเรียก API ของ SET แบบ Real-time
ขั้นตอน:
- Initialize Session: Warm-up Session ด้วยการเรียกหน้าเว็บ SET หลายหน้าเพื่อรับ Cookies
https://www.set.or.th/en/homehttps://www.set.or.th/en/markethttps://www.set.or.th/en/market/product/stockhttps://www.set.or.th/en/market/product/stock/quote/SCB/price- อ่าน Report Date จาก Shared State
- วนลูป Symbol ใน Sheet
Data-RegisShares: - กรองเฉพาะแถวที่ Date (Column F) ตรงกับ Report Date เท่านั้น
- เรียก API:
https://www.set.or.th/api/set/stock/{symbol}/info?lang=en - อ่านค่า
listedShareจาก Response JSON - เขียนค่าลง Column E
- หน่วงเวลา 0.7 วินาทีระหว่าง request
- Session Management: ถ้าเจอ 401/403/429 → ล้าง Session → Warm-up ใหม่ → Retry
เทคนิค Session Reuse: - Session ถูกสร้างที่ระดับ Module (Singleton pattern) - Cookie Persistence: cookies จาก warm-up ถูกส่งอัตโนมัติ - Referer Header: เปลี่ยนตาม symbol เพื่อเลียนแบบการเรียกจากหน้าเว็บจริง
7.16 Combine Listed Company Flow
ไฟล์: flows/combine_listed_company_flow.py → tasks/combine_listed_company_tasks.py
วัตถุประสงค์: รวมไฟล์ Listed Companies (TH และ EN) ที่ดาวน์โหลดมาเป็นไฟล์ .xlsx เดียว
การทำงาน:
1. อ่านไฟล์ listedCompanies_th_TH.xls และ listedCompanies_en_US.xls ด้วย pandas.read_html() (เนื่องจากเป็น HTML table format)
2. สร้าง Workbook ใหม่ที่มี 2 Sheets:
- TH: ข้อมูลภาษาไทย
- EN: ข้อมูลภาษาอังกฤษ
3. คัดลอกข้อมูลตั้งแต่ Row 2 (ข้าม header), Column A-J (10 columns)
4. จัดรูปแบบ Header (พื้นสีเทา D9D9D9, ตัวหนา, จัดกึ่งกลาง)
5. บันทึกที่ {DataOutput_Path}/listedCompanies.xlsx
7.17 Summary Output Flow (Enhanced)
ไฟล์: flows/enhanced_summary_output_flow.py → tasks/enhanced_summary_output_tasks.py
วัตถุประสงค์: ตรวจสอบและคัดลอกไฟล์ผลลัพธ์ไปยัง TemplateInput_Path โดย Master_Template.xlsx รองรับการ Append ข้อมูล
การทำงานแบ่งตามประเภทไฟล์:
สำหรับ Master_Template.xlsx
Flow จะตัดสินใจ Action โดยอัตโนมัติผ่านฟังก์ชัน decide_master_template_action():
| Action | เงื่อนไข | การทำงาน |
|---|---|---|
overwrite |
1) ไม่มีไฟล์ Master_Template ที่ TemplateInput_Path 2) หรือมีไฟล์แต่ Sheets ไม่ครบ 7 Sheets 3) หรือไม่มี Report Date ใน Shared State |
คัดลอกไฟล์ใหม่ทั้งเล่ม (เขียนทับ) |
append |
มีไฟล์ Master_Template อยู่แล้ว, Sheets ครบ, และ Report Date ไม่ซ้ำกับข้อมูลที่มี | ต่อท้ายข้อมูลใหม่จาก Data-OS, Data-Limit, Data-%Free float, Data-AmtShares, Data-%Margin Loan, Data-RegisShares, Data-COL_STOCK |
overwrite_specific |
มีไฟล์ Master_Template อยู่แล้ว, Sheets ครบ, และ Report Date ซ้ำกับข้อมูลที่มี | 1. ลบแถวที่มีวันที่ตรงกับ Report Date ออกจากทุก Sheets 2. ต่อท้ายข้อมูลใหม่จากต้นทาง |
สำหรับ Manual_Mapping.xlsx และ listedCompanies.xlsx
- เขียนทับ (overwrite) เหมือนเดิมทุกครั้ง ไม่มีการ Append
ขั้นตอนโดยรวม:
- คัดลอก Manual Mapping จาก DataInput_Path ไปยัง DataOutput_Path
- ตรวจสอบไฟล์ทั้ง 3 ที่ DataOutput_Path:
Master_Template.xlsxManual_Mapping.xlsxlistedCompanies.xlsx- เชื่อมต่อไปยัง TemplateInput_Path:
- ทดสอบ connection ก่อน (ลอง list directory)
- ถ้าไม่ได้ → ดึง credential จาก Windows Credential Manager → เชื่อมต่อด้วย
net use - จัดการ Master_Template.xlsx:
- ตรวจสอบว่ามีไฟล์อยู่แล้ว → ตรวจสอบ sheets → ตรวจสอบวันที่ซ้ำ
- ตัดสินใจ Action: overwrite / append / overwrite_specific
- ดำเนินการตาม Action
- คัดลอก Manual_Mapping.xlsx ไปยัง TemplateInput_Path (เขียนทับ)
- คัดลอก listedCompanies.xlsx ไปยัง TemplateInput_Path (เขียนทับ)
8. Utility Modules
| Module | ไฟล์ | หน้าที่ |
|---|---|---|
| logger | utils/logger.py |
ตั้งค่า logging system: activity.log + marginLoanProcessing.log + console output (marginLoanProcessing.log สร้างใหม่ทุกครั้งด้วย mode="w") |
| credential_utils | utils/credential_utils.py |
ดึงรหัสผ่านจาก Windows Credential Manager ผ่าน keyring library |
| date_utils | utils/date_utils.py |
กำหนดวันที่ทำงาน (Auto/Manual/Default) และสร้าง URL ดาวน์โหลด Margin Loan |
| download_utils | utils/download_utils.py |
ดาวน์โหลดไฟล์ด้วย Playwright browser automation (ใช้ expect_download() + wait_until="commit") |
| excel_utils | utils/excel_utils.py |
จัดรูปแบบ Header Excel (พื้นสีเทา D9D9D9, ตัวหนา, จัดกึ่งกลาง) |
| excel_copy_utils | utils/excel_copy_utils.py |
คัดลอกข้อมูลระหว่างไฟล์ Excel |
| summary_master_utils | utils/summary_master_utils.py |
Extract Report Date จากไฟล์ Margin Loan, สร้าง Symbol Master, เขียนข้อมูล OS/Limit |
| master_template_date_check_utils | utils/master_template_date_check_utils.py |
Shared State (_WRITE_MODE, _REPORT_DATE), ตรวจสอบวันที่, ตัดสินใจ Write Mode, ลบแถวตามวันที่, ค้นหาแถวแรกตามวันที่ |
| master_excel_helper | utils/master_excel_helper.py |
โหลด workbook, อ่าน/เขียนข้อมูลจาก sheet (read_columns_from_sheet, write_to_sheet) |
| pledged_update_master_utils | utils/pledged_update_master_utils.py |
สร้าง Data Map จากไฟล์ Margin Loan (อ่านจาก Row 10, Key=Column B, Value=Column ที่กำหนด) |
| public_company_utils | utils/public_company_utils.py |
จัดรูปแบบ Header สำหรับ Temp Public Company (สีเขียว 92D050) |
| set_api_utils | utils/set_api_utils.py |
เรียก SET API เพื่อดึงข้อมูล Listed Shares (Session Reuse + Cookie Persistence + Warm-up + Auto-retry) |
9. การทำงานกับ Prefect
9.1 เปิด/ปิด Prefect
ตั้งค่า UsePrefect_Variable ใน ConfigPy.xlsx:
- TRUE = ใช้ Prefect Workflow Engine
- FALSE = รันฟังก์ชันปกติ (โดยตรง, ไม่ผ่าน Prefect)
9.2 การทำงานเมื่อเปิด Prefect
- แต่ละ Flow จะถูกแปลงเป็น Prefect Flow (ด้วย
@flowdecorator) แบบ Runtime (สร้าง decorator ตอนเรียกฟังก์ชัน) - แต่ละ Task จะถูกแปลงเป็น Prefect Task (ด้วย
@taskdecorator) แบบ Module-level (ประกาศไว้ล่วงหน้า) - มีการตั้งค่า retry (
RETRY_COUNT,RETRY_DELAY_SECONDS) สำหรับบาง Task
9.3 การทำงานเมื่อปิด Prefect
- ฟังก์ชันจะรันโดยตรง โดยไม่มี Prefect orchestration
- เหมาะสำหรับการรันแบบ standalone หรือ debug
9.4 Special Subprocess Handling
ใน main.py มีกลไก handle_special_subprocess_modes() สำหรับจัดการกับกรณีที่ Prefect เรียกใช้ uvicorn ผ่าน frozen executable โดย:
- ตรวจสอบ argument -m uvicorn
- ตัด sys.argv เพื่อลบ [-m, uvicorn] ออก
- เรียก uvicorn.main.main() โดยตรง
10. การ Build เป็น .exe ด้วย PyInstaller
10.1 ไฟล์ main.spec
โปรเจคมีไฟล์ main.spec สำหรับ PyInstaller ไว้แล้ว โดยมีการตั้งค่า:
- ชื่อ executable: main.exe
- รูปแบบ: One File (onedir=False)
10.2 คำสั่ง Build
pyinstaller main.spec
หรือสร้าง spec ใหม่:
pyinstaller --onefile --name main main.py
10.3 ข้อควรระวัง
- PyInstaller ใช้
--onefileซึ่งอาจทำให้ antivirus แจ้งเตือน (false positive) - หลัง build ต้องแน่ใจว่าไฟล์
.exeอยู่ในตำแหน่งเดียวกับโฟลเดอร์config/(หรือปรับ_get_base_path()ใน settings.py)
11. การแก้ไขปัญหา (Troubleshooting)
11.1 "ไม่พบไฟล์ Input"
สาเหตุ: ไม่สามารถเข้าถึง Input_Path หรือไม่พบไฟล์ InputName_FileName
แนวทางแก้ไข: 1. ตรวจสอบว่า Input_Path ใน ConfigPy.xlsx ถูกต้อง 2. ตรวจสอบว่าไฟล์มีอยู่จริงใน path นั้น 3. ถ้าใช้ UNC Path: ตรวจสอบ Windows Credential Manager 4. ระบบจะ retry อัตโนมัติ 3 ครั้ง ห่างกันครั้งละ 5 นาที
11.2 "ไม่พบไฟล์ Manual Mapping"
สาเหตุ: ไม่สามารถเข้าถึง TemplateInput_Path หรือไม่พบไฟล์ Manual_Mapping.xlsx
แนวทางแก้ไข: 1. ตรวจสอบ TemplateInput_Path ใน ConfigPy.xlsx 2. ตรวจสอบว่าไฟล์ Manual_Mapping.xlsx มีอยู่จริง 3. ระบบจะ retry อัตโนมัติ 3 ครั้ง ห่างกันครั้งละ 5 นาที
11.3 "ไม่พบไฟล์ Margin Loan"
สาเหตุ: ไม่พบไฟล์ *Securities_Pledged_MarginAccounts_en.xlsx ใน Download_Path
แนวทางแก้ไข:
1. ตรวจสอบว่า Download Flow ทำงานสำเร็จ
2. ตรวจสอบการเชื่อมต่ออินเทอร์เน็ต
3. ถ้าดาวน์โหลดไม่สำเร็จ ให้ลองตั้งค่า PlaywrightHeadless_Variable = FALSE เพื่อดู browser
11.4 "ไม่สามารถเชื่อมต่อ TemplateInput_Path"
สาเหตุ: ไม่สามารถเข้าถึงปลายทางสำหรับส่งออกไฟล์
แนวทางแก้ไข: 1. ตรวจสอบ TemplateInput_Path ใน ConfigPy.xlsx 2. ตรวจสอบ Windows Credential Manager (WIN_ServiceName, WIN_Username) 3. ตรวจสอบสิทธิ์การเข้าถึง Network Path
11.5 "Credential ไม่ถูกต้อง"
สาเหตุ: รหัสผ่านใน Windows Credential Manager ไม่ถูกต้องหรือหมดอายุ
แนวทางแก้ไข: 1. เปิด Credential Manager → Windows Credentials 2. อัปเดตรหัสผ่านสำหรับ WIN_ServiceName
11.6 "SET API Error"
สาเหตุ: ไม่สามารถเรียก API ของ SET ได้
แนวทางแก้ไข: 1. ตรวจสอบการเชื่อมต่ออินเทอร์เน็ต 2. ระบบมี Session Refresh อัตโนมัติเมื่อเจอ 401/403/429 3. ตรวจสอบว่า Symbol ที่เรียกมีอยู่ใน SET จริง
11.7 "Download Failed"
สาเหตุ: ไม่สามารถดาวน์โหลดไฟล์จาก SET ด้วย Playwright
แนวทางแก้ไข:
1. ตรวจสอบการเชื่อมต่ออินเทอร์เน็ต
2. ตรวจสอบว่า Chrome ทำงานได้ปกติ
3. ตรวจสอบ CHROME_PATH ใน ConfigPy.xlsx
4. ลองตั้งค่า PlaywrightHeadless_Variable = FALSE เพื่อดู browser ขณะดาวน์โหลด
11.8 "Prefect Error ตอน Build .exe"
สาเหตุ: Prefect สร้าง subprocess ที่ไม่เข้ากับ PyInstaller
แนวทางแก้ไข:
1. ตั้งค่า UsePrefect_Variable = FALSE เพื่อ bypass ปัญหา
2. หรือตรวจสอบว่า handle_special_subprocess_modes() ทำงานถูกต้อง
11.9 Log Files
ระบบสร้าง Log หลายประเภทเพื่อช่วยในการแก้ไขปัญหา:
| Log File | ตำแหน่ง | รายละเอียด |
|---|---|---|
activity.log |
PythonLogs_Path |
บันทึกกิจกรรมหลักทั้งหมด (append) |
not_found.log |
PythonLogs_Path |
บันทึก warning และ error |
marginLoanProcessing.log |
Python_Path |
บันทึกการประมวลผล (สร้างใหม่ทุกครั้ง) |
ภาคผนวก
A: ไฟล์ที่เกี่ยวข้อง
| ไฟล์ | Path | ถูกสร้างโดย |
|---|---|---|
COL_STOCK_Public_Company_*.xlsx |
Input_Path → DataInput_Path | ระบบภายนอก |
Manual_Mapping.xlsx |
TemplateInput_Path → DataInput_Path → DataOutput_Path | ผู้ใช้ |
listedCompanies_th_TH.xls |
Download_Path | Flow 7.1 |
listedCompanies_en_US.xls |
Download_Path | Flow 7.1 |
*_Securities_Pledged_MarginAccounts_en.xlsx |
Download_Path | Flow 7.1 |
Master_Template.xlsx |
DataOutput_Path | Flow 7.6 |
_tempLHBPublicCompany.xlsx |
Temp_Path | Flow 7.8 |
listedCompanies.xlsx |
DataOutput_Path | Flow 7.16 |
B: ลำดับ Columns ใน Data-COL_STOCK Sheet
| Column | Header | รายละเอียด |
|---|---|---|
| A | CIF_Key | รหัสลูกค้า |
| B | IDNumber | เลขประจำตัว |
| C | Company_type | ประเภทบริษัท |
| D | CusNameTh | ชื่อลูกค้าภาษาไทย |
| E | CusNameEn | ชื่อลูกค้าภาษาอังกฤษ |
| F | BusinessSize | ขนาดธุรกิจ |
| G | BUS_Size_Description | คำอธิบายขนาดธุรกิจ |
| H | BPBTYP_Lv1 | ระดับธุรกิจ Lv1 ประเภท |
| I | BPBDSC_Lv1_TH | ระดับธุรกิจ Lv1 คำอธิบาย TH |
| J | BPBDSC_Lv1_EN | ระดับธุรกิจ Lv1 คำอธิบาย EN |
| K | BPBTYP_Lv2 | ระดับธุรกิจ Lv2 ประเภท |
| L | BPBDSC_Lv2_TH | ระดับธุรกิจ Lv2 คำอธิบาย TH |
| M | BPBDSC_Lv2_EN | ระดับธุรกิจ Lv2 คำอธิบาย EN |
| N | BPBTYP_Lv3 | ระดับธุรกิจ Lv3 ประเภท |
| O | BPBDSC_Lv3_TH | ระดับธุรกิจ Lv3 คำอธิบาย TH |
| P | BPBDSC_Lv3_EN | ระดับธุรกิจ Lv3 คำอธิบาย EN |
| Q | BTMBTY | ประเภทย่อย |
| R | BPBDSC_Lv4_TH | ระดับธุรกิจ Lv4 คำอธิบาย TH |
| S | BPBDSC_Lv4_EN | ระดับธุรกิจ Lv4 คำอธิบาย EN |
| T | BTCTYP | ประเภทธุรกิจ |
| U | BPADSC | คำอธิบายธุรกิจ |
| V | SEGMENT | Segment |
| W | RM_NAME_TH | ชื่อ RM |
| X | VP_TH | VP |
| Y | GROUP_SLL_CIFNO | กลุ่ม SLL CIFNO |
| Z | GROUP_SLL_NAME | กลุ่ม SLL ชื่อ |
| AA | GROUP_SLL_NUMBER | กลุ่ม SLL หมายเลข |
| AB | First_contact | วันที่ติดต่อครั้งแรก |
| AC | SUM_A1IMLMTE | Limit |
| AD | SUM_A1UTILIT | Utilized |
| AE | SUM_A1UNTILIT | Unutilized |
| AF | SUM_CBAL | OS |
| AG | GROUP_CCDCID | กลุ่ม CCD CID |
| AH | GROUP_CCDDSC | กลุ่ม CCD คำอธิบาย |
| AI | UNIT | หน่วย |
| AJ | GROUP_CCDSID | รหัส CCDS |
| AK | PRICE | ราคา |
| AL | SUM_CCDCMV | Market Value |
| AM | Percent_LTV | %LTV |
| AN | C_CCDNAM | ชื่อ CCD |
| AO | HAVE_STOCK | มี Stock หรือไม่ |
| AP | ORI_ORR_CRR_RSME | ORR/CRR เดิม (รวม RSME) |
| AQ | CURRENT_ORR_CRR_RSME | ORR/CRR ปัจจุบัน (รวม RSME) |
| AR | I9LNCL1 | I9LNCL1 |
| AS | ORI_ORR_CRR | ORR/CRR เดิม |
| AT | CURRENT_ORR_CRR | ORR/CRR ปัจจุบัน |
| AU | (ว่าง) | |
| AV | Date | วันที่รายงาน |
เอกสารนี้สร้างขึ้นเมื่อ 2 มิถุนายน 2026 สำหรับโปรเจค LHB-MarginLoan4