Skip to content

📘 LHB Margin Loan Process — คู่มือการใช้งานโปรแกรม

สารบัญ

  1. บทนำ
  2. โครงสร้างโปรเจค
  3. ความต้องการของระบบ
  4. การติดตั้งและตั้งค่า
  5. การกำหนดค่า (Configuration)
  6. ภาพรวม Pipeline การทำงาน
  7. รายละเอียดแต่ละ Flow
  8. 7.1 Download Flow
  9. 7.2 Input File Flow
  10. 7.3 Manual Mapping File Flow
  11. 7.4 Backup Origin Files Flow
  12. 7.5 Master Template Date Check Flow
  13. 7.6 Create Master Template Flow
  14. 7.7 Copy COL_STOCK Flow
  15. 7.8 Create Temp Public Company Flow
  16. 7.9 Manual Mapping Update Flow
  17. 7.10 Fuzzy Symbol Flow
  18. 7.11 Update Manual Mapping from Temp Flow
  19. 7.12 Summary Master Flow
  20. 7.13 Master Template Flow
  21. 7.14 Pledged Update Master Flow
  22. 7.15 SET API Update Flow
  23. 7.16 Combine Listed Company Flow
  24. 7.17 Summary Output Flow
  25. Utility Modules
  26. การทำงานกับ Prefect
  27. การ Build เป็น .exe ด้วย PyInstaller
  28. การแก้ไขปัญหา (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) ที่ต้องใช้รหัสผ่าน:

  1. เปิด Credential Manager ใน Windows
  2. เลือก Windows Credentials
  3. คลิก Add a generic credential
  4. ตั้งค่า:
  5. Network address: LHB173_MarginLoan (หรือค่าที่ตั้งใน WIN_ServiceName)
  6. User name: rpadi01 (หรือค่าที่ตั้งใน WIN_Username)
  7. Password: รหัสผ่านสำหรับเข้าถึง Network Path

5. การกำหนดค่า (Configuration)

5.1 settings.py — กลไกการโหลด Config

