CoolFace
Modelpublic

quyenca/TCB_PRINTING

sourceHugging Faceupdated 7mo agoView on Hugging Face
0likes
main.py431 linesDownload Raw Back to root
1import flet as ft2import threading3import time4from selenium import webdriver5from selenium.webdriver.firefox.service import Service6from selenium.webdriver.firefox.options import Options7from selenium.webdriver.support.ui import WebDriverWait8from selenium.webdriver.support import expected_conditions as EC9from selenium.webdriver.common.by import By10import pandas as pd11from datetime import datetime12import logging13import uuid14from Utils import PandasTable15 16 17# Set up logging18logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')19logger = logging.getLogger(__name__)20 21# Simulated user database22USER_CREDENTIALS = {"user":"password"}23 24# Selenium Functions25def mo_trinh_duyet():26    gecko_path =r"D:\Quyen\XuLyDuLieu\Du an\TCB_printing\geckodriver.exe"27    profile = webdriver.FirefoxProfile()28    profile.set_preference("print.always_print_silent", True)29    profile.set_preference("print.show_print_progress", False)30    options = Options()31    options.profile = profile32    service = Service(executable_path=gecko_path)33    driver = webdriver.Firefox(options=options,34                               service=service)35    path = "https://ib.techcombank.com.vn/corp/servlet/BrowserServlet"36    driver.get(path)37    time.sleep(2)38    print('''Mo trinh duyet thanh cong''')39    return driver40 41def log_in(driver, username, password):42    try:43        user = WebDriverWait(driver, 10).until(44            EC.presence_of_element_located(45                (By.XPATH, '/html/body/div/form/div[3]/div[2]/div[2]/div[1]/div[1]/div[2]/input'))46        )47        user.send_keys(username)48        pass_word = driver.find_element(By.XPATH, '/html/body/div/form/div[3]/div[2]/div[2]/div[1]/div[1]/div[4]/input')49        pass_word.send_keys(password)50        dang_nhap = driver.find_element(By.XPATH,51                                        '/html/body/div/form/div[3]/div[2]/div[2]/div[1]/div[1]/div[9]/input[1]')52        dang_nhap.click()53        time.sleep(2)54        logger.info("Login successful")55        return True56    except Exception as e:57        logger.error(f"Login failed: {str(e)}")58        return False59 60def button_click(driver, xpath, description="button"):61    try:62        btn = WebDriverWait(driver, 10).until(63            EC.element_to_be_clickable((By.XPATH, xpath))64        )65        btn.click()66        logger.info(f"Clicked {description}")67        return True68    except Exception as e:69        logger.error(f"Failed to click {description}: {str(e)}")70        return False71 72def fill_in_blank(driver, xpath, value, field_name="field"):73    try:74        txt_box = WebDriverWait(driver, 10).until(75            EC.presence_of_element_located((By.XPATH, xpath))76        )77        txt_box.clear()78        txt_box.send_keys(value)79        logger.info(f"Filled {field_name} with value: {value}")80        return True81    except Exception as e:82        logger.error(f"Failed to fill {field_name} with value {value}: {str(e)}")83        return False84 85def fetch_transactions(driver, account_number, start_date, end_date):86    try:87        if not button_click(driver, '/html/body/div/table/tbody/tr[2]/td/table/tbody/tr/td[1]/div[3]/ul[1]/li/span',88                            "Account Info menu"):89            return None90        if not button_click(driver,91                            '/html/body/div/table/tbody/tr[2]/td/table/tbody/tr/td[1]/div[3]/ul[1]/li/ul/li[1]/a',92                            "Transaction Query link"):93            return None94 95        if not fill_in_blank(driver, '//*[@id="fieldName:FIELD.1"]', account_number, "Account Number"):96            return None97        if not fill_in_blank(driver, '//*[@id="fieldName:DATE.FIELD.1"]', start_date, "Start Date"):98            return None99        if not fill_in_blank(driver, '//*[@id="fieldName:DATE.FIELD.2"]', end_date, "End Date"):100            return None101 102        if not button_click(driver,103                            '/html/body/div/table/tbody/tr[2]/td/table/tbody/tr/td[2]/div[3]/div[2]/form[1]/div[4]/table[2]/tbody/tr/td[2]/a',104                            "Execute Query button"):105            return None106 107        body_path = '/html/body/div[1]/table/tbody/tr[2]/td/table/tbody/tr/td[2]/div[3]/div/form/div/table/tbody/tr[2]/td[2]/div[2]/div/table/tbody'108        body = WebDriverWait(driver, 10).until(109            EC.presence_of_element_located((By.XPATH, body_path))110        )111        rows = body.find_elements(By.TAG_NAME, 'tr')112        lst = []113        for index, row in enumerate(rows, start=1):114            cells = row.find_elements(By.TAG_NAME, 'td')115            dic = {'Số TT': index}116            for i, cell in enumerate(cells, start=1):117                dic[f"Cột {i}"] = cell.text118            lst.append(dic)119 120        dt = pd.DataFrame(lst)121        dt.rename(columns={122            'Số TT': 'Số TT',123            'Cột 1': 'Ngày',124            'Cột 2': 'Số bút toán',125            'Cột 3': 'Tài khoản đích',126            'Cột 4': 'Diễn giải',127            'Cột 5': 'Số tiền ghi nợ',128            'Cột 6': 'Số tiền ghi có',129            'Cột 7': 'Số dư',130            'Cột 8': 'Print'131        }, inplace=True)132        # dt['Số tiền ghi nợ'] = dt['Số tiền ghi nợ'].str.replace(',', '')133        # dt['Số tiền ghi có'] = dt['Số tiền ghi có'].str.replace(',', '')134        # dt['Số tiền ghi nợ'] = pd.to_numeric(dt['Số tiền ghi nợ'])135        # dt['Số tiền ghi có'] = pd.to_numeric(dt['Số tiền ghi có'])136        logger.info(f"Fetched {len(dt)} transactions")137        return dt138    except Exception as e:139        logger.error(f"Failed to fetch transactions: {str(e)}")140        return None141 142def print_transaction(driver, index, main_window):143    try:144        print_buttons = driver.find_elements(By.XPATH,145                                             "/html/body/div/table/tbody/tr[2]/td/table/tbody/tr/td[2]/div[3]/div/form/div/table/tbody/tr[2]/td[2]/div[2]/div/table/tbody/tr/td[8]/a/img")146        print_buttons[index].click()147        WebDriverWait(driver, 10).until(lambda d: len(d.window_handles) > 1)148        for handle in driver.window_handles:149            if handle != main_window:150                driver.switch_to.window(handle)151                break152        time.sleep(3)153        button_click(driver, '/html/body/div/table/tbody/tr[1]/td/a/img', "Print command")154        driver.close()155        driver.switch_to.window(main_window)156        logger.info(f"Printed transaction at index {index}")157        return True158    except Exception as e:159        logger.error(f"Failed to print transaction at index {index}: {str(e)}")160        driver.switch_to.window(main_window)161        return False162 163# Flet App164def main(page: ft.Page):165    page.title = "Bank Transaction Printer"166    page.theme_mode = ft.ThemeMode.LIGHT167    page.padding = 20168    page.window_width = 1200169    page.window_height = 800170    driver = None171    main_window = None172    transactions = None173    printed_transactions = []174 175    def show_login_view():176        page.controls.clear()177        username = ft.TextField(label="Username", width=300)178        password = ft.TextField(label="Password", password=True, width=300,can_reveal_password=True)179        show_password = ft.IconButton(180            icon=ft.icons.VISIBILITY_OFF,181            on_click=lambda e: toggle_password_visibility(e, password)182        )183        login_error = ft.Text(color=ft.Colors.RED)184        login_btn = ft.ElevatedButton("Login", on_click=lambda e: start_login_thread())185 186        def start_login_thread():187            login_error.value = ""188            login_btn.disabled = True189            login_btn.text = "Starting browser..."190            page.update()191            threading.Thread(target=login_task, daemon=True).start()192 193        def login_task():194            nonlocal driver, main_window195            try:196                # Attempt to open browser197                driver = mo_trinh_duyet()198                main_window = driver.current_window_handle199                # Actually perform login on the portal200                if not log_in(driver, username.value, password.value):201                    login_error.value = "Failed to log in to bank portal. Please check credentials."202                    login_btn.disabled = False203                    login_btn.text = "Login"204                    page.update()205                    return206                207                # If successful, proceed to main view208                show_main_view(username.value, password.value)209            except Exception as e:210                login_error.value = f"Could not start browser or login: {str(e)}"211                login_btn.disabled = False212                login_btn.text = "Login"213                page.update()214 215        page.add(216            ft.Column(217                [218                    ft.Text("Login", size=30, weight=ft.FontWeight.BOLD),219                    ft.Row([username], spacing=0,alignment=ft.MainAxisAlignment.CENTER),220                    ft.Row([password], spacing=0, alignment=ft.MainAxisAlignment.CENTER),221                    login_error,222                    login_btn223                ],224                alignment=ft.MainAxisAlignment.CENTER,225                horizontal_alignment=ft.CrossAxisAlignment.CENTER,226                spacing=20227            )228        )229        page.update()230 231    def show_main_view(user_name,password):232        page.controls.clear()233        # account_number = ft.TextField(label="Account Number", value="19025071243072", width=300)234        account_number = ft.Dropdown(235            label="Account Number",236            width=300,237            options=[238                ft.dropdown.Option("19025071243072"),239                ft.dropdown.Option("10225071243011"),240                ft.dropdown.Option("19125071243018"),241            ],242            value="19025071243072"  # giá trị mặc định243        )244        start_date = ft.TextField(label="Start Date (DD/MM/YYYY)", value="15/05/2025", width=300)245        end_date = ft.TextField(label="End Date (DD/MM/YYYY)", value="20/05/2025", width=300)246        status_text = ft.Text()247        error_log = ft.Text(value="", color=ft.Colors.RED, size=12)248        stats_text = ft.Text()249        data_table = ft.DataTable(250            columns=[251                ft.DataColumn(ft.Text("Select")),252                ft.DataColumn(ft.Text("Số TT")),253                ft.DataColumn(ft.Text("Ngày")),254                ft.DataColumn(ft.Text("Số bút toán")),255                ft.DataColumn(ft.Text("Tài khoản đích")),256                ft.DataColumn(ft.Text("Diễn giải")),257                ft.DataColumn(ft.Text("Số tiền ghi nợ")),258                ft.DataColumn(ft.Text("Số tiền ghi có")),259                ft.DataColumn(ft.Text("Số dư"))260            ],261            rows=[],262            column_spacing=10,263            horizontal_lines=ft.BorderSide(1, ft.Colors.GREY),264            vertical_lines=ft.BorderSide(1, ft.Colors.GREY)265        )266        print_status = ft.Text()267        printed_list = ft.ListView(expand=True, spacing=5, padding=10)268 269        def update_statistics():270            if transactions is not None and not transactions.empty:271                total_debit = pd.to_numeric(transactions['Số tiền ghi nợ'].str.replace(',',''), errors='coerce').sum()272                total_credit = pd.to_numeric(transactions['Số tiền ghi có'].str.replace(',',''), errors='coerce').sum()273                stats_text.value = f"Total Debit: {total_debit:,.2f} | Total Credit: {total_credit:,.2f}"274            else:275                stats_text.value = "No data available"276            page.update()277 278        def update_printed_list():279            printed_list.controls.clear()280            for idx in printed_transactions:281                if idx < len(transactions):282                    row = transactions.iloc[idx]283                    printed_list.controls.append(284                        ft.Text(f"Printed: {row['Ngày']} - {row['Số bút toán']} - {row['Diễn giải']}")285                    )286            page.update()287 288        def toggle_select(value: bool):289            for row in data_table.rows:290                row.cells[0].content.value = value291            page.update()292 293        def fetch_data(e):294            nonlocal driver, main_window, transactions295            status_text.value = "Fetching data..."296            error_log.value = ""297            page.update()298 299            def run_selenium():300                nonlocal driver, transactions301                try:302                    if driver is None:303                        status_text.value = "Browser not started. Please login again."304                        page.update()305                        return306 307                    transactions = fetch_transactions(driver, account_number.value, start_date.value, end_date.value)308                    if transactions is not None and not transactions.empty:309                        data_table.rows.clear()310                        for idx, row in transactions.iterrows():311                            checkbox = ft.Checkbox(value=False, data=idx)312                            data_table.rows.append(313                                ft.DataRow(cells=[314                                    ft.DataCell(checkbox),315                                    ft.DataCell(ft.Text(str(row['Số TT']))),316                                    ft.DataCell(ft.Text(row['Ngày'])),317                                    ft.DataCell(ft.Text(row['Số bút toán'])),318                                    ft.DataCell(ft.Text(row['Tài khoản đích'])),319                                    ft.DataCell(ft.Text(row['Diễn giải'])),320                                    ft.DataCell(ft.Text(row['Số tiền ghi nợ'])),321                                    ft.DataCell(ft.Text(row['Số tiền ghi có'])),322                                    ft.DataCell(ft.Text(row['Số dư']))323                                ])324                            )325                        status_text.value = "Data fetched successfully"326                        update_statistics()327                    else:328                        status_text.value = "No transactions found or error occurred"329                        error_log.value = "Check portal for results or verify account/dates"330                except Exception as ex:331                    status_text.value = "Error during data fetch"332                    error_log.value = f"Error: {str(ex)}"333                finally:334                    page.update()335 336            threading.Thread(target=run_selenium, daemon=True).start()337 338            # threading.Thread(target=run_selenium, daemon=True).start()339 340        def print_selected(e):341            nonlocal driver, main_window342            if driver is None or transactions is None:343                print_status.value = "Please fetch data first"344                page.update()345                return346 347            selected_indices = [row.cells[0].content.data for row in data_table.rows if row.cells[0].content.value]348            if not selected_indices:349                print_status.value = "No transactions selected"350                page.update()351                return352 353            def run_print():354                nonlocal printed_transactions355                printed = []356                for idx in selected_indices:357                    if print_transaction(driver, idx, main_window):358                        printed.append(idx)359                printed_transactions.extend(printed)360                print_status.value = f"Printed {len(printed)} transaction(s) successfully"361                update_printed_list()362                page.update()363 364            print_status.value = "Printing..."365            page.update()366            threading.Thread(target=run_print, daemon=True).start()367 368        horizontal_scroll_container = ft.Container(369            content=data_table,370            width=1000,  # hoặc giá trị lớn hơn màn hình nếu muốn scroll ngang371            scale=True,  # kích hoạt scroll ngang khi tràn372 373        )374 375        # ListView để cuộn dọc376        list_view = ft.ListView(377            controls=[horizontal_scroll_container],378            expand=True379        )380        page.add(381            ft.Column(382                [383                    ft.Text("Bank Transaction Printer", size=30, weight=ft.FontWeight.BOLD),384                    ft.Row([account_number, start_date, end_date], spacing=20),385                    ft.Row([386                        ft.ElevatedButton("Fetch Transactions", on_click=fetch_data, icon=ft.Icons.DOWNLOAD),387                        ft.ElevatedButton("Select All", on_click=lambda _: toggle_select(True), icon=ft.Icons.SELECT_ALL),388                        ft.ElevatedButton("Deselect All", on_click=lambda _: toggle_select(False), icon=ft.Icons.DESELECT),389                        ft.ElevatedButton("Print Selected", on_click=print_selected, icon=ft.Icons.PRINT)390                    ], spacing=10),391                    status_text,392                    stats_text,393                    error_log,394                    # ft.Container(395                    ft.Container(396                        content = ft.Column([data_table], scroll=ft.ScrollMode.ALWAYS),397                        border=ft.border.all(1, ft.Colors.BLACK),398                        padding=10,399                        width=1150,400                        height=400,401                    ),402                    print_status,403                    ft.Container(404                        content=ft.Column([405                            ft.Text("Printed Transactions:", weight=ft.FontWeight.BOLD),406                            printed_list407                        ]),408                        border=ft.border.all(1, ft.Colors.BLACK),409                        padding=10,410                        width=1100,411                        height=100,412                    )413                ],414                spacing=20415            )416        )417        page.update()418 419    def cleanup():420        nonlocal driver421        if driver:422            try:423                driver.quit()424            except:425                pass426 427    page.on_close = cleanup428    show_login_view()429 430if __name__ == "__main__":431    ft.app(target=main)