129 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			129 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Python
		
	
	
	
import csv
 | 
						|
import time
 | 
						|
from services.core.loading_service import run_with_progress
 | 
						|
from database.models.product import Product
 | 
						|
 | 
						|
from PyQt6.QtWidgets import (
 | 
						|
    QWidget,
 | 
						|
    QVBoxLayout,
 | 
						|
    QPushButton,
 | 
						|
    QFileDialog,
 | 
						|
    QTableWidget,
 | 
						|
    QTableWidgetItem,
 | 
						|
    QHBoxLayout,
 | 
						|
    QMessageBox,
 | 
						|
)
 | 
						|
 | 
						|
 | 
						|
class ImportTab(QWidget):
 | 
						|
    def __init__(self):
 | 
						|
        super().__init__()
 | 
						|
        layout = QVBoxLayout()
 | 
						|
 | 
						|
        # --- Action buttons ---
 | 
						|
        btn_layout = QHBoxLayout()
 | 
						|
 | 
						|
        self.btn_import_csv = QPushButton("Import from CSV")
 | 
						|
        self.btn_import_csv.clicked.connect(self.import_csv)
 | 
						|
        btn_layout.addWidget(self.btn_import_csv)
 | 
						|
 | 
						|
        self.btn_import_api = QPushButton("Import from API")
 | 
						|
        self.btn_import_api.clicked.connect(self.import_api)
 | 
						|
        btn_layout.addWidget(self.btn_import_api)
 | 
						|
 | 
						|
        self.btn_save = QPushButton("Save to Database")
 | 
						|
        self.btn_save.clicked.connect(self.save_to_db)
 | 
						|
        self.btn_save.setEnabled(False)
 | 
						|
        btn_layout.addWidget(self.btn_save)
 | 
						|
 | 
						|
        layout.addLayout(btn_layout)
 | 
						|
 | 
						|
        # --- Table preview ---
 | 
						|
        self.table = QTableWidget()
 | 
						|
        layout.addWidget(self.table)
 | 
						|
 | 
						|
        self.setLayout(layout)
 | 
						|
        self.preview_data = []  # store imported data
 | 
						|
 | 
						|
    def import_csv(self):
 | 
						|
        file_path, _ = QFileDialog.getOpenFileName(
 | 
						|
            self, "Select CSV File", "", "CSV Files (*.csv)"
 | 
						|
        )
 | 
						|
        if not file_path:
 | 
						|
            return
 | 
						|
 | 
						|
        try:
 | 
						|
            # đọc CSV chuẩn với DictReader
 | 
						|
            with open(file_path, newline="", encoding="utf-8-sig") as csvfile:
 | 
						|
                reader = csv.DictReader(csvfile)
 | 
						|
                headers = reader.fieldnames
 | 
						|
                rows = list(reader)
 | 
						|
 | 
						|
            if not headers or not rows:
 | 
						|
                QMessageBox.warning(self, "Warning", "CSV file is empty or invalid.")
 | 
						|
                return
 | 
						|
 | 
						|
            self.table.setColumnCount(len(headers))
 | 
						|
            self.table.setHorizontalHeaderLabels(headers)
 | 
						|
 | 
						|
            # Hiển thị preview (giới hạn 200 dòng để tránh lag)
 | 
						|
            preview_limit = min(len(rows), 200)
 | 
						|
            self.table.setRowCount(preview_limit)
 | 
						|
 | 
						|
            for i in range(preview_limit):
 | 
						|
                for j, header in enumerate(headers):
 | 
						|
                    value = rows[i].get(header, "")
 | 
						|
                    self.table.setItem(i, j, QTableWidgetItem(value))
 | 
						|
 | 
						|
            self.table.resizeColumnsToContents()
 | 
						|
            self.preview_data = rows
 | 
						|
            self.btn_save.setEnabled(True)
 | 
						|
 | 
						|
        except Exception as e:
 | 
						|
            QMessageBox.critical(self, "Error", f"Failed to read CSV: {e}")
 | 
						|
 | 
						|
    def import_api(self):
 | 
						|
        QMessageBox.information(
 | 
						|
            self, "Info", "API import feature will be developed later 😉"
 | 
						|
        )
 | 
						|
 | 
						|
    def save_to_db(self):
 | 
						|
        if not self.preview_data:
 | 
						|
            QMessageBox.warning(self, "Warning", "No data to save.")
 | 
						|
            return
 | 
						|
 | 
						|
        # Xác nhận trước khi import
 | 
						|
        reply = QMessageBox.question(
 | 
						|
            self,
 | 
						|
            "Confirm Import",
 | 
						|
            f"Are you sure you want to import {len(self.preview_data)} rows?",
 | 
						|
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
 | 
						|
        )
 | 
						|
        if reply != QMessageBox.StandardButton.Yes:
 | 
						|
            return
 | 
						|
 | 
						|
        def handler(item):
 | 
						|
            try:
 | 
						|
                Product.insert_from_import(item)
 | 
						|
                return True
 | 
						|
            except Exception as e:
 | 
						|
                print(f"Failed to import row: {e}")
 | 
						|
                return False
 | 
						|
 | 
						|
        success, fail = run_with_progress(
 | 
						|
            self.preview_data, handler=handler, message="Importing data...", parent=self
 | 
						|
        )
 | 
						|
 | 
						|
        QMessageBox.information(
 | 
						|
            self,
 | 
						|
            "Import Completed",
 | 
						|
            f"Successfully imported {success}/{len(self.preview_data)} rows.\nFailed: {fail} rows.",
 | 
						|
        )
 | 
						|
 | 
						|
        # ✅ Clear preview sau khi import xong
 | 
						|
        self.preview_data.clear()
 | 
						|
        self.table.clearContents()
 | 
						|
        self.table.setRowCount(0)
 | 
						|
        self.table.setColumnCount(0)
 | 
						|
        self.btn_save.setEnabled(False)
 |