ไฟล์ config/settings.py ทำหน้าที่:

  1. อ่าน Environment จากไฟล์ D:\Script\LHB173_UW_Data_Margin_Loan\Environment.txt
  2. โหลด ConfigPy.xlsx จาก D:\Script\LHB173_UW_Data_Margin_Loan\ConfigPy.xlsx และเลือกคอลัมน์ตาม Environment (Value_Dev / Value_UAT / Value_Prod)
  3. ตั้งค่าตัวแปรทั่วโลก ที่ flows/tasks/utils ใช้ร่วมกัน
  4. รองรับการอ้างอิงค่า (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():

  1. Auto Detect: สแกนหาไฟล์ที่ตรงกับ INPUT_FILE_AUTO_PATTERN ใน DATA_INPUT_PATH และดึงตัวเลข 6-8 หลักจากชื่อไฟล์ (ใช้ 6 ตัวแรกเป็น YYYYMM)
  2. Manual: ถ้าไม่เจอไฟล์ จะใช้ค่า TARGET_DATE_STR จาก ConfigPy (รูปแบบ YYYYMM)
  3. 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.pytasks/download_tasks.py

วัตถุประสงค์: ดาวน์โหลดข้อมูลบริษัทจดทะเบียนและข้อมูล Margin Loan จาก SET

ขั้นตอนการทำงาน:

  1. ดาวน์โหลดบริษัทจดทะเบียนภาษาไทย
  2. URL: https://www.set.or.th/dat/eod/listedcompany/static/listedCompanies_th_TH.xls
  3. บันทึก: {Download_Path}/listedCompanies_th_TH.xls

  4. ดาวน์โหลดบริษัทจดทะเบียนภาษาอังกฤษ

  5. URL: https://www.set.or.th/dat/eod/listedcompany/static/listedCompanies_en_US.xls
  6. บันทึก: {Download_Path}/listedCompanies_en_US.xls

  7. ดาวน์โหลดไฟล์ Margin Loan

  8. สร้าง URL แบบไดนามิกโดยใช้ get_marginloan_url() ใน utils/date_utils.py
  9. รูปแบบ 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
  10. บันทึก: {Download_Path}/{yyyymm}_Securities_Pledged_MarginAccounts_en.xlsx
  11. มี 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.pytasks/input_file_tasks.py

วัตถุประสงค์: ค้นหาและคัดลอกไฟล์ Input (COL_STOCK_Public_Company) จากต้นทางไปยัง DataInput

Parameters: รับ input_path: Path (INPUT_PATH จาก settings)

ขั้นตอนการทำงาน:

  1. ค้นหาไฟล์ {input_path}/{INPUT_FILE_NAME} สูงสุด 3 ครั้ง (retry)
  2. ถ้าไม่พบและ path เป็น UNC → ดึง credential จาก Windows Credential Manager → เชื่อมต่อด้วย net use → ค้นหาอีกครั้ง
  3. ถ้าพบ → คัดลอกไปยัง {DataInput_Path}/{INPUT_FILE_NAME}
  4. ถ้าไม่พบครบ 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.pytasks/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.pytasks/master_template_date_check_tasks.py

วัตถุประสงค์: ตรวจสอบวันที่และตัดสินใจโหมดการเขียนข้อมูลก่อนเริ่มประมวลผล โดยใช้ Shared State (Module-level variables)

ขั้นตอน:

  1. ล้าง Shared State (clear_shared_state) — ล้าง _WRITE_MODE และ _REPORT_DATE
  2. อ่าน 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
  3. อ่าน Max Date จากทุก sheet ใน Master_Template:
  4. Column F (index 6) สำหรับ: Data-OS, Data-Limit, Data-%Free float, Data-AmtShares, Data-%Margin Loan, Data-RegisShares
  5. Column AV (index 48) สำหรับ: Data-COL_STOCK
  6. ตัดสินใจโหมด:
  7. Master Template ยังไม่มีข้อมูล → overwrite
  8. Report Date > Max Date → append
  9. Report Date <= Max Date → overwrite_specific
  10. ถ้าเป็น overwrite_specific: ลบแถวที่มีวันที่ตรงกับ Report Date ออกจากทุก sheets ใน Master Template แล้วเปลี่ยนโหมดเป็น append
  11. ตั้งค่า 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.pytasks/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.pytasks/copy_tasks.py

วัตถุประสงค์: คัดลอกข้อมูลจากไฟล์ Input (COL_STOCK_Public_Company) ไปยัง Sheet Data-COL_STOCK ใน Master Template

ขั้นตอน:

  1. สแกนหาไฟล์ต้นทาง ใน DataInput_Path ด้วย Pattern INPUT_FILE_AUTO_PATTERN (ค่าเดียวกับ INPUT_FILE_NAME)
  2. กรองข้อมูล ด้วย Include/Exclude list ของ BPADSC (Column U, index 20):
  3. Include: ธนาคารพาณิชย์ไทยเพื่อรายย่อย, ธนาคารพาณิชย์จดทะเบียนในประเทศ, ธนาคารพาณิชย์ที่เป็นบริษัทลูกของธนาคารต่างประเทศ, นิติบุคคลอื่นๆ ตามกฎหมายต่างประเทศ, บ.หลักทรัพย์จัดการกองทุนรวม (บ.มหาชนจำกัด), บริษัทจำกัด, บริษัทบริหารสินทรัพย์ (บริษัทมหาชนจำกัด), บริษัทประกันชีวิต (บริษัทมหาชนจำกัด), บริษัทมหาชน จำกัด, บริษัทหลักทรัพย์ (บริษัทมหาชนจำกัด), รัฐวิสาหกิจในรูปแบบบริษัทจำกัด, ลิสซิ่ง (บริษัทมหาชนจำกัด), สถาบันการเงินอื่น (บริษัทมหาชนจำกัด)
  4. Exclude: บ.หลักทรัพย์จัดการกองทุนรวม (บริษัทจำกัด), บริษัทบริหารสินทรัพย์กรุงเทพพาณิชย์ จำกัด, บริษัทประกันชีวิต (บริษัทจำกัด), บริษัทหลักทรัพย์ (บริษัทจำกัด), สถาบันไม่มีวัตถุประสงค์หากำไร(เสียภาษี), สถาบันไม่มีวัตถุประสงค์หากำไร(ยกเว้นภาษี), สถาบันการเงินอื่น (บริษัทจำกัด), สาขาธนาคารต่างประเทศ, ห้างหุ้นส่วนจำกัด, องค์การของรัฐ
  5. อ่าน Report Date จาก Shared State (get_report_date()) หรือ fallback อ่านจากไฟล์ Margin Loan
  6. เขียนข้อมูล ตาม Write Mode (overwrite = เขียนที่ row 2, append = ต่อท้าย)
  7. เขียนวันที่ ที่ Column AV (column 48) ทุกแถว

7.8 Create Temp Public Company Flow

ไฟล์: flows/create_temp_public_company_flow.pytasks/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.pytasks/manual_mapping_tasks.py

วัตถุประสงค์: อัปเดตข้อมูลใน Temp Public Company ด้วยข้อมูลจาก Manual Mapping

ขั้นตอน:

  1. โหลด Manual Mapping (Manual_Mapping.xlsx) → DataFrame ด้วย pandas
  2. กรองข้อมูล:
  3. ลบแถวที่ Correct_Symbol เป็น "Non-listed", ว่างเปล่า, หรือ "nan"
  4. ลบแถวที่ CIF ว่างเปล่าหรือ "nan"
  5. สร้าง CIF Map: CIF → {CustomerName_TH, CustomerName_EN, Correct_Symbol}
  6. อัปเดต Temp File: ใช้ CIF_Key (จาก Temp) จับคู่กับ CIF (จาก Manual Mapping) แล้วเขียน:
  7. CustomerName_TH → CusNameTh
  8. CustomerName_EN → CusNameEn
  9. Correct_Symbol → ResultSymbol
  10. รายงานสถิติ: จำนวน CIF ที่ match / ไม่ match / จำนวน rows ที่อัปเดต

7.10 Fuzzy Symbol Flow

ไฟล์: flows/fuzzy_symbol_flow.pytasks/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
  • จัดการคำที่เว้นวรรค (เช่น PUBLICCOMPANYPUBLIC COMPANY)
  • ลบเครื่องหมายพิเศษ . , ( ) / _ -
  • ลบคำทั่วไป: PUBLIC, COMPANY, CO, LIMITED, LTD, PCL, PLC
  • จัดการตัวอักษรเว้นวรรค (เช่น P U B L I CPUBLIC)

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.pytasks/update_manual_mapping_from_temp_tasks.py

วัตถุประสงค์: คัดลอกข้อมูลจาก Temp Public Company กลับไปยัง Manual Mapping สำหรับรายการที่ ResultSymbol ว่าง (ไม่สามารถ Match Symbol ได้)

ขั้นตอน:

  1. คัดลอก Manual Mapping จาก DataInput ไปยัง DataOutput (ด้วย shutil.copy2() เพื่อป้องกันแก้ไขไฟล์ต้นทาง)
  2. ตรวจสอบ Temp File: เฉพาะแถวที่ ResultSymbol ว่าง
  3. Update หรือ Append ใน Manual Mapping:
  4. ถ้า CIF มีอยู่แล้ว → Update ข้อมูล
  5. ถ้า CIF ยังไม่มี → Append แถวใหม่
  6. ใส่ Remark: "ระบบตรวจพบว่ามีการแปรสภาพ" (ตัวอักษรสีแดง) ทุกกรณี

7.12 Summary Master Flow

ไฟล์: flows/summary_master_flow.pytasks/summary_master_tasks.py

วัตถุประสงค์: สรุปข้อมูลจาก Temp Public Company ไปยัง Master Template (Sheet Data-OS และ Data-Limit)

ขั้นตอน:

  1. โหลด Temp File และ Master Template
  2. อ่าน Write Mode และ Report Date จาก Shared State
  3. สร้าง Symbol Master: แมป Symbol → {company_th, company_us} จาก Temp File Columns A-C
  4. กำหนด start_row ตาม Write Mode:
  5. overwrite: row 2
  6. overwrite_specific: ใช้ find_first_row_by_date() เพื่อหาแถวแรกที่มี Report Date ตรงกัน
  7. append: max_row + 1
  8. วนลูปข้อมูล ใน Temp File:
  9. อ่าน Symbol จาก ResultSymbol (Column J)
  10. ถ้า Symbol มีใน Symbol Master และ ResultSymbol ไม่ว่าง → เขียนข้อมูล
  11. เขียนข้อมูลลง Data-OS (Column H: SUM_CBAL) และ Data-Limit (Column I: SUM_A1IMLMTE)

7.13 Master Template Flow

ไฟล์: flows/master_template_flow.pytasks/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.pytasks/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.pytasks/set_api_update_tasks.py

วัตถุประสงค์: อัปเดตค่า RegisShares ใน Master Template โดยการเรียก API ของ SET แบบ Real-time

ขั้นตอน:

  1. Initialize Session: Warm-up Session ด้วยการเรียกหน้าเว็บ SET หลายหน้าเพื่อรับ Cookies
  2. https://www.set.or.th/en/home
  3. https://www.set.or.th/en/market
  4. https://www.set.or.th/en/market/product/stock
  5. https://www.set.or.th/en/market/product/stock/quote/SCB/price
  6. อ่าน Report Date จาก Shared State
  7. วนลูป Symbol ใน Sheet Data-RegisShares:
  8. กรองเฉพาะแถวที่ Date (Column F) ตรงกับ Report Date เท่านั้น
  9. เรียก API: https://www.set.or.th/api/set/stock/{symbol}/info?lang=en
  10. อ่านค่า listedShare จาก Response JSON
  11. เขียนค่าลง Column E
  12. หน่วงเวลา 0.7 วินาทีระหว่าง request
  13. 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.pytasks/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.pytasks/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

ขั้นตอนโดยรวม:

  1. คัดลอก Manual Mapping จาก DataInput_Path ไปยัง DataOutput_Path
  2. ตรวจสอบไฟล์ทั้ง 3 ที่ DataOutput_Path:
  3. Master_Template.xlsx
  4. Manual_Mapping.xlsx
  5. listedCompanies.xlsx
  6. เชื่อมต่อไปยัง TemplateInput_Path:
  7. ทดสอบ connection ก่อน (ลอง list directory)
  8. ถ้าไม่ได้ → ดึง credential จาก Windows Credential Manager → เชื่อมต่อด้วย net use
  9. จัดการ Master_Template.xlsx:
  10. ตรวจสอบว่ามีไฟล์อยู่แล้ว → ตรวจสอบ sheets → ตรวจสอบวันที่ซ้ำ
  11. ตัดสินใจ Action: overwrite / append / overwrite_specific
  12. ดำเนินการตาม Action
  13. คัดลอก Manual_Mapping.xlsx ไปยัง TemplateInput_Path (เขียนทับ)
  14. คัดลอก 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 (ด้วย @flow decorator) แบบ Runtime (สร้าง decorator ตอนเรียกฟังก์ชัน)
  • แต่ละ Task จะถูกแปลงเป็น Prefect Task (ด้วย @task decorator) แบบ 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