diff --git a/backend/src/service_api.py b/backend/src/service_api.py index c1e24fed..a0dea93d 100644 --- a/backend/src/service_api.py +++ b/backend/src/service_api.py @@ -405,8 +405,10 @@ def _payload_from_form_json(form_json: Dict[str, Any], variant: Optional[str]) - # Detect variant if AUTO or not specified if variant is None or variant == "AUTO": detected_variant = core.detect_variant(form_json) + print(f"DEBUG - Variant auto-detected as: {detected_variant}") else: detected_variant = variant + print(f"DEBUG - Variant explicitly set to: {detected_variant}") mapped = core.map_form_to_payload(form_json, detected_variant) model = core.payload_to_model(mapped) from dataclasses import asdict @@ -469,6 +471,9 @@ def create_application( # Rate-Limit nach IP rate_limit_ip(x_forwarded_for or "") + # Debug: Log received variant parameter + print(f"DEBUG CREATE - Received variant parameter: '{variant}'") + # Payload beschaffen payload: Dict[str, Any] raw_form: Optional[Dict[str, Any]] = None @@ -483,6 +488,9 @@ def create_application( try: raw = base64.b64decode(form_json_b64) raw_form = json.loads(raw.decode("utf-8")) + # Debug: Log raw form data for financing fields + financing_fields = {k: v for k, v in raw_form.items() if 'financing' in k.lower() or 'qsm' in k.lower() or 'vsm' in k.lower()} + print(f"DEBUG CREATE - Raw form financing fields: {json.dumps(financing_fields, indent=2, default=str)}") except Exception as e: raise HTTPException(status_code=400, detail=f"Invalid form_json_b64: {e}") payload, detected_variant = _payload_from_form_json(raw_form, variant or "AUTO") @@ -494,6 +502,12 @@ def create_application( if pa_meta.get("id"): raise HTTPException(status_code=400, detail="pa-id already set; use update endpoint") + # Debug: Log financing fields specifically + pa_data = payload.get("pa", {}) + project_data = pa_data.get("project", {}) + financing_data = project_data.get("financing", {}) + print(f"DEBUG CREATE - Financing data: {json.dumps(financing_data, indent=2, default=str)}") + # Erzeugen in TX try: with db.begin(): @@ -638,12 +652,21 @@ def update_application( try: raw = base64.b64decode(form_json_b64) raw_form = json.loads(raw.decode("utf-8")) + # Debug: Log raw form data for financing fields + financing_fields = {k: v for k, v in raw_form.items() if 'financing' in k.lower() or 'qsm' in k.lower() or 'vsm' in k.lower()} + print(f"DEBUG UPDATE - Raw form financing fields: {json.dumps(financing_fields, indent=2, default=str)}") except Exception as e: raise HTTPException(status_code=400, detail=f"Invalid form_json_b64: {e}") payload, _ = _payload_from_form_json(raw_form, variant or app_row.variant) else: raise HTTPException(status_code=400, detail="Provide either PDF file or form_json_b64") + # Debug: Log financing fields specifically + pa_data = payload.get("pa", {}) + project_data = pa_data.get("project", {}) + financing_data = project_data.get("financing", {}) + print(f"DEBUG UPDATE - Financing data: {json.dumps(financing_data, indent=2, default=str)}") + # Immer mit bestehender ID, Key NICHT in DB-Payload speichern render = _inject_meta_for_render(payload, app_row.pa_id, None) # Key nicht neu ausgeben store_payload = _sanitize_payload_for_db(payload) @@ -886,6 +909,13 @@ def get_application( } return StreamingResponse(io.BytesIO(pdf_bytes), media_type="application/pdf", headers=headers) + # Debug: Log financing data from database + if app_row.payload_json: + pa_data = app_row.payload_json.get("pa", {}) + project_data = pa_data.get("project", {}) + financing_data = project_data.get("financing", {}) + print(f"DEBUG GET - Financing data from DB: {json.dumps(financing_data, indent=2, default=str)}") + # Sonst JSON return { "pa_id": app_row.pa_id, diff --git a/frontend/src/pages/AdminDashboard.tsx b/frontend/src/pages/AdminDashboard.tsx index bd2d1a39..c45e3341 100644 --- a/frontend/src/pages/AdminDashboard.tsx +++ b/frontend/src/pages/AdminDashboard.tsx @@ -929,7 +929,7 @@ const AdminDashboard: React.FC = () => { zIndex: 1100, display: "flex", justifyContent: "center", - maxWidth: "calc(100vw - 120px)", + maxWidth: "calc(100vw - 300px)", margin: "0 auto", pointerEvents: "none", // Allow clicks through the container }} diff --git a/test_financing.py b/test_financing.py new file mode 100644 index 00000000..3f925025 --- /dev/null +++ b/test_financing.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 +""" +Test script to debug financing fields issue in STUPA PDF API +""" + +import json +import base64 +import requests +from typing import Dict, Any + +# Test data with financing fields +def create_test_form_data() -> Dict[str, Any]: + """Create test form data with financing fields""" + return { + # Basic fields + "pa-first-name": {"/V": "Test"}, + "pa-last-name": {"/V": "User"}, + "pa-email": {"/V": "test@example.com"}, + "pa-project-name": {"/V": "Test Project"}, + "pa-start-date": {"/V": "2025-01-01"}, + "pa-end-date": {"/V": "2025-06-30"}, + "pa-participants": {"/V": 10}, + "pa-project-description": {"/V": "Test description"}, + "pa-requested-amount-euro-sum": {"/V": 1000}, + + # Cost positions + "pa-cost-1-name": {"/V": "Test Cost"}, + "pa-cost-1-amount-euro": {"/V": 1000}, + + # QSM Financing fields - this is what should be saved but might be missing + "pa-qsm-financing": {"/V": "vwv-3-2-1-1"}, + "pa-qsm-stellenfinanzierungen": {"/V": True}, + "pa-qsm-studierende": {"/V": True}, + "pa-qsm-individuell": {"/V": True}, + + # VSM Financing fields + "pa-vsm-financing": {"/V": "lhg-01"}, + "pa-vsm-aufgaben": {"/V": True}, + "pa-vsm-individuell": {"/V": True}, + } + +def test_create_application(): + """Test creating an application with financing fields""" + print("=== Testing CREATE Application ===") + + form_data = create_test_form_data() + form_json = json.dumps(form_data) + form_json_b64 = base64.b64encode(form_json.encode('utf-8')).decode('utf-8') + + # Test QSM variant + print("\n--- Testing QSM Application ---") + response = requests.post( + "http://localhost:8000/applications", + params={ + "return_format": "json", + "variant": "QSM" + }, + data={ + "form_json_b64": form_json_b64 + } + ) + + print(f"Status Code: {response.status_code}") + if response.status_code == 200: + # Check if we got JSON or PDF + content_type = response.headers.get('content-type', '') + if 'application/json' in content_type: + data = response.json() + print(f"Created Application: {data['pa_id']}") + print(f"Key: {data['pa_key']}") + return data['pa_id'], data['pa_key'] + else: + # PDF response, extract from headers + pa_id = response.headers.get('X-PA-ID') + pa_key = response.headers.get('X-PA-KEY') + print(f"Created Application: {pa_id}") + print(f"Key: {pa_key}") + return pa_id, pa_key + else: + print(f"Error: {response.text}") + return None, None + +def test_update_application(pa_id: str, pa_key: str): + """Test updating an application with financing fields""" + print(f"\n=== Testing UPDATE Application {pa_id} ===") + + # Create form data with updated financing fields + form_data = create_test_form_data() + # Change financing code to test if it saves + form_data["pa-qsm-financing"] = {"/V": "vwv-3-2-1-2"} # Different value + + form_json = json.dumps(form_data) + form_json_b64 = base64.b64encode(form_json.encode('utf-8')).decode('utf-8') + + response = requests.put( + f"http://localhost:8000/applications/{pa_id}", + params={ + "return_format": "json" + }, + data={ + "form_json_b64": form_json_b64 + }, + headers={ + "X-PA-KEY": pa_key + } + ) + + print(f"Status Code: {response.status_code}") + if response.status_code != 200: + print(f"Error: {response.text}") + +def test_get_application(pa_id: str, pa_key: str): + """Test retrieving an application to check if financing fields are saved""" + print(f"\n=== Testing GET Application {pa_id} ===") + + response = requests.get( + f"http://localhost:8000/applications/{pa_id}", + headers={ + "X-PA-KEY": pa_key + } + ) + + print(f"Status Code: {response.status_code}") + if response.status_code == 200: + data = response.json() + + # Check financing fields - correct payload structure + payload = data.get('payload', {}) + pa = payload.get('pa', {}) + project = pa.get('project', {}) + financing = project.get('financing', {}) + + print(f"\nFinancing data in response:") + print(json.dumps(financing, indent=2)) + + # Check specific fields + qsm = financing.get('qsm', {}) + vsm = financing.get('vsm', {}) + + print(f"\nQSM financing code: {qsm.get('code')}") + print(f"QSM flags: {qsm.get('flags')}") + print(f"VSM financing code: {vsm.get('code')}") + print(f"VSM flags: {vsm.get('flags')}") + + # Check if fields are missing (the main issue) + if not qsm.get('code') and not vsm.get('code'): + print("\nโŒ ISSUE FOUND: No financing code saved!") + else: + print("\nโœ… Financing code found") + + if not qsm.get('flags') and not vsm.get('flags'): + print("โŒ ISSUE FOUND: No financing flags saved!") + else: + print("โœ… Financing flags found") + else: + print(f"Error: {response.text}") + +def main(): + """Run all tests""" + print("๐Ÿงช Testing Financing Fields Issue") + print("=" * 50) + + # Create application + pa_id, pa_key = test_create_application() + + if pa_id and pa_key: + # Update application + test_update_application(pa_id, pa_key) + + # Check if data was saved correctly + test_get_application(pa_id, pa_key) + + print("\n" + "=" * 50) + print("๐Ÿ” Check the API logs with: docker compose logs api | grep DEBUG") + +if __name__ == "__main__": + main()