diff --git a/frontend/src/components/ApplicationForm/ApplicationForm.tsx b/frontend/src/components/ApplicationForm/ApplicationForm.tsx index dc1ead52..71384dab 100644 --- a/frontend/src/components/ApplicationForm/ApplicationForm.tsx +++ b/frontend/src/components/ApplicationForm/ApplicationForm.tsx @@ -776,25 +776,7 @@ const ApplicationForm: React.FC = ({ } /> } - label="Es handelt sich um Stellenfinanzierungen" - required - /> - - setFormData((prev: any) => ({ - ...prev, - qsmFlags: { - ...prev.qsmFlags, - studierende: e.target.checked, - }, - })) - } - /> - } - label="Die Studierenden werden an der Planung und Durchführung der Maßnahme beteiligt" + label="Es sind keine unbefristeten Stellenfinanzierungen enthalten" required /> = ({ } /> } - label="Die beantragte Exkursion wurde von den zuständigen Stellen genehmigt" + label="Die Exkursion wurde von der Fakultät genehmigt (*)" /> = ({ } /> } - label="Die Exkursion wird bereits aus anderen Mitteln bezuschusst" + label="Die Exkursion wird bereits aus anderen Mitteln bezuschusst (*)" /> )} - {/* Anhänge Section */} - - - Anhänge - - - - handleChange("comparativeOffers", e.target.checked) - } - /> - } - label="Vergleichsangebote liegen bei" - /> - {variant === "QSM" && ( - - handleChange("fakultaet", e.target.checked) - } - /> - } - label="Die Fakultät ist über den Antrag informiert" - required - /> - )} - - - {/* Kostenpositionen Section */} { E-Mail - {formData.email} + + {formData.email ? ( + + {formData.email} + + ) : ( + "-" + )} + Telefon - {formData.phone || "-"} + + {formData.phone ? ( + + {formData.phone} + + ) : ( + "-" + )} + @@ -428,12 +450,21 @@ const AdminApplicationView: React.FC = () => { : "Erfüllte Aufgabe der VS nach §65 des Landeshochschulgesetzes"} - {currentApplication.variant === "QSM" && formData.qsmFinancing - ? QSM_FINANCING_LABELS[formData.qsmFinancing] || + {currentApplication.variant === "QSM" && + (formData.financingCode || formData.qsmFinancing) + ? QSM_FINANCING_LABELS[ + (formData.financingCode || + formData.qsmFinancing) as keyof typeof QSM_FINANCING_LABELS + ] || + formData.financingCode || formData.qsmFinancing : currentApplication.variant === "VSM" && - formData.vsmFinancing - ? VSM_FINANCING_LABELS[formData.vsmFinancing] || + (formData.financingCode || formData.vsmFinancing) + ? VSM_FINANCING_LABELS[ + (formData.financingCode || + formData.vsmFinancing) as keyof typeof VSM_FINANCING_LABELS + ] || + formData.financingCode || formData.vsmFinancing : "-"} diff --git a/frontend/src/pages/ViewApplicationPage.tsx b/frontend/src/pages/ViewApplicationPage.tsx index bffbad34..177eec97 100644 --- a/frontend/src/pages/ViewApplicationPage.tsx +++ b/frontend/src/pages/ViewApplicationPage.tsx @@ -282,6 +282,24 @@ const ViewApplicationPage: React.FC = () => { + + + Telefon + + + {formData.phone ? ( + + {formData.phone} + + ) : ( + "-" + )} + + + Institution @@ -370,16 +388,25 @@ const ViewApplicationPage: React.FC = () => { {currentApplication.variant === "QSM" - ? "Erfüllte Aufgabe der QSM" + ? "Erfüllte Aufgabe nach VWV zur Verwendung von QS-Mitteln" : "Erfüllte Aufgabe der VS nach §65 des Landeshochschulgesetzes"} - {currentApplication.variant === "QSM" && formData.qsmFinancing - ? QSM_FINANCING_LABELS[formData.qsmFinancing] || + {currentApplication.variant === "QSM" && + (formData.financingCode || formData.qsmFinancing) + ? QSM_FINANCING_LABELS[ + (formData.financingCode || + formData.qsmFinancing) as keyof typeof QSM_FINANCING_LABELS + ] || + formData.financingCode || formData.qsmFinancing : currentApplication.variant === "VSM" && - formData.vsmFinancing - ? VSM_FINANCING_LABELS[formData.vsmFinancing] || + (formData.financingCode || formData.vsmFinancing) + ? VSM_FINANCING_LABELS[ + (formData.financingCode || + formData.vsmFinancing) as keyof typeof VSM_FINANCING_LABELS + ] || + formData.financingCode || formData.vsmFinancing : "-"} diff --git a/frontend/src/store/applicationStore.ts b/frontend/src/store/applicationStore.ts index 07ef677b..aa819fb6 100644 --- a/frontend/src/store/applicationStore.ts +++ b/frontend/src/store/applicationStore.ts @@ -1198,8 +1198,12 @@ function createFormJsonFromData(formData: Partial): string { } // Add variant-specific fields - if (formData.variant === "QSM" && formData.qsmFinancing) { - formJson["pa-qsm-financing"] = { "/V": formData.qsmFinancing }; + if (formData.variant === "QSM") { + if (formData.financingCode || formData.qsmFinancing) { + formJson["pa-qsm-financing"] = { + "/V": formData.financingCode || formData.qsmFinancing, + }; + } if (formData.qsmFlags) { formJson["pa-qsm-stellenfinanzierungen"] = { "/V": formData.qsmFlags.stellenfinanzierungen, @@ -1213,14 +1217,28 @@ function createFormJsonFromData(formData: Partial): string { "/V": formData.qsmFlags.exkursionBezuschusst, }; } - } else if (formData.variant === "VSM" && formData.vsmFinancing) { - formJson["pa-vsm-financing"] = { "/V": formData.vsmFinancing }; + } else if (formData.variant === "VSM") { + if (formData.financingCode || formData.vsmFinancing) { + formJson["pa-vsm-financing"] = { + "/V": formData.financingCode || formData.vsmFinancing, + }; + } if (formData.vsmFlags) { formJson["pa-vsm-aufgaben"] = { "/V": formData.vsmFlags.aufgaben }; formJson["pa-vsm-individuell"] = { "/V": formData.vsmFlags.individuell }; } } + // Add attachments + if (formData.comparativeOffers !== undefined) { + formJson["pa-anh-vergleichsangebote"] = { + "/V": formData.comparativeOffers, + }; + } + if (formData.fakultaet !== undefined) { + formJson["pa-anh-fakultaet"] = { "/V": formData.fakultaet }; + } + const jsonString = JSON.stringify(formJson); return btoa(unescape(encodeURIComponent(jsonString))); // Base64 encode with UTF-8 support } @@ -1258,11 +1276,13 @@ function convertPayloadToFormData(payload: RootPayload): Partial { name: cost.name || "", amountEur: cost.amountEur || 0, })), - variant: (pa.project.financing.qsm - ? "QSM" - : pa.project.financing.vsm - ? "VSM" + variant: (pa.project.financing.vsm?.code + ? "VSM" + : pa.project.financing.qsm?.code + ? "QSM" : "COMMON") as Variant, + financingCode: + pa.project.financing.qsm?.code || pa.project.financing.vsm?.code || "", qsmFinancing: pa.project.financing.qsm?.code as any, qsmFlags: pa.project.financing.qsm?.flags ? { diff --git a/frontend/src/types/api.ts b/frontend/src/types/api.ts index 8681fb41..f4233a9c 100644 --- a/frontend/src/types/api.ts +++ b/frontend/src/types/api.ts @@ -284,6 +284,7 @@ export interface FormData { // Financing variant: Variant; + financingCode?: string; qsmFinancing?: QSMFinancingCode; qsmFlags?: { stellenfinanzierungen: boolean; diff --git a/src/pdf_filler.py b/src/pdf_filler.py index 50aed516..c1a22cde 100644 --- a/src/pdf_filler.py +++ b/src/pdf_filler.py @@ -155,7 +155,7 @@ def fill_pdf(payload: Dict[str, Any], variant: str, out_path: Optional[str] = No writer.add_page(p) # Flatten payload first - mapping = core._merge_mapping(variant) + mapping = core._merge_mapping(variant, {}) flat = _flatten(payload) # Calculate total amount from costs diff --git a/src/pdf_to_struct.py b/src/pdf_to_struct.py index 2b2b3847..c8b3a1a4 100755 --- a/src/pdf_to_struct.py +++ b/src/pdf_to_struct.py @@ -239,8 +239,23 @@ def _set_nested(root: Dict[str, Any], dotted: str, value: Any) -> None: curr[part] = {} curr = curr[part] -def _merge_mapping(variant: str) -> Dict[str, Dict[str, Any]]: +def _detect_best_mapping(form_fields: Mapping[str, Any]) -> str: + # Implement logic to detect best mapping based on form fields + # Example: Check for specific field names or patterns + # Return "QSM", "VSM", or "COMMON" based on the detection + if "pa-qsm-financing" in form_fields: + return "QSM" + if "pa-vsm-financing" in form_fields: + return "VSM" + return "COMMON" + +def _merge_mapping(variant: str, form_fields: Mapping[str, Any]) -> Dict[str, Dict[str, Any]]: v = (variant or "").strip().upper() + + if v == "AUTO": + # Find best mapping based on form fields + return _merge_mapping(_detect_best_mapping(form_fields), form_fields) + if v == "QSM": return {**TEXT_MAPPING_COMMON, **TEXT_MAPPING_QSM} if v == "VSM": @@ -259,13 +274,14 @@ def detect_variant(form_fields: Mapping[str, Any]) -> str: return "VSM" return "COMMON" - def map_form_to_payload(form_json: Dict[str, Dict[str, Any]], variant: str) -> Dict[str, Any]: """ Map PDF-like form JSON (fieldName -> dict with '/V', etc.) to nested payload using TEXT_MAPPING_* dicts. Unknown/empty fields are skipped. """ - mapping = _merge_mapping(variant) + + form_fields = form_json.keys() + mapping = _merge_mapping(variant, form_fields) out: Dict[str, Any] = {} # Pre-collect costs