Enhancements
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user