Fix AUTO detection

This commit is contained in:
Frederik Beimgraben 2025-09-01 02:21:09 +02:00
parent c40198c906
commit 6772e3d8f6
7 changed files with 121 additions and 82 deletions

View File

@ -776,25 +776,7 @@ const ApplicationForm: React.FC<ApplicationFormProps> = ({
} }
/> />
} }
label="Es handelt sich um Stellenfinanzierungen" label="Es sind keine unbefristeten Stellenfinanzierungen enthalten"
required
/>
<FormControlLabel
control={
<Checkbox
checked={formData.qsmFlags?.studierende || false}
onChange={(e) =>
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"
required required
/> />
<FormControlLabel <FormControlLabel
@ -830,7 +812,7 @@ const ApplicationForm: React.FC<ApplicationFormProps> = ({
} }
/> />
} }
label="Die beantragte Exkursion wurde von den zuständigen Stellen genehmigt" label="Die Exkursion wurde von der Fakultät genehmigt (*)"
/> />
<FormControlLabel <FormControlLabel
control={ control={
@ -847,50 +829,12 @@ const ApplicationForm: React.FC<ApplicationFormProps> = ({
} }
/> />
} }
label="Die Exkursion wird bereits aus anderen Mitteln bezuschusst" label="Die Exkursion wird bereits aus anderen Mitteln bezuschusst (*)"
/> />
</FormGroup> </FormGroup>
</Paper> </Paper>
)} )}
{/* Anhänge Section */}
<Paper variant="outlined" sx={{ p: 3, mb: 3 }}>
<Typography
variant="h6"
gutterBottom
sx={{ borderBottom: 1, borderColor: "divider", pb: 1, mb: 2 }}
>
Anhänge
</Typography>
<FormGroup>
<FormControlLabel
control={
<Checkbox
checked={formData.comparativeOffers || false}
onChange={(e) =>
handleChange("comparativeOffers", e.target.checked)
}
/>
}
label="Vergleichsangebote liegen bei"
/>
{variant === "QSM" && (
<FormControlLabel
control={
<Checkbox
checked={formData.fakultaet || false}
onChange={(e) =>
handleChange("fakultaet", e.target.checked)
}
/>
}
label="Die Fakultät ist über den Antrag informiert"
required
/>
)}
</FormGroup>
</Paper>
{/* Kostenpositionen Section */} {/* Kostenpositionen Section */}
<Paper variant="outlined" sx={{ p: 3, mb: 3 }}> <Paper variant="outlined" sx={{ p: 3, mb: 3 }}>
<Typography <Typography

View File

@ -319,14 +319,36 @@ const AdminApplicationView: React.FC = () => {
<Typography variant="subtitle2" color="text.secondary"> <Typography variant="subtitle2" color="text.secondary">
E-Mail E-Mail
</Typography> </Typography>
<Typography variant="body1">{formData.email}</Typography> <Typography variant="body1">
{formData.email ? (
<a
href={`mailto:${formData.email}`}
style={{ color: "inherit" }}
>
{formData.email}
</a>
) : (
"-"
)}
</Typography>
</Grid> </Grid>
<Grid item xs={12} sm={6}> <Grid item xs={12} sm={6}>
<Typography variant="subtitle2" color="text.secondary"> <Typography variant="subtitle2" color="text.secondary">
Telefon Telefon
</Typography> </Typography>
<Typography variant="body1">{formData.phone || "-"}</Typography> <Typography variant="body1">
{formData.phone ? (
<a
href={`tel:${formData.phone}`}
style={{ color: "inherit" }}
>
{formData.phone}
</a>
) : (
"-"
)}
</Typography>
</Grid> </Grid>
<Grid item xs={12} sm={6}> <Grid item xs={12} sm={6}>
@ -428,12 +450,21 @@ const AdminApplicationView: React.FC = () => {
: "Erfüllte Aufgabe der VS nach §65 des Landeshochschulgesetzes"} : "Erfüllte Aufgabe der VS nach §65 des Landeshochschulgesetzes"}
</Typography> </Typography>
<Typography variant="body1"> <Typography variant="body1">
{currentApplication.variant === "QSM" && formData.qsmFinancing {currentApplication.variant === "QSM" &&
? QSM_FINANCING_LABELS[formData.qsmFinancing] || (formData.financingCode || formData.qsmFinancing)
? QSM_FINANCING_LABELS[
(formData.financingCode ||
formData.qsmFinancing) as keyof typeof QSM_FINANCING_LABELS
] ||
formData.financingCode ||
formData.qsmFinancing formData.qsmFinancing
: currentApplication.variant === "VSM" && : currentApplication.variant === "VSM" &&
formData.vsmFinancing (formData.financingCode || formData.vsmFinancing)
? VSM_FINANCING_LABELS[formData.vsmFinancing] || ? VSM_FINANCING_LABELS[
(formData.financingCode ||
formData.vsmFinancing) as keyof typeof VSM_FINANCING_LABELS
] ||
formData.financingCode ||
formData.vsmFinancing formData.vsmFinancing
: "-"} : "-"}
</Typography> </Typography>

