feat: Extend React/Java app to match Lua functionality
Backend: - Add Pretreatment record for pre-treatment data - Extend Sample with pretreatment, clinicalExamDate, internalNote - Extend TherapyRecommendation with detail fields (count, duration, dosage, location) - Add startvacVaccination and noAntibioticTreatment flags - Add null-safety defaults for MongoDB compatibility Frontend: - Add pretreatment fields to SampleRegistrationPage - Add special pathogens section to AnamnesisPage - Add therapy detail pickers to TherapyPage - Improve AntibiogramPage: full text labels, centered headers - Fix AdminDashboardPage TypeScript error in chart tooltip Styling: - Enlarge matrix buttons for S/I/R text - Add matrix-col class for centered table columns
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
package de.svencarstensen.muh.domain;
|
||||
|
||||
public record Pretreatment(
|
||||
String inUdderInjector,
|
||||
String systemicAntibiotics,
|
||||
String painMedication,
|
||||
String dryOffTreatment
|
||||
) {
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package de.svencarstensen.muh.domain;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@@ -29,6 +30,10 @@ public record Sample(
|
||||
LocalDateTime completedAt,
|
||||
String ownerAccountId,
|
||||
String createdByUserCode,
|
||||
String createdByDisplayName
|
||||
String createdByDisplayName,
|
||||
// Additional fields from Lua version
|
||||
Pretreatment pretreatment,
|
||||
LocalDate clinicalExamDate,
|
||||
String internalNote
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -16,6 +16,15 @@ public record TherapyRecommendation(
|
||||
List<String> dryAntibioticKeys,
|
||||
List<String> dryAntibioticNames,
|
||||
String farmerNote,
|
||||
String internalNote
|
||||
String internalNote,
|
||||
// Additional fields from Lua version
|
||||
String inUdderCount,
|
||||
String inUdderDuration,
|
||||
String systemicCount,
|
||||
String systemicDuration,
|
||||
String systemicDosage,
|
||||
String systemicLocation,
|
||||
Boolean startvacVaccination,
|
||||
Boolean noAntibioticTreatment
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -537,7 +537,7 @@ public class CatalogService {
|
||||
return toSessionResponse(user);
|
||||
}
|
||||
|
||||
public SessionResponse registerCustomer(RegistrationMutation mutation) {
|
||||
public RegistrationResponse registerCustomer(RegistrationMutation mutation) {
|
||||
if (isBlank(mutation.companyName())
|
||||
|| isBlank(mutation.street())
|
||||
|| isBlank(mutation.houseNumber())
|
||||
|
||||
@@ -4,6 +4,7 @@ import de.svencarstensen.muh.domain.AntibiogramEntry;
|
||||
import de.svencarstensen.muh.domain.AppUser;
|
||||
import de.svencarstensen.muh.domain.PathogenCatalogItem;
|
||||
import de.svencarstensen.muh.domain.PathogenKind;
|
||||
import de.svencarstensen.muh.domain.Pretreatment;
|
||||
import de.svencarstensen.muh.domain.QuarterAntibiogram;
|
||||
import de.svencarstensen.muh.domain.QuarterFinding;
|
||||
import de.svencarstensen.muh.domain.QuarterKey;
|
||||
@@ -22,6 +23,8 @@ import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
@@ -105,6 +108,18 @@ public class SampleService {
|
||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Landwirt nicht gefunden"));
|
||||
|
||||
long sampleNumber = reserveNextSampleNumber(actorId);
|
||||
Pretreatment pretreatment = request.pretreatmentInUdderInjector() == null &&
|
||||
request.pretreatmentSystemicAntibiotics() == null &&
|
||||
request.pretreatmentPainMedication() == null &&
|
||||
request.pretreatmentDryOffTreatment() == null
|
||||
? null
|
||||
: new Pretreatment(
|
||||
blankToNull(request.pretreatmentInUdderInjector()),
|
||||
blankToNull(request.pretreatmentSystemicAntibiotics()),
|
||||
blankToNull(request.pretreatmentPainMedication()),
|
||||
blankToNull(request.pretreatmentDryOffTreatment())
|
||||
);
|
||||
|
||||
Sample sample = new Sample(
|
||||
null,
|
||||
sampleNumber,
|
||||
@@ -127,7 +142,10 @@ public class SampleService {
|
||||
null,
|
||||
authorizationService.accountId(actor),
|
||||
request.userCode(),
|
||||
request.userDisplayName()
|
||||
request.userDisplayName(),
|
||||
pretreatment,
|
||||
parseClinicalExamDate(request.clinicalExamDate()),
|
||||
blankToNull(request.internalNote())
|
||||
);
|
||||
|
||||
return toDetail(sampleRepository.save(sample));
|
||||
@@ -144,6 +162,18 @@ public class SampleService {
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Landwirt nicht gefunden"));
|
||||
|
||||
Pretreatment pretreatment = request.pretreatmentInUdderInjector() == null &&
|
||||
request.pretreatmentSystemicAntibiotics() == null &&
|
||||
request.pretreatmentPainMedication() == null &&
|
||||
request.pretreatmentDryOffTreatment() == null
|
||||
? existing.pretreatment()
|
||||
: new Pretreatment(
|
||||
blankToNull(request.pretreatmentInUdderInjector()),
|
||||
blankToNull(request.pretreatmentSystemicAntibiotics()),
|
||||
blankToNull(request.pretreatmentPainMedication()),
|
||||
blankToNull(request.pretreatmentDryOffTreatment())
|
||||
);
|
||||
|
||||
Sample saved = sampleRepository.save(new Sample(
|
||||
existing.id(),
|
||||
existing.sampleNumber(),
|
||||
@@ -166,7 +196,14 @@ public class SampleService {
|
||||
existing.completedAt(),
|
||||
existing.ownerAccountId(),
|
||||
existing.createdByUserCode(),
|
||||
existing.createdByDisplayName()
|
||||
existing.createdByDisplayName(),
|
||||
pretreatment,
|
||||
parseClinicalExamDate(request.clinicalExamDate()) != null
|
||||
? parseClinicalExamDate(request.clinicalExamDate())
|
||||
: existing.clinicalExamDate(),
|
||||
request.internalNote() != null
|
||||
? blankToNull(request.internalNote())
|
||||
: existing.internalNote()
|
||||
));
|
||||
|
||||
return toDetail(saved);
|
||||
@@ -233,7 +270,10 @@ public class SampleService {
|
||||
existing.completedAt(),
|
||||
existing.ownerAccountId(),
|
||||
existing.createdByUserCode(),
|
||||
existing.createdByDisplayName()
|
||||
existing.createdByDisplayName(),
|
||||
existing.pretreatment(),
|
||||
existing.clinicalExamDate(),
|
||||
existing.internalNote()
|
||||
));
|
||||
return toDetail(saved);
|
||||
}
|
||||
@@ -324,7 +364,10 @@ public class SampleService {
|
||||
existing.completedAt(),
|
||||
existing.ownerAccountId(),
|
||||
existing.createdByUserCode(),
|
||||
existing.createdByDisplayName()
|
||||
existing.createdByDisplayName(),
|
||||
existing.pretreatment(),
|
||||
existing.clinicalExamDate(),
|
||||
existing.internalNote()
|
||||
));
|
||||
return toDetail(saved);
|
||||
}
|
||||
@@ -334,7 +377,7 @@ public class SampleService {
|
||||
if (existing.currentStep() == SampleWorkflowStep.COMPLETED) {
|
||||
TherapyRecommendation previous = existing.therapyRecommendation();
|
||||
TherapyRecommendation updated = previous == null
|
||||
? new TherapyRecommendation(false, false, List.of(), List.of(), null, List.of(), List.of(), null, List.of(), List.of(), List.of(), List.of(), null, blankToNull(request.internalNote()))
|
||||
? new TherapyRecommendation(false, false, List.of(), List.of(), null, List.of(), List.of(), null, List.of(), List.of(), List.of(), List.of(), null, blankToNull(request.internalNote()), null, null, null, null, null, null, Boolean.FALSE, Boolean.FALSE)
|
||||
: new TherapyRecommendation(
|
||||
previous.continueStarted(),
|
||||
previous.switchTherapy(),
|
||||
@@ -349,7 +392,15 @@ public class SampleService {
|
||||
previous.dryAntibioticKeys(),
|
||||
previous.dryAntibioticNames(),
|
||||
previous.farmerNote(),
|
||||
blankToNull(request.internalNote())
|
||||
blankToNull(request.internalNote()),
|
||||
previous.inUdderCount(),
|
||||
previous.inUdderDuration(),
|
||||
previous.systemicCount(),
|
||||
previous.systemicDuration(),
|
||||
previous.systemicDosage(),
|
||||
previous.systemicLocation(),
|
||||
previous.startvacVaccination() != null ? previous.startvacVaccination() : Boolean.FALSE,
|
||||
previous.noAntibioticTreatment() != null ? previous.noAntibioticTreatment() : Boolean.FALSE
|
||||
);
|
||||
return toDetail(sampleRepository.save(new Sample(
|
||||
existing.id(),
|
||||
@@ -373,7 +424,10 @@ public class SampleService {
|
||||
existing.completedAt(),
|
||||
existing.ownerAccountId(),
|
||||
existing.createdByUserCode(),
|
||||
existing.createdByDisplayName()
|
||||
existing.createdByDisplayName(),
|
||||
existing.pretreatment(),
|
||||
existing.clinicalExamDate(),
|
||||
existing.internalNote()
|
||||
)));
|
||||
}
|
||||
|
||||
@@ -396,7 +450,15 @@ public class SampleService {
|
||||
request.dryAntibioticKeys(),
|
||||
resolveMedicationNames(request.dryAntibioticKeys(), medications),
|
||||
blankToNull(request.farmerNote()),
|
||||
blankToNull(request.internalNote())
|
||||
blankToNull(request.internalNote()),
|
||||
blankToNull(request.inUdderCount()),
|
||||
blankToNull(request.inUdderDuration()),
|
||||
blankToNull(request.systemicCount()),
|
||||
blankToNull(request.systemicDuration()),
|
||||
blankToNull(request.systemicDosage()),
|
||||
blankToNull(request.systemicLocation()),
|
||||
request.startvacVaccination(),
|
||||
request.noAntibioticTreatment()
|
||||
);
|
||||
|
||||
Sample saved = sampleRepository.save(new Sample(
|
||||
@@ -421,7 +483,10 @@ public class SampleService {
|
||||
LocalDateTime.now(),
|
||||
existing.ownerAccountId(),
|
||||
existing.createdByUserCode(),
|
||||
existing.createdByDisplayName()
|
||||
existing.createdByDisplayName(),
|
||||
existing.pretreatment(),
|
||||
existing.clinicalExamDate(),
|
||||
existing.internalNote()
|
||||
));
|
||||
return toDetail(saved);
|
||||
}
|
||||
@@ -450,7 +515,10 @@ public class SampleService {
|
||||
existing.completedAt(),
|
||||
existing.ownerAccountId(),
|
||||
existing.createdByUserCode(),
|
||||
existing.createdByDisplayName()
|
||||
existing.createdByDisplayName(),
|
||||
existing.pretreatment(),
|
||||
existing.clinicalExamDate(),
|
||||
existing.internalNote()
|
||||
));
|
||||
}
|
||||
|
||||
@@ -478,7 +546,10 @@ public class SampleService {
|
||||
existing.completedAt(),
|
||||
existing.ownerAccountId(),
|
||||
existing.createdByUserCode(),
|
||||
existing.createdByDisplayName()
|
||||
existing.createdByDisplayName(),
|
||||
existing.pretreatment(),
|
||||
existing.clinicalExamDate(),
|
||||
existing.internalNote()
|
||||
));
|
||||
}
|
||||
|
||||
@@ -643,7 +714,10 @@ public class SampleService {
|
||||
sample.completedAt(),
|
||||
resolvedAccountId,
|
||||
sample.createdByUserCode(),
|
||||
sample.createdByDisplayName()
|
||||
sample.createdByDisplayName(),
|
||||
sample.pretreatment(),
|
||||
sample.clinicalExamDate(),
|
||||
sample.internalNote()
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -737,7 +811,10 @@ public class SampleService {
|
||||
SampleWorkflowRules.canEditAnamnesis(sample),
|
||||
SampleWorkflowRules.canEditAntibiogram(sample),
|
||||
SampleWorkflowRules.canEditTherapy(sample),
|
||||
sample.currentStep() == SampleWorkflowStep.COMPLETED
|
||||
sample.currentStep() == SampleWorkflowStep.COMPLETED,
|
||||
sample.pretreatment(),
|
||||
sample.clinicalExamDate(),
|
||||
sample.internalNote()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -759,7 +836,15 @@ public class SampleService {
|
||||
therapy.dryAntibioticKeys(),
|
||||
therapy.dryAntibioticNames(),
|
||||
therapy.farmerNote(),
|
||||
therapy.internalNote()
|
||||
therapy.internalNote(),
|
||||
therapy.inUdderCount(),
|
||||
therapy.inUdderDuration(),
|
||||
therapy.systemicCount(),
|
||||
therapy.systemicDuration(),
|
||||
therapy.systemicDosage(),
|
||||
therapy.systemicLocation(),
|
||||
therapy.startvacVaccination() != null ? therapy.startvacVaccination() : Boolean.FALSE,
|
||||
therapy.noAntibioticTreatment() != null ? therapy.noAntibioticTreatment() : Boolean.FALSE
|
||||
);
|
||||
}
|
||||
|
||||
@@ -877,7 +962,15 @@ public class SampleService {
|
||||
List<String> dryAntibioticKeys,
|
||||
List<String> dryAntibioticNames,
|
||||
String farmerNote,
|
||||
String internalNote
|
||||
String internalNote,
|
||||
String inUdderCount,
|
||||
String inUdderDuration,
|
||||
String systemicCount,
|
||||
String systemicDuration,
|
||||
String systemicDosage,
|
||||
String systemicLocation,
|
||||
Boolean startvacVaccination,
|
||||
Boolean noAntibioticTreatment
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -909,7 +1002,10 @@ public class SampleService {
|
||||
boolean anamnesisEditable,
|
||||
boolean antibiogramEditable,
|
||||
boolean therapyEditable,
|
||||
boolean completed
|
||||
boolean completed,
|
||||
Pretreatment pretreatment,
|
||||
LocalDate clinicalExamDate,
|
||||
String internalNote
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -921,7 +1017,13 @@ public class SampleService {
|
||||
SamplingMode samplingMode,
|
||||
List<QuarterKey> flaggedQuarters,
|
||||
String userCode,
|
||||
String userDisplayName
|
||||
String userDisplayName,
|
||||
String pretreatmentInUdderInjector,
|
||||
String pretreatmentSystemicAntibiotics,
|
||||
String pretreatmentPainMedication,
|
||||
String pretreatmentDryOffTreatment,
|
||||
String clinicalExamDate,
|
||||
String internalNote
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -955,7 +1057,33 @@ public class SampleService {
|
||||
List<String> drySealerKeys,
|
||||
List<String> dryAntibioticKeys,
|
||||
String farmerNote,
|
||||
String internalNote
|
||||
String internalNote,
|
||||
String inUdderCount,
|
||||
String inUdderDuration,
|
||||
String systemicCount,
|
||||
String systemicDuration,
|
||||
String systemicDosage,
|
||||
String systemicLocation,
|
||||
Boolean startvacVaccination,
|
||||
Boolean noAntibioticTreatment
|
||||
) {
|
||||
}
|
||||
|
||||
private LocalDate parseClinicalExamDate(String dateStr) {
|
||||
if (dateStr == null || dateStr.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
// Try ISO format first (YYYY-MM-DD)
|
||||
return LocalDate.parse(dateStr);
|
||||
} catch (DateTimeParseException e) {
|
||||
try {
|
||||
// Try German format (DD.MM.YYYY)
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
|
||||
return LocalDate.parse(dateStr, formatter);
|
||||
} catch (DateTimeParseException e2) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,13 @@ public class SampleController {
|
||||
request.samplingMode(),
|
||||
request.flaggedQuarters(),
|
||||
deriveUserLabel(user.displayName()),
|
||||
user.displayName()
|
||||
user.displayName(),
|
||||
request.pretreatmentInUdderInjector(),
|
||||
request.pretreatmentSystemicAntibiotics(),
|
||||
request.pretreatmentPainMedication(),
|
||||
request.pretreatmentDryOffTreatment(),
|
||||
request.clinicalExamDate(),
|
||||
request.internalNote()
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user