mirror of
https://github.com/s-frick/effigenix.git
synced 2026-03-28 08:29:36 +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:
parent
b06157b92c
commit
b46495e1aa
64 changed files with 414 additions and 256 deletions
|
|
@ -7,7 +7,8 @@ import de.effigenix.shared.common.Result;
|
|||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
|
|
@ -71,7 +72,7 @@ public class AuthenticateUser {
|
|||
SessionToken token = sessionManager.createSession(user);
|
||||
|
||||
// 5. Update last login timestamp (immutable)
|
||||
return user.withLastLogin(LocalDateTime.now())
|
||||
return user.withLastLogin(OffsetDateTime.now(ZoneOffset.UTC))
|
||||
.flatMap(updated -> userRepository.save(updated)
|
||||
.mapError(err -> (UserError) new UserError.RepositoryFailure(err.message()))
|
||||
.map(ignored -> {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package de.effigenix.application.usermanagement.dto;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
|
||||
/**
|
||||
* JWT session token returned after successful authentication.
|
||||
|
|
@ -9,7 +10,7 @@ public record SessionToken(
|
|||
String accessToken,
|
||||
String tokenType,
|
||||
long expiresIn, // in seconds
|
||||
LocalDateTime expiresAt,
|
||||
OffsetDateTime expiresAt,
|
||||
String refreshToken // for future refresh token support
|
||||
) {
|
||||
public static SessionToken create(String accessToken, long expiresInMs, String refreshToken) {
|
||||
|
|
@ -17,7 +18,7 @@ public record SessionToken(
|
|||
accessToken,
|
||||
"Bearer",
|
||||
expiresInMs / 1000, // convert to seconds
|
||||
LocalDateTime.now().plusSeconds(expiresInMs / 1000),
|
||||
OffsetDateTime.now(ZoneOffset.UTC).plusSeconds(expiresInMs / 1000),
|
||||
refreshToken
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package de.effigenix.application.usermanagement.dto;
|
|||
import de.effigenix.domain.usermanagement.User;
|
||||
import de.effigenix.domain.usermanagement.UserStatus;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
|
@ -18,8 +18,8 @@ public record UserDTO(
|
|||
Set<RoleDTO> roles,
|
||||
String branchId,
|
||||
UserStatus status,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime lastLogin
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime lastLogin
|
||||
) {
|
||||
/**
|
||||
* Maps a User entity to a UserDTO.
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public record MinimumLevel(Quantity quantity) {
|
|||
// MinimumLevel erlaubt amount == 0 (kein Mindestbestand)
|
||||
// Quantity.of() verlangt amount > 0, daher Reconstitute verwenden
|
||||
if (parsedAmount.compareTo(BigDecimal.ZERO) == 0) {
|
||||
return Result.success(new MinimumLevel(Quantity.reconstitute(parsedAmount, parsedUnit, null, null)));
|
||||
return Result.success(new MinimumLevel(Quantity.reconstitute(parsedAmount, parsedUnit)));
|
||||
}
|
||||
|
||||
return Quantity.of(parsedAmount, parsedUnit)
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ public class StockBatch {
|
|||
return Result.failure(new StockError.NegativeStockNotAllowed());
|
||||
}
|
||||
if (remaining.compareTo(BigDecimal.ZERO) == 0) {
|
||||
return Result.success(Quantity.reconstitute(BigDecimal.ZERO, this.quantity.uom(), null, null));
|
||||
return Result.success(Quantity.reconstitute(BigDecimal.ZERO, this.quantity.uom()));
|
||||
}
|
||||
switch (Quantity.of(remaining, this.quantity.uom())) {
|
||||
case Result.Failure(var err) -> {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ import de.effigenix.shared.common.Result;
|
|||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
|
|
@ -26,8 +27,8 @@ public class Article {
|
|||
private final List<SalesUnit> salesUnits;
|
||||
private ArticleStatus status;
|
||||
private final Set<SupplierId> supplierReferences;
|
||||
private final LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
private final OffsetDateTime createdAt;
|
||||
private OffsetDateTime updatedAt;
|
||||
|
||||
private Article(
|
||||
ArticleId id,
|
||||
|
|
@ -37,8 +38,8 @@ public class Article {
|
|||
List<SalesUnit> salesUnits,
|
||||
ArticleStatus status,
|
||||
Set<SupplierId> supplierReferences,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime updatedAt
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt
|
||||
) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
|
|
@ -88,7 +89,7 @@ public class Article {
|
|||
case Success(var val) -> salesUnit = val;
|
||||
}
|
||||
|
||||
var now = LocalDateTime.now();
|
||||
var now = OffsetDateTime.now(ZoneOffset.UTC);
|
||||
return Result.success(new Article(
|
||||
ArticleId.generate(),
|
||||
name,
|
||||
|
|
@ -110,8 +111,8 @@ public class Article {
|
|||
List<SalesUnit> salesUnits,
|
||||
ArticleStatus status,
|
||||
Set<SupplierId> supplierReferences,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime updatedAt
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt
|
||||
) {
|
||||
return new Article(id, name, articleNumber, categoryId, salesUnits, status,
|
||||
supplierReferences, createdAt, updatedAt);
|
||||
|
|
@ -208,7 +209,7 @@ public class Article {
|
|||
}
|
||||
|
||||
private void touch() {
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
this.updatedAt = OffsetDateTime.now(ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
// ==================== Getters ====================
|
||||
|
|
@ -220,8 +221,8 @@ public class Article {
|
|||
public List<SalesUnit> salesUnits() { return Collections.unmodifiableList(salesUnits); }
|
||||
public ArticleStatus status() { return status; }
|
||||
public Set<SupplierId> supplierReferences() { return Collections.unmodifiableSet(supplierReferences); }
|
||||
public LocalDateTime createdAt() { return createdAt; }
|
||||
public LocalDateTime updatedAt() { return updatedAt; }
|
||||
public OffsetDateTime createdAt() { return createdAt; }
|
||||
public OffsetDateTime updatedAt() { return updatedAt; }
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ import de.effigenix.shared.common.Result;
|
|||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
|
|
@ -33,8 +34,8 @@ public class Customer {
|
|||
private FrameContract frameContract;
|
||||
private final Set<CustomerPreference> preferences;
|
||||
private CustomerStatus status;
|
||||
private final LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
private final OffsetDateTime createdAt;
|
||||
private OffsetDateTime updatedAt;
|
||||
|
||||
private Customer(
|
||||
CustomerId id,
|
||||
|
|
@ -47,8 +48,8 @@ public class Customer {
|
|||
FrameContract frameContract,
|
||||
Set<CustomerPreference> preferences,
|
||||
CustomerStatus status,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime updatedAt
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt
|
||||
) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
|
|
@ -100,7 +101,7 @@ public class Customer {
|
|||
}
|
||||
}
|
||||
|
||||
var now = LocalDateTime.now();
|
||||
var now = OffsetDateTime.now(ZoneOffset.UTC);
|
||||
return Result.success(new Customer(
|
||||
CustomerId.generate(), name, draft.type(), billingAddress, contactInfo, paymentTerms,
|
||||
List.of(), null, Set.of(), CustomerStatus.ACTIVE, now, now
|
||||
|
|
@ -118,8 +119,8 @@ public class Customer {
|
|||
FrameContract frameContract,
|
||||
Set<CustomerPreference> preferences,
|
||||
CustomerStatus status,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime updatedAt
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt
|
||||
) {
|
||||
return new Customer(id, name, type, billingAddress, contactInfo, paymentTerms,
|
||||
deliveryAddresses, frameContract, preferences, status, createdAt, updatedAt);
|
||||
|
|
@ -235,7 +236,7 @@ public class Customer {
|
|||
// ==================== Helpers ====================
|
||||
|
||||
private void touch() {
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
this.updatedAt = OffsetDateTime.now(ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
// ==================== Getters ====================
|
||||
|
|
@ -250,8 +251,8 @@ public class Customer {
|
|||
public FrameContract frameContract() { return frameContract; }
|
||||
public Set<CustomerPreference> preferences() { return Collections.unmodifiableSet(preferences); }
|
||||
public CustomerStatus status() { return status; }
|
||||
public LocalDateTime createdAt() { return createdAt; }
|
||||
public LocalDateTime updatedAt() { return updatedAt; }
|
||||
public OffsetDateTime createdAt() { return createdAt; }
|
||||
public OffsetDateTime updatedAt() { return updatedAt; }
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ import de.effigenix.shared.common.Address;
|
|||
import de.effigenix.shared.common.ContactInfo;
|
||||
import de.effigenix.shared.common.PaymentTerms;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
|
@ -31,8 +32,8 @@ public class Supplier {
|
|||
private final List<QualityCertificate> certificates;
|
||||
private SupplierRating rating;
|
||||
private SupplierStatus status;
|
||||
private final LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
private final OffsetDateTime createdAt;
|
||||
private OffsetDateTime updatedAt;
|
||||
|
||||
private Supplier(
|
||||
SupplierId id,
|
||||
|
|
@ -43,8 +44,8 @@ public class Supplier {
|
|||
List<QualityCertificate> certificates,
|
||||
SupplierRating rating,
|
||||
SupplierStatus status,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime updatedAt
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt
|
||||
) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
|
|
@ -96,7 +97,7 @@ public class Supplier {
|
|||
}
|
||||
}
|
||||
|
||||
var now = LocalDateTime.now();
|
||||
var now = OffsetDateTime.now(ZoneOffset.UTC);
|
||||
return Result.success(new Supplier(
|
||||
SupplierId.generate(), name, address, contactInfo, paymentTerms,
|
||||
List.of(), null, SupplierStatus.ACTIVE, now, now
|
||||
|
|
@ -112,8 +113,8 @@ public class Supplier {
|
|||
List<QualityCertificate> certificates,
|
||||
SupplierRating rating,
|
||||
SupplierStatus status,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime updatedAt
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt
|
||||
) {
|
||||
return new Supplier(id, name, address, contactInfo, paymentTerms,
|
||||
certificates, rating, status, createdAt, updatedAt);
|
||||
|
|
@ -200,7 +201,7 @@ public class Supplier {
|
|||
// ==================== Helpers ====================
|
||||
|
||||
private void touch() {
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
this.updatedAt = OffsetDateTime.now(ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
// ==================== Getters ====================
|
||||
|
|
@ -213,8 +214,8 @@ public class Supplier {
|
|||
public List<QualityCertificate> certificates() { return Collections.unmodifiableList(certificates); }
|
||||
public SupplierRating rating() { return rating; }
|
||||
public SupplierStatus status() { return status; }
|
||||
public LocalDateTime createdAt() { return createdAt; }
|
||||
public LocalDateTime updatedAt() { return updatedAt; }
|
||||
public OffsetDateTime createdAt() { return createdAt; }
|
||||
public OffsetDateTime updatedAt() { return updatedAt; }
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ import de.effigenix.shared.common.UnitOfMeasure;
|
|||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
|
||||
/**
|
||||
* Batch aggregate root.
|
||||
|
|
@ -27,8 +28,8 @@ public class Batch {
|
|||
private final Quantity plannedQuantity;
|
||||
private final LocalDate productionDate;
|
||||
private final LocalDate bestBeforeDate;
|
||||
private final LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
private final OffsetDateTime createdAt;
|
||||
private OffsetDateTime updatedAt;
|
||||
|
||||
private Batch(
|
||||
BatchId id,
|
||||
|
|
@ -38,8 +39,8 @@ public class Batch {
|
|||
Quantity plannedQuantity,
|
||||
LocalDate productionDate,
|
||||
LocalDate bestBeforeDate,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime updatedAt
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt
|
||||
) {
|
||||
this.id = id;
|
||||
this.batchNumber = batchNumber;
|
||||
|
|
@ -88,7 +89,7 @@ public class Batch {
|
|||
"Invalid unit: " + draft.plannedQuantityUnit()));
|
||||
}
|
||||
|
||||
var now = LocalDateTime.now();
|
||||
var now = OffsetDateTime.now(ZoneOffset.UTC);
|
||||
return Result.success(new Batch(
|
||||
BatchId.generate(),
|
||||
batchNumber,
|
||||
|
|
@ -110,8 +111,8 @@ public class Batch {
|
|||
Quantity plannedQuantity,
|
||||
LocalDate productionDate,
|
||||
LocalDate bestBeforeDate,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime updatedAt
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt
|
||||
) {
|
||||
return new Batch(id, batchNumber, recipeId, status, plannedQuantity, productionDate, bestBeforeDate, createdAt, updatedAt);
|
||||
}
|
||||
|
|
@ -123,6 +124,6 @@ public class Batch {
|
|||
public Quantity plannedQuantity() { return plannedQuantity; }
|
||||
public LocalDate productionDate() { return productionDate; }
|
||||
public LocalDate bestBeforeDate() { return bestBeforeDate; }
|
||||
public LocalDateTime createdAt() { return createdAt; }
|
||||
public LocalDateTime updatedAt() { return updatedAt; }
|
||||
public OffsetDateTime createdAt() { return createdAt; }
|
||||
public OffsetDateTime updatedAt() { return updatedAt; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ import de.effigenix.shared.common.Result;
|
|||
import de.effigenix.shared.common.UnitOfMeasure;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
|
@ -44,8 +45,8 @@ public class Recipe {
|
|||
private RecipeStatus status;
|
||||
private final List<Ingredient> ingredients;
|
||||
private final List<ProductionStep> productionSteps;
|
||||
private final LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
private final OffsetDateTime createdAt;
|
||||
private OffsetDateTime updatedAt;
|
||||
|
||||
private Recipe(
|
||||
RecipeId id,
|
||||
|
|
@ -59,8 +60,8 @@ public class Recipe {
|
|||
RecipeStatus status,
|
||||
List<Ingredient> ingredients,
|
||||
List<ProductionStep> productionSteps,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime updatedAt
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt
|
||||
) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
|
|
@ -123,7 +124,7 @@ public class Recipe {
|
|||
return Result.failure(new RecipeError.ValidationFailure("Invalid output quantity: " + e.getMessage()));
|
||||
}
|
||||
|
||||
var now = LocalDateTime.now();
|
||||
var now = OffsetDateTime.now(ZoneOffset.UTC);
|
||||
return Result.success(new Recipe(
|
||||
RecipeId.generate(), name, draft.version(), draft.type(),
|
||||
draft.description(), yieldPercentage, shelfLifeDays, outputQuantity,
|
||||
|
|
@ -146,8 +147,8 @@ public class Recipe {
|
|||
RecipeStatus status,
|
||||
List<Ingredient> ingredients,
|
||||
List<ProductionStep> productionSteps,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime updatedAt
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt
|
||||
) {
|
||||
return new Recipe(id, name, version, type, description,
|
||||
yieldPercentage, shelfLifeDays, outputQuantity, status, ingredients, productionSteps, createdAt, updatedAt);
|
||||
|
|
@ -255,8 +256,8 @@ public class Recipe {
|
|||
public RecipeStatus status() { return status; }
|
||||
public List<Ingredient> ingredients() { return Collections.unmodifiableList(ingredients); }
|
||||
public List<ProductionStep> productionSteps() { return Collections.unmodifiableList(productionSteps); }
|
||||
public LocalDateTime createdAt() { return createdAt; }
|
||||
public LocalDateTime updatedAt() { return updatedAt; }
|
||||
public OffsetDateTime createdAt() { return createdAt; }
|
||||
public OffsetDateTime updatedAt() { return updatedAt; }
|
||||
|
||||
// ==================== Helpers ====================
|
||||
|
||||
|
|
@ -269,7 +270,7 @@ public class Recipe {
|
|||
}
|
||||
|
||||
private void touch() {
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
this.updatedAt = OffsetDateTime.now(ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ package de.effigenix.domain.usermanagement;
|
|||
|
||||
import de.effigenix.shared.common.Result;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
|
@ -33,8 +34,8 @@ public class User {
|
|||
private final Set<Role> roles;
|
||||
private final String branchId;
|
||||
private final UserStatus status;
|
||||
private final LocalDateTime createdAt;
|
||||
private final LocalDateTime lastLogin;
|
||||
private final OffsetDateTime createdAt;
|
||||
private final OffsetDateTime lastLogin;
|
||||
|
||||
private User(
|
||||
UserId id,
|
||||
|
|
@ -44,8 +45,8 @@ public class User {
|
|||
Set<Role> roles,
|
||||
String branchId,
|
||||
UserStatus status,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime lastLogin
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime lastLogin
|
||||
) {
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
|
|
@ -54,7 +55,7 @@ public class User {
|
|||
this.roles = roles != null ? Set.copyOf(roles) : Set.of();
|
||||
this.branchId = branchId;
|
||||
this.status = status;
|
||||
this.createdAt = createdAt != null ? createdAt : LocalDateTime.now();
|
||||
this.createdAt = createdAt != null ? createdAt : OffsetDateTime.now(ZoneOffset.UTC);
|
||||
this.lastLogin = lastLogin;
|
||||
}
|
||||
|
||||
|
|
@ -86,7 +87,7 @@ public class User {
|
|||
roles,
|
||||
branchId,
|
||||
UserStatus.ACTIVE,
|
||||
LocalDateTime.now(),
|
||||
OffsetDateTime.now(ZoneOffset.UTC),
|
||||
null
|
||||
));
|
||||
}
|
||||
|
|
@ -102,15 +103,15 @@ public class User {
|
|||
Set<Role> roles,
|
||||
String branchId,
|
||||
UserStatus status,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime lastLogin
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime lastLogin
|
||||
) {
|
||||
return new User(id, username, email, passwordHash, roles, branchId, status, createdAt, lastLogin);
|
||||
}
|
||||
|
||||
// ==================== Business Methods (Wither-Pattern) ====================
|
||||
|
||||
public Result<UserError, User> withLastLogin(LocalDateTime timestamp) {
|
||||
public Result<UserError, User> withLastLogin(OffsetDateTime timestamp) {
|
||||
return Result.success(new User(id, username, email, passwordHash, roles, branchId, status, createdAt, timestamp));
|
||||
}
|
||||
|
||||
|
|
@ -218,8 +219,8 @@ public class User {
|
|||
public Set<Role> roles() { return Collections.unmodifiableSet(roles); }
|
||||
public String branchId() { return branchId; }
|
||||
public UserStatus status() { return status; }
|
||||
public LocalDateTime createdAt() { return createdAt; }
|
||||
public LocalDateTime lastLogin() { return lastLogin; }
|
||||
public OffsetDateTime createdAt() { return createdAt; }
|
||||
public OffsetDateTime lastLogin() { return lastLogin; }
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ import jakarta.persistence.*;
|
|||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
|
||||
/**
|
||||
* JPA Entity for Audit Logs.
|
||||
|
|
@ -43,7 +44,7 @@ public class AuditLogEntity {
|
|||
private String details;
|
||||
|
||||
@Column(name = "timestamp", nullable = false)
|
||||
private LocalDateTime timestamp;
|
||||
private OffsetDateTime timestamp;
|
||||
|
||||
@Column(name = "ip_address", length = 45) // IPv6 max length
|
||||
private String ipAddress;
|
||||
|
|
@ -53,7 +54,7 @@ public class AuditLogEntity {
|
|||
|
||||
@CreatedDate
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
private OffsetDateTime createdAt;
|
||||
|
||||
// JPA requires no-arg constructor
|
||||
protected AuditLogEntity() {
|
||||
|
|
@ -65,7 +66,7 @@ public class AuditLogEntity {
|
|||
String entityId,
|
||||
String performedBy,
|
||||
String details,
|
||||
LocalDateTime timestamp,
|
||||
OffsetDateTime timestamp,
|
||||
String ipAddress,
|
||||
String userAgent
|
||||
) {
|
||||
|
|
@ -77,7 +78,7 @@ public class AuditLogEntity {
|
|||
this.timestamp = timestamp;
|
||||
this.ipAddress = ipAddress;
|
||||
this.userAgent = userAgent;
|
||||
this.createdAt = LocalDateTime.now();
|
||||
this.createdAt = OffsetDateTime.now(ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
// Getters only (immutable after creation)
|
||||
|
|
@ -101,7 +102,7 @@ public class AuditLogEntity {
|
|||
return details;
|
||||
}
|
||||
|
||||
public LocalDateTime getTimestamp() {
|
||||
public OffsetDateTime getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
|
|
@ -113,7 +114,7 @@ public class AuditLogEntity {
|
|||
return userAgent;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
public OffsetDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import de.effigenix.application.usermanagement.AuditEvent;
|
|||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -34,7 +34,7 @@ public interface AuditLogJpaRepository extends JpaRepository<AuditLogEntity, Str
|
|||
/**
|
||||
* Finds all audit logs within a time range.
|
||||
*/
|
||||
List<AuditLogEntity> findByTimestampBetween(LocalDateTime start, LocalDateTime end);
|
||||
List<AuditLogEntity> findByTimestampBetween(OffsetDateTime start, OffsetDateTime end);
|
||||
|
||||
/**
|
||||
* Finds all audit logs for a specific event and actor.
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
|
|
@ -52,7 +53,7 @@ public class DatabaseAuditLogger implements AuditLogger {
|
|||
entityId,
|
||||
performedBy.value(),
|
||||
null, // no additional details
|
||||
LocalDateTime.now(),
|
||||
OffsetDateTime.now(ZoneOffset.UTC),
|
||||
getClientIpAddress(),
|
||||
getUserAgent()
|
||||
);
|
||||
|
|
@ -75,7 +76,7 @@ public class DatabaseAuditLogger implements AuditLogger {
|
|||
null, // no entity ID
|
||||
null, // no actor (e.g., system event)
|
||||
details,
|
||||
LocalDateTime.now(),
|
||||
OffsetDateTime.now(ZoneOffset.UTC),
|
||||
getClientIpAddress(),
|
||||
getUserAgent()
|
||||
);
|
||||
|
|
@ -97,7 +98,7 @@ public class DatabaseAuditLogger implements AuditLogger {
|
|||
entityId,
|
||||
performedBy.value(),
|
||||
details,
|
||||
LocalDateTime.now(),
|
||||
OffsetDateTime.now(ZoneOffset.UTC),
|
||||
getClientIpAddress(),
|
||||
getUserAgent()
|
||||
);
|
||||
|
|
@ -119,7 +120,7 @@ public class DatabaseAuditLogger implements AuditLogger {
|
|||
null, // no entity ID
|
||||
performedBy.value(),
|
||||
null, // no additional details
|
||||
LocalDateTime.now(),
|
||||
OffsetDateTime.now(ZoneOffset.UTC),
|
||||
getClientIpAddress(),
|
||||
getUserAgent()
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,26 @@
|
|||
package de.effigenix.infrastructure.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.data.auditing.DateTimeProvider;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Aktiviert JPA-Auditing nur, wenn eine Datenbankverbindung vorhanden ist.
|
||||
* Verwendet OffsetDateTime (UTC) statt LocalDateTime für @CreatedDate/@LastModifiedDate.
|
||||
*/
|
||||
@Configuration
|
||||
@Profile("!no-db")
|
||||
@EnableJpaAuditing
|
||||
@EnableJpaAuditing(dateTimeProviderRef = "utcDateTimeProvider")
|
||||
public class JpaAuditingConfig {
|
||||
|
||||
@Bean
|
||||
public DateTimeProvider utcDateTimeProvider() {
|
||||
return () -> Optional.of(OffsetDateTime.now(ZoneOffset.UTC));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,8 +42,7 @@ public class StockMapper {
|
|||
if (entity.getMinimumLevelAmount() != null && entity.getMinimumLevelUnit() != null) {
|
||||
var quantity = Quantity.reconstitute(
|
||||
entity.getMinimumLevelAmount(),
|
||||
UnitOfMeasure.valueOf(entity.getMinimumLevelUnit()),
|
||||
null, null
|
||||
UnitOfMeasure.valueOf(entity.getMinimumLevelUnit())
|
||||
);
|
||||
minimumLevel = new MinimumLevel(quantity);
|
||||
}
|
||||
|
|
@ -87,8 +86,7 @@ public class StockMapper {
|
|||
new BatchReference(entity.getBatchId(), BatchType.valueOf(entity.getBatchType())),
|
||||
Quantity.reconstitute(
|
||||
entity.getQuantityAmount(),
|
||||
UnitOfMeasure.valueOf(entity.getQuantityUnit()),
|
||||
null, null
|
||||
UnitOfMeasure.valueOf(entity.getQuantityUnit())
|
||||
),
|
||||
entity.getExpiryDate(),
|
||||
StockBatchStatus.valueOf(entity.getStatus()),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package de.effigenix.infrastructure.masterdata.persistence.entity;
|
|||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
|
@ -29,10 +29,10 @@ public class ArticleEntity {
|
|||
private String status;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
private OffsetDateTime createdAt;
|
||||
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private LocalDateTime updatedAt;
|
||||
private OffsetDateTime updatedAt;
|
||||
|
||||
@OneToMany(mappedBy = "article", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private List<SalesUnitEntity> salesUnits = new ArrayList<>();
|
||||
|
|
@ -45,7 +45,7 @@ public class ArticleEntity {
|
|||
protected ArticleEntity() {}
|
||||
|
||||
public ArticleEntity(String id, String name, String articleNumber, String categoryId,
|
||||
String status, LocalDateTime createdAt, LocalDateTime updatedAt) {
|
||||
String status, OffsetDateTime createdAt, OffsetDateTime updatedAt) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.articleNumber = articleNumber;
|
||||
|
|
@ -60,8 +60,8 @@ public class ArticleEntity {
|
|||
public String getArticleNumber() { return articleNumber; }
|
||||
public String getCategoryId() { return categoryId; }
|
||||
public String getStatus() { return status; }
|
||||
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
||||
public OffsetDateTime getCreatedAt() { return createdAt; }
|
||||
public OffsetDateTime getUpdatedAt() { return updatedAt; }
|
||||
public List<SalesUnitEntity> getSalesUnits() { return salesUnits; }
|
||||
public Set<String> getSupplierIds() { return supplierIds; }
|
||||
|
||||
|
|
@ -70,8 +70,8 @@ public class ArticleEntity {
|
|||
public void setArticleNumber(String articleNumber) { this.articleNumber = articleNumber; }
|
||||
public void setCategoryId(String categoryId) { this.categoryId = categoryId; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||
public void setCreatedAt(OffsetDateTime createdAt) { this.createdAt = createdAt; }
|
||||
public void setUpdatedAt(OffsetDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||
public void setSalesUnits(List<SalesUnitEntity> salesUnits) { this.salesUnits = salesUnits; }
|
||||
public void setSupplierIds(Set<String> supplierIds) { this.supplierIds = supplierIds; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package de.effigenix.infrastructure.masterdata.persistence.entity;
|
|||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
|
@ -56,10 +56,10 @@ public class CustomerEntity {
|
|||
private String status;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
private OffsetDateTime createdAt;
|
||||
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private LocalDateTime updatedAt;
|
||||
private OffsetDateTime updatedAt;
|
||||
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "delivery_addresses", joinColumns = @JoinColumn(name = "customer_id"))
|
||||
|
|
@ -91,8 +91,8 @@ public class CustomerEntity {
|
|||
public Integer getPaymentDueDays() { return paymentDueDays; }
|
||||
public String getPaymentDescription() { return paymentDescription; }
|
||||
public String getStatus() { return status; }
|
||||
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
||||
public OffsetDateTime getCreatedAt() { return createdAt; }
|
||||
public OffsetDateTime getUpdatedAt() { return updatedAt; }
|
||||
public List<DeliveryAddressEmbeddable> getDeliveryAddresses() { return deliveryAddresses; }
|
||||
public Set<de.effigenix.domain.masterdata.CustomerPreference> getPreferences() { return preferences; }
|
||||
public FrameContractEntity getFrameContract() { return frameContract; }
|
||||
|
|
@ -111,8 +111,8 @@ public class CustomerEntity {
|
|||
public void setPaymentDueDays(Integer paymentDueDays) { this.paymentDueDays = paymentDueDays; }
|
||||
public void setPaymentDescription(String paymentDescription) { this.paymentDescription = paymentDescription; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||
public void setCreatedAt(OffsetDateTime createdAt) { this.createdAt = createdAt; }
|
||||
public void setUpdatedAt(OffsetDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||
public void setDeliveryAddresses(List<DeliveryAddressEmbeddable> deliveryAddresses) { this.deliveryAddresses = deliveryAddresses; }
|
||||
public void setPreferences(Set<de.effigenix.domain.masterdata.CustomerPreference> preferences) { this.preferences = preferences; }
|
||||
public void setFrameContract(FrameContractEntity frameContract) { this.frameContract = frameContract; }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package de.effigenix.infrastructure.masterdata.persistence.entity;
|
|||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -60,10 +60,10 @@ public class SupplierEntity {
|
|||
private String status;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
private OffsetDateTime createdAt;
|
||||
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private LocalDateTime updatedAt;
|
||||
private OffsetDateTime updatedAt;
|
||||
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "quality_certificates", joinColumns = @JoinColumn(name = "supplier_id"))
|
||||
|
|
@ -87,8 +87,8 @@ public class SupplierEntity {
|
|||
public Integer getDeliveryScore() { return deliveryScore; }
|
||||
public Integer getPriceScore() { return priceScore; }
|
||||
public String getStatus() { return status; }
|
||||
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
||||
public OffsetDateTime getCreatedAt() { return createdAt; }
|
||||
public OffsetDateTime getUpdatedAt() { return updatedAt; }
|
||||
public List<QualityCertificateEmbeddable> getCertificates() { return certificates; }
|
||||
|
||||
public void setId(String id) { this.id = id; }
|
||||
|
|
@ -107,7 +107,7 @@ public class SupplierEntity {
|
|||
public void setDeliveryScore(Integer deliveryScore) { this.deliveryScore = deliveryScore; }
|
||||
public void setPriceScore(Integer priceScore) { this.priceScore = priceScore; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||
public void setCreatedAt(OffsetDateTime createdAt) { this.createdAt = createdAt; }
|
||||
public void setUpdatedAt(OffsetDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||
public void setCertificates(List<QualityCertificateEmbeddable> certificates) { this.certificates = certificates; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import de.effigenix.domain.masterdata.Article;
|
|||
import de.effigenix.domain.masterdata.SupplierId;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(requiredProperties = {"id", "name", "articleNumber", "categoryId", "salesUnits", "status", "supplierIds", "createdAt", "updatedAt"})
|
||||
|
|
@ -16,8 +16,8 @@ public record ArticleResponse(
|
|||
List<SalesUnitResponse> salesUnits,
|
||||
String status,
|
||||
List<String> supplierIds,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime updatedAt
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt
|
||||
) {
|
||||
public static ArticleResponse from(Article article) {
|
||||
return new ArticleResponse(
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import de.effigenix.domain.masterdata.Customer;
|
|||
import de.effigenix.domain.masterdata.CustomerPreference;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(requiredProperties = {"id", "name", "type", "billingAddress", "contactInfo", "deliveryAddresses", "preferences", "status", "createdAt", "updatedAt"})
|
||||
|
|
@ -19,8 +19,8 @@ public record CustomerResponse(
|
|||
@Schema(nullable = true) FrameContractResponse frameContract,
|
||||
List<String> preferences,
|
||||
String status,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime updatedAt
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt
|
||||
) {
|
||||
public static CustomerResponse from(Customer customer) {
|
||||
return new CustomerResponse(
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package de.effigenix.infrastructure.masterdata.web.dto;
|
|||
import de.effigenix.domain.masterdata.Supplier;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(requiredProperties = {"id", "name", "contactInfo", "certificates", "status", "createdAt", "updatedAt"})
|
||||
|
|
@ -16,8 +16,8 @@ public record SupplierResponse(
|
|||
List<QualityCertificateResponse> certificates,
|
||||
@Schema(nullable = true) SupplierRatingResponse rating,
|
||||
String status,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime updatedAt
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt
|
||||
) {
|
||||
public static SupplierResponse from(Supplier supplier) {
|
||||
return new SupplierResponse(
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@ package de.effigenix.infrastructure.production.persistence;
|
|||
import de.effigenix.domain.production.BatchError;
|
||||
import de.effigenix.domain.production.BatchNumber;
|
||||
import de.effigenix.domain.production.BatchNumberGenerator;
|
||||
import de.effigenix.infrastructure.production.persistence.repository.BatchJpaRepository;
|
||||
import de.effigenix.infrastructure.production.persistence.entity.BatchNumberSequenceEntity;
|
||||
import de.effigenix.infrastructure.production.persistence.repository.BatchNumberSequenceJpaRepository;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
|
|
@ -14,17 +16,25 @@ import java.time.LocalDate;
|
|||
@Profile("!no-db")
|
||||
public class JpaBatchNumberGenerator implements BatchNumberGenerator {
|
||||
|
||||
private final BatchJpaRepository batchJpaRepository;
|
||||
private final BatchNumberSequenceJpaRepository sequenceRepository;
|
||||
|
||||
public JpaBatchNumberGenerator(BatchJpaRepository batchJpaRepository) {
|
||||
this.batchJpaRepository = batchJpaRepository;
|
||||
public JpaBatchNumberGenerator(BatchNumberSequenceJpaRepository sequenceRepository) {
|
||||
this.sequenceRepository = sequenceRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<BatchError, BatchNumber> generateNext(LocalDate date) {
|
||||
try {
|
||||
int count = batchJpaRepository.countByProductionDate(date);
|
||||
int nextSequence = count + 1;
|
||||
var sequence = sequenceRepository.findByProductionDate(date);
|
||||
int nextSequence;
|
||||
if (sequence.isPresent()) {
|
||||
nextSequence = sequence.get().getLastSequence() + 1;
|
||||
sequence.get().setLastSequence(nextSequence);
|
||||
} else {
|
||||
nextSequence = 1;
|
||||
sequenceRepository.save(new BatchNumberSequenceEntity(date, 1));
|
||||
}
|
||||
if (nextSequence > 999) {
|
||||
return Result.failure(new BatchError.ValidationFailure(
|
||||
"Maximum batch number sequence (999) reached for date " + date));
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import jakarta.persistence.*;
|
|||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "batches")
|
||||
|
|
@ -36,10 +36,10 @@ public class BatchEntity {
|
|||
private LocalDate bestBeforeDate;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
private OffsetDateTime createdAt;
|
||||
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private LocalDateTime updatedAt;
|
||||
private OffsetDateTime updatedAt;
|
||||
|
||||
protected BatchEntity() {}
|
||||
|
||||
|
|
@ -52,8 +52,8 @@ public class BatchEntity {
|
|||
String plannedQuantityUnit,
|
||||
LocalDate productionDate,
|
||||
LocalDate bestBeforeDate,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime updatedAt
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt
|
||||
) {
|
||||
this.id = id;
|
||||
this.batchNumber = batchNumber;
|
||||
|
|
@ -75,6 +75,6 @@ public class BatchEntity {
|
|||
public String getPlannedQuantityUnit() { return plannedQuantityUnit; }
|
||||
public LocalDate getProductionDate() { return productionDate; }
|
||||
public LocalDate getBestBeforeDate() { return bestBeforeDate; }
|
||||
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
||||
public OffsetDateTime getCreatedAt() { return createdAt; }
|
||||
public OffsetDateTime getUpdatedAt() { return updatedAt; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
package de.effigenix.infrastructure.production.persistence.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Entity
|
||||
@Table(name = "batch_number_sequences")
|
||||
public class BatchNumberSequenceEntity {
|
||||
|
||||
@Id
|
||||
@Column(name = "production_date", nullable = false)
|
||||
private LocalDate productionDate;
|
||||
|
||||
@Column(name = "last_sequence", nullable = false)
|
||||
private int lastSequence;
|
||||
|
||||
protected BatchNumberSequenceEntity() {
|
||||
}
|
||||
|
||||
public BatchNumberSequenceEntity(LocalDate productionDate, int lastSequence) {
|
||||
this.productionDate = productionDate;
|
||||
this.lastSequence = lastSequence;
|
||||
}
|
||||
|
||||
public LocalDate getProductionDate() {
|
||||
return productionDate;
|
||||
}
|
||||
|
||||
public int getLastSequence() {
|
||||
return lastSequence;
|
||||
}
|
||||
|
||||
public void setLastSequence(int lastSequence) {
|
||||
this.lastSequence = lastSequence;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ package de.effigenix.infrastructure.production.persistence.entity;
|
|||
import jakarta.persistence.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -44,10 +44,10 @@ public class RecipeEntity {
|
|||
private String status;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
private OffsetDateTime createdAt;
|
||||
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private LocalDateTime updatedAt;
|
||||
private OffsetDateTime updatedAt;
|
||||
|
||||
@OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
@OrderBy("position ASC")
|
||||
|
|
@ -61,7 +61,7 @@ public class RecipeEntity {
|
|||
|
||||
public RecipeEntity(String id, String name, int version, String type, String description,
|
||||
int yieldPercentage, Integer shelfLifeDays, BigDecimal outputQuantity,
|
||||
String outputUom, String status, LocalDateTime createdAt, LocalDateTime updatedAt) {
|
||||
String outputUom, String status, OffsetDateTime createdAt, OffsetDateTime updatedAt) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
|
|
@ -86,8 +86,8 @@ public class RecipeEntity {
|
|||
public BigDecimal getOutputQuantity() { return outputQuantity; }
|
||||
public String getOutputUom() { return outputUom; }
|
||||
public String getStatus() { return status; }
|
||||
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
||||
public OffsetDateTime getCreatedAt() { return createdAt; }
|
||||
public OffsetDateTime getUpdatedAt() { return updatedAt; }
|
||||
public List<IngredientEntity> getIngredients() { return ingredients; }
|
||||
public List<ProductionStepEntity> getProductionSteps() { return productionSteps; }
|
||||
|
||||
|
|
@ -101,8 +101,8 @@ public class RecipeEntity {
|
|||
public void setOutputQuantity(BigDecimal outputQuantity) { this.outputQuantity = outputQuantity; }
|
||||
public void setOutputUom(String outputUom) { this.outputUom = outputUom; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||
public void setCreatedAt(OffsetDateTime createdAt) { this.createdAt = createdAt; }
|
||||
public void setUpdatedAt(OffsetDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||
public void setIngredients(List<IngredientEntity> ingredients) { this.ingredients = ingredients; }
|
||||
public void setProductionSteps(List<ProductionStepEntity> productionSteps) { this.productionSteps = productionSteps; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,8 +32,7 @@ public class BatchMapper {
|
|||
BatchStatus.valueOf(entity.getStatus()),
|
||||
Quantity.reconstitute(
|
||||
entity.getPlannedQuantityAmount(),
|
||||
UnitOfMeasure.valueOf(entity.getPlannedQuantityUnit()),
|
||||
null, null
|
||||
UnitOfMeasure.valueOf(entity.getPlannedQuantityUnit())
|
||||
),
|
||||
entity.getProductionDate(),
|
||||
entity.getBestBeforeDate(),
|
||||
|
|
|
|||
|
|
@ -62,8 +62,7 @@ public class RecipeMapper {
|
|||
entity.getShelfLifeDays(),
|
||||
Quantity.reconstitute(
|
||||
entity.getOutputQuantity(),
|
||||
UnitOfMeasure.valueOf(entity.getOutputUom()),
|
||||
null, null
|
||||
UnitOfMeasure.valueOf(entity.getOutputUom())
|
||||
),
|
||||
RecipeStatus.valueOf(entity.getStatus()),
|
||||
ingredients,
|
||||
|
|
@ -114,8 +113,7 @@ public class RecipeMapper {
|
|||
entity.getArticleId(),
|
||||
Quantity.reconstitute(
|
||||
entity.getQuantity(),
|
||||
UnitOfMeasure.valueOf(entity.getUom()),
|
||||
null, null
|
||||
UnitOfMeasure.valueOf(entity.getUom())
|
||||
),
|
||||
entity.getSubRecipeId(),
|
||||
entity.isSubstitutable()
|
||||
|
|
|
|||
|
|
@ -2,12 +2,6 @@ package de.effigenix.infrastructure.production.persistence.repository;
|
|||
|
||||
import de.effigenix.infrastructure.production.persistence.entity.BatchEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public interface BatchJpaRepository extends JpaRepository<BatchEntity, String> {
|
||||
|
||||
@Query("SELECT COUNT(b) FROM BatchEntity b WHERE b.productionDate = :date")
|
||||
int countByProductionDate(LocalDate date);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
package de.effigenix.infrastructure.production.persistence.repository;
|
||||
|
||||
import de.effigenix.infrastructure.production.persistence.entity.BatchNumberSequenceEntity;
|
||||
import jakarta.persistence.LockModeType;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Lock;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface BatchNumberSequenceJpaRepository extends JpaRepository<BatchNumberSequenceEntity, LocalDate> {
|
||||
|
||||
@Lock(LockModeType.PESSIMISTIC_WRITE)
|
||||
Optional<BatchNumberSequenceEntity> findByProductionDate(LocalDate productionDate);
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ package de.effigenix.infrastructure.production.web.dto;
|
|||
import de.effigenix.domain.production.Batch;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
public record BatchResponse(
|
||||
String id,
|
||||
|
|
@ -14,8 +14,8 @@ public record BatchResponse(
|
|||
String plannedQuantityUnit,
|
||||
LocalDate productionDate,
|
||||
LocalDate bestBeforeDate,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime updatedAt
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt
|
||||
) {
|
||||
public static BatchResponse from(Batch batch) {
|
||||
return new BatchResponse(
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package de.effigenix.infrastructure.production.web.dto;
|
|||
import de.effigenix.domain.production.Recipe;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(requiredProperties = {"id", "name", "version", "type", "description", "yieldPercentage", "outputQuantity", "outputUom", "status", "ingredients", "productionSteps", "createdAt", "updatedAt"})
|
||||
|
|
@ -20,8 +20,8 @@ public record RecipeResponse(
|
|||
String status,
|
||||
List<IngredientResponse> ingredients,
|
||||
List<ProductionStepResponse> productionSteps,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime updatedAt
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt
|
||||
) {
|
||||
public static RecipeResponse from(Recipe recipe) {
|
||||
return new RecipeResponse(
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package de.effigenix.infrastructure.production.web.dto;
|
|||
import de.effigenix.domain.production.Recipe;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
@Schema(requiredProperties = {"id", "name", "version", "type", "description", "yieldPercentage", "outputQuantity", "outputUom", "status", "ingredientCount", "stepCount", "createdAt", "updatedAt"})
|
||||
public record RecipeSummaryResponse(
|
||||
|
|
@ -19,8 +19,8 @@ public record RecipeSummaryResponse(
|
|||
String status,
|
||||
int ingredientCount,
|
||||
int stepCount,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime updatedAt
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime updatedAt
|
||||
) {
|
||||
public static RecipeSummaryResponse from(Recipe recipe) {
|
||||
return new RecipeSummaryResponse(
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import jakarta.persistence.*;
|
|||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
|
@ -48,10 +48,10 @@ public class UserEntity {
|
|||
|
||||
@CreatedDate
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
private OffsetDateTime createdAt;
|
||||
|
||||
@Column(name = "last_login")
|
||||
private LocalDateTime lastLogin;
|
||||
private OffsetDateTime lastLogin;
|
||||
|
||||
// JPA requires no-arg constructor
|
||||
protected UserEntity() {
|
||||
|
|
@ -65,8 +65,8 @@ public class UserEntity {
|
|||
Set<RoleEntity> roles,
|
||||
String branchId,
|
||||
UserStatus status,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime lastLogin
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime lastLogin
|
||||
) {
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
|
|
@ -136,19 +136,19 @@ public class UserEntity {
|
|||
this.status = status;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
public OffsetDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(LocalDateTime createdAt) {
|
||||
public void setCreatedAt(OffsetDateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getLastLogin() {
|
||||
public OffsetDateTime getLastLogin() {
|
||||
return lastLogin;
|
||||
}
|
||||
|
||||
public void setLastLogin(LocalDateTime lastLogin) {
|
||||
public void setLastLogin(OffsetDateTime lastLogin) {
|
||||
this.lastLogin = lastLogin;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ package de.effigenix.infrastructure.usermanagement.web.dto;
|
|||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -23,7 +24,7 @@ public record ErrorResponse(
|
|||
int status,
|
||||
|
||||
@Schema(description = "Timestamp when error occurred")
|
||||
LocalDateTime timestamp,
|
||||
OffsetDateTime timestamp,
|
||||
|
||||
@Schema(description = "Request path where error occurred", example = "/api/users/user-123")
|
||||
String path,
|
||||
|
|
@ -44,7 +45,7 @@ public record ErrorResponse(
|
|||
code,
|
||||
message,
|
||||
status,
|
||||
LocalDateTime.now(),
|
||||
OffsetDateTime.now(ZoneOffset.UTC),
|
||||
path,
|
||||
null
|
||||
);
|
||||
|
|
@ -63,7 +64,7 @@ public record ErrorResponse(
|
|||
"VALIDATION_ERROR",
|
||||
message,
|
||||
status,
|
||||
LocalDateTime.now(),
|
||||
OffsetDateTime.now(ZoneOffset.UTC),
|
||||
path,
|
||||
validationErrors
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package de.effigenix.infrastructure.usermanagement.web.dto;
|
|||
import de.effigenix.application.usermanagement.dto.SessionToken;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
/**
|
||||
* Response DTO for successful login.
|
||||
|
|
@ -25,7 +25,7 @@ public record LoginResponse(
|
|||
long expiresIn,
|
||||
|
||||
@Schema(description = "Token expiration timestamp")
|
||||
LocalDateTime expiresAt,
|
||||
OffsetDateTime expiresAt,
|
||||
|
||||
@Schema(description = "Refresh token for obtaining new access token")
|
||||
String refreshToken
|
||||
|
|
|
|||
|
|
@ -69,7 +69,14 @@ public final class Quantity {
|
|||
}
|
||||
|
||||
/**
|
||||
* Reconstitutes a Quantity from persistence. No validation.
|
||||
* Reconstitutes a simple Quantity from persistence. No validation.
|
||||
*/
|
||||
public static Quantity reconstitute(BigDecimal amount, UnitOfMeasure uom) {
|
||||
return new Quantity(amount, uom, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstitutes a dual Quantity (catch-weight) from persistence. No validation.
|
||||
*/
|
||||
public static Quantity reconstitute(BigDecimal amount, UnitOfMeasure uom,
|
||||
BigDecimal secondaryAmount, UnitOfMeasure secondaryUom) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<databaseChangeLog
|
||||
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
|
||||
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
|
||||
|
||||
<changeSet id="016-create-batch-number-sequences-table" author="effigenix">
|
||||
<createTable tableName="batch_number_sequences">
|
||||
<column name="production_date" type="DATE">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="last_sequence" type="INT" defaultValueNumeric="0">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<databaseChangeLog
|
||||
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
|
||||
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
|
||||
|
||||
<changeSet id="017-timestamps-to-timestamptz" author="effigenix">
|
||||
<comment>Migrate all TIMESTAMP columns to TIMESTAMP WITH TIME ZONE for consistent timezone handling</comment>
|
||||
|
||||
<!-- users -->
|
||||
<sql>ALTER TABLE users ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;</sql>
|
||||
<sql>ALTER TABLE users ALTER COLUMN last_login TYPE TIMESTAMP WITH TIME ZONE;</sql>
|
||||
|
||||
<!-- audit_logs -->
|
||||
<sql>ALTER TABLE audit_logs ALTER COLUMN timestamp TYPE TIMESTAMP WITH TIME ZONE;</sql>
|
||||
<sql>ALTER TABLE audit_logs ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;</sql>
|
||||
|
||||
<!-- articles -->
|
||||
<sql>ALTER TABLE articles ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;</sql>
|
||||
<sql>ALTER TABLE articles ALTER COLUMN updated_at TYPE TIMESTAMP WITH TIME ZONE;</sql>
|
||||
|
||||
<!-- suppliers -->
|
||||
<sql>ALTER TABLE suppliers ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;</sql>
|
||||
<sql>ALTER TABLE suppliers ALTER COLUMN updated_at TYPE TIMESTAMP WITH TIME ZONE;</sql>
|
||||
|
||||
<!-- customers -->
|
||||
<sql>ALTER TABLE customers ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;</sql>
|
||||
<sql>ALTER TABLE customers ALTER COLUMN updated_at TYPE TIMESTAMP WITH TIME ZONE;</sql>
|
||||
|
||||
<!-- recipes -->
|
||||
<sql>ALTER TABLE recipes ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;</sql>
|
||||
<sql>ALTER TABLE recipes ALTER COLUMN updated_at TYPE TIMESTAMP WITH TIME ZONE;</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
|
|
@ -20,5 +20,7 @@
|
|||
<include file="db/changelog/changes/013-create-stock-schema.xml"/>
|
||||
<include file="db/changelog/changes/014-create-stock-batches-table.xml"/>
|
||||
<include file="db/changelog/changes/015-create-batches-table.xml"/>
|
||||
<include file="db/changelog/changes/016-create-batch-number-sequences-table.xml"/>
|
||||
<include file="db/changelog/changes/017-timestamps-to-timestamptz.xml"/>
|
||||
|
||||
</databaseChangeLog>
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"))));
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
||||
|
|
|
|||
|
|
@ -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!");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue