176 lines
6.0 KiB
Python
176 lines
6.0 KiB
Python
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'
|
||
)
|