209 lines
6.9 KiB
Python
209 lines
6.9 KiB
Python
import models.models as models
|
|
from reportlab.lib.pagesizes import A4, landscape
|
|
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
|
from reportlab.lib.units import mm
|
|
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
|
|
from reportlab.lib import colors
|
|
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
|
|
from datetime import datetime
|
|
import locale
|
|
import os
|
|
from config_loader import load_config
|
|
from models.database import engine, SessionLocal
|
|
from sqlalchemy import func
|
|
|
|
cfg = load_config()
|
|
year = cfg['year']
|
|
|
|
locale.setlocale(locale.LC_ALL, '')
|
|
|
|
def get_payment_table_data():
|
|
"""Get payment data organized by member with summary columns"""
|
|
|
|
db = SessionLocal()
|
|
|
|
try:
|
|
# Query members with their payment information
|
|
members = db.query(models.Members).filter(
|
|
models.Members.member_active == True
|
|
).order_by(
|
|
models.Members.member_surname,
|
|
models.Members.member_firstname
|
|
).all()
|
|
|
|
table_data = []
|
|
|
|
# Header row
|
|
table_data.append([
|
|
'Paid 2024',
|
|
'Paid 2025'
|
|
])
|
|
|
|
# Data rows - one per member
|
|
for member in members:
|
|
payments = db.query(models.MembersPaidYears).filter(
|
|
models.MembersPaidYears.id == member.id
|
|
)
|
|
|
|
if payments:
|
|
table_data.append([
|
|
'✓' if payments.paid_2024 else '✗',
|
|
'✓' if payments.paid_2025 else '✗'
|
|
])
|
|
|
|
return table_data
|
|
|
|
finally:
|
|
db.close()
|
|
|
|
def create_payment_summary_table():
|
|
"""Create a single table with payment summary for all members"""
|
|
|
|
try:
|
|
# Get table data
|
|
table_data = get_payment_table_data()
|
|
|
|
if len(table_data) <= 1:
|
|
print("⚠️ No member data found")
|
|
return None
|
|
|
|
# Create filename
|
|
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
|
output_path = os.path.join(
|
|
os.path.expanduser("~"),
|
|
"sust",
|
|
f"payment_reports_{year}",
|
|
f"payment_summary_{timestamp}.pdf"
|
|
)
|
|
|
|
# Ensure directory exists
|
|
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
|
|
|
# Create PDF document
|
|
doc = SimpleDocTemplate(
|
|
output_path,
|
|
pagesize=landscape(A4),
|
|
topMargin=15*mm,
|
|
bottomMargin=15*mm,
|
|
leftMargin=10*mm,
|
|
rightMargin=10*mm
|
|
)
|
|
elements = []
|
|
|
|
# Title
|
|
styles = getSampleStyleSheet()
|
|
title_style = ParagraphStyle(
|
|
'CustomTitle',
|
|
parent=styles['Heading1'],
|
|
fontSize=16,
|
|
textColor=colors.HexColor('#1f4788'),
|
|
spaceAfter=15,
|
|
alignment=TA_CENTER
|
|
)
|
|
title = Paragraph(f"Zahlungsübersicht Mitgliederbeiträge {year}", title_style)
|
|
elements.append(title)
|
|
|
|
# Create table
|
|
table = Table(table_data, repeatRows=1)
|
|
|
|
# Style table
|
|
table.setStyle(TableStyle([
|
|
# Header styling
|
|
('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#1f4788')),
|
|
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
|
|
('ALIGN', (0, 0), (-1, 0), TA_CENTER),
|
|
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
|
|
('FONTSIZE', (0, 0), (-1, 0), 9),
|
|
('BOTTOMPADDING', (0, 0), (-1, 0), 12),
|
|
('TOPPADDING', (0, 0), (-1, 0), 8),
|
|
|
|
# Body styling
|
|
('ALIGN', (0, 1), (0, -1), TA_CENTER), # Member ID centered
|
|
('ALIGN', (1, 1), (1, -1), TA_LEFT), # Name left
|
|
('ALIGN', (2, 1), (2, -1), TA_LEFT), # Email left
|
|
('ALIGN', (3, 1), (3, -1), TA_CENTER), # Member Count centered
|
|
('ALIGN', (4, 1), (6, -1), TA_CENTER), # Payment columns centered
|
|
|
|
('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
|
|
('FONTSIZE', (0, 1), (-1, -1), 8),
|
|
('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, colors.HexColor('#f9f9f9')]),
|
|
('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
|
|
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
|
|
('LEFTPADDING', (0, 0), (-1, -1), 5),
|
|
('RIGHTPADDING', (0, 0), (-1, -1), 5),
|
|
('TOPPADDING', (0, 1), (-1, -1), 4),
|
|
('BOTTOMPADDING', (0, 1), (-1, -1), 4),
|
|
|
|
# Highlight payment status columns
|
|
('BACKGROUND', (4, 0), (5, -1), colors.HexColor('#f0f8ff')),
|
|
]))
|
|
|
|
elements.append(table)
|
|
|
|
# Add footer with summary
|
|
elements.append(Spacer(1, 1.5*mm))
|
|
summary_style = ParagraphStyle(
|
|
'Summary',
|
|
parent=styles['Normal'],
|
|
fontSize=8,
|
|
textColor=colors.grey
|
|
)
|
|
summary = Paragraph(
|
|
f"Total Members: {len(table_data) - 1} | Generated: {datetime.now().strftime('%d.%m.%Y %H:%M:%S')}",
|
|
summary_style
|
|
)
|
|
elements.append(summary)
|
|
|
|
# Build PDF
|
|
doc.build(elements)
|
|
|
|
print(f"✅ Payment summary created: {output_path}")
|
|
print(f"📊 Total members: {len(table_data) - 1}")
|
|
return output_path
|
|
|
|
except Exception as e:
|
|
print(f"❌ Error creating payment summary: {str(e)}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return None
|
|
|
|
# Function to integrate into existing PDF
|
|
def get_payment_table_element():
|
|
"""Return a ReportLab Table element for embedding in existing PDFs"""
|
|
|
|
table_data = get_payment_table_data()
|
|
|
|
if len(table_data) <= 1:
|
|
return None
|
|
|
|
table = Table(table_data, repeatRows=1)
|
|
|
|
table.setStyle(TableStyle([
|
|
# Header styling
|
|
('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#1f4788')),
|
|
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
|
|
('ALIGN', (0, 0), (-1, 0), TA_CENTER),
|
|
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
|
|
('FONTSIZE', (0, 0), (-1, 0), 9),
|
|
('BOTTOMPADDING', (0, 0), (-1, 0), 8),
|
|
|
|
# Body styling
|
|
('ALIGN', (0, 1), (0, -1), TA_CENTER),
|
|
('ALIGN', (1, 1), (1, -1), TA_LEFT),
|
|
('ALIGN', (2, 1), (2, -1), TA_LEFT),
|
|
('ALIGN', (3, 1), (-1, -1), TA_CENTER),
|
|
('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
|
|
('FONTSIZE', (0, 1), (-1, -1), 7),
|
|
('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, colors.HexColor('#f9f9f9')]),
|
|
('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
|
|
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
|
|
('LEFTPADDING', (0, 0), (-1, -1), 3),
|
|
('RIGHTPADDING', (0, 0), (-1, -1), 3),
|
|
('TOPPADDING', (0, 1), (-1, -1), 2),
|
|
('BOTTOMPADDING', (0, 1), (-1, -1), 2),
|
|
]))
|
|
|
|
return table
|
|
|
|
if __name__ == '__main__':
|
|
create_payment_summary_table() |