from DepositAPI.api.Api import BaseApiView
from DepositAPI.model.BaseModel import BaseModel
from DepositAPI.model.Product import Product as DBModel
from DepositAPI.model.ProductQuote import ProductQuote
from DepositAPI.api.Response import SuccessResponse, ErrorResponse
from DepositAPI.libs.db.RDbSql import DbMySql
from DepositAPI.common.Utility import get_prop
from DepositAPI.common.Decorator import require_jwt_authent
from DepositAPI.common.const.hpodconst import ROLE_TYPE
import itertools
import os
import time
import json
import hashlib
from datetime import datetime, timedelta

import xlsxwriter
from DepositAPI import settings
from django.http import HttpResponse
import requests
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont
from dateutil import parser
import textwrap

class Product(BaseApiView, BaseModel):
    def __init__(self):
        self.modelClass = DBModel()
        self.productQuoteModel = ProductQuote()
    
    def check_partner_name_duplicate(self, partner_name, current_id=None):
        """Kiểm tra PartnerName có bị trùng không"""
        if not partner_name or not partner_name.strip():
            return False, "Mã đối tác không được để trống"
        
        partner_name = partner_name.strip()
        db = DbMySql()
        
        if current_id:
            # Khi update, check trùng với các ID khác
            query_sql = "SELECT ID FROM tbl_product WHERE PartnerName = :partner_name AND ID != :current_id LIMIT 1"
            params = {'partner_name': partner_name, 'current_id': current_id}
        else:
            # Khi insert, check trùng tất cả
            query_sql = "SELECT ID FROM tbl_product WHERE PartnerName = :partner_name LIMIT 1"
            params = {'partner_name': partner_name}
        
        rows = db.query(query=query_sql, params=params)
        result = self.process_in_pandas(rows)
        if result and len(result) > 0:
            return False, f"Mã đối tác '{partner_name}' đã tồn tại trong hệ thống"
        
        return True, None
    
    def generate_bill_code(self, request):
        # Lấy thông tin TransactionCode từ Packages và gán vào SuffixBill
        packages = get_prop(request, 'Packages', False, None)
        if packages is not None:
            try:
                packages_list = json.loads(packages) if isinstance(packages, str) else packages
                transaction_codes = [p.get('TransactionCode', '').strip() for p in packages_list if p.get('TransactionCode', '').strip()]
                if transaction_codes:
                    # Gán SuffixBill là chuỗi các TransactionCode nối với nhau bằng dấu phẩy
                    request.data['SuffixBill'] = ', '.join(transaction_codes)
                else:
                    request.data['SuffixBill'] = ''
            except Exception as e:
                print(f"Error processing Packages for SuffixBill: {e}")
                request.data['SuffixBill'] = ''
    
    def add_entry(self, request):
        # Kiểm tra PartnerName không trùng
        partner_name = get_prop(request, 'PartnerName', False, None)
        if partner_name:
            is_valid, error_msg = self.check_partner_name_duplicate(partner_name)
            if not is_valid:
                return ErrorResponse(status=202, reason=error_msg)
        
        self.generate_bill_code(request)
        
        # Extract QuoteIDs before insert
        quote_ids = get_prop(request, 'QuoteIDs', True, None)
        if quote_ids and isinstance(quote_ids, str):
            try:
                quote_ids = json.loads(quote_ids)
            except:
                quote_ids = None
        
        item = self.modelClass.insert(request)
        
        # Link quotes to product if provided
        if item and quote_ids and isinstance(quote_ids, list) and len(quote_ids) > 0:
            product_id = item.get('ID')
            username = request.user.username if hasattr(request, 'user') else None
            self.productQuoteModel.link_product_quote(product_id, quote_ids, username)
        
        return SuccessResponse( data=item )
    
    def edit_data(self, request, pk):
        # Kiểm tra PartnerName không trùng
        partner_name = get_prop(request, 'PartnerName', False, None)
        if partner_name:
            is_valid, error_msg = self.check_partner_name_duplicate(partner_name, current_id=pk)
            if not is_valid:
                return ErrorResponse(status=202, reason=error_msg)
        
        self.generate_bill_code(request)
        
        # Extract QuoteIDs before update
        quote_ids = get_prop(request, 'QuoteIDs', True, None)
        if quote_ids and isinstance(quote_ids, str):
            try:
                quote_ids = json.loads(quote_ids)
            except:
                quote_ids = None
        
        # Update product-quote links if provided
        if quote_ids is not None:  # Allow empty array to clear links
            username = request.user.username if hasattr(request, 'user') else None
            if isinstance(quote_ids, list):
                self.productQuoteModel.link_product_quote(pk, quote_ids, username)
        
        # Gọi method update của parent class
        ret = self.modelClass.update(request, pk)
        return SuccessResponse(data=ret)
    
    def get_item_detail(self, request, pk):
        """Override to include linked quotes"""
        self.get_request_info(request)
        item = self.modelClass.get_detail(pk)
        
        # Get linked quote IDs
        if item:
            quote_ids = self.productQuoteModel.get_quote_ids_by_product(pk)
            item['QuoteIDs'] = quote_ids
        
        return SuccessResponse(data=item)
    
    def _set_default_quote_values(self, item):
        """Set giá trị mặc định cho các trường quote khi không có quote"""
        item['QuoteImageUrl'] = ''
        item['PackType'] = ''
        item['ProductNumber'] = 0
        item['ProductName'] = ''
        item['ProductNameVN'] = ''
        item['ProductSize'] = ''
        item['ProductCapacity'] = ''
        item['ProductMaterial'] = ''
        item['ProductUses'] = ''
        item['ProductWeight'] = 0
        item['ModelBrand'] = ''
        item['Manufacturer'] = ''
        item['ManufacturerAddress'] = ''
        item['LabelCode'] = item.get('SuffixBill', '') or item.get('Code', '')
        item['LabelDate'] = datetime.now().strftime('%Y-%-m-%-d')
        item['CustomsRequirement'] = ''
        item['CustomsUnit'] = ''
        item['CustomsWeightPrice'] = 0
        return item
        
    def get_cached_image(self, image_url, cache_duration_days=7):
        """Cache hình ảnh trong cache_duration_days ngày để tăng tốc export"""
        if not image_url or not image_url.startswith(('http://', 'https://')):
            return None
            
        try:
            # Tạo cache key từ URL
            cache_key = hashlib.md5(image_url.encode()).hexdigest()
            cache_dir = os.path.join(settings.TEMP_DOWNLOAD_PATH, 'image_cache')
            if not os.path.exists(cache_dir):
                os.makedirs(cache_dir)
                
            cache_file = os.path.join(cache_dir, f"{cache_key}.cache")
            
            # Kiểm tra cache có tồn tại và chưa hết hạn
            if os.path.exists(cache_file):
                # Kiểm tra thời gian tạo file
                file_time = datetime.fromtimestamp(os.path.getctime(cache_file))
                if datetime.now() - file_time < timedelta(days=cache_duration_days):
                    # Cache còn hiệu lực, đọc từ file
                    with open(cache_file, 'rb') as f:
                        return BytesIO(f.read())
            
            # Cache không tồn tại hoặc đã hết hạn, tải mới
            response_img = requests.get(image_url, timeout=5, stream=True)
            if response_img.status_code == 200:
                image_content = response_img.content
                
                # Lưu vào cache
                with open(cache_file, 'wb') as f:
                    f.write(image_content)
                    
                return BytesIO(image_content)
            else:
                return None
                
        except Exception as e:
            print(f"Error caching image {image_url}: {e}")
            return None
    
    def resize_image_to_fit(self, image_data, target_width, target_height):
        """Resize ảnh về kích thước cố định để fit vào cell Excel"""
        if not image_data:
            return None
            
        try:
            # Load ảnh từ BytesIO
            img = Image.open(image_data)
            
            # Convert sang RGB nếu cần (để tránh lỗi với PNG có alpha channel)
            if img.mode in ('RGBA', 'LA', 'P'):
                background = Image.new('RGB', img.size, (255, 255, 255))
                if img.mode == 'P':
                    img = img.convert('RGBA')
                background.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None)
                img = background
            elif img.mode != 'RGB':
                img = img.convert('RGB')
            
            # Tính toán tỷ lệ để giữ aspect ratio
            img_width, img_height = img.size
            width_ratio = target_width / img_width
            height_ratio = target_height / img_height
            
            # Chọn ratio nhỏ hơn để ảnh vừa khít trong kích thước target
            scale_ratio = min(width_ratio, height_ratio)
            
            # Tính kích thước mới
            new_width = int(img_width * scale_ratio)
            new_height = int(img_height * scale_ratio)
            
            # Resize ảnh
            img_resized = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
            
            # Tạo ảnh nền trắng với kích thước target
            final_img = Image.new('RGB', (target_width, target_height), (255, 255, 255))
            
            # Paste ảnh đã resize vào giữa
            x_offset = (target_width - new_width) // 2
            y_offset = (target_height - new_height) // 2
            final_img.paste(img_resized, (x_offset, y_offset))
            
            # Convert thành BytesIO
            output = BytesIO()
            final_img.save(output, format='PNG')
            output.seek(0)
            
            return output
            
        except Exception as e:
            print(f"Error resizing image: {e}")
            return None
    
    def generate_label_image(self, item):
        """Tạo ảnh nhãn dán cho sản phẩm"""
        try:
            # Kích thước nhãn (width x height)
            width, height = 300, 200
            
            # Tạo ảnh trắng
            img = Image.new('RGB', (width, height), 'white')
            draw = ImageDraw.Draw(img)
            
            # Font - sử dụng font hệ thống
            try:
                # Thử load font Arial hoặc Helvetica trên macOS
                font_paths = [
                    "/System/Library/Fonts/Arial.ttf",
                    "/System/Library/Fonts/Helvetica.ttc",
                    "/System/Library/Fonts/Times.ttc"
                ]
                font_large = None
                font_small = None
                font_medium = None
                
                for font_path in font_paths:
                    if os.path.exists(font_path):
                        font_large = ImageFont.truetype(font_path, 12)
                        font_small = ImageFont.truetype(font_path, 10)
                        font_medium = ImageFont.truetype(font_path, 11)
                        break
                        
                if font_large is None:
                    raise Exception("No font found")
                    
            except:
                # Nếu không load được, dùng font mặc định
                font_large = ImageFont.load_default()
                font_small = ImageFont.load_default()
                font_medium = ImageFont.load_default()
            
            def wrap_text(text, font, max_width):
                """Tự động xuống dòng text nếu quá dài"""
                words = text.split(' ')
                lines = []
                current_line = []
                
                for word in words:
                    test_line = ' '.join(current_line + [word])
                    bbox = draw.textbbox((0, 0), test_line, font=font)
                    test_width = bbox[2] - bbox[0]
                    
                    if test_width <= max_width:
                        current_line.append(word)
                    else:
                        if current_line:
                            lines.append(' '.join(current_line))
                            current_line = [word]
                        else:
                            # Từ đơn quá dài, phải cắt
                            lines.append(word)
                
                if current_line:
                    lines.append(' '.join(current_line))
                
                return lines
            
            y_offset = 8
            line_height = 14
            left_margin = 8
            max_text_width = width - left_margin * 2
            
            # Product Name
            product_name = item.get('ProductName', '')
            if product_name:
                product_lines = wrap_text(f"Product Name: {product_name}", font_small, max_text_width)
                for line in product_lines:
                    draw.text((left_margin, y_offset), line, fill='black', font=font_small)
                    y_offset += line_height
            else:
                draw.text((left_margin, y_offset), "Product Name:", fill='black', font=font_small)
                y_offset += line_height
            
            # Manufacturer - tự động xuống dòng
            manufacturer = item.get('Manufacturer', '')
            if manufacturer:
                manufacturer_lines = wrap_text(f"Manufacturer: {manufacturer}", font_small, max_text_width)
                for line in manufacturer_lines:
                    draw.text((left_margin, y_offset), line, fill='black', font=font_small)
                    y_offset += line_height
            else:
                draw.text((left_margin, y_offset), "Manufacturer:", fill='black', font=font_small)
                y_offset += line_height
            
            # Address - tự động xuống dòng
            address = item.get('ManufacturerAddress', '')
            if address:
                address_lines = wrap_text(f"Address: {address}", font_small, max_text_width)
                for line in address_lines:
                    draw.text((left_margin, y_offset), line, fill='black', font=font_small)
                    y_offset += line_height
            else:
                draw.text((left_margin, y_offset), "Address:", fill='black', font=font_small)
                y_offset += line_height
            
            # Code
            draw.text((left_margin, y_offset), f"Code: {item.get('LabelCode', '')}", fill='black', font=font_small)
            y_offset += line_height
            
            # Date
            draw.text((left_margin, y_offset), f"Date: {item.get('LabelDate', '')}", fill='black', font=font_small)
            y_offset += line_height + 3
            
            # MADE IN CHINA
            draw.text((left_margin, y_offset), "MADE IN CHINA", fill='black', font=font_small)
            y_offset += line_height + 8
            
            # Username - in lớn và đậm ở giữa
            username = f"{item.get('UserName', '')} - {item.get('NumberOfPack', '')}"
            if username:
                # Tính toán để căn giữa
                bbox = draw.textbbox((0, 0), username, font=font_large)
                text_width = bbox[2] - bbox[0]
                x_centered = (width - text_width) // 2
                draw.text((x_centered, y_offset), username, fill='black', font=font_large)
            
            # Vẽ border
            draw.rectangle([(0, 0), (width-1, height-1)], outline='black', width=2)
            
            # Convert thành BytesIO
            img_buffer = BytesIO()
            img.save(img_buffer, format='PNG')
            img_buffer.seek(0)
            
            return img_buffer
            
        except Exception as e:
            print(f"Error generating label image: {e}")
            return None

    def aggregate_data(self, request):
        self.get_request_info(request)
        self.get_common_query_string(request)
        action = self.params.get("action")
        items, totalRow, summary = self.modelClass.get_list(self.user_id, self.role_id, self.filter, self.quickFilter, self.sortBy, self.descending, self.rowsPerPage, self.offset, action)
        return SuccessResponse(data=items, total=totalRow, offset=self.offset, rowsPerPage=self.rowsPerPage, summary=summary)

    @require_jwt_authent
    def export_selected(self, request):
        if request.user.roleid == ROLE_TYPE.Customer:
            return ErrorResponse(status=403, reason="Bạn không có quyền xuất kho.")
        if not isinstance(request.data, dict):
            return ErrorResponse(status=400, reason="Dữ liệu xuất kho không hợp lệ.")
        try:
            result = self.modelClass.create_stock_export(
                request.data.get('Items'), request.user.username
            )
        except ValueError as error:
            return ErrorResponse(status=400, reason=str(error))
        return SuccessResponse(data=result)
    
    def available_product(self, request):
        self.get_request_info(request)
        self.get_common_query_string(request)
        db = DbMySql()
        query_sql = """ SELECT p.*, u.FullName, p.NumberOfPack - op.NumberOfPack as AvailableNumberOfPack FROM tbl_product as p LEFT JOIN (SELECT ProductID, IFNULL(SUM(NumberOfPack),0) as NumberOfPack FROM tbl_truck_product GROUP BY ProductID) as op ON p.ID = op.ProductID LEFT JOIN tbl_user as u ON p.UID = u.ID WHERE op.NumberOfPack IS NULL OR p.NumberOfPack > op.NumberOfPack;"""
        rows = db.query(query=query_sql)
        data = self.process_in_pandas(rows)
        return SuccessResponse(data=data)

    def order_product(self, request, pk):
        self.get_request_info(request)
        self.get_common_query_string(request)
        db = DbMySql()
        query_sql = f""" SELECT p.*, u.FullName, op.NumberOfPack as OrderNumberOfPack FROM tbl_product as p LEFT JOIN tbl_truck_product as op ON p.ID = op.ProductID LEFT JOIN tbl_user as u  ON p.UID = u.ID WHERE op.TruckID = {pk};"""
        rows = db.query(query=query_sql)
        data = self.process_in_pandas(rows)
        return SuccessResponse(data=data)
    
    def bill_product(self, request, pk):
        self.get_request_info(request)
        self.get_common_query_string(request)
        db = DbMySql()
        query_sql = f""" SELECT p.ID, p.UID, p.UserName, p.PartnerName, p.ProductNameCN, p.Code, p.SuffixBill, p.Deposit, p.IsSplitTax, op.* FROM tbl_product as p LEFT JOIN tbl_bill_product as op ON p.ID = op.ProductID WHERE op.BillID = {pk};"""
        rows = db.query(query=query_sql)
        data = self.process_in_pandas(rows)
        return SuccessResponse(data=data)

    def export_list(self, request):
        self.get_request_info(request)
        self.get_common_query_string(request)
        timenow = time.time()
        file_name = "product_%s.xlsx" % (timenow)
        if not os.path.exists(settings.TEMP_DOWNLOAD_PATH):
            os.makedirs(settings.TEMP_DOWNLOAD_PATH)
        file_path = os.path.join(settings.TEMP_DOWNLOAD_PATH, file_name)
        # Create a workbook and add a worksheet.
        workbook = xlsxwriter.Workbook(file_path)
        # Start from the first cell. Rows and columns are zero indexed.
        row = itertools.count(0)
        col = itertools.count(0)
        # Define format cell
        cell_title = workbook.add_format({'bold': True, 'align': 'center', 'valign': 'vcenter', 'font_name': 'Calibri', 'font_size': 14})
        align_left = workbook.add_format({'align': 'left', 'valign': 'vcenter', 'font_name': 'Calibri', 'font_size': 12, 'border': 1})
        cell_header = workbook.add_format({'bold': True, 'align': 'left', 'valign': 'vcenter', 'font_name': 'Calibri', 'font_size': 12, 'border': 1})
        cell_header_center = workbook.add_format({'bold': True, 'align': 'center', 'valign': 'vcenter', 'font_name': 'Calibri', 'font_size': 12, 'border': 1})
        currency = workbook.add_format({'align': 'right', 'valign': 'vcenter', 'num_format': '#,##0.00', 'font_name': 'Calibri', 'font_size': 12, 'border': 1})
        number = workbook.add_format({'align': 'right', 'valign': 'vcenter', 'num_format': '#,##0', 'font_name': 'Calibri', 'font_size': 12, 'border': 1})
        number_bold = workbook.add_format({'bold': True, 'align': 'right', 'valign': 'vcenter', 'num_format': '#,##0', 'font_name': 'Calibri', 'font_size': 12, 'border': 1})
        #  Get list item to export
        action = self.params.get("action")
        items, totalRow, summary = self.modelClass.get_list(self.user_id, self.role_id, self.filter, self.quickFilter, self.sortBy, self.descending, 1000000, 0, action)
        worksheet = workbook.add_worksheet('Danh sách bill')
        # Initial header
        row_index = next(row)
        worksheet.write(row_index, next(col), 'Mã KH', cell_header)
        worksheet.write(row_index, next(col), 'Tên khách', cell_header)
        worksheet.write(row_index, next(col), 'Tên hàng', cell_header)
        worksheet.write(row_index, next(col), 'Xếp xe', cell_header)
        worksheet.write(row_index, next(col), 'Xuất kho', cell_header)
        worksheet.write(row_index, next(col), 'Mã vào kho', cell_header)
        worksheet.write(row_index, next(col), 'Mã vận đơn', cell_header)
        worksheet.write(row_index, next(col), 'Phí bảo hiểm', cell_header)
        worksheet.write(row_index, next(col), 'Ship nội địa (¥)', cell_header)
        worksheet.write(row_index, next(col), 'Chi xe kéo (¥)', cell_header)
        worksheet.write(row_index, next(col), 'Chi xe nâng (¥)', cell_header)
        worksheet.write(row_index, next(col), 'Tỷ giá', cell_header)
        worksheet.write(row_index, next(col), 'Tổng cân', cell_header)
        worksheet.write(row_index, next(col), 'Tổng khối', cell_header)
        worksheet.write(row_index, next(col), 'Tổng kiện', cell_header)
        worksheet.write(row_index, next(col), 'Tổng kiện đã xếp xe', cell_header)
        worksheet.write(row_index, next(col), 'Tổng kiện nhập kho VN', cell_header)
        worksheet.write(row_index, next(col), 'Tổng kiện xuất kho VN', cell_header)
        worksheet.write(row_index, next(col), 'Cách tính phí', cell_header)
        worksheet.write(row_index, next(col), 'Giá cân', cell_header)
        worksheet.write(row_index, next(col), 'Giá khối', cell_header)
        worksheet.write(row_index, next(col), 'Phí vận chuyển', cell_header)
        for item in items:
            col = itertools.count(0)
            row_index = next(row)
            worksheet.write(row_index, next(col), item['UserName'], align_left)
            worksheet.write(row_index, next(col), item['PartnerName'], align_left)
            worksheet.write(row_index, next(col), item['ProductNameCN'], align_left)
            worksheet.write(row_index, next(col), item['OrderCodes'], align_left)
            worksheet.write(row_index, next(col), item['BillCodes'], align_left)
            worksheet.write(row_index, next(col), item['Code'], align_left)
            worksheet.write(row_index, next(col), item['SuffixBill'], align_left)
            worksheet.write(row_index, next(col), item['FeeCare'], number)
            worksheet.write(row_index, next(col), item['TransactionDeposit'], currency)
            worksheet.write(row_index, next(col), item['PedicabDeposit'], currency)
            worksheet.write(row_index, next(col), item['LoadDeposit'], currency)
            worksheet.write(row_index, next(col), item['ExchangeRate'], currency)
            worksheet.write(row_index, next(col), item['Weight'], currency)
            worksheet.write(row_index, next(col), item['Volume'], currency)
            worksheet.write(row_index, next(col), item['NumberOfPack'], number)
            worksheet.write(row_index, next(col), item['NumberOfPackTruck'], number)
            worksheet.write(row_index, next(col), item['NumberOfPackImport'], number)
            worksheet.write(row_index, next(col), item['NumberOfPackExport'], number)
            worksheet.write(row_index, next(col), item['PriceType'], number)
            worksheet.write(row_index, next(col), item['WeightPrice'], number)
            worksheet.write(row_index, next(col), item['VolumePrice'], number)
            worksheet.write(row_index, next(col), item['TotalFeeWeight'], number)
            
        workbook.close()

        f = open(file_path, 'rb')
        response = HttpResponse(f, content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
        response['Content-Disposition'] = 'attachment; filename=%s' % file_name

        try:
            os.remove(file_path)
        except OSError:
            pass

        return response

    def export_tieu_ngach(self, request):
        """Xuất file tiểu ngạch - chỉ bao gồm thông tin từ nhập kho TQ"""
        self.get_request_info(request)
        self.get_common_query_string(request)
        timenow = time.time()
        file_name = "tieu_ngach_%s.xlsx" % (timenow)
        if not os.path.exists(settings.TEMP_DOWNLOAD_PATH):
            os.makedirs(settings.TEMP_DOWNLOAD_PATH)
        file_path = os.path.join(settings.TEMP_DOWNLOAD_PATH, file_name)
        
        # Create a workbook and add a worksheet.
        workbook = xlsxwriter.Workbook(file_path)
        row = itertools.count(0)
        
        # Define format cell
        cell_header = workbook.add_format({'bold': True, 'align': 'left', 'valign': 'vcenter', 'font_name': 'Calibri', 'font_size': 12, 'border': 1})
        align_left = workbook.add_format({'align': 'left', 'valign': 'vcenter', 'font_name': 'Calibri', 'font_size': 12, 'border': 1, 'text_wrap': True})
        number = workbook.add_format({'align': 'right', 'valign': 'vcenter', 'num_format': '#,##0', 'font_name': 'Calibri', 'font_size': 12, 'border': 1})
        currency = workbook.add_format({'align': 'right', 'valign': 'vcenter', 'num_format': '#,##0.00', 'font_name': 'Calibri', 'font_size': 12, 'border': 1})
        cell_header_wrap = workbook.add_format({
            'bold': True, 'align': 'left', 'valign': 'vcenter',
            'font_name': 'Calibri', 'font_size': 12, 'border': 1,
            'text_wrap': True
        })
        #  Get list item to export
        action = self.params.get("action")
        selected_ids = self.params.get("selectedIds")
        
        print(f"Debug export_tieu_ngach: user_id={self.user_id}, role_id={self.role_id}, action={action}")
        print(f"Debug export_tieu_ngach: selected_ids={selected_ids}")
        
        # Nếu có selectedIds thì chỉ lấy các item được chọn
        if selected_ids:
            try:
                # Xử lý selectedIds có thể là string "468,469" hoặc JSON array "[468,469]"
                if isinstance(selected_ids, str):
                    # Nếu bắt đầu bằng '[' thì là JSON array
                    if selected_ids.strip().startswith('['):
                        selected_ids_list = json.loads(selected_ids)
                    else:
                        # Nếu không thì là chuỗi phân tách bằng dấu phẩy
                        selected_ids_list = [int(x.strip()) for x in selected_ids.split(',') if x.strip().isdigit()]
                else:
                    selected_ids_list = selected_ids if isinstance(selected_ids, list) else [selected_ids]
                
                if selected_ids_list and len(selected_ids_list) > 0:
                    # Lấy dữ liệu theo IDs được chọn
                    db = DbMySql()
                    ids_str = ','.join(map(str, selected_ids_list))
                    query_sql = f"""
                        SELECT p.*, u.FullName as UserFullName
                        FROM tbl_product p 
                        LEFT JOIN tbl_user u ON p.UID = u.ID 
                        WHERE p.ID IN ({ids_str})
                        ORDER BY p.ID DESC
                    """
                    rows = db.query(query=query_sql)
                    items = self.process_in_pandas(rows)
                    totalRow = len(items) if items else 0
                    summary = None
                    print(f"Debug export_tieu_ngach: Found {len(items) if items else 0} selected items")
                else:
                    items = []
                    totalRow = 0
                    summary = None
            except Exception as e:
                print(f"Error processing selectedIds: {e}")
                items = []
                totalRow = 0
                summary = None
        else:
            # Export theo filter như cũ
            items, totalRow, summary = self.modelClass.get_list(self.user_id, self.role_id, self.filter, self.quickFilter, self.sortBy, self.descending, 1000000, 0, action)
            print(f"Debug export_tieu_ngach: Found {len(items) if items else 0} items")
        
        # Bổ sung thông tin quote cho từng item để lấy Model/Nhãn hiệu
        if items and len(items) > 0:
            db = DbMySql()
            for item in items:
                quote_id = item.get('QuoteID')
                if quote_id:
                    try:
                        quote_query = """
                            SELECT BrandName, Model
                            FROM tbl_quote 
                            WHERE ID = :quote_id
                        """
                        quote_rows = db.query(query=quote_query, params={'quote_id': quote_id})
                        if quote_rows:
                            # Xử lý ResultProxy object
                            if hasattr(quote_rows, 'fetchone'):
                                quote_info = quote_rows.fetchone()
                                if quote_info:
                                    # Convert RowProxy thành dict
                                    quote_info = dict(quote_info._mapping) if hasattr(quote_info, '_mapping') else dict(quote_info)
                            elif isinstance(quote_rows, list) and len(quote_rows) > 0:
                                quote_info = quote_rows[0]
                                quote_info = dict(quote_info._mapping) if hasattr(quote_info, '_mapping') else dict(quote_info)
                            else:
                                quote_info = None
                                
                            if quote_info:
                                # Ưu tiên Model, nếu không có thì dùng BrandName, cuối cùng là ProductNameCN
                                model_brand = (quote_info.get('Model', '') or 
                                             quote_info.get('BrandName', ''))
                                item['ModelBrand'] = model_brand
                            else:
                                item['ModelBrand'] = ''
                    except Exception as e:
                        print(f"Debug: Error getting quote data for ID {quote_id}: {e}")
                        item['ModelBrand'] = ''
                else:
                    item['ModelBrand'] = ''
        worksheet = workbook.add_worksheet('File Tiểu Ngạch')
        
        # Set column widths
        worksheet.set_column('A:A', 15)  # Hình ảnh - giảm kích thước cột
        worksheet.set_column('B:I', 12)  # Other columns
        
        # Initial header
        row_index = next(row)
        col = itertools.count(0)
        worksheet.write(row_index, next(col), 'Hình ảnh sản phẩm\n产品图片', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Mã khách hàng\n客户代码', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Tên khách hàng\n客户名称', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Tên hàng\n商品名', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Mã Vận Đơn\n运单号', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Tổng kiện\n总件数', cell_header_wrap) # ----
        worksheet.write(row_index, next(col), 'Kích Thước Kiện\n外箱尺寸', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Số m3/kiện\n每箱立方数', cell_header_wrap) # ----
        worksheet.write(row_index, next(col), 'Tổng M3\n总立方数', cell_header)
        worksheet.write(row_index, next(col), 'Cân nặng/kiện\n每箱重量', cell_header_wrap) # ----
        worksheet.write(row_index, next(col), 'Tổng Cân\n总重量', cell_header)
        worksheet.write(row_index, next(col), 'Nhãn Hiệu\n品牌', cell_header)

        for item in items:
            col = itertools.count(0)
            row_index = next(row)
            
            # Set row height to accommodate images - giảm chiều cao
            worksheet.set_row(row_index, 50)
            
            # Lấy hình ảnh đầu tiên từ field Images nếu có
            image_url = ''
            images = item.get('Images', '')
            if images:
                try:
                    images_list = json.loads(images) if isinstance(images, str) else images
                    if images_list and len(images_list) > 0:
                        image_url = images_list[0].get('url', '')
                except Exception:
                    image_url = ''
            
            # Xử lý hình ảnh cho cột đầu tiên (sử dụng cache)
            if image_url:
                try:
                    image_data = self.get_cached_image(image_url)
                    if image_data:
                        worksheet.insert_image(row_index, next(col), image_url, {
                            'image_data': image_data, 
                            'x_scale': 0.15, 
                            'y_scale': 0.15,
                            'x_offset': 3,
                            'y_offset': 3
                        })
                    else:
                        worksheet.write(row_index, next(col), "Lỗi tải ảnh", align_left)
                except Exception as e:
                    worksheet.write(row_index, next(col), f"Lỗi: {str(e)[:50]}", align_left)
            else:
                worksheet.write(row_index, next(col), 'Không có ảnh', align_left)
            worksheet.write(row_index, next(col), item.get('UserName', ''), align_left)
            worksheet.write(row_index, next(col), item.get('PartnerName', ''), align_left)
            worksheet.write(row_index, next(col), item.get('ProductNameCN', ''), align_left)
            
            # Kích thước kiện - từ field Packages
            tran_codes = ''
            dimensions = ''
            weights = ''
            volumes = ''
            if item.get('Packages'):
                try:
                    packages = json.loads(item.get('Packages', '[]')) if isinstance(item.get('Packages', ''), str) else item.get('Packages', [])
                    for pkg in packages:
                        length = pkg.get('Length', 0) or 0
                        width = pkg.get('Width', 0) or 0
                        height = pkg.get('Height', 0) or 0
                        dimensions += f"{length} x {width} x {height} cm\n"
                        weights += f"{pkg.get('Weight', 0) or 0} kg\n"
                        volumes += f"{length * width * height / 1000000} m3\n"
                        tran_codes += f"{pkg.get('TransactionCode', '')}\n"
                except:
                    dimensions = ''
            worksheet.write(row_index, next(col), tran_codes, align_left)
            worksheet.write(row_index, next(col), item.get('NumberOfPack', 0) or 0, number)
            worksheet.write(row_index, next(col), dimensions, align_left)
            worksheet.write(row_index, next(col), volumes, align_left)
            worksheet.write(row_index, next(col), item.get('Volume', 0) or 0, currency)
            worksheet.write(row_index, next(col), weights, align_left)
            worksheet.write(row_index, next(col), item.get('Weight', 0) or 0, currency)
            worksheet.write(row_index, next(col), item.get('ModelBrand', ''), align_left)  # Model/Nhãn hiệu từ khai báo
            
        workbook.close()

        f = open(file_path, 'rb')
        response = HttpResponse(f, content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
        response['Content-Disposition'] = 'attachment; filename=%s' % file_name

        try:
            os.remove(file_path)
        except OSError:
            pass

        return response

    def export_chinh_ngach(self, request):
        """Xuất file chính ngạch - bao gồm thông tin từ nhập kho TQ + thông tin từ khai báo"""
        self.get_request_info(request)
        self.get_common_query_string(request)
        timenow = time.time()
        file_name = "chinh_ngach_%s.xlsx" % (timenow)
        if not os.path.exists(settings.TEMP_DOWNLOAD_PATH):
            os.makedirs(settings.TEMP_DOWNLOAD_PATH)
        file_path = os.path.join(settings.TEMP_DOWNLOAD_PATH, file_name)
        
        # Create a workbook and add a worksheet.
        workbook = xlsxwriter.Workbook(file_path)
        row = itertools.count(0)
        
        # Define format cell
        cell_header = workbook.add_format({'bold': True, 'align': 'left', 'valign': 'vcenter', 'font_name': 'Calibri', 'font_size': 12, 'border': 1})
        align_left = workbook.add_format({'align': 'left', 'valign': 'vcenter', 'font_name': 'Calibri', 'font_size': 12, 'border': 1, 'text_wrap': True})
        number = workbook.add_format({'align': 'right', 'valign': 'vcenter', 'num_format': '#,##0', 'font_name': 'Calibri', 'font_size': 12, 'border': 1})
        currency = workbook.add_format({'align': 'right', 'valign': 'vcenter', 'num_format': '#,##0.00', 'font_name': 'Calibri', 'font_size': 12, 'border': 1})
        
        # Get list item to export - sử dụng cùng logic như export_tieu_ngach
        action = self.params.get("action")
        selected_ids = self.params.get("selectedIds")
        
        print(f"Debug export_chinh_ngach: user_id={self.user_id}, role_id={self.role_id}, action={action}")
        print(f"Debug export_chinh_ngach: selected_ids={selected_ids}")
        
        # Nếu có selectedIds thì chỉ lấy các item được chọn
        if selected_ids:
            try:
                # Xử lý selectedIds có thể là string "468,469" hoặc JSON array "[468,469]"
                if isinstance(selected_ids, str):
                    # Nếu bắt đầu bằng '[' thì là JSON array
                    if selected_ids.strip().startswith('['):
                        selected_ids_list = json.loads(selected_ids)
                    else:
                        # Nếu không thì là chuỗi phân tách bằng dấu phẩy
                        selected_ids_list = [int(x.strip()) for x in selected_ids.split(',') if x.strip().isdigit()]
                else:
                    selected_ids_list = selected_ids if isinstance(selected_ids, list) else [selected_ids]
                
                if selected_ids_list and len(selected_ids_list) > 0:
                    # Lấy dữ liệu theo IDs được chọn
                    db = DbMySql()
                    ids_str = ','.join(map(str, selected_ids_list))
                    query_sql = f"""
                        SELECT p.*, u.FullName as UserFullName
                        FROM tbl_product p 
                        LEFT JOIN tbl_user u ON p.UID = u.ID 
                        WHERE p.ID IN ({ids_str})
                        ORDER BY p.ID DESC
                    """
                    rows = db.query(query=query_sql)
                    items = self.process_in_pandas(rows)
                    totalRow = len(items) if items else 0
                    summary = None
                    print(f"Debug export_chinh_ngach: Found {len(items) if items else 0} selected items")
                else:
                    items = []
                    totalRow = 0
                    summary = None
            except Exception as e:
                print(f"Error processing selectedIds: {e}")
                items = []
                totalRow = 0
                summary = None
        else:
            # Export theo filter như cũ
            items, totalRow, summary = self.modelClass.get_list(self.user_id, self.role_id, self.filter, self.quickFilter, self.sortBy, self.descending, 1000000, 0, action)
            print(f"Debug: Found {len(items) if items else 0} items for export_chinh_ngach")
            
            # Nếu không có items, thử lấy tất cả sản phẩm
            if not items or len(items) == 0:
                print("Debug: No items found, trying to get all products")
                items, totalRow, summary = self.modelClass.get_list(self.user_id, self.role_id, [], [], self.sortBy, self.descending, 1000000, 0, None)
                print(f"Debug: After retry, found {len(items) if items else 0} items")
        
        # Bổ sung thông tin quote cho từng item - xử lý nhiều quote cho mỗi product
        # Tạo danh sách expanded_items để mở rộng product thành nhiều dòng nếu có nhiều quote
        expanded_items = []
        if items and len(items) > 0:
            db = DbMySql()
            for item in items:
                # Lấy tất cả các quote liên kết với product này qua bảng tbl_product_quote
                product_id = item.get('ID')
                try:
                    # Query để lấy tất cả quote IDs liên kết với product
                    quote_link_query = """
                        SELECT QuoteID 
                        FROM tbl_product_quote 
                        WHERE ProductID = :product_id
                        ORDER BY QuoteID
                    """
                    quote_link_rows = db.query(query=quote_link_query, params={'product_id': product_id})
                    
                    quote_ids = []
                    if quote_link_rows:
                        for quote_row in quote_link_rows:
                            if hasattr(quote_row, '_mapping'):
                                quote_ids.append(quote_row._mapping['QuoteID'])
                            elif isinstance(quote_row, dict):
                                quote_ids.append(quote_row['QuoteID'])
                            else:
                                quote_ids.append(quote_row[0])
                    
                    # Nếu có quote, tạo một dòng cho mỗi quote
                    if quote_ids and len(quote_ids) > 0:
                        for quote_id in quote_ids:
                            # Copy item để tạo dòng mới
                            item_copy = dict(item)
                            
                            # Query thông tin chi tiết của quote
                            quote_query = """
                                SELECT q.ImageUrl, q.PackType, q.ProductNumber, q.ProductSize, 
                                       q.ProductCapacity, q.ProductMaterial, q.ProductUses,
                                       q.ProductName, q.ProductNameVN, q.BrandName, q.Manufacturer, 
                                       q.ManufacturerAddress, q.LabelCode, q.LabelDate, q.NumberOfPack,
                                       q.CustomsContent, q.CustomsUnit, q.CustomsPriceVND, q.Weight
                                FROM tbl_quote as q
                                WHERE q.ID = :quote_id
                            """
                            quote_rows = db.query(query=quote_query, params={'quote_id': quote_id})
                            quote_rows = db.query(query=quote_query, params={'quote_id': quote_id})
                            
                            if quote_rows:
                                # Xử lý ResultProxy object
                                if hasattr(quote_rows, 'fetchone'):
                                    quote_info = quote_rows.fetchone()
                                    if quote_info:
                                        quote_info = dict(quote_info._mapping) if hasattr(quote_info, '_mapping') else dict(quote_info)
                                elif isinstance(quote_rows, list) and len(quote_rows) > 0:
                                    quote_info = quote_rows[0]
                                    quote_info = dict(quote_info._mapping) if hasattr(quote_info, '_mapping') else dict(quote_info)
                                else:
                                    quote_info = None
                                
                                if quote_info:
                                    item_copy['QuoteImageUrl'] = quote_info.get('ImageUrl', '')
                                    item_copy['PackType'] = quote_info.get('PackType', '')
                                    item_copy['ProductNumber'] = quote_info.get('ProductNumber', 0)
                                    item_copy['ProductName'] = quote_info.get('ProductName', '')
                                    item_copy['ProductNameVN'] = quote_info.get('ProductNameVN', '')
                                    item_copy['ProductSize'] = quote_info.get('ProductSize', '')
                                    item_copy['ProductCapacity'] = quote_info.get('ProductCapacity', '')
                                    item_copy['ProductMaterial'] = quote_info.get('ProductMaterial', '')
                                    item_copy['ProductUses'] = quote_info.get('ProductUses', '')
                                    item_copy['ProductWeight'] = quote_info.get('Weight', 0)
                                    item_copy['ModelBrand'] = quote_info.get('BrandName', '')
                                    item_copy['Manufacturer'] = quote_info.get('Manufacturer', '')
                                    item_copy['ManufacturerAddress'] = quote_info.get('ManufacturerAddress', '')
                                    item_copy['LabelCode'] = quote_info.get('LabelCode', '') or item_copy.get('SuffixBill', '') or item_copy.get('Code', '')
                                    item_copy['LabelDate'] = quote_info.get('LabelDate', '') or datetime.now().strftime('%Y-%-m-%-d')
                                    item_copy['CustomsRequirement'] = quote_info.get('CustomsContent', '')
                                    item_copy['CustomsUnit'] = quote_info.get('CustomsUnit', '')
                                    item_copy['CustomsWeightPrice'] = quote_info.get('CustomsPriceVND', 0) or 0
                                    
                                    expanded_items.append(item_copy)
                                else:
                                    # Nếu không có quote info, thêm item với giá trị mặc định
                                    item_copy = self._set_default_quote_values(item_copy)
                                    expanded_items.append(item_copy)
                            else:
                                # Nếu không query được quote, thêm item với giá trị mặc định
                                item_copy = self._set_default_quote_values(item_copy)
                                expanded_items.append(item_copy)
                    else:
                        # Nếu product không có quote nào, thêm dòng với giá trị mặc định
                        item_copy = self._set_default_quote_values(dict(item))
                        expanded_items.append(item_copy)
                        
                except Exception as e:
                    print(f"Debug: Error getting quotes for product ID {product_id}: {e}")
                    # Nếu có lỗi, thêm item gốc với giá trị mặc định
                    item_copy = self._set_default_quote_values(dict(item))
                    expanded_items.append(item_copy)
        
        # Sử dụng expanded_items thay vì items cho việc export
        items = expanded_items if expanded_items else items
        
        worksheet = workbook.add_worksheet('File Chính Ngạch')
        
        # Set column widths
        worksheet.set_column('A:A', 15)  # Hình ảnh nhập kho - giảm kích thước
        worksheet.set_column('B:I', 12)  # Basic columns
        worksheet.set_column('J:J', 15)  # Hình ảnh khai báo - giảm kích thước
        worksheet.set_column('K:P', 12)  # Quote columns
        worksheet.set_column('Q:S', 14)  # Các cột khai báo mới
        worksheet.set_column('T:T', 18)  # Cột nhãn dán - rộng hơn để chứa ảnh
        
        # Initial header - Bao gồm cột tiểu ngạch + cột chính ngạch
        row_index = next(row)
        col = itertools.count(0)
        # Cột từ file tiểu ngạch
        # ensure header supports wrapping and is tall enough for two lines
        cell_header_wrap = workbook.add_format({
            'bold': True, 'align': 'left', 'valign': 'vcenter',
            'font_name': 'Calibri', 'font_size': 12, 'border': 1,
            'text_wrap': True
        })
        worksheet.set_row(row_index, 90)  # tăng chiều cao header để hiển thị 2 dòng
        # Thiết lập chiều rộng cho các cột header và các cột mở rộng
        worksheet.set_column('A:A', 30)  # Hình ảnh sản phẩm
        worksheet.set_column('B:B', 30)  # Hình ảnh catalog
        worksheet.set_column('C:C', 18)  # Ngày nhập kho
        worksheet.set_column('D:D', 20)  # Mã khách hàng
        worksheet.set_column('E:E', 18)  # Tên khách hàng
        worksheet.set_column('F:F', 24)  # Tên hàng (CN)
        worksheet.set_column('G:G', 24)  # Tên hàng (vi)
        worksheet.set_column('H:H', 14)  # Nhãn Hiệu
        worksheet.set_column('I:I', 25)  # Công Suất/Dung Tích
        worksheet.set_column('J:J', 14)  # Chất Liệu
        worksheet.set_column('K:K', 16)  # Quy Cách Đóng Gói
        worksheet.set_column('L:L', 20)  # Tổng sản phẩm
        worksheet.set_column('M:M', 25)  # Kích Thước Sản Phẩm
        worksheet.set_column('N:N', 20)  # Cân nặng sản phẩm
        worksheet.set_column('O:O', 12)  # Tổng kiện
        worksheet.set_column('P:P', 20)  # Kích thước kiện (nhiều dòng)
        worksheet.set_column('Q:Q', 12)  # Số m3/kiện
        worksheet.set_column('R:R', 12)  # Tổng m3
        worksheet.set_column('S:S', 12)  # Cân nặng/kiện
        worksheet.set_column('T:T', 12)  # Tổng Cân
        worksheet.set_column('U:U', 40)  # Nhãn Dán
        worksheet.write(row_index, next(col), 'Hình ảnh sản phẩm\n产品图片', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Hình ảnh Catalog', cell_header)
        worksheet.write(row_index, next(col), 'Ngày nhập kho\n入库日期', cell_header)
        worksheet.write(row_index, next(col), 'Mã khách hàng\n客户代码', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Tên khách hàng\n客户名称', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Tên hàng\n商品名', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Tên hàng (vi)\n商品名（越南语）', cell_header_wrap)
        # worksheet.write(row_index, next(col), 'Mã Vận Đơn', cell_header)
        # worksheet.write(row_index, next(col), 'Kích Thước Kiện', cell_header)
       
        # Cột bổ sung từ khai báo
        worksheet.write(row_index, next(col), 'Nhãn Hiệu\n品牌', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Công Suất/Dung Tích\n功率/容量', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Chất Liệu\n材质', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Quy Cách Đóng Gói\n包装规格', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Tổng sản phẩm\n产品总数', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Kích Thước Sản Phẩm\n产品尺寸', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Cân nặng sản phẩm\n产品净重', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Tổng kiện\n总件数', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Kích thước kiện\n外箱尺寸', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Số m3/kiện\n每箱立方数', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Tổng m3\n总立方数', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Cân nặng/kiện\n每箱重量', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Tổng Cân\n总重量', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Nhãn Dán\n标签', cell_header_wrap)
        # worksheet.write(row_index, next(col), 'Ghi chú', cell_header)
        
        
        
        # worksheet.write(row_index, next(col), 'Công Dụng', cell_header)
        # worksheet.write(row_index, next(col), 'Yêu cầu khai báo', cell_header)
        # worksheet.write(row_index, next(col), 'Đơn vị khai báo', cell_header)
        # worksheet.write(row_index, next(col), 'Giá cân khai báo', cell_header)
        
        # Debug: log before processing items
        print(f"Debug: Processing {len(items) if items else 0} items in export_chinh_ngach")
        print(f"Debug: items type: {type(items)}")
        
        # Ensure items is a list
        if items is None:
            items = []
        
        for item in items:
            col = itertools.count(0)
            row_index = next(row)
            
            # Set row height to accommodate images - tăng chiều cao cho nhãn dán
            worksheet.set_row(row_index, 80)
            
            # Lấy hình ảnh từ field Images cho cột tiểu ngạch
            image_url = ''
            images = item.get('Images', '')
            if images:
                try:
                    images_list = json.loads(images) if isinstance(images, str) else images
                    if images_list and len(images_list) > 0:
                        image_url = images_list[0].get('url', '')
                except Exception:
                    image_url = ''
            
            # Xử lý hình ảnh cho cột đầu tiên (hình ảnh nhập kho TQ, sử dụng cache và resize)
            if image_url:
                try:
                    image_data = self.get_cached_image(image_url)
                    if image_data:
                        # Resize ảnh về kích thước 70x70 pixels
                        resized_image = self.resize_image_to_fit(image_data, 100, 100)
                        if resized_image:
                            worksheet.insert_image(row_index, next(col), image_url, {
                                'image_data': resized_image, 
                                'x_scale': 1.0, 
                                'y_scale': 1.0,
                                'x_offset': 2,
                                'y_offset': 2,
                                'url': image_url  # Hyperlink đến ảnh gốc
                            })
                        else:
                            worksheet.write(row_index, next(col), "Lỗi resize ảnh", align_left)
                    else:
                        worksheet.write(row_index, next(col), "Lỗi tải ảnh", align_left)
                except Exception as e:
                    worksheet.write(row_index, next(col), f"Lỗi: {str(e)[:50]}", align_left)
            else:
                worksheet.write(row_index, next(col), 'Không có ảnh', align_left)
            # Cột bổ sung từ khai báo - Hình ảnh khai báo (sử dụng cache và resize)
            quote_image_url = item.get('QuoteImageUrl', '') or ''
            if quote_image_url:
                try:
                    image_data = self.get_cached_image(quote_image_url)
                    if image_data:
                        # Resize ảnh về kích thước 70x70 pixels
                        resized_image = self.resize_image_to_fit(image_data, 70, 70)
                        if resized_image:
                            worksheet.insert_image(row_index, next(col), quote_image_url, {
                                'image_data': resized_image, 
                                'x_scale': 1.0, 
                                'y_scale': 1.0,
                                'x_offset': 2,
                                'y_offset': 2,
                                'url': quote_image_url  # Hyperlink đến ảnh gốc
                            })
                        else:
                            worksheet.write(row_index, next(col), "Lỗi resize ảnh", align_left)
                    else:
                        worksheet.write(row_index, next(col), "Lỗi tải ảnh khai báo", align_left)
                except Exception as e:
                    worksheet.write(row_index, next(col), f"Lỗi: {str(e)[:50]}", align_left)
            else:
                worksheet.write(row_index, next(col), 'Không có ảnh khai báo', align_left)
            worksheet.write(row_index, next(col), parser.parse(item['ReceiveDate']).strftime('%d-%m-%Y') if item['ReceiveDate'] is not None else '', align_left)
            worksheet.write(row_index, next(col), item.get('UserName', ''), align_left)
            worksheet.write(row_index, next(col), item.get('PartnerName', ''), align_left)
            worksheet.write(row_index, next(col), item.get('ProductNameCN', ''), align_left)
            worksheet.write(row_index, next(col), item.get('ProductNameVN', ''), align_left)
            # worksheet.write(row_index, next(col), item.get('SuffixBill', '') or item.get('Code', ''), align_left)
            
            # Kích thước kiện - từ field Packages
            tran_codes = ''
            dimensions = ''
            weights = ''
            volumes = ''
            if item.get('Packages'):
                try:
                    packages = json.loads(item.get('Packages', '[]')) if isinstance(item.get('Packages', ''), str) else item.get('Packages', [])
                    for pkg in packages:
                        length = pkg.get('Length', 0) or 0
                        width = pkg.get('Width', 0) or 0
                        height = pkg.get('Height', 0) or 0
                        dimensions += f"{length} x {width} x {height} cm\n"
                        weights += f"{pkg.get('Weight', 0) or 0} kg\n"
                        volumes += f"{length * width * height / 1000000} m3\n"
                        tran_codes += f"{pkg.get('TransactionCode', '')}\n"
                except:
                    dimensions = ''
            
            worksheet.write(row_index, next(col), item.get('ModelBrand', ''), align_left)  # Model/Nhãn hiệu từ khai báo
            worksheet.write(row_index, next(col), item.get('ProductCapacity', ''), align_left)
            worksheet.write(row_index, next(col), item.get('ProductMaterial', ''), align_left)
            worksheet.write(row_index, next(col), item.get('PackType', ''), align_left)
            worksheet.write(row_index, next(col), item.get('ProductNumber', 0) or 0, number)
            worksheet.write(row_index, next(col), item.get('ProductSize', ''), align_left)
            worksheet.write(row_index, next(col), item.get('ProductWeight', 0) or 0, number) # Cân nặng sản phẩm
            worksheet.write(row_index, next(col), item.get('NumberOfPack', 0) or 0, number)
            worksheet.write(row_index, next(col), dimensions, align_left)
            worksheet.write(row_index, next(col), volumes, align_left)
            worksheet.write(row_index, next(col), item.get('Volume', 0) or 0, currency)
            worksheet.write(row_index, next(col), weights, align_left)
            worksheet.write(row_index, next(col), item.get('Weight', 0) or 0, currency)
            # worksheet.write(row_index, next(col), item.get('Note', ''), align_left)
            
            # worksheet.write(row_index, next(col), item.get('ProductUses', ''), align_left)
            
            # Các cột khai báo mới
            # worksheet.write(row_index, next(col), item.get('CustomsRequirement', ''), align_left)  # Yêu cầu khai báo
            # worksheet.write(row_index, next(col), item.get('CustomsUnit', ''), align_left)  # Đơn vị khai báo
            # worksheet.write(row_index, next(col), item.get('CustomsWeightPrice', 0) or 0, currency)  # Giá cân khai báo
            
            # Nhãn dán - tạo ảnh nhãn thay vì text
            try:
                label_image = self.generate_label_image(item)
                if label_image:
                    worksheet.insert_image(row_index, next(col), f"label_{item.get('Code', 'unknown')}", {
                        'image_data': label_image,
                        'x_scale': 0.25,
                        'y_scale': 0.35,
                        'x_offset': 2,
                        'y_offset': 2
                    })
                else:
                    # Fallback về text nếu không tạo được ảnh
                    label_info_lines = []
                    manufacturer = item.get('ProductMaterial', '')
                    if manufacturer:
                        label_info_lines.append(f"Manufacturer: {manufacturer}")
                    code = item.get('SuffixBill', '') or item.get('Code', '')
                    if code:
                        label_info_lines.append(f"Code: {code}")
                    label_info_lines.append(f"Date: {datetime.now().strftime('%d/%m/%Y')}")
                    label_info_lines.append("MADE IN CHINA")
                    if item.get('UserName'):
                        label_info_lines.append(f"{item.get('UserName')} - {item.get('NumberOfPack',0)}")
                    label_info = '\n'.join(label_info_lines)
                    worksheet.write(row_index, next(col), label_info, align_left)
            except Exception as e:
                print(f"Error inserting label image: {e}")
                # Fallback về text
                worksheet.write(row_index, next(col), f"Label Error: {str(e)[:20]}", align_left)
        workbook.close()

        f = open(file_path, 'rb')
        response = HttpResponse(f, content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
        response['Content-Disposition'] = 'attachment; filename=%s' % file_name

        try:
            os.remove(file_path)
        except OSError:
            pass

        return response
    
    def export_chinh_ngach_vi(self, request):
        """Xuất file chính ngạch - bao gồm thông tin từ nhập kho TQ + thông tin từ khai báo"""
        self.get_request_info(request)
        self.get_common_query_string(request)
        isSentCustoms = self.params.get("isSentCustoms")
        timenow = time.time()
        file_name = "chinh_ngach_%s.xlsx" % (timenow)
        if not os.path.exists(settings.TEMP_DOWNLOAD_PATH):
            os.makedirs(settings.TEMP_DOWNLOAD_PATH)
        file_path = os.path.join(settings.TEMP_DOWNLOAD_PATH, file_name)
        
        # Create a workbook and add a worksheet.
        workbook = xlsxwriter.Workbook(file_path)
        row = itertools.count(0)
        
        # Define format cell
        cell_header = workbook.add_format({'bold': True, 'align': 'left', 'valign': 'vcenter', 'font_name': 'Calibri', 'font_size': 12, 'border': 1})
        align_left = workbook.add_format({'align': 'left', 'valign': 'vcenter', 'font_name': 'Calibri', 'font_size': 12, 'border': 1, 'text_wrap': True})
        number = workbook.add_format({'align': 'right', 'valign': 'vcenter', 'num_format': '#,##0', 'font_name': 'Calibri', 'font_size': 12, 'border': 1})
        currency = workbook.add_format({'align': 'right', 'valign': 'vcenter', 'num_format': '#,##0.00', 'font_name': 'Calibri', 'font_size': 12, 'border': 1})
        
        # Get list item to export - sử dụng cùng logic như export_tieu_ngach
        action = self.params.get("action")
        selected_ids = self.params.get("selectedIds")
        
        print(f"Debug export_chinh_ngach: user_id={self.user_id}, role_id={self.role_id}, action={action}")
        print(f"Debug export_chinh_ngach: selected_ids={selected_ids}")
        
        # Nếu có selectedIds thì chỉ lấy các item được chọn
        if selected_ids:
            try:
                # Xử lý selectedIds có thể là string "468,469" hoặc JSON array "[468,469]"
                if isinstance(selected_ids, str):
                    # Nếu bắt đầu bằng '[' thì là JSON array
                    if selected_ids.strip().startswith('['):
                        selected_ids_list = json.loads(selected_ids)
                    else:
                        # Nếu không thì là chuỗi phân tách bằng dấu phẩy
                        selected_ids_list = [int(x.strip()) for x in selected_ids.split(',') if x.strip().isdigit()]
                else:
                    selected_ids_list = selected_ids if isinstance(selected_ids, list) else [selected_ids]
                
                if selected_ids_list and len(selected_ids_list) > 0:
                    # Lấy dữ liệu theo IDs được chọn
                    db = DbMySql()
                    ids_str = ','.join(map(str, selected_ids_list))
                    if isSentCustoms and str(isSentCustoms) == '1':
                        db.query(query="UPDATE tbl_product SET IsSentCustoms=1 WHERE ID IN (%s) AND Status = 1" % ids_str)
                    query_sql = f"""
                        SELECT p.*, u.FullName as UserFullName
                        FROM tbl_product p 
                        LEFT JOIN tbl_user u ON p.UID = u.ID 
                        WHERE p.ID IN ({ids_str})
                        ORDER BY p.ID DESC
                    """
                    rows = db.query(query=query_sql)
                    items = self.process_in_pandas(rows)
                    totalRow = len(items) if items else 0
                    summary = None
                    print(f"Debug export_chinh_ngach: Found {len(items) if items else 0} selected items")
                else:
                    items = []
                    totalRow = 0
                    summary = None
            except Exception as e:
                print(f"Error processing selectedIds: {e}")
                items = []
                totalRow = 0
                summary = None
        else:
            # Export theo filter như cũ
            items, totalRow, summary = self.modelClass.get_list(self.user_id, self.role_id, self.filter, self.quickFilter, self.sortBy, self.descending, 1000000, 0, action)
            print(f"Debug: Found {len(items) if items else 0} items for export_chinh_ngach")
            
            # Nếu không có items, thử lấy tất cả sản phẩm
            if not items or len(items) == 0:
                print("Debug: No items found, trying to get all products")
                items, totalRow, summary = self.modelClass.get_list(self.user_id, self.role_id, [], [], self.sortBy, self.descending, 1000000, 0, None)
                print(f"Debug: After retry, found {len(items) if items else 0} items")
        
        # Bổ sung thông tin quote cho từng item - xử lý nhiều quote cho mỗi product
        # Tạo danh sách expanded_items để mở rộng product thành nhiều dòng nếu có nhiều quote
        expanded_items = []
        if items and len(items) > 0:
            db = DbMySql()
            for item in items:
                # Lấy tất cả các quote liên kết với product này qua bảng tbl_product_quote
                product_id = item.get('ID')
                try:
                    # Query để lấy tất cả quote IDs liên kết với product
                    quote_link_query = """
                        SELECT QuoteID 
                        FROM tbl_product_quote 
                        WHERE ProductID = :product_id
                        ORDER BY QuoteID
                    """
                    quote_link_rows = db.query(query=quote_link_query, params={'product_id': product_id})
                    
                    quote_ids = []
                    if quote_link_rows:
                        for quote_row in quote_link_rows:
                            if hasattr(quote_row, '_mapping'):
                                quote_ids.append(quote_row._mapping['QuoteID'])
                            elif isinstance(quote_row, dict):
                                quote_ids.append(quote_row['QuoteID'])
                            else:
                                quote_ids.append(quote_row[0])
                    
                    # Nếu có quote, tạo một dòng cho mỗi quote
                    if quote_ids and len(quote_ids) > 0:
                        for quote_id in quote_ids:
                            # Copy item để tạo dòng mới
                            item_copy = dict(item)
                            
                            # Query thông tin chi tiết của quote
                            quote_query = """
                                SELECT q.ImageUrl, q.PackType, q.ProductNumber, q.ProductSize, 
                                       q.ProductCapacity, q.ProductMaterial, q.ProductUses, q.CustomsPriceNote, q.HsCode,
                                       q.ProductName, q.ProductNameVN, q.BrandName, q.Manufacturer, 
                                       q.ManufacturerAddress, q.LabelCode, q.LabelDate, q.NumberOfPack,
                                       q.CustomsContent, q.CustomsUnit, q.CustomsPriceVND, q.Weight
                                FROM tbl_quote as q
                                WHERE q.ID = :quote_id
                            """
                            quote_rows = db.query(query=quote_query, params={'quote_id': quote_id})
                            
                            if quote_rows:
                                # Xử lý ResultProxy object
                                if hasattr(quote_rows, 'fetchone'):
                                    quote_info = quote_rows.fetchone()
                                    if quote_info:
                                        quote_info = dict(quote_info._mapping) if hasattr(quote_info, '_mapping') else dict(quote_info)
                                elif isinstance(quote_rows, list) and len(quote_rows) > 0:
                                    quote_info = quote_rows[0]
                                    quote_info = dict(quote_info._mapping) if hasattr(quote_info, '_mapping') else dict(quote_info)
                                else:
                                    quote_info = None
                                
                                if quote_info:
                                    item_copy['QuoteImageUrl'] = quote_info.get('ImageUrl', '')
                                    item_copy['PackType'] = quote_info.get('PackType', '')
                                    item_copy['ProductNumber'] = quote_info.get('ProductNumber', 0)
                                    item_copy['ProductName'] = quote_info.get('ProductName', '')
                                    item_copy['ProductNameVN'] = quote_info.get('ProductNameVN', '')
                                    item_copy['ProductSize'] = quote_info.get('ProductSize', '')
                                    item_copy['ProductCapacity'] = quote_info.get('ProductCapacity', '')
                                    item_copy['ProductMaterial'] = quote_info.get('ProductMaterial', '')
                                    item_copy['ProductUses'] = quote_info.get('ProductUses', '')
                                    item_copy['ProductWeight'] = quote_info.get('Weight', 0)
                                    item_copy['ModelBrand'] = quote_info.get('BrandName', '')
                                    item_copy['Manufacturer'] = quote_info.get('Manufacturer', '')
                                    item_copy['ManufacturerAddress'] = quote_info.get('ManufacturerAddress', '')
                                    item_copy['LabelCode'] = quote_info.get('LabelCode', '') or item_copy.get('SuffixBill', '') or item_copy.get('Code', '')
                                    item_copy['LabelDate'] = quote_info.get('LabelDate', '') or datetime.now().strftime('%Y-%-m-%-d')
                                    item_copy['CustomsPriceNote'] = quote_info.get('CustomsPriceNote', '')
                                    item_copy['HsCode'] = quote_info.get('HsCode', '')
                                    item_copy['CustomsRequirement'] = quote_info.get('CustomsContent', '')
                                    item_copy['CustomsUnit'] = quote_info.get('CustomsUnit', '')
                                    item_copy['CustomsWeightPrice'] = quote_info.get('CustomsPriceVND', 0) or 0
                                    
                                    expanded_items.append(item_copy)
                                else:
                                    # Nếu không có quote info, thêm item với giá trị mặc định
                                    item_copy['CustomsPriceNote'] = ''
                                    item_copy['HsCode'] = ''
                                    item_copy = self._set_default_quote_values(item_copy)
                                    expanded_items.append(item_copy)
                            else:
                                # Nếu không query được quote, thêm item với giá trị mặc định
                                item_copy['CustomsPriceNote'] = ''
                                item_copy['HsCode'] = ''
                                item_copy = self._set_default_quote_values(item_copy)
                                expanded_items.append(item_copy)
                    else:
                        # Nếu product không có quote nào, thêm dòng với giá trị mặc định
                        item_copy = dict(item)
                        item_copy['CustomsPriceNote'] = ''
                        item_copy['HsCode'] = ''
                        item_copy = self._set_default_quote_values(item_copy)
                        expanded_items.append(item_copy)
                        
                except Exception as e:
                    print(f"Debug: Error getting quotes for product ID {product_id}: {e}")
                    # Nếu có lỗi, thêm item gốc với giá trị mặc định
                    item_copy = dict(item)
                    item_copy['CustomsPriceNote'] = ''
                    item_copy['HsCode'] = ''
                    item_copy = self._set_default_quote_values(item_copy)
                    expanded_items.append(item_copy)
        
        # Sử dụng expanded_items thay vì items cho việc export
        items = expanded_items if expanded_items else items
        
        worksheet = workbook.add_worksheet('File Chính Ngạch')
        
        # Set column widths
        worksheet.set_column('A:A', 15)  # Hình ảnh nhập kho - giảm kích thước
        worksheet.set_column('B:I', 12)  # Basic columns
        worksheet.set_column('J:J', 15)  # Hình ảnh khai báo - giảm kích thước
        worksheet.set_column('K:P', 12)  # Quote columns
        worksheet.set_column('Q:S', 14)  # Các cột khai báo mới
        worksheet.set_column('T:T', 18)  # Cột nhãn dán - rộng hơn để chứa ảnh
        
        # Initial header - Bao gồm cột tiểu ngạch + cột chính ngạch
        row_index = next(row)
        col = itertools.count(0)
        # Cột từ file tiểu ngạch
        # ensure header supports wrapping and is tall enough for two lines
        cell_header_wrap = workbook.add_format({
            'bold': True, 'align': 'left', 'valign': 'vcenter',
            'font_name': 'Calibri', 'font_size': 12, 'border': 1,
            'text_wrap': True
        })
        worksheet.set_row(row_index, 90)  # tăng chiều cao header để hiển thị 2 dòng
        # Thiết lập chiều rộng cho các cột header và các cột mở rộng
        worksheet.set_column('A:A', 30)  # Hình ảnh sản phẩm
        worksheet.set_column('B:B', 20)  # Mã khách hàng
        worksheet.set_column('C:C', 18)  # Tên khách hàng
        worksheet.set_column('D:D', 24)  # Tên hàng (CN)
        worksheet.set_column('E:E', 24)  # Tên hàng (vi)
        worksheet.set_column('F:F', 14)  # Nhãn Hiệu
        worksheet.set_column('G:G', 25)  # Công Suất/Dung Tích
        worksheet.set_column('H:H', 14)  # Chất Liệu
        worksheet.set_column('I:I', 16)  # Quy Cách Đóng Gói
        worksheet.set_column('J:J', 20)  # Tổng sản phẩm
        worksheet.set_column('K:K', 25)  # Kích Thước Sản Phẩm
        worksheet.set_column('L:L', 20)  # Cân nặng sản phẩm
        worksheet.set_column('M:M', 12)  # Tổng kiện
        worksheet.set_column('N:N', 20)  # Kích thước kiện (nhiều dòng)
        worksheet.set_column('O:O', 12)  # Số m3/kiện
        worksheet.set_column('P:P', 12)  # Tổng m3
        worksheet.set_column('Q:Q', 12)  # Cân nặng/kiện
        worksheet.set_column('R:R', 12)  # Tổng Cân
        worksheet.set_column('S:S', 40)  # Nhãn Dán
        worksheet.write(row_index, next(col), 'Hình ảnh hàng', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Mã khách hàng', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Tên khách hàng', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Tên hàng', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Quy Cách Đóng Gói', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Tổng sản phẩm', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Kích Thước Sản Phẩm', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Cân nặng sản phẩm', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Tổng kiện', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Kích thước kiện', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Số m3/kiện', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Tổng m3', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Cân nặng/kiện', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Tổng Cân', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Hình ảnh Catalog', cell_header)
        # worksheet.write(row_index, next(col), 'Mã Vận Đơn', cell_header)
        # worksheet.write(row_index, next(col), 'Kích Thước Kiện', cell_header)
       
        # Cột bổ sung từ khai báo
        worksheet.write(row_index, next(col), 'Model/Nhãn Hiệu', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Công Suất/Dung Tích', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Tên khai báo', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Giá khai báo', cell_header)
        worksheet.write(row_index, next(col), 'Đơn vị khai báo', cell_header)
        worksheet.write(row_index, next(col), 'Mã HSCODE', cell_header)
        worksheet.write(row_index, next(col), 'Chất Liệu', cell_header_wrap)
        worksheet.write(row_index, next(col), 'Công Dụng', cell_header)
        worksheet.write(row_index, next(col), 'Yêu cầu khai báo', cell_header)
        worksheet.write(row_index, next(col), 'Giá cần khai báo', cell_header)
        worksheet.write(row_index, next(col), 'Nhãn Dán', cell_header_wrap)
        # Debug: log before processing items
        print(f"Debug: Processing {len(items) if items else 0} items in export_chinh_ngach")
        print(f"Debug: items type: {type(items)}")
        
        # Ensure items is a list
        if items is None:
            items = []
        
        for item in items:
            col = itertools.count(0)
            row_index = next(row)
            
            # Set row height to accommodate images - tăng chiều cao cho nhãn dán
            worksheet.set_row(row_index, 80)
            
            # Lấy hình ảnh từ field Images cho cột tiểu ngạch
            image_url = ''
            images = item.get('Images', '')
            if images:
                try:
                    images_list = json.loads(images) if isinstance(images, str) else images
                    if images_list and len(images_list) > 0:
                        image_url = images_list[0].get('url', '')
                except Exception:
                    image_url = ''
            
            # Xử lý hình ảnh cho cột đầu tiên (hình ảnh nhập kho TQ, sử dụng cache và resize)
            if image_url:
                try:
                    image_data = self.get_cached_image(image_url)
                    if image_data:
                        # Resize ảnh về kích thước 100x100 pixels
                        resized_image = self.resize_image_to_fit(image_data, 100, 100)
                        if resized_image:
                            worksheet.insert_image(row_index, next(col), image_url, {
                                'image_data': resized_image, 
                                'x_scale': 1.0, 
                                'y_scale': 1.0,
                                'x_offset': 2,
                                'y_offset': 2,
                                'url': image_url  # Hyperlink đến ảnh gốc
                            })
                        else:
                            worksheet.write(row_index, next(col), "Lỗi resize ảnh", align_left)
                    else:
                        worksheet.write(row_index, next(col), "Lỗi tải ảnh", align_left)
                except Exception as e:
                    worksheet.write(row_index, next(col), f"Lỗi: {str(e)[:50]}", align_left)
            else:
                worksheet.write(row_index, next(col), 'Không có ảnh', align_left)
            
            # Kích thước kiện - từ field Packages
            dimensions = ''
            weights = ''
            volumes = ''
            if item.get('Packages'):
                try:
                    packages = json.loads(item.get('Packages', '[]')) if isinstance(item.get('Packages', ''), str) else item.get('Packages', [])
                    for pkg in packages:
                        length = pkg.get('Length', 0) or 0
                        width = pkg.get('Width', 0) or 0
                        height = pkg.get('Height', 0) or 0
                        dimensions += f"{length} x {width} x {height} cm\n"
                        weights += f"{pkg.get('Weight', 0) or 0} kg\n"
                        volumes += f"{length * width * height / 1000000} m3\n"
                except:
                    dimensions = ''
            
            worksheet.write(row_index, next(col), item.get('UserName', ''), align_left)
            worksheet.write(row_index, next(col), item.get('PartnerName', ''), align_left)
            worksheet.write(row_index, next(col), item.get('ProductNameVN', ''), align_left)
            worksheet.write(row_index, next(col), item.get('PackType', ''), align_left)
            worksheet.write(row_index, next(col), item.get('ProductNumber', 0) or 0, number)
            worksheet.write(row_index, next(col), item.get('ProductSize', ''), align_left)
            worksheet.write(row_index, next(col), item.get('ProductWeight', 0) or 0, number) # Cân nặng sản phẩm
            worksheet.write(row_index, next(col), item.get('NumberOfPack', 0) or 0, number)
            worksheet.write(row_index, next(col), dimensions, align_left)
            worksheet.write(row_index, next(col), volumes, align_left)
            worksheet.write(row_index, next(col), item.get('Volume', 0) or 0, currency)
            worksheet.write(row_index, next(col), weights, align_left)
            worksheet.write(row_index, next(col), item.get('Weight', 0) or 0, currency)
            # worksheet.write(row_index, next(col), item.get('SuffixBill', '') or item.get('Code', ''), align_left)
            
            # Cột bổ sung từ khai báo - Hình ảnh khai báo (sử dụng cache và resize)
            quote_image_url = item.get('QuoteImageUrl', '') or ''
            if quote_image_url:
                try:
                    image_data = self.get_cached_image(quote_image_url)
                    if image_data:
                        # Resize ảnh về kích thước 70x70 pixels
                        resized_image = self.resize_image_to_fit(image_data, 70, 70)
                        if resized_image:
                            worksheet.insert_image(row_index, next(col), quote_image_url, {
                                'image_data': resized_image, 
                                'x_scale': 1.0, 
                                'y_scale': 1.0,
                                'x_offset': 2,
                                'y_offset': 2,
                                'url': quote_image_url  # Hyperlink đến ảnh gốc
                            })
                        else:
                            worksheet.write(row_index, next(col), "Lỗi resize ảnh", align_left)
                    else:
                        worksheet.write(row_index, next(col), "Lỗi tải ảnh khai báo", align_left)
                except Exception as e:
                    worksheet.write(row_index, next(col), f"Lỗi: {str(e)[:50]}", align_left)
            else:
                worksheet.write(row_index, next(col), 'Không có ảnh khai báo', align_left)

            worksheet.write(row_index, next(col), item.get('ModelBrand', ''), align_left)  # Model/Nhãn hiệu từ khai báo
            worksheet.write(row_index, next(col), item.get('ProductCapacity', ''), align_left)
            worksheet.write(row_index, next(col), item.get('ProductInfo', ''), align_left)
            worksheet.write(row_index, next(col), item.get('CustomsPriceNote', ''), align_left) # Giá khai báo
            worksheet.write(row_index, next(col), item.get('CustomsUnit', ''), align_left)  # Đơn vị khai báo
            worksheet.write(row_index, next(col), item.get('HsCode', ''), align_left)  # Mã HSCODE
            worksheet.write(row_index, next(col), item.get('ProductMaterial', ''), align_left)
            worksheet.write(row_index, next(col), item.get('ProductUses', ''), align_left)
            worksheet.write(row_index, next(col), item.get('CustomsRequirement', ''), align_left)  # Yêu cầu khai báo
            worksheet.write(row_index, next(col), item.get('CustomsWeightPrice', ''), number)  # Giá cần khai báo
            
            # Nhãn dán - tạo ảnh nhãn thay vì text
            try:
                label_image = self.generate_label_image(item)
                if label_image:
                    worksheet.insert_image(row_index, next(col), f"label_{item.get('Code', 'unknown')}", {
                        'image_data': label_image,
                        'x_scale': 0.25,
                        'y_scale': 0.35,
                        'x_offset': 2,
                        'y_offset': 2
                    })
                else:
                    # Fallback về text nếu không tạo được ảnh
                    label_info_lines = []
                    manufacturer = item.get('ProductMaterial', '')
                    if manufacturer:
                        label_info_lines.append(f"Manufacturer: {manufacturer}")
                    code = item.get('SuffixBill', '') or item.get('Code', '')
                    if code:
                        label_info_lines.append(f"Code: {code}")
                    label_info_lines.append(f"Date: {datetime.now().strftime('%d/%m/%Y')}")
                    label_info_lines.append("MADE IN CHINA")
                    if item.get('UserName'):
                        label_info_lines.append(f"{item.get('UserName')} - {item.get('NumberOfPack',0)}")
                    label_info = '\n'.join(label_info_lines)
                    worksheet.write(row_index, next(col), label_info, align_left)
            except Exception as e:
                print(f"Error inserting label image: {e}")
                # Fallback về text
                worksheet.write(row_index, next(col), f"Label Error: {str(e)[:20]}", align_left)
            
        workbook.close()

        f = open(file_path, 'rb')
        response = HttpResponse(f, content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
        response['Content-Disposition'] = 'attachment; filename=%s' % file_name

        try:
            os.remove(file_path)
        except OSError:
            pass

        return response

    def quote_product(self, request, pk):
        self.get_request_info(request)
        self.get_common_query_string(request)
        db = DbMySql()
        query_sql = f""" SELECT p.* FROM tbl_product as p WHERE p.QuoteID = {pk};"""
        rows = db.query(query=query_sql)
        data = self.process_in_pandas(rows)
        return SuccessResponse(data=data)