View File

@ -282,6 +282,24 @@ const ViewApplicationPage: React.FC = () => {
</Typography> </Typography>
</Grid> </Grid>
<Grid item xs={12} sm={6}>
<Typography variant="subtitle2" color="text.secondary">
Telefon
</Typography>
<Typography variant="body1">
{formData.phone ? (
<a
href={`tel:${formData.phone}`}
style={{ color: "inherit" }}
>
{formData.phone}
</a>
) : (
"-"
)}
</Typography>
</Grid>
<Grid item xs={12} sm={6}> <Grid item xs={12} sm={6}>
<Typography variant="subtitle2" color="text.secondary"> <Typography variant="subtitle2" color="text.secondary">
Institution Institution
@ -370,16 +388,25 @@ const ViewApplicationPage: React.FC = () => {
<Paper sx={{ p: 3, mb: 3 }}> <Paper sx={{ p: 3, mb: 3 }}>
<Typography variant="h6" gutterBottom> <Typography variant="h6" gutterBottom>
{currentApplication.variant === "QSM" {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"} : "Erfüllte Aufgabe der VS nach §65 des Landeshochschulgesetzes"}
</Typography> </Typography>
<Typography variant="body1"> <Typography variant="body1">
{currentApplication.variant === "QSM" && formData.qsmFinancing {currentApplication.variant === "QSM" &&
? QSM_FINANCING_LABELS[formData.qsmFinancing] || (formData.financingCode || formData.qsmFinancing)
? QSM_FINANCING_LABELS[
(formData.financingCode ||
formData.qsmFinancing) as keyof typeof QSM_FINANCING_LABELS
] ||
formData.financingCode ||
formData.qsmFinancing formData.qsmFinancing
: currentApplication.variant === "VSM" && : currentApplication.variant === "VSM" &&
formData.vsmFinancing (formData.financingCode || formData.vsmFinancing)
? VSM_FINANCING_LABELS[formData.vsmFinancing] || ? VSM_FINANCING_LABELS[
(formData.financingCode ||
formData.vsmFinancing) as keyof typeof VSM_FINANCING_LABELS
] ||
formData.financingCode ||
formData.vsmFinancing formData.vsmFinancing
: "-"} : "-"}
</Typography> </Typography>

View File

@ -1198,8 +1198,12 @@ function createFormJsonFromData(formData: Partial<FormData>): string {
} }
// Add variant-specific fields // Add variant-specific fields
if (formData.variant === "QSM" && formData.qsmFinancing) { if (formData.variant === "QSM") {
formJson["pa-qsm-financing"] = { "/V": formData.qsmFinancing }; if (formData.financingCode || formData.qsmFinancing) {
formJson["pa-qsm-financing"] = {
"/V": formData.financingCode || formData.qsmFinancing,
};
}
if (formData.qsmFlags) { if (formData.qsmFlags) {
formJson["pa-qsm-stellenfinanzierungen"] = { formJson["pa-qsm-stellenfinanzierungen"] = {
"/V": formData.qsmFlags.stellenfinanzierungen, "/V": formData.qsmFlags.stellenfinanzierungen,
@ -1213,14 +1217,28 @@ function createFormJsonFromData(formData: Partial<FormData>): string {
"/V": formData.qsmFlags.exkursionBezuschusst, "/V": formData.qsmFlags.exkursionBezuschusst,
}; };
} }
} else if (formData.variant === "VSM" && formData.vsmFinancing) { } else if (formData.variant === "VSM") {
formJson["pa-vsm-financing"] = { "/V": formData.vsmFinancing }; if (formData.financingCode || formData.vsmFinancing) {
formJson["pa-vsm-financing"] = {
"/V": formData.financingCode || formData.vsmFinancing,
};
}
if (formData.vsmFlags) { if (formData.vsmFlags) {
formJson["pa-vsm-aufgaben"] = { "/V": formData.vsmFlags.aufgaben }; formJson["pa-vsm-aufgaben"] = { "/V": formData.vsmFlags.aufgaben };
formJson["pa-vsm-individuell"] = { "/V": formData.vsmFlags.individuell }; 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); const jsonString = JSON.stringify(formJson);
return btoa(unescape(encodeURIComponent(jsonString))); // Base64 encode with UTF-8 support return btoa(unescape(encodeURIComponent(jsonString))); // Base64 encode with UTF-8 support
} }
@ -1258,11 +1276,13 @@ function convertPayloadToFormData(payload: RootPayload): Partial<FormData> {
name: cost.name || "", name: cost.name || "",
amountEur: cost.amountEur || 0, amountEur: cost.amountEur || 0,
})), })),
variant: (pa.project.financing.qsm variant: (pa.project.financing.vsm?.code
? "QSM" ? "VSM"
: pa.project.financing.vsm : pa.project.financing.qsm?.code
? "VSM" ? "QSM"
: "COMMON") as Variant, : "COMMON") as Variant,
financingCode:
pa.project.financing.qsm?.code || pa.project.financing.vsm?.code || "",
qsmFinancing: pa.project.financing.qsm?.code as any, qsmFinancing: pa.project.financing.qsm?.code as any,
qsmFlags: pa.project.financing.qsm?.flags qsmFlags: pa.project.financing.qsm?.flags
? { ? {

View File

@ -284,6 +284,7 @@ export interface FormData {
// Financing // Financing
variant: Variant; variant: Variant;
financingCode?: string;
qsmFinancing?: QSMFinancingCode; qsmFinancing?: QSMFinancingCode;
qsmFlags?: { qsmFlags?: {
stellenfinanzierungen: boolean; stellenfinanzierungen: boolean;

View File

@ -155,7 +155,7 @@ def fill_pdf(payload: Dict[str, Any], variant: str, out_path: Optional[str] = No
writer.add_page(p) writer.add_page(p)
# Flatten payload first # Flatten payload first
mapping = core._merge_mapping(variant) mapping = core._merge_mapping(variant, {})
flat = _flatten(payload) flat = _flatten(payload)
# Calculate total amount from costs # Calculate total amount from costs

View File

@ -239,8 +239,23 @@ def _set_nested(root: Dict[str, Any], dotted: str, value: Any) -> None:
curr[part] = {} curr[part] = {}
curr = 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() 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": if v == "QSM":
return {**TEXT_MAPPING_COMMON, **TEXT_MAPPING_QSM} return {**TEXT_MAPPING_COMMON, **TEXT_MAPPING_QSM}
if v == "VSM": if v == "VSM":
@ -259,13 +274,14 @@ def detect_variant(form_fields: Mapping[str, Any]) -> str:
return "VSM" return "VSM"
return "COMMON" return "COMMON"
def map_form_to_payload(form_json: Dict[str, Dict[str, Any]], variant: str) -> Dict[str, Any]: 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 Map PDF-like form JSON (fieldName -> dict with '/V', etc.) to nested payload
using TEXT_MAPPING_* dicts. Unknown/empty fields are skipped. 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] = {} out: Dict[str, Any] = {}
# Pre-collect costs # Pre-collect costs