1
0
Fork 0
mirror of https://github.com/s-frick/effigenix.git synced 2026-03-28 12:09:35 +01:00

fix(production): JPA-Save-Pattern, Optimistic Locking und Domain-Validierung

- Managed-Entity-Update statt detach/merge (verhindert DELETE+INSERT-Churn)
- @Version für Optimistic Locking mit ConcurrentModification-Error
- Null-Checks für quantityUsed/quantityUnit vor BigDecimal-Parsing
- Duplicate-Check nach Consumption.create() für robustere Validierung
- FetchType.EAGER→LAZY für BatchEntity.consumptions
- Liquibase-Migration 020 für version-Spalte
This commit is contained in:
Sebastian Frick 2026-02-20 16:52:11 +01:00
parent a9f5956812
commit 9eb9c93fb7
17 changed files with 133 additions and 37 deletions

View file

@ -53,7 +53,7 @@ class FindBatchByNumberTest {
LocalDate.of(2026, 6, 1),
OffsetDateTime.now(ZoneOffset.UTC),
OffsetDateTime.now(ZoneOffset.UTC),
List.of()
0L, List.of()
);
}

View file

@ -51,7 +51,7 @@ class GetBatchTest {
LocalDate.of(2026, 6, 1),
OffsetDateTime.now(ZoneOffset.UTC),
OffsetDateTime.now(ZoneOffset.UTC),
List.of()
0L, List.of()
);
}

View file

@ -55,7 +55,7 @@ class ListBatchesTest {
LocalDate.of(2026, 6, 1),
OffsetDateTime.now(ZoneOffset.UTC),
OffsetDateTime.now(ZoneOffset.UTC),
List.of()
0L, List.of()
);
}

View file

@ -52,7 +52,7 @@ class RecordConsumptionTest {
LocalDate.of(2026, 6, 1),
OffsetDateTime.now(ZoneOffset.UTC),
OffsetDateTime.now(ZoneOffset.UTC),
List.of()
0L, List.of()
);
}
@ -67,7 +67,7 @@ class RecordConsumptionTest {
LocalDate.of(2026, 6, 1),
OffsetDateTime.now(ZoneOffset.UTC),
OffsetDateTime.now(ZoneOffset.UTC),
List.of()
0L, List.of()
);
}

View file

@ -52,7 +52,7 @@ class StartBatchTest {
LocalDate.of(2026, 6, 1),
OffsetDateTime.now(ZoneOffset.UTC),
OffsetDateTime.now(ZoneOffset.UTC),
List.of()
0L, List.of()
);
}
@ -67,7 +67,7 @@ class StartBatchTest {
LocalDate.of(2026, 6, 1),
OffsetDateTime.now(ZoneOffset.UTC),
OffsetDateTime.now(ZoneOffset.UTC),
List.of()
0L, List.of()
);
}

View file

@ -210,7 +210,7 @@ class BatchTest {
Quantity.of(new BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
PRODUCTION_DATE, BEST_BEFORE_DATE,
OffsetDateTime.now(ZoneOffset.UTC), OffsetDateTime.now(ZoneOffset.UTC),
List.of()
0L, List.of()
);
var result = batch.startProduction();
@ -231,7 +231,7 @@ class BatchTest {
Quantity.of(new BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
PRODUCTION_DATE, BEST_BEFORE_DATE,
OffsetDateTime.now(ZoneOffset.UTC), OffsetDateTime.now(ZoneOffset.UTC),
List.of()
0L, List.of()
);
var result = batch.startProduction();
@ -249,7 +249,7 @@ class BatchTest {
Quantity.of(new BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
PRODUCTION_DATE, BEST_BEFORE_DATE,
OffsetDateTime.now(ZoneOffset.UTC), OffsetDateTime.now(ZoneOffset.UTC),
List.of()
0L, List.of()
);
var result = batch.startProduction();
@ -313,7 +313,7 @@ class BatchTest {
Quantity.of(new BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
PRODUCTION_DATE, BEST_BEFORE_DATE,
OffsetDateTime.now(ZoneOffset.UTC), OffsetDateTime.now(ZoneOffset.UTC),
List.of()
0L, List.of()
);
var draft = new ConsumptionDraft("input-1", "article-1", "5.0", "KILOGRAM");
@ -379,7 +379,7 @@ class BatchTest {
BEST_BEFORE_DATE,
OffsetDateTime.now(ZoneOffset.UTC),
OffsetDateTime.now(ZoneOffset.UTC),
List.of()
0L, List.of()
);
assertThat(batch.id().value()).isEqualTo("batch-1");

View file

@ -111,6 +111,28 @@ class ConsumptionTest {
assertThat(result.unsafeGetError()).isInstanceOf(BatchError.InvalidConsumptionQuantity.class);
}
@Test
@DisplayName("should fail when quantity is null")
void should_Fail_When_QuantityNull() {
var draft = new ConsumptionDraft("input-batch-1", "article-1", null, "KILOGRAM");
var result = Consumption.create(draft);
assertThat(result.isFailure()).isTrue();
assertThat(result.unsafeGetError()).isInstanceOf(BatchError.InvalidConsumptionQuantity.class);
}
@Test
@DisplayName("should fail when unit is null")
void should_Fail_When_UnitNull() {
var draft = new ConsumptionDraft("input-batch-1", "article-1", "10", null);
var result = Consumption.create(draft);
assertThat(result.isFailure()).isTrue();
assertThat(result.unsafeGetError()).isInstanceOf(BatchError.InvalidConsumptionQuantity.class);
}
@Test
@DisplayName("should fail when unit is invalid")
void should_Fail_When_UnitInvalid() {