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

refactor: OffsetDateTime-Migration, atomare Batch-Sequenznummern und Quantity.reconstitute-Overload

- LocalDateTime → OffsetDateTime (UTC) in allen Domain-Klassen, JPA Entities, DTOs und Tests
- Liquibase-Migration 017: TIMESTAMP → TIMESTAMP WITH TIME ZONE für bestehende Spalten
- Custom DateTimeProvider für Spring Data @CreatedDate-Kompatibilität mit OffsetDateTime
- Neue Sequenztabelle (016) mit JPA Entity + PESSIMISTIC_WRITE Lock statt COUNT-basierter
  Batch-Nummernvergabe (Race Condition Fix)
- Quantity.reconstitute(amount, uom) 2-Parameter-Overload für bessere Lesbarkeit
This commit is contained in:
Sebastian Frick 2026-02-20 00:40:58 +01:00
parent b06157b92c
commit b46495e1aa
64 changed files with 414 additions and 256 deletions

View file

@ -119,7 +119,7 @@ class AddStockBatchTest {
List.of(StockBatch.reconstitute(
StockBatchId.generate(),
new BatchReference("BATCH-001", BatchType.PRODUCED),
Quantity.reconstitute(new BigDecimal("5"), UnitOfMeasure.KILOGRAM, null, null),
Quantity.reconstitute(new BigDecimal("5"), UnitOfMeasure.KILOGRAM),
LocalDate.of(2026, 12, 31),
StockBatchStatus.AVAILABLE,
Instant.now()

View file

@ -43,7 +43,7 @@ class RemoveStockBatchTest {
var batch = StockBatch.reconstitute(
batchId,
new BatchReference("BATCH-001", BatchType.PRODUCED),
Quantity.reconstitute(new BigDecimal("10"), UnitOfMeasure.KILOGRAM, null, null),
Quantity.reconstitute(new BigDecimal("10"), UnitOfMeasure.KILOGRAM),
LocalDate.of(2026, 12, 31),
StockBatchStatus.AVAILABLE,
Instant.now()

View file

@ -15,7 +15,8 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Optional;
@ -61,7 +62,7 @@ class ActivateRecipeTest {
null, new YieldPercentage(85), 14,
Quantity.of(new BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
RecipeStatus.ACTIVE, List.of(), List.of(),
LocalDateTime.now(), LocalDateTime.now()
OffsetDateTime.now(ZoneOffset.UTC), OffsetDateTime.now(ZoneOffset.UTC)
);
}

View file

@ -15,7 +15,8 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Optional;
@ -45,7 +46,7 @@ class ArchiveRecipeTest {
null, new YieldPercentage(85), 14,
Quantity.of(new BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
RecipeStatus.ACTIVE, List.of(), List.of(),
LocalDateTime.now(), LocalDateTime.now()
OffsetDateTime.now(ZoneOffset.UTC), OffsetDateTime.now(ZoneOffset.UTC)
);
}
@ -118,7 +119,7 @@ class ArchiveRecipeTest {
null, new YieldPercentage(85), 14,
Quantity.of(new BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
RecipeStatus.ARCHIVED, List.of(), List.of(),
LocalDateTime.now(), LocalDateTime.now()
OffsetDateTime.now(ZoneOffset.UTC), OffsetDateTime.now(ZoneOffset.UTC)
);
when(authPort.can(performedBy, ProductionAction.RECIPE_WRITE)).thenReturn(true);
when(recipeRepository.findById(RecipeId.of("recipe-2"))).thenReturn(Result.success(Optional.of(recipe)));

View file

@ -14,7 +14,8 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Optional;
@ -43,7 +44,7 @@ class GetRecipeTest {
"Beschreibung", new YieldPercentage(85), 14,
Quantity.of(new BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
RecipeStatus.ACTIVE, List.of(), List.of(),
LocalDateTime.now(), LocalDateTime.now()
OffsetDateTime.now(ZoneOffset.UTC), OffsetDateTime.now(ZoneOffset.UTC)
);
}

View file

@ -14,7 +14,8 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@ -42,7 +43,7 @@ class ListRecipesTest {
null, new YieldPercentage(85), 14,
Quantity.of(new BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
status, List.of(), List.of(),
LocalDateTime.now(), LocalDateTime.now()
OffsetDateTime.now(ZoneOffset.UTC), OffsetDateTime.now(ZoneOffset.UTC)
);
}

View file

@ -17,7 +17,8 @@ import org.mockito.junit.jupiter.MockitoExtension;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Optional;
@ -57,7 +58,7 @@ class PlanBatchTest {
null, new YieldPercentage(85), 14,
Quantity.of(new BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
RecipeStatus.ACTIVE, List.of(), List.of(),
LocalDateTime.now(), LocalDateTime.now()
OffsetDateTime.now(ZoneOffset.UTC), OffsetDateTime.now(ZoneOffset.UTC)
);
}
@ -67,7 +68,7 @@ class PlanBatchTest {
null, new YieldPercentage(85), 14,
Quantity.of(new BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
RecipeStatus.DRAFT, List.of(), List.of(),
LocalDateTime.now(), LocalDateTime.now()
OffsetDateTime.now(ZoneOffset.UTC), OffsetDateTime.now(ZoneOffset.UTC)
);
}

View file

@ -13,7 +13,8 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Optional;
@ -48,7 +49,7 @@ class RecipeCycleCheckerTest {
null, new YieldPercentage(100), 14,
Quantity.of(new BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
RecipeStatus.DRAFT, ingredients, List.of(),
LocalDateTime.now(), LocalDateTime.now());
OffsetDateTime.now(ZoneOffset.UTC), OffsetDateTime.now(ZoneOffset.UTC));
}
private Recipe recipeWithoutSubRecipes(String id) {
@ -145,7 +146,7 @@ class RecipeCycleCheckerTest {
null, new YieldPercentage(100), 14,
Quantity.of(new BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
RecipeStatus.DRAFT, ingredients, List.of(),
LocalDateTime.now(), LocalDateTime.now());
OffsetDateTime.now(ZoneOffset.UTC), OffsetDateTime.now(ZoneOffset.UTC));
when(recipeRepository.findById(RecipeId.of("B"))).thenReturn(Result.success(Optional.of(recipeB)));
when(recipeRepository.findById(RecipeId.of("C"))).thenReturn(Result.success(Optional.of(recipeWithoutSubRecipes("C"))));

View file

@ -13,7 +13,8 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.HashSet;
import java.util.Optional;
@ -42,7 +43,7 @@ class AssignRoleTest {
testUser = User.reconstitute(
UserId.of("user-1"), "john.doe", "john@example.com",
new PasswordHash("$2a$12$R9h/cIPz0gi.URNN3kh2OPST9EBwVeL00lzQRYe3z08MZx3e8YCWW"),
new HashSet<>(), "branch-1", UserStatus.ACTIVE, LocalDateTime.now(), null
new HashSet<>(), "branch-1", UserStatus.ACTIVE, OffsetDateTime.now(ZoneOffset.UTC), null
);
workerRole = Role.reconstitute(RoleId.generate(), RoleName.PRODUCTION_WORKER, new HashSet<>(), "Production Worker");
}

View file

@ -13,7 +13,8 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.HashSet;
import java.util.Optional;
@ -45,10 +46,10 @@ class AuthenticateUserTest {
testUser = User.reconstitute(
UserId.of("user-1"), "john.doe", "john@example.com", validPasswordHash,
new HashSet<>(), "branch-1", UserStatus.ACTIVE, LocalDateTime.now(), null
new HashSet<>(), "branch-1", UserStatus.ACTIVE, OffsetDateTime.now(ZoneOffset.UTC), null
);
sessionToken = new SessionToken("jwt-token", "Bearer", 3600L, LocalDateTime.now().plusSeconds(3600), "refresh-token");
sessionToken = new SessionToken("jwt-token", "Bearer", 3600L, OffsetDateTime.now(ZoneOffset.UTC).plusSeconds(3600), "refresh-token");
}
@Test
@ -84,7 +85,7 @@ class AuthenticateUserTest {
void should_FailWithLockedUser_When_UserStatusIsLocked() {
User lockedUser = User.reconstitute(
UserId.of("user-2"), "john.doe", "john@example.com", validPasswordHash,
new HashSet<>(), "branch-1", UserStatus.LOCKED, LocalDateTime.now(), null
new HashSet<>(), "branch-1", UserStatus.LOCKED, OffsetDateTime.now(ZoneOffset.UTC), null
);
when(userRepository.findByUsername("john.doe")).thenReturn(Result.success(Optional.of(lockedUser)));
@ -100,7 +101,7 @@ class AuthenticateUserTest {
void should_FailWithInactiveUser_When_UserStatusIsInactive() {
User inactiveUser = User.reconstitute(
UserId.of("user-3"), "john.doe", "john@example.com", validPasswordHash,
new HashSet<>(), "branch-1", UserStatus.INACTIVE, LocalDateTime.now(), null
new HashSet<>(), "branch-1", UserStatus.INACTIVE, OffsetDateTime.now(ZoneOffset.UTC), null
);
when(userRepository.findByUsername("john.doe")).thenReturn(Result.success(Optional.of(inactiveUser)));
@ -143,7 +144,7 @@ class AuthenticateUserTest {
void should_NotCreateSession_When_UserLocked() {
User lockedUser = User.reconstitute(
UserId.of("user-4"), "john.doe", "john@example.com", validPasswordHash,
new HashSet<>(), "branch-1", UserStatus.LOCKED, LocalDateTime.now(), null
new HashSet<>(), "branch-1", UserStatus.LOCKED, OffsetDateTime.now(ZoneOffset.UTC), null
);
when(userRepository.findByUsername("john.doe")).thenReturn(Result.success(Optional.of(lockedUser)));

View file

@ -12,7 +12,8 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.HashSet;
import java.util.Optional;
@ -44,7 +45,7 @@ class ChangePasswordTest {
testUser = User.reconstitute(
UserId.of("user-123"), "john.doe", "john@example.com", oldPasswordHash,
new HashSet<>(), "branch-1", UserStatus.ACTIVE, LocalDateTime.now(), null
new HashSet<>(), "branch-1", UserStatus.ACTIVE, OffsetDateTime.now(ZoneOffset.UTC), null
);
validCommand = new ChangePasswordCommand("user-123", "OldPassword123!", "NewPassword456!");

View file

@ -12,7 +12,8 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.HashSet;
import java.util.Optional;
@ -37,7 +38,7 @@ class GetUserTest {
testUser = User.reconstitute(
UserId.of("user-1"), "john.doe", "john@example.com",
new PasswordHash("$2a$12$R9h/cIPz0gi.URNN3kh2OPST9EBwVeL00lzQRYe3z08MZx3e8YCWW"),
new HashSet<>(), "branch-1", UserStatus.ACTIVE, LocalDateTime.now(), null
new HashSet<>(), "branch-1", UserStatus.ACTIVE, OffsetDateTime.now(ZoneOffset.UTC), null
);
}

View file

@ -13,7 +13,8 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.HashSet;
import java.util.List;
@ -39,12 +40,12 @@ class ListUsersTest {
user1 = User.reconstitute(
UserId.of("user-1"), "john.doe", "john@example.com",
new PasswordHash("$2a$12$R9h/cIPz0gi.URNN3kh2OPST9EBwVeL00lzQRYe3z08MZx3e8YCWW"),
new HashSet<>(), "branch-1", UserStatus.ACTIVE, LocalDateTime.now(), null
new HashSet<>(), "branch-1", UserStatus.ACTIVE, OffsetDateTime.now(ZoneOffset.UTC), null
);
user2 = User.reconstitute(
UserId.of("user-2"), "jane.doe", "jane@example.com",
new PasswordHash("$2a$12$R9h/cIPz0gi.URNN3kh2OPST9EBwVeL00lzQRYe3z08MZx3e8YCWW"),
new HashSet<>(), "branch-1", UserStatus.ACTIVE, LocalDateTime.now(), null
new HashSet<>(), "branch-1", UserStatus.ACTIVE, OffsetDateTime.now(ZoneOffset.UTC), null
);
}

View file

@ -13,7 +13,8 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.HashSet;
import java.util.Optional;
@ -40,7 +41,7 @@ class LockUserTest {
activeUser = User.reconstitute(
UserId.of("user-1"), "john.doe", "john@example.com",
new PasswordHash("$2a$12$R9h/cIPz0gi.URNN3kh2OPST9EBwVeL00lzQRYe3z08MZx3e8YCWW"),
new HashSet<>(), "branch-1", UserStatus.ACTIVE, LocalDateTime.now(), null
new HashSet<>(), "branch-1", UserStatus.ACTIVE, OffsetDateTime.now(ZoneOffset.UTC), null
);
}
@ -100,7 +101,7 @@ class LockUserTest {
User lockedUser = User.reconstitute(
UserId.of("user-2"), "jane.doe", "jane@example.com",
new PasswordHash("$2a$12$R9h/cIPz0gi.URNN3kh2OPST9EBwVeL00lzQRYe3z08MZx3e8YCWW"),
new HashSet<>(), "branch-1", UserStatus.LOCKED, LocalDateTime.now(), null
new HashSet<>(), "branch-1", UserStatus.LOCKED, OffsetDateTime.now(ZoneOffset.UTC), null
);
when(authPort.can(performedBy, UserManagementAction.USER_LOCK)).thenReturn(true);
when(userRepository.findById(UserId.of("user-2"))).thenReturn(Result.success(Optional.of(lockedUser)));
@ -118,7 +119,7 @@ class LockUserTest {
User inactiveUser = User.reconstitute(
UserId.of("user-3"), "bob", "bob@example.com",
new PasswordHash("$2a$12$R9h/cIPz0gi.URNN3kh2OPST9EBwVeL00lzQRYe3z08MZx3e8YCWW"),
new HashSet<>(), "branch-1", UserStatus.INACTIVE, LocalDateTime.now(), null
new HashSet<>(), "branch-1", UserStatus.INACTIVE, OffsetDateTime.now(ZoneOffset.UTC), null
);
when(authPort.can(performedBy, UserManagementAction.USER_LOCK)).thenReturn(true);
when(userRepository.findById(UserId.of("user-3"))).thenReturn(Result.success(Optional.of(inactiveUser)));

View file

@ -13,7 +13,8 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
@ -44,7 +45,7 @@ class RemoveRoleTest {
userWithRole = User.reconstitute(
UserId.of("user-1"), "john.doe", "john@example.com",
new PasswordHash("$2a$12$R9h/cIPz0gi.URNN3kh2OPST9EBwVeL00lzQRYe3z08MZx3e8YCWW"),
new HashSet<>(Set.of(workerRole)), "branch-1", UserStatus.ACTIVE, LocalDateTime.now(), null
new HashSet<>(Set.of(workerRole)), "branch-1", UserStatus.ACTIVE, OffsetDateTime.now(ZoneOffset.UTC), null
);
}

View file

@ -13,7 +13,8 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.HashSet;
import java.util.Optional;
@ -40,7 +41,7 @@ class UnlockUserTest {
lockedUser = User.reconstitute(
UserId.of("user-1"), "john.doe", "john@example.com",
new PasswordHash("$2a$12$R9h/cIPz0gi.URNN3kh2OPST9EBwVeL00lzQRYe3z08MZx3e8YCWW"),
new HashSet<>(), "branch-1", UserStatus.LOCKED, LocalDateTime.now(), null
new HashSet<>(), "branch-1", UserStatus.LOCKED, OffsetDateTime.now(ZoneOffset.UTC), null
);
}
@ -100,7 +101,7 @@ class UnlockUserTest {
User activeUser = User.reconstitute(
UserId.of("user-2"), "jane.doe", "jane@example.com",
new PasswordHash("$2a$12$R9h/cIPz0gi.URNN3kh2OPST9EBwVeL00lzQRYe3z08MZx3e8YCWW"),
new HashSet<>(), "branch-1", UserStatus.ACTIVE, LocalDateTime.now(), null
new HashSet<>(), "branch-1", UserStatus.ACTIVE, OffsetDateTime.now(ZoneOffset.UTC), null
);
when(authPort.can(performedBy, UserManagementAction.USER_UNLOCK)).thenReturn(true);
when(userRepository.findById(UserId.of("user-2"))).thenReturn(Result.success(Optional.of(activeUser)));
@ -118,7 +119,7 @@ class UnlockUserTest {
User inactiveUser = User.reconstitute(
UserId.of("user-3"), "bob", "bob@example.com",
new PasswordHash("$2a$12$R9h/cIPz0gi.URNN3kh2OPST9EBwVeL00lzQRYe3z08MZx3e8YCWW"),
new HashSet<>(), "branch-1", UserStatus.INACTIVE, LocalDateTime.now(), null
new HashSet<>(), "branch-1", UserStatus.INACTIVE, OffsetDateTime.now(ZoneOffset.UTC), null
);
when(authPort.can(performedBy, UserManagementAction.USER_UNLOCK)).thenReturn(true);
when(userRepository.findById(UserId.of("user-3"))).thenReturn(Result.success(Optional.of(inactiveUser)));

View file

@ -13,7 +13,8 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.HashSet;
import java.util.Optional;
@ -40,7 +41,7 @@ class UpdateUserTest {
testUser = User.reconstitute(
UserId.of("user-1"), "john.doe", "john@example.com",
new PasswordHash("$2a$12$R9h/cIPz0gi.URNN3kh2OPST9EBwVeL00lzQRYe3z08MZx3e8YCWW"),
new HashSet<>(), "branch-1", UserStatus.ACTIVE, LocalDateTime.now(), null
new HashSet<>(), "branch-1", UserStatus.ACTIVE, OffsetDateTime.now(ZoneOffset.UTC), null
);
}

View file

@ -266,7 +266,7 @@ class StockTest {
var id = StockId.generate();
var articleId = ArticleId.of("article-1");
var locationId = StorageLocationId.of("location-1");
var quantity = Quantity.reconstitute(new BigDecimal("10"), UnitOfMeasure.KILOGRAM, null, null);
var quantity = Quantity.reconstitute(new BigDecimal("10"), UnitOfMeasure.KILOGRAM);
var minimumLevel = new MinimumLevel(quantity);
var minimumShelfLife = new MinimumShelfLife(30);
@ -606,7 +606,7 @@ class StockTest {
var batch = StockBatch.reconstitute(
StockBatchId.generate(),
new BatchReference("BATCH-001", BatchType.PRODUCED),
Quantity.reconstitute(new BigDecimal(amount), uom, null, null),
Quantity.reconstitute(new BigDecimal(amount), uom),
LocalDate.of(2026, 12, 31),
status,
Instant.now()

View file

@ -8,7 +8,8 @@ import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import static org.assertj.core.api.Assertions.assertThat;
@ -187,8 +188,8 @@ class BatchTest {
Quantity.of(new BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
PRODUCTION_DATE,
BEST_BEFORE_DATE,
LocalDateTime.now(),
LocalDateTime.now()
OffsetDateTime.now(ZoneOffset.UTC),
OffsetDateTime.now(ZoneOffset.UTC)
);
assertThat(batch.id().value()).isEqualTo("batch-1");

View file

@ -239,7 +239,7 @@ class RecipeTest {
null, new YieldPercentage(85), 14,
Quantity.of(new java.math.BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
RecipeStatus.ACTIVE, List.of(), List.of(),
java.time.LocalDateTime.now(), java.time.LocalDateTime.now()
java.time.OffsetDateTime.now(java.time.ZoneOffset.UTC), java.time.OffsetDateTime.now(java.time.ZoneOffset.UTC)
);
var result = recipe.addIngredient(validIngredientDraft(1));
@ -322,7 +322,7 @@ class RecipeTest {
null, new YieldPercentage(85), 14,
Quantity.of(new java.math.BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
RecipeStatus.ACTIVE, List.of(), List.of(),
java.time.LocalDateTime.now(), java.time.LocalDateTime.now()
java.time.OffsetDateTime.now(java.time.ZoneOffset.UTC), java.time.OffsetDateTime.now(java.time.ZoneOffset.UTC)
);
var result = recipe.removeIngredient(IngredientId.generate());
@ -376,7 +376,7 @@ class RecipeTest {
null, new YieldPercentage(85), 14,
Quantity.of(new java.math.BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
RecipeStatus.ACTIVE, List.of(), List.of(),
java.time.LocalDateTime.now(), java.time.LocalDateTime.now()
java.time.OffsetDateTime.now(java.time.ZoneOffset.UTC), java.time.OffsetDateTime.now(java.time.ZoneOffset.UTC)
);
var result = recipe.addProductionStep(new ProductionStepDraft(1, "Mischen", null, null));
@ -445,7 +445,7 @@ class RecipeTest {
null, new YieldPercentage(85), 14,
Quantity.of(new java.math.BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
RecipeStatus.ACTIVE, List.of(), List.of(),
java.time.LocalDateTime.now(), java.time.LocalDateTime.now()
java.time.OffsetDateTime.now(java.time.ZoneOffset.UTC), java.time.OffsetDateTime.now(java.time.ZoneOffset.UTC)
);
var result = recipe.removeProductionStep(1);
@ -507,7 +507,7 @@ class RecipeTest {
null, new YieldPercentage(85), 14,
Quantity.of(new java.math.BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
RecipeStatus.ACTIVE, List.of(), List.of(),
java.time.LocalDateTime.now(), java.time.LocalDateTime.now()
java.time.OffsetDateTime.now(java.time.ZoneOffset.UTC), java.time.OffsetDateTime.now(java.time.ZoneOffset.UTC)
);
var result = recipe.activate();
@ -528,7 +528,7 @@ class RecipeTest {
null, new YieldPercentage(85), 14,
Quantity.of(new java.math.BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
RecipeStatus.ARCHIVED, List.of(), List.of(),
java.time.LocalDateTime.now(), java.time.LocalDateTime.now()
java.time.OffsetDateTime.now(java.time.ZoneOffset.UTC), java.time.OffsetDateTime.now(java.time.ZoneOffset.UTC)
);
var result = recipe.activate();
@ -554,7 +554,7 @@ class RecipeTest {
null, new YieldPercentage(85), 14,
Quantity.of(new java.math.BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
RecipeStatus.ACTIVE, List.of(), List.of(),
java.time.LocalDateTime.now(), java.time.LocalDateTime.now()
java.time.OffsetDateTime.now(java.time.ZoneOffset.UTC), java.time.OffsetDateTime.now(java.time.ZoneOffset.UTC)
);
var updatedBefore = recipe.updatedAt();
@ -588,7 +588,7 @@ class RecipeTest {
null, new YieldPercentage(85), 14,
Quantity.of(new java.math.BigDecimal("100"), UnitOfMeasure.KILOGRAM).unsafeGetValue(),
RecipeStatus.ARCHIVED, List.of(), List.of(),
java.time.LocalDateTime.now(), java.time.LocalDateTime.now()
java.time.OffsetDateTime.now(java.time.ZoneOffset.UTC), java.time.OffsetDateTime.now(java.time.ZoneOffset.UTC)
);
var result = recipe.archive();

View file

@ -7,7 +7,8 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.*;
import static org.assertj.core.api.Assertions.*;
@ -25,7 +26,7 @@ class UserTest {
private PasswordHash passwordHash;
private Set<Role> roles;
private String branchId;
private LocalDateTime createdAt;
private OffsetDateTime createdAt;
@BeforeEach
void setUp() {
@ -35,7 +36,7 @@ class UserTest {
passwordHash = new PasswordHash("$2a$12$R9h/cIPz0gi.URNN3kh2OPST9EBwVeL00lzQRYe3z08MZx3e8YCWW");
roles = new HashSet<>();
branchId = "branch-1";
createdAt = LocalDateTime.now();
createdAt = OffsetDateTime.now(ZoneOffset.UTC);
}
@Test
@ -56,9 +57,9 @@ class UserTest {
@Test
@DisplayName("should_SetDefaultCreatedAtToNow_When_NullProvidedForCreatedAt")
void should_SetDefaultCreatedAtToNow_When_NullProvidedForCreatedAt() {
LocalDateTime before = LocalDateTime.now();
OffsetDateTime before = OffsetDateTime.now(ZoneOffset.UTC);
User user = User.reconstitute(userId, username, email, passwordHash, roles, branchId, UserStatus.ACTIVE, null, null);
LocalDateTime after = LocalDateTime.now();
OffsetDateTime after = OffsetDateTime.now(ZoneOffset.UTC);
assertThat(user.createdAt()).isNotNull();
assertThat(user.createdAt()).isBetween(before, after);
@ -129,7 +130,7 @@ class UserTest {
@DisplayName("should_ReturnNewUserWithLastLogin_When_WithLastLoginCalled")
void should_ReturnNewUserWithLastLogin_When_WithLastLoginCalled() {
User user = User.create(username, email, passwordHash, roles, branchId).unsafeGetValue();
LocalDateTime now = LocalDateTime.now();
OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
User updated = user.withLastLogin(now).unsafeGetValue();

View file

@ -18,7 +18,8 @@ import org.springframework.transaction.annotation.Transactional;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.Set;
import java.util.UUID;
@ -102,7 +103,7 @@ public abstract class AbstractIntegrationTest {
UserEntity user = new UserEntity(
UUID.randomUUID().toString(), username, email,
BCRYPT_PASS123, roles,
branchId, UserStatus.ACTIVE, LocalDateTime.now(), null);
branchId, UserStatus.ACTIVE, OffsetDateTime.now(ZoneOffset.UTC), null);
return userRepository.save(user);
}
}

View file

@ -7,7 +7,8 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.HashSet;
import java.util.Set;
@ -29,11 +30,11 @@ class UserMapperTest {
private User domainUser;
private UserEntity jpaEntity;
private LocalDateTime createdAt;
private OffsetDateTime createdAt;
@BeforeEach
void setUp() {
createdAt = LocalDateTime.now();
createdAt = OffsetDateTime.now(ZoneOffset.UTC);
// Create JPA entity first
jpaEntity = new UserEntity(
@ -112,7 +113,7 @@ class UserMapperTest {
@DisplayName("should_PreserveAllUserFields_When_MappingToEntity")
void should_PreserveAllUserFields_When_MappingToEntity() {
// Arrange
LocalDateTime lastLogin = LocalDateTime.now();
OffsetDateTime lastLogin = OffsetDateTime.now(ZoneOffset.UTC);
UserEntity sourceEntity = new UserEntity(
"user-456",
"jane.smith",
@ -144,7 +145,7 @@ class UserMapperTest {
@DisplayName("should_PreserveAllEntityFields_When_MappingToDomain")
void should_PreserveAllEntityFields_When_MappingToDomain() {
// Arrange
LocalDateTime lastLogin = LocalDateTime.now();
OffsetDateTime lastLogin = OffsetDateTime.now(ZoneOffset.UTC);
UserEntity entityWithLastLogin = new UserEntity(
"user-789",
"bob.jones",

View file

@ -18,7 +18,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Set;
import java.util.UUID;
@ -327,7 +328,7 @@ class SecurityIntegrationTest extends AbstractIntegrationTest {
.orElseThrow();
assertThat(auditLog.getTimestamp()).isNotNull();
assertThat(auditLog.getTimestamp()).isAfter(LocalDateTime.now().minusMinutes(1));
assertThat(auditLog.getTimestamp()).isAfter(OffsetDateTime.now(ZoneOffset.UTC).minusMinutes(1));
}
@Test