import io import os import pandas as pd from flask import Blueprint, send_file, jsonify, make_response from reportlab.lib.pagesizes import letter from reportlab.pdfgen import canvas from reportlab.lib import colors from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont from ..db import get_db_connection, release_db_connection from ..middleware import token_required reports_blueprint = Blueprint('reports', __name__) # Попытка зарегистрировать кириллический шрифт FONT_PATH = os.path.join(os.path.dirname(__file__), '..', 'fonts', 'DejaVuSans.ttf') FONT_NAME = 'DejaVuSans' try: if os.path.exists(FONT_PATH): pdfmetrics.registerFont(TTFont(FONT_NAME, FONT_PATH)) else: # Пытаемся найти системный шрифт на Windows или Linux sys_fonts = [ '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 'C:\\Windows\\Fonts\\arial.ttf' ] for f in sys_fonts: if os.path.exists(f): pdfmetrics.registerFont(TTFont(FONT_NAME, f)) break except Exception as e: print(f"Warning: Could not register Cyrillic font: {e}") FONT_NAME = 'Helvetica' # Fallback @reports_blueprint.route('/reports/cases/csv', methods=['GET']) @token_required def export_cases_csv(current_user_id): """ Экспорт всех кейсов в CSV --- tags: - Reports security: - APIKeyHeader: [] responses: 200: description: CSV файл """ conn = get_db_connection() query = """ SELECT id, platform, violator_url, violator_article, my_article, comment, status, created_at FROM cases WHERE user_id = %s """ df = pd.read_sql(query, conn, params=(current_user_id,)) release_db_connection(conn) output = io.BytesIO() df.to_csv(output, index=False, encoding='utf-8-sig') output.seek(0) return send_file( output, mimetype='text/csv', as_attachment=True, download_name=f'cases_export_{current_user_id}.csv' ) @reports_blueprint.route('/reports/case//pdf', methods=['GET']) @token_required def export_case_pdf(current_user_id, case_id): """ Генерация PDF претензии для конкретного кейса --- tags: - Reports security: - APIKeyHeader: [] parameters: - name: case_id in: path type: integer required: true responses: 200: description: PDF файл претензии """ conn = get_db_connection() cur = conn.cursor() cur.execute(""" SELECT platform, violator_url, violator_article, my_article, comment, status, created_at FROM cases WHERE id = %s AND user_id = %s """, (case_id, current_user_id)) row = cur.fetchone() release_db_connection(conn) if not row: return jsonify({"error": "Case not found"}), 404 platform, v_url, v_art, my_art, comment, status, created_at = row buffer = io.BytesIO() doc = SimpleDocTemplate(buffer, pagesize=letter) styles = getSampleStyleSheet() # Custom style for Russian text ru_style = ParagraphStyle( 'Russian', parent=styles['Normal'], fontName=FONT_NAME, fontSize=10, leading=12 ) title_style = ParagraphStyle( 'RussianTitle', parent=styles['Title'], fontName=FONT_NAME, fontSize=18, spaceAfter=20 ) elements = [] # Header / Title elements.append(Paragraph(f"Официальная претензия #{case_id}", title_style)) elements.append(Paragraph(f"Система мониторинга AutoMarket (OzonGuard)", ru_style)) elements.append(Spacer(1, 20)) # Info table data = [ [Paragraph("Параметр", ru_style), Paragraph("Значение", ru_style)], [Paragraph("Маркетплейс", ru_style), platform.upper()], [Paragraph("Дата создания", ru_style), created_at.strftime('%Y-%m-%d %H:%M') if created_at else "-"], [Paragraph("Артикул нарушителя", ru_style), v_art], [Paragraph("Ссылка на товар", ru_style), Paragraph(v_url, ru_style)], [Paragraph("Ваш артикул", ru_style), my_art or "-"], [Paragraph("Текущий статус", ru_style), status.upper()] ] t = Table(data, colWidths=[150, 350]) t.setStyle(TableStyle([ ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#2c3e50')), ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke), ('ALIGN', (0, 0), (-1, -1), 'LEFT'), ('FONTNAME', (0, 0), (-1, -1), FONT_NAME), ('FONTSIZE', (0, 0), (-1, -1), 10), ('BOTTOMPADDING', (0, 0), (-1, 0), 12), ('BACKGROUND', (0, 1), (-1, -1), colors.whitesmoke), ('GRID', (0, 0), (-1, -1), 1, colors.grey), ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ])) elements.append(t) elements.append(Spacer(1, 24)) # Description elements.append(Paragraph("Описание нарушения:", ParagraphStyle('Sub', parent=ru_style, fontSize=12, spaceAfter=10))) elements.append(Paragraph(comment or "Комментарий отсутствует", ru_style)) elements.append(Spacer(1, 40)) elements.append(Paragraph("Сгенерировано автоматически. Данный документ является официальным уведомлением о нарушении правил платформы.", ParagraphStyle('Footer', parent=ru_style, fontSize=8, textColor=colors.grey))) doc.build(elements) buffer.seek(0) return send_file( buffer, mimetype='application/pdf', as_attachment=True, download_name=f'complaint_{case_id}.pdf' )