Enhancements

This commit is contained in:
2026-06-25 11:19:08 +02:00
parent 8804d21c32
commit 9343657d20
62 changed files with 10210 additions and 976 deletions
+116 -15
View File
@@ -1,12 +1,16 @@
from fastapi import FastAPI, HTTPException, Depends, WebSocket
from fastapi.security import OAuth2PasswordBearer
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import List, Annotated, Optional
from pydantic import BaseModel, ConfigDict, Field, model_validator
from typing import List, Annotated, Optional, Union
from sustApp.models.models import Base, Members, Payments
from sustApp.models.database import engine, SessionLocal
from sqlalchemy.orm import Session
from sqlalchemy import func
from datetime import datetime
from fastapi.encoders import jsonable_encoder
# from create_payment_report import create_payment_report
import asyncio
import logging
@@ -31,6 +35,7 @@ origins = [
"http://localhost:8080",
"http://localhost:3000",
"http://localhost:5173",
"http://localhost:5174",
]
app.add_middleware(
@@ -91,10 +96,12 @@ class User(BaseModel):
class DeliveryBase(BaseModel):
delivery_date: datetime
delivered_by: int
delivered_by_id: int | None = None
class PaymentBase(BaseModel):
payment_date: datetime
payment_date: datetime | None = None
payment_year: datetime | None = None
class MemberBase(BaseModel):
member_count: int
@@ -105,19 +112,31 @@ class MemberBase(BaseModel):
member_street: str
member_streetnumber: str | None = None
member_email: str | None = None
member_zip: int
member_zip: int | None = Field(default=None, description="Member ZIP code")
#member_zip: Optional[int] = Field(default=None, description="Member ZIP code")
member_printed: bool | None = None
member_city: str
member_active: bool
member_active: bool | None = None
member_gender: str | None = None
member_connected: int | None = None
member_printed: bool
#member_coordinates:
#payments: Optional[List[PaymentBase]]
member_deliveries: Optional[List[DeliveryBase]]
#deliveries: Mapped[List["DeliveryBase"]] = relationship()
member_deliveries: Optional[List[DeliveryBase]] = []
member_payments: Optional[List[PaymentBase]] = []
current_state_code: str | None = None
current_state_name: str | None = None
@model_validator(mode='before')
@classmethod
def handle_empty_strings(cls, data):
"""Convert empty strings to None for int fields"""
if isinstance(data, dict):
if data.get('member_zip') == '':
data['member_zip'] = None
return data
model_config = ConfigDict(from_attributes=True) # Enables SQLAlchemy object conversion
def get_db():
db = SessionLocal()
try:
@@ -128,17 +147,84 @@ def get_db():
db_dependency = Annotated[Session, Depends(get_db)]
@app.get("/members/", response_model=List[MemberBase])
async def read_members(db: db_dependency, skip: int = 0, limit: int = 100):
members = db.query(Members).offset(skip).limit(limit).all()
if not members:
raise HTTPException(status_code=404, detail='No members found')
return [
{
"id": m.id,
"member_firstname": m.member_firstname,
"member_surname": m.member_surname,
"member_count": m.member_count,
"member_street": m.member_street,
"member_zip": m.member_zip,
"member_city": m.member_city,
"member_active": m.member_active,
"member_printed": m.member_printed,
"member_deliveries": [
{
"id": d.id,
"delivery_date": d.delivery_date, # Correct field
"delivered_by_id": d.delivered_by_id,
# Add any other required delivery fields here
}
for d in m.member_deliveries
] if m.member_deliveries else [],
"member_payments": [
{
"id": p.id,
"payment_date": p.payment_date,
"payment_year": p.payment_year,
# Add any other required delivery fields here
}
for p in m.member_payments
] if m.member_payments else []
}
for m in members
]
""" @app.get("/members/", response_model=List[MemberBase])
async def read_members(db: db_dependency, skip: int = 0, limit: int = 100):
members = db.query(Members).offset(skip).limit(limit).all()
if not members:
raise HTTPException(status_code=404, detail='No members found') # Use 404 for not found
# DEBUG: Print first member attributes
if members:
print("First member:", vars(members[0]))
print("First member type:", type(members[0]))
# TEMP: Return dicts to bypass Pydantic entirely
#return [{"id": m.id, "name": getattr(m, 'name', None)} for m in members] #
# Safe conversion - handles any SQLAlchemy objects
return jsonable_encoder(members)
# return members # Now works with ORM mode enabled """
""" @app.get("/members/", response_model=List[MemberBase])
async def read_members(db: db_dependency, skip: int = 0, limit: int = 100 ):
members = db.query(Members).offset(skip).limit(limit).all()
if not members:
raise HTTPException(status_code=400, detail='No members')
return members
return members """
@app.get("/activememberscount/", response_model=int)
async def read_activememberscount(db: db_dependency):
count = db.query(Members).filter(Members.member_active == True).count()
logger.info("This is a test log message from backend!")
return count
count = db.query(func.sum(Members.member_count)).filter(Members.current_state_code == 'A', Members.member_primary == True).scalar()
return count or 0
@app.get("/inactivememberscount/", response_model=int)
async def read_inactivememberscount(db: db_dependency):
count = db.query(func.sum(Members.member_count)).filter(Members.current_state_code == 'I', Members.member_primary == True).scalar()
return count or 0
@app.get("/deactivatedmemberscount/", response_model=int)
async def read_deactivatedmemberscount(db: db_dependency):
count = db.query(func.sum(Members.member_count)).filter(Members.current_state_code == 'D', Members.member_primary == True).scalar()
return count or 0
@app.get("/member/{member_id}")
async def read_member(member_id: int, db: db_dependency): #, token: Annotated[str, Depends(oauth2_scheme)]):
@@ -151,9 +237,16 @@ async def read_member(member_id: int, db: db_dependency): #, token: Annotated[st
return result
@app.get("/payments/")
async def read_all_payments(db: db_dependency):
result = db.query(Payments).all()
if not result:
raise HTTPException(status_code=400, detail=f'No payments found')
return result
@app.get("/payments/{member_id}")
async def read_payments(member_id: int, db: db_dependency):
result = db.query(Members).filter(Members.id == member_id).all()
result = db.query(Payments).filter(Payments.member_id == member_id).all()
if not result:
raise HTTPException(status_code=400, detail=f'No payments found for member {member_id}')
return result
@@ -191,4 +284,12 @@ async def create_members(members: List[MemberBase], db: db_dependency):
db_payment = Payments(payment_date=payment.payment_date,
member_id=db_member.id)
db.add(db_payment)
db.commit()
db.commit()
# @app.get("/api/reports/payments")
# async def get_payment_report():
# try:
# report_path = create_payment_report()
# return {"message": "Report generated", "path": report_path}
# except Exception as e:
# raise HTTPException(status_code=500, detail=str(e))