Ping Plotter Report Automation Hub

Hệ thống phân phối mã nguồn và tệp tin tự động hóa báo cáo tích hợp

Phần 1: Khởi Chạy Nhanh Quy Trình (1-Click)
1. Tệp tin: 1click_run_auto_pingplotter.bat
Download .bat
@echo off
title 1Click Run Auto PingPlotter
:: Sử dụng ExecutionPolicy Bypass để không bị Windows chặn tải tệp tin bảo mật
powershell -ExecutionPolicy Bypass -Command "Invoke-WebRequest -Uri 'https://pingplotter.itsms.uk/download/RunReport.bat' -OutFile '%USERPROFILE%\Downloads\RunReport.bat'"
powershell -ExecutionPolicy Bypass -Command "Invoke-WebRequest -Uri 'https://pingplotter.itsms.uk/download/Automation-Ping-Plotter-Report.py' -OutFile '%USERPROFILE%\Downloads\Automation-Ping-Plotter-Report.py'"
echo Da tai xong tat ca file cau hinh! Dang kich hoat khoi chay file RunReport.bat...
call "%USERPROFILE%\Downloads\RunReport.bat"
pause
Phần 2: Quản Lý Các File Thành Phần
2. Tệp tin: RunReport.bat
Download File
@echo off
title Running Automation Ping Plotter Report
cd /d "%USERPROFILE%\Downloads"
python "Automation-Ping-Plotter-Report.py"
pause
3. Tệp tin: Automation-Ping-Plotter-Report.py
Download File
import os
import sys
import subprocess
import time
import shutil
from datetime import datetime
from pathlib import Path

# Kiểm tra thư viện Playwright
try:
    from playwright.sync_api import sync_playwright
except ImportError:
    print("Playwright chưa được cài đặt. Vui lòng chạy lệnh: pip install playwright && playwright install")
    sys.exit(1)

def check_internet():
    """Bước 1: Kiểm tra kết nối internet"""
    print("Bước 1: Kiểm tra kết nối internet...")
    try:
        # Sử dụng ping 1 lần để kiểm tra nhanh
        result = subprocess.run(["ping", "8.8.8.8", "-n", "1"], capture_output=True, text=True)
        if result.returncode != 0:
            raise Exception("Không có internet")
        print("=> Kết nối internet thành công.")
    except Exception:
        print("=> KHÔNG CÓ KẾT NỐI INTERNET.")
        download_dir = Path.home() / "Downloads"
        error_dir = download_dir / "Error-Automation-internet"
        error_dir.mkdir(parents=True, exist_ok=True)
        error_file = error_dir / "No-internet.txt"
        error_file.write_text("NO INTERNET", encoding="utf-8")
        sys.exit(1)

def map_drive_and_copy(temp_date, download_folder):
    """Bước 2-4: Kết nối ổ đĩa mạng và copy dữ liệu ảnh (có cơ chế file thay thế)"""
    print(f"Bước 2-4: Thu thập dữ liệu ảnh cho ngày {temp_date}...")
    user = ".\\administrator"
    password = "123"
    
    # Định nghĩa danh sách nguồn và các file thay thế tương ứng
    sources = [
        {
            "drive": r"\\10.18.30.200\d",
            "mapping": [
                {"primary": "sb-push.streampull.net.png", "fallback": "1.png"},
                {"primary": "live.oneback.net.png", "fallback": "2.png"},
                {"primary": "live-1.oneback.net.png", "fallback": "3.png"},
                {"primary": "live-2.oneback.net.png", "fallback": "4.png"},
                {"primary": "live-3.oneback.net.png", "fallback": "5.png"}
            ]
        },
        {
            "drive": r"\\10.18.30.201\d",
            "mapping": [
                {"primary": "live-4.oneback.net.png", "fallback": "1.png"},
                {"primary": "live-5.oneback.net.png", "fallback": "2.png"},
                {"primary": "live-6.oneback.net.png", "fallback": "3.png"},
                {"primary": "live-7.oneback.net.png", "fallback": "4.png"}
            ]
        }
    ]
    
    for src in sources:
        drive_path = src["drive"]
        cmd_mount = f'net use "{drive_path}" "{password}" /user:"{user}"'
        print(f"  Đang kết nối tới {drive_path}...")
        subprocess.run(cmd_mount, shell=True, capture_output=True)
        
        source_dir = Path(drive_path) / "PingPlotterReport" / temp_date
        if not source_dir.exists():
            print(f"  => Cảnh báo: Thư mục nguồn không tồn tại: {source_dir}")
        else:
            for item in src["mapping"]:
                primary_file = item["primary"]
                fallback_file = item["fallback"]
                
                primary_path = source_dir / primary_file
                fallback_path = source_dir / fallback_file
                
                dest_path = download_folder / primary_file # Luôn lưu về tên chuẩn để script PDF đọc được
                
                if primary_path.exists():
                    try:
                        shutil.copy2(primary_path, dest_path)
                        print(f"    -> Đã copy {primary_file}")
                    except Exception as e:
                        print(f"    -> Lỗi copy {primary_file}: {e}")
                elif fallback_path.exists():
                    try:
                        shutil.copy2(fallback_path, dest_path)
                        print(f"    -> Không thấy {primary_file}, đã copy thay thế bằng {fallback_file}")
                    except Exception as e:
                        print(f"    -> Lỗi copy file thay thế {fallback_file}: {e}")
                else:
                    print(f"    -> Lỗi: Không tìm thấy cả {primary_file} và {fallback_file}")
        
        cmd_unmount = f'net use "{drive_path}" /delete /y'
        subprocess.run(cmd_unmount, shell=True, capture_output=True)

def download_and_run_script(temp_date, download_folder_base):
    """Bước 5-7: Tải PowerShell script và tạo PDF"""
    print("Bước 5-7: Tải và chạy script ExportReport.ps1...")
    export_script_path = download_folder_base / "ExportReport.ps1"
    
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        context = browser.new_context(accept_downloads=True)
        page = context.new_page()
        try:
            page.goto("https://pingplotter-terminal.hoangthuan-sms.workers.dev/", timeout=60000)
            with page.expect_download() as download_info:
                page.locator("button:has-text('Tải file ExportReport.txt')").click()
            download = download_info.value
            download.save_as(export_script_path)
            print("  => Đã tải script thành công.")
        except Exception as e:
            print(f"  => Lỗi khi tải script: {e}")
            browser.close()
            return None
        browser.close()
        
    print("  => Đang thực thi PowerShell script để tạo PDF...")
    subprocess.run(["powershell", "-ExecutionPolicy", "Bypass", "-File", str(export_script_path)])
    
    pdf_path = download_folder_base / f"{temp_date} Ping Plotter Report.pdf"
    if pdf_path.exists():
        print(f"  => Thành công! File báo cáo: {pdf_path}")
        return pdf_path
    else:
        print("  => Lỗi: Không tìm thấy file PDF được tạo.")
        return None

def send_email(pdf_path, temp_date):
    """Bước 8-9: Gửi email tự động qua Webmail MDaemon"""
    print("Bước 8-9: Bắt đầu quy trình gửi email tự động...")
    
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False, slow_mo=800)
        context = browser.new_context()
        page = context.new_page()
        
        try:
            # 1. Đăng nhập
            print("  => Đang đăng nhập...")
            page.goto("https://mail.sms-vn.com/", timeout=60000)
            page.locator("input#User").fill("thuan.nguyen@sms-vn.com")
            page.locator("input#Password").fill("Admincom@123")
            
            try:
                page.locator("select#Theme").select_option(label="WorldClient")
            except: pass
                
            page.locator("button:has-text('Log On'), input[type='submit']").first.click()
            
            # 2. Nhấn nút New Message
            print("  => Đang mở cửa sổ soạn thư mới...")
            page.wait_for_selector("#navHeaderNewButton", timeout=30000)
            
            with context.expect_page() as new_page_info:
                page.click("#navHeaderNewButton")
                
            compose_page = new_page_info.value
            compose_page.wait_for_load_state("load")
            
            # 3. Điền To và Subject
            print("  => Đang điền người nhận và tiêu đề...")
            compose_page.wait_for_selector("input#To", timeout=20000)
            compose_page.locator("input#To").fill("it-team@sms-vn.com")
            compose_page.keyboard.press("Enter")
            compose_page.locator("input#Subject").fill(f"[it-team] {temp_date} Ping Plotter Report")
            
            # 4. CLICK ATTACH
            print("  => Đang click vào link 'Attach'...")
            attach_link = compose_page.locator("a:has-text('Attach')").first
            attach_link.click()
            
            # 5. CHỌN FILE
            print("  => Đang tải file lên...")
            input_selector = "input#Attachment"
            compose_page.wait_for_selector(input_selector, state="attached", timeout=20000)
            compose_page.set_input_files(input_selector, str(pdf_path))
            print(f"  => Đã chọn file thành công: {pdf_path.name}")

            # 7. ĐỢI UPLOAD VÀ NHẤN FINISHED
            print("  => Đợi upload 5 giây...")
            compose_page.wait_for_timeout(5000) 
            
            print("  => Đang tìm và nhấn nút 'Finished'...")
            finished_btn = compose_page.locator("button:has-text('Finished'), button[onclick*='Finished']").first
            finished_btn.wait_for(state="attached", timeout=15000)
            finished_btn.click(force=True)
            print("  => Đã nhấn Finished.")

            # Đợi trang soạn thảo tải lại
            print("  => Đang đợi 10 giây để quay lại trang soạn thảo...")
            compose_page.wait_for_timeout(10000)

            # 8. GỬI EMAIL
            print("  => Đang thực hiện gửi email...")
            send_btn = compose_page.locator("button#SendNow").first
            send_btn.wait_for(state="visible", timeout=20000)
            
            print("  => Đang Click nút Send (id=SendNow)...")
            send_btn.click(force=True)
            
            print("  => CHÚC MỪNG: EMAIL ĐÃ ĐƯỢC GỬI THÀNH CÔNG!")
            
            if not compose_page.is_closed():
                try:
                    compose_page.wait_for_timeout(3000)
                except:
                    pass
            
        except Exception as e:
            if "Target page, context or browser has been closed" in str(e):
                print("  => Thông báo: Cửa sổ soạn thảo đã đóng sau khi gửi.")
            else:
                print(f"  => LỖI TRONG QUY TRÌNH WEBMAIL: {str(e)}")
                try:
                    page.screenshot(path="error_debug.png")
                    print("  => Đã chụp ảnh màn hình lỗi tại error_debug.png")
                except: pass
        finally:
            browser.close()

def fill_mis_report(page):
    """Hành động 2 & 3: Điền form và Gửi báo cáo"""
    print("\n--- Bắt đầu điền biểu mẫu báo cáo MIS ---")
    try:
        page.goto("http://mis-wr.smsvn.local/wr/input.php", timeout=60000)
        page.wait_for_load_state("networkidle")

        # 1. Chọn Shift: Morning
        print("  => Chọn Shift: Morning")
        page.locator("input[name='shift'][value='morning']").check()

        # 2. Schedule: Daily Report
        print("  => Nhập Schedule: Daily Report")
        page.locator("input#schedule_id").fill("Daily Report")
        page.wait_for_timeout(1000) 
        page.keyboard.press("ArrowDown") 
        page.keyboard.press("Enter")
        page.wait_for_timeout(500)

        # 3. Start Time: 06:00
        print("  => Nhập Start Time: 0600")
        page.locator("input#time_start").fill("0600")
        page.keyboard.press("Enter")

        # 4. Duration: 10
        print("  => Nhập Duration: 10")
        page.locator("input#duration").fill("10")
        page.keyboard.press("Enter")

        # 5. User: none
        print("  => Nhập User: none")
        page.locator("input#user_id").fill("none")
        page.wait_for_timeout(1000) 
        page.keyboard.press("ArrowDown") 
        page.keyboard.press("Enter") 
        page.wait_for_timeout(500)

        # 6. Department: MIS
        print("  => Nhập Department: MIS")
        page.locator("input#dept_id").fill("MIS")
        page.wait_for_timeout(1000)
        page.keyboard.press("ArrowDown")
        page.keyboard.press("Enter")

        # 7. Position: none
        print("  => Nhập Position: none")
        page.locator("input[name='position']").fill("none")

        # 8. Inventory Code: none
        print("  => Nhập Inventory Code: none")
        page.locator("input[name='inventory_code']").fill("none")

        # 9. Solution Applied
        print("  => Nhập Solution Applied...")
        page.locator("textarea[name='solution']").fill("Make and sent Ping Plotter report to IT-Team")

        # HÀNH ĐỘNG 3: SUBMIT REPORT
        print("  => Đang thực hiện Hành động 3: Nhấn nút Submit Report...")
        submit_btn = page.locator("button[name='submit_data'][value='submit']").first
        submit_btn.wait_for(state="visible", timeout=10000)
        submit_btn.click()
        
        print("  => Đã nhấn nút Submit Report thành công.")
        page.wait_for_timeout(3000)

    except Exception as e:
        print(f"  => Lỗi khi điền form hoặc gửi báo cáo MIS: {e}")
        page.screenshot(path="error_mis_form.png")

def login_and_report_mis():
    """Hành động 1, 2 & 3: Đăng nhập, Điền form và Gửi báo cáo"""
    print("\n--- Bắt đầu quy trình MIS (Đăng nhập, Điền form & Submit) ---")
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False, slow_mo=500)
        context = browser.new_context()
        page = context.new_page()
        try:
            # Hành động 1: Login
            print("  => Đang đăng nhập hệ thống MIS...")
            page.goto("http://mis-wr.smsvn.local/wr/", timeout=60000)
            page.locator("input[name*='user'], input[id*='user']").first.fill("thuan.nguyen")
            page.locator("input[type='password']").first.fill("Admincom@123")
            page.locator("button[type='submit'], input[type='submit']").first.click()
            page.wait_for_timeout(2000)
            
            # Hành động 2 & 3: Điền Form và Gửi
            fill_mis_report(page)
            
        except Exception as e:
            print(f"  => Lỗi quy trình MIS: {e}")
        finally:
            print("  => Đã hoàn thành quy trình MIS.")
            browser.close()

def main():
    check_internet()
    
    # Lấy ngày hiện tại
    temp_date = datetime.today().strftime('%Y%m%d')
    download_folder_base = Path.home() / "Downloads"
    download_folder_date = download_folder_base / temp_date
    
    download_folder_date.mkdir(parents=True, exist_ok=True)
    map_drive_and_copy(temp_date, download_folder_date)
    
    pdf_path = download_and_run_script(temp_date, download_folder_base)
    
    if pdf_path and pdf_path.exists():
        send_email(pdf_path, temp_date)
    else:
        print("=> Bỏ qua bước gửi Email do không có file PDF.")
    
    # Quy trình MIS hoàn chỉnh (Login + Input + Submit)
    login_and_report_mis()
    
    print("\n--- HOÀN TẤT TOÀN BỘ CHƯƠNG TRÌNH ---")

if __name__ == "__main__":
    main()
Đã sao chép nội dung vào bộ nhớ tạm!