Files
AutoMarket/backend/routes/reports.py

176 lines
6.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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/<int:case_id>/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'
)