feat: extend farmer data model with complete address fields and customer number
Backend: - Add customerNumber, companyName, contactPerson, street, houseNumber, postalCode, city, phoneNumber to Farmer domain model - Update FarmerRow and FarmerMutation records with new fields - Update repositories, services and controllers for new farmer structure - Fix CORS configuration to allow credentials - Remove unused authorizationService and imports - Update data migration for new farmer schema Frontend: - Update FarmerRow and FarmerOption interfaces - Extend AdministrationPage with new farmer form fields - Update SampleRegistrationPage and SearchFarmerPage for new structure
This commit is contained in:
@@ -18,7 +18,8 @@ public class CorsConfig {
|
||||
configuration.setAllowedOrigins(allowedOrigins);
|
||||
configuration.setAllowedHeaders(List.of("*"));
|
||||
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
|
||||
configuration.setAllowCredentials(false);
|
||||
configuration.setAllowCredentials(true);
|
||||
configuration.setExposedHeaders(List.of("Authorization"));
|
||||
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/api/**", configuration);
|
||||
|
||||
@@ -10,8 +10,15 @@ public record Farmer(
|
||||
@Id String id,
|
||||
String accountId,
|
||||
String businessKey,
|
||||
String name,
|
||||
String customerNumber,
|
||||
String companyName,
|
||||
String contactPerson,
|
||||
String street,
|
||||
String houseNumber,
|
||||
String postalCode,
|
||||
String city,
|
||||
String email,
|
||||
String phoneNumber,
|
||||
boolean active,
|
||||
String supersedesId,
|
||||
LocalDateTime createdAt,
|
||||
|
||||
@@ -6,11 +6,11 @@ import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import java.util.List;
|
||||
|
||||
public interface FarmerRepository extends MongoRepository<Farmer, String> {
|
||||
List<Farmer> findByActiveTrueOrderByNameAsc();
|
||||
List<Farmer> findByActiveTrueOrderByCompanyNameAsc();
|
||||
|
||||
List<Farmer> findByAccountIdOrderByNameAsc(String accountId);
|
||||
List<Farmer> findByAccountIdOrderByCompanyNameAsc(String accountId);
|
||||
|
||||
List<Farmer> findByAccountIdAndActiveTrueOrderByNameAsc(String accountId);
|
||||
List<Farmer> findByAccountIdAndActiveTrueOrderByCompanyNameAsc(String accountId);
|
||||
|
||||
List<Farmer> findByNameContainingIgnoreCaseOrderByNameAsc(String name);
|
||||
List<Farmer> findByCompanyNameContainingIgnoreCaseOrderByCompanyNameAsc(String companyName);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import de.svencarstensen.muh.repository.FarmerRepository;
|
||||
import de.svencarstensen.muh.repository.MedicationCatalogRepository;
|
||||
import de.svencarstensen.muh.repository.PathogenCatalogRepository;
|
||||
import de.svencarstensen.muh.security.AuthTokenService;
|
||||
import de.svencarstensen.muh.security.AuthorizationService;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
@@ -42,7 +41,7 @@ public class CatalogService {
|
||||
|
||||
private static final Comparator<FarmerRow> FARMER_ROW_COMPARATOR = Comparator
|
||||
.comparing(FarmerRow::active).reversed()
|
||||
.thenComparing(FarmerRow::name, String.CASE_INSENSITIVE_ORDER)
|
||||
.thenComparing(FarmerRow::companyName, String.CASE_INSENSITIVE_ORDER)
|
||||
.thenComparing(FarmerRow::updatedAt, Comparator.nullsLast(Comparator.reverseOrder()));
|
||||
|
||||
private static final Comparator<MedicationRow> MEDICATION_ROW_COMPARATOR = Comparator
|
||||
@@ -67,7 +66,6 @@ public class CatalogService {
|
||||
private final AppUserRepository appUserRepository;
|
||||
private final MongoTemplate mongoTemplate;
|
||||
private final AuthTokenService authTokenService;
|
||||
private final AuthorizationService authorizationService;
|
||||
private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
|
||||
public CatalogService(
|
||||
@@ -77,8 +75,7 @@ public class CatalogService {
|
||||
AntibioticCatalogRepository antibioticRepository,
|
||||
AppUserRepository appUserRepository,
|
||||
MongoTemplate mongoTemplate,
|
||||
AuthTokenService authTokenService,
|
||||
AuthorizationService authorizationService
|
||||
AuthTokenService authTokenService
|
||||
) {
|
||||
this.farmerRepository = farmerRepository;
|
||||
this.medicationRepository = medicationRepository;
|
||||
@@ -87,7 +84,6 @@ public class CatalogService {
|
||||
this.appUserRepository = appUserRepository;
|
||||
this.mongoTemplate = mongoTemplate;
|
||||
this.authTokenService = authTokenService;
|
||||
this.authorizationService = authorizationService;
|
||||
}
|
||||
|
||||
public ActiveCatalogSummary activeCatalogSummary(String actorId) {
|
||||
@@ -113,7 +109,7 @@ public class CatalogService {
|
||||
|
||||
// Hilfsmethoden für Datenzugriff (immer nur eigene Daten des Hauptbenutzers)
|
||||
private List<Farmer> listActiveFarmersForActor(AppUser actor) {
|
||||
return farmerRepository.findByAccountIdAndActiveTrueOrderByNameAsc(resolveAccountId(actor));
|
||||
return farmerRepository.findByAccountIdAndActiveTrueOrderByCompanyNameAsc(resolveAccountId(actor));
|
||||
}
|
||||
|
||||
private List<MedicationCatalogItem> listActiveMedicationsForActor(AppUser actor) {
|
||||
@@ -129,7 +125,7 @@ public class CatalogService {
|
||||
}
|
||||
|
||||
private List<FarmerRow> listFarmerRowsForActor(AppUser actor) {
|
||||
return farmerRepository.findByAccountIdOrderByNameAsc(resolveAccountId(actor)).stream()
|
||||
return farmerRepository.findByAccountIdOrderByCompanyNameAsc(resolveAccountId(actor)).stream()
|
||||
.map(this::toFarmerRow)
|
||||
.sorted(FARMER_ROW_COMPARATOR)
|
||||
.toList();
|
||||
@@ -160,7 +156,7 @@ public class CatalogService {
|
||||
AppUser actor = requireActiveActor(actorId, "Nicht berechtigt");
|
||||
String accountId = resolveAccountId(actor);
|
||||
for (FarmerMutation mutation : mutations) {
|
||||
if (isBlank(mutation.name())) {
|
||||
if (isBlank(mutation.companyName())) {
|
||||
continue;
|
||||
}
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
@@ -169,8 +165,15 @@ public class CatalogService {
|
||||
null,
|
||||
accountId,
|
||||
UUID.randomUUID().toString(),
|
||||
mutation.name().trim(),
|
||||
blankToNull(mutation.customerNumber()),
|
||||
mutation.companyName().trim(),
|
||||
blankToNull(mutation.contactPerson()),
|
||||
blankToNull(mutation.street()),
|
||||
blankToNull(mutation.houseNumber()),
|
||||
blankToNull(mutation.postalCode()),
|
||||
blankToNull(mutation.city()),
|
||||
blankToNull(mutation.email()),
|
||||
blankToNull(mutation.phoneNumber()),
|
||||
mutation.active(),
|
||||
null,
|
||||
now,
|
||||
@@ -185,15 +188,29 @@ public class CatalogService {
|
||||
if (!accountId.equals(existing.accountId())) {
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Nicht berechtigt");
|
||||
}
|
||||
boolean changed = !existing.name().equals(mutation.name().trim())
|
||||
|| !safeEquals(existing.email(), blankToNull(mutation.email()));
|
||||
boolean changed = !existing.companyName().equals(mutation.companyName().trim())
|
||||
|| !safeEquals(existing.customerNumber(), blankToNull(mutation.customerNumber()))
|
||||
|| !safeEquals(existing.contactPerson(), blankToNull(mutation.contactPerson()))
|
||||
|| !safeEquals(existing.street(), blankToNull(mutation.street()))
|
||||
|| !safeEquals(existing.houseNumber(), blankToNull(mutation.houseNumber()))
|
||||
|| !safeEquals(existing.postalCode(), blankToNull(mutation.postalCode()))
|
||||
|| !safeEquals(existing.city(), blankToNull(mutation.city()))
|
||||
|| !safeEquals(existing.email(), blankToNull(mutation.email()))
|
||||
|| !safeEquals(existing.phoneNumber(), blankToNull(mutation.phoneNumber()));
|
||||
if (changed) {
|
||||
farmerRepository.save(new Farmer(
|
||||
existing.id(),
|
||||
existing.accountId(),
|
||||
existing.businessKey(),
|
||||
existing.name(),
|
||||
existing.customerNumber(),
|
||||
existing.companyName(),
|
||||
existing.contactPerson(),
|
||||
existing.street(),
|
||||
existing.houseNumber(),
|
||||
existing.postalCode(),
|
||||
existing.city(),
|
||||
existing.email(),
|
||||
existing.phoneNumber(),
|
||||
false,
|
||||
existing.supersedesId(),
|
||||
existing.createdAt(),
|
||||
@@ -203,8 +220,15 @@ public class CatalogService {
|
||||
null,
|
||||
existing.accountId(),
|
||||
existing.businessKey(),
|
||||
mutation.name().trim(),
|
||||
blankToNull(mutation.customerNumber()),
|
||||
mutation.companyName().trim(),
|
||||
blankToNull(mutation.contactPerson()),
|
||||
blankToNull(mutation.street()),
|
||||
blankToNull(mutation.houseNumber()),
|
||||
blankToNull(mutation.postalCode()),
|
||||
blankToNull(mutation.city()),
|
||||
blankToNull(mutation.email()),
|
||||
blankToNull(mutation.phoneNumber()),
|
||||
mutation.active(),
|
||||
existing.id(),
|
||||
now,
|
||||
@@ -217,8 +241,15 @@ public class CatalogService {
|
||||
existing.id(),
|
||||
existing.accountId(),
|
||||
existing.businessKey(),
|
||||
existing.name(),
|
||||
existing.customerNumber(),
|
||||
existing.companyName(),
|
||||
existing.contactPerson(),
|
||||
existing.street(),
|
||||
existing.houseNumber(),
|
||||
existing.postalCode(),
|
||||
existing.city(),
|
||||
existing.email(),
|
||||
existing.phoneNumber(),
|
||||
mutation.active(),
|
||||
existing.supersedesId(),
|
||||
existing.createdAt(),
|
||||
@@ -746,8 +777,15 @@ public class CatalogService {
|
||||
return new FarmerRow(
|
||||
farmer.id(),
|
||||
farmer.businessKey(),
|
||||
farmer.name(),
|
||||
farmer.customerNumber(),
|
||||
farmer.companyName(),
|
||||
farmer.contactPerson(),
|
||||
farmer.street(),
|
||||
farmer.houseNumber(),
|
||||
farmer.postalCode(),
|
||||
farmer.city(),
|
||||
farmer.email(),
|
||||
farmer.phoneNumber(),
|
||||
farmer.active(),
|
||||
farmer.updatedAt()
|
||||
);
|
||||
@@ -812,7 +850,7 @@ public class CatalogService {
|
||||
}
|
||||
|
||||
private FarmerOption toFarmerOption(Farmer farmer) {
|
||||
return new FarmerOption(farmer.businessKey(), farmer.name(), farmer.email());
|
||||
return new FarmerOption(farmer.businessKey(), farmer.companyName(), farmer.contactPerson(), farmer.email());
|
||||
}
|
||||
|
||||
private MedicationOption toMedicationOption(MedicationCatalogItem item) {
|
||||
@@ -1077,20 +1115,31 @@ public class CatalogService {
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
// Migriere Farmers ohne accountId
|
||||
// Migriere Farmers ohne accountId oder mit altem Schema
|
||||
farmerRepository.findAll().stream()
|
||||
.filter(farmer -> isBlank(farmer.accountId()))
|
||||
.forEach(farmer -> farmerRepository.save(new Farmer(
|
||||
farmer.id(),
|
||||
defaultAccountId,
|
||||
farmer.businessKey(),
|
||||
farmer.name(),
|
||||
farmer.email(),
|
||||
farmer.active(),
|
||||
farmer.supersedesId(),
|
||||
farmer.createdAt(),
|
||||
now
|
||||
)));
|
||||
.filter(farmer -> isBlank(farmer.accountId()) || isBlank(farmer.companyName()))
|
||||
.forEach(farmer -> {
|
||||
// Wenn companyName fehlt, nutze businessKey als Fallback
|
||||
String companyName = isBlank(farmer.companyName()) ? farmer.businessKey() : farmer.companyName();
|
||||
farmerRepository.save(new Farmer(
|
||||
farmer.id(),
|
||||
isBlank(farmer.accountId()) ? defaultAccountId : farmer.accountId(),
|
||||
farmer.businessKey(),
|
||||
null, // customerNumber
|
||||
companyName,
|
||||
null, // contactPerson
|
||||
null, // street
|
||||
null, // houseNumber
|
||||
null, // postalCode
|
||||
null, // city
|
||||
farmer.email(),
|
||||
null, // phoneNumber
|
||||
farmer.active(),
|
||||
farmer.supersedesId(),
|
||||
farmer.createdAt(),
|
||||
now
|
||||
));
|
||||
});
|
||||
|
||||
// Migriere Medications ohne accountId
|
||||
medicationRepository.findAll().stream()
|
||||
@@ -1213,7 +1262,7 @@ public class CatalogService {
|
||||
) {
|
||||
}
|
||||
|
||||
public record FarmerOption(String businessKey, String name, String email) {
|
||||
public record FarmerOption(String businessKey, String companyName, String contactPerson, String email) {
|
||||
}
|
||||
|
||||
public record MedicationOption(String businessKey, String name, MedicationCategory category) {
|
||||
@@ -1249,14 +1298,33 @@ public class CatalogService {
|
||||
public record FarmerRow(
|
||||
String id,
|
||||
String businessKey,
|
||||
String name,
|
||||
String customerNumber,
|
||||
String companyName,
|
||||
String contactPerson,
|
||||
String street,
|
||||
String houseNumber,
|
||||
String postalCode,
|
||||
String city,
|
||||
String email,
|
||||
String phoneNumber,
|
||||
boolean active,
|
||||
LocalDateTime updatedAt
|
||||
) {
|
||||
}
|
||||
|
||||
public record FarmerMutation(String id, String name, String email, boolean active) {
|
||||
public record FarmerMutation(
|
||||
String id,
|
||||
String customerNumber,
|
||||
String companyName,
|
||||
String contactPerson,
|
||||
String street,
|
||||
String houseNumber,
|
||||
String postalCode,
|
||||
String city,
|
||||
String email,
|
||||
String phoneNumber,
|
||||
boolean active
|
||||
) {
|
||||
}
|
||||
|
||||
public record MedicationRow(
|
||||
|
||||
@@ -14,10 +14,8 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
|
||||
@@ -31,7 +31,7 @@ public class PortalService {
|
||||
LocalDate date
|
||||
) {
|
||||
List<CatalogService.FarmerOption> matchingFarmers = catalogService.activeCatalogSummary(actorId).farmers().stream()
|
||||
.filter(farmer -> farmerQuery == null || farmerQuery.isBlank() || farmer.name().toLowerCase(Locale.ROOT).contains(farmerQuery.toLowerCase(Locale.ROOT)))
|
||||
.filter(farmer -> farmerQuery == null || farmerQuery.isBlank() || farmer.companyName().toLowerCase(Locale.ROOT).contains(farmerQuery.toLowerCase(Locale.ROOT)))
|
||||
.toList();
|
||||
|
||||
List<PortalSampleRow> sampleRows;
|
||||
|
||||
@@ -124,7 +124,7 @@ public class SampleService {
|
||||
null,
|
||||
sampleNumber,
|
||||
farmer.businessKey(),
|
||||
farmer.name(),
|
||||
farmer.companyName(),
|
||||
farmer.email(),
|
||||
request.cowNumber().trim(),
|
||||
blankToNull(request.cowName()),
|
||||
@@ -178,7 +178,7 @@ public class SampleService {
|
||||
existing.id(),
|
||||
existing.sampleNumber(),
|
||||
farmer.businessKey(),
|
||||
farmer.name(),
|
||||
farmer.companyName(),
|
||||
farmer.email(),
|
||||
request.cowNumber().trim(),
|
||||
blankToNull(request.cowName()),
|
||||
|
||||
Reference in New Issue
Block a user