сейчас я пользуюсь вот таким кодом для формирования нужного отчёта. Но я хочу оформить это отдельной программой для windows, что бы была возможность выбирать файлы для output_file, xls_file, ini_file

import configparser
import pandas as pd
import webbrowser
from pathlib import Path

class ConfigReader:
    def __init__(self, ini_file):
        self.ini_file = ini_file
        self.config = configparser.ConfigParser()
        self.config.read(ini_file)
        self.data = self.parse_config()

    def parse_config(self):
        data = {}
        for section in self.config.sections():
            items = self.config[section]
            numbers = items.get('numbers', '').split(',')
            icon = items.get('icon', '')
            data[section] = {'numbers': [num.strip() for num in numbers], 'icon': icon}
        return data


class XLSParser:
    def __init__(self, xls_file):
        self.xls_file = xls_file
        # Читать с 7 строки, соответственно, задаем header=6
        self.column_names = ['mc', 'Number', 'edizm', 'sklad', 'mol', 'part', 'price', 'ost_qnty', 'ost_sum', 'rez_qnty', 'rez_sum', 'doc', 'input_sklad1','input_sklad2', 'free_qnty', 'free_sum']
        self.df = pd.read_excel(xls_file,header=None, names=self.column_names,skiprows=1, dtype={'Number': str} )
        # Преобразуем 'Number' в тип string
        #self.df['Number'] = self.df['Number'].astype(str)

    def extract_data(self, config_data):
        extracted_data = {}

        # Получаем список допустимых номеров из INI файла
        valid_numbers = {num for section in config_data.values() for num in section['numbers']}
        
        # Проходим по всем строкам DataFrame
        for index, row in self.df.iterrows():
            number = row['Number']  # 'Number' в строковом формате
            sklad = row['sklad']
            free_qty = row['free_qnty']
            mc = row['mc']  # Сохраняем значение mc
            
            # Проверяем, находится ли номер в списке valid_numbers
            if number not in valid_numbers:
                continue  # Пропускаем номера, которые не указаны в INI файле

            # Проверяем, есть ли уже этот номер в extracted_data
            if number not in extracted_data:
                extracted_data[number] = {
                    'mc': mc,                 # Сохраняем значение mc
                    'sklads': {}              # Создаем пустой словарь для склада
                }
            
            # Проверяем, есть ли уже этот склад
            if sklad not in extracted_data[number]['sklads']:
                extracted_data[number]['sklads'][sklad] = 0  # Инициализируем сумму free_qty для склада

            # Суммируем значения free_qnty
            extracted_data[number]['sklads'][sklad] += free_qty  # Суммируем значения free_qty

        return extracted_data

class HTMLReportGenerator:
    def __init__(self, report_data, config_data, output_file):
        self.report_data = report_data
        self.config_data = config_data  # Храним данные из INI файла
        self.output_file = output_file

    def generate_html(self):
        html_content = "<html><head><title>Report</title></head><body>"
        html_content += "<h1>Сводная информация</h1>"

        # Создаём таблицу для отображения отчета
        html_content += "<table border='1'><tr><th>Section</th><th>MC</th><th>Number</th><th>Склад</th><th>Free Quantity</th></tr>"

        # Проходим по секциям из конфигурации
        for section, values in self.config_data.items():
            html_content += f"<tr><td colspan='5'><strong>{section}</strong></td></tr>"  # Выводим название секции
            
            # Перебираем номера из секции
            for number in values['numbers']:
                number_str = str(number)  # Преобразуем в строку, если это не строка
                
                if number_str in self.report_data:  # Проверяем, есть ли номер в отчете
                    mc_value = self.report_data[number_str]['mc']  # Получаем значение mc
                    for sklad, free_qty in self.report_data[number_str]['sklads'].items():
                        html_content += f"<tr><td></td><td>{mc_value}</td><td>{number_str}</td><td>{sklad}</td><td>{free_qty}</td></tr>"

        html_content += "</table></body></html>"

        # Запись HTML в файл
        with open(self.output_file, 'w') as f:
            f.write(html_content)

    def open_in_browser(self):
        webbrowser.open_new_tab(f'file://{Path(self.output_file).resolve()}')
        
def main(ini_file, xls_file, output_file):
    config_reader = ConfigReader(ini_file)
    xls_parser = XLSParser(xls_file)
    
    extracted_data = xls_parser.extract_data(config_reader.data)
    
    report_generator = HTMLReportGenerator(extracted_data, config_reader.data, output_file)
    report_generator.generate_html()
    report_generator.open_in_browser()


if __name__ == "__main__":
    # Укажите пути к вашим файлам
    ini_file = r'D:\Project\СКЛАД\2025\config.ini'
    xls_file = r'D:\Project\СКЛАД\2025\2025-03-25 склад +.xlsx'
    output_file = r'D:\Project\СКЛАД\2025\report.html'
    
    main(ini_file, xls_file, output_file)