mirror of
https://github.com/s-frick/effigenix.git
synced 2026-03-28 15:59:35 +01:00
refactor(usermanagement,masterdata): UnitOfWork-Pattern + JdbcClient-Migration
Migriert UserManagement und MasterData BCs von JPA/Spring Data auf JdbcClient + UnitOfWork, analog zum Production-BC. Inventory bleibt auf JPA. - 6 neue JdbcClient-Repositories (User, Role, Article, Supplier, Customer, ProductCategory) - 45 Use Cases: UoW für schreibende, @Transactional entfernt bei allen - AbstractIntegrationTest + 20 Integration-Tests auf JdbcClient umgestellt - 12 Unit-Test-Klassen mit UoW-Mock erweitert - 34 alte JPA-Dateien gelöscht (Entities, Spring Data Repos, Adapter, Mapper)
This commit is contained in:
parent
e5bc5690da
commit
46275f6d59
117 changed files with 2258 additions and 3549 deletions
|
|
@ -2,18 +2,19 @@ package de.effigenix.application.masterdata;
|
|||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class ActivateArticle {
|
||||
|
||||
private final ArticleRepository articleRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public ActivateArticle(ArticleRepository articleRepository) {
|
||||
public ActivateArticle(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
this.articleRepository = articleRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<ArticleError, Article> execute(ArticleId articleId, ActorId performedBy) {
|
||||
|
|
@ -30,12 +31,13 @@ public class ActivateArticle {
|
|||
}
|
||||
article.activate();
|
||||
|
||||
switch (articleRepository.save(article)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(article);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (articleRepository.save(article)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(article);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,18 +2,19 @@ package de.effigenix.application.masterdata;
|
|||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class ActivateCustomer {
|
||||
|
||||
private final CustomerRepository customerRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public ActivateCustomer(CustomerRepository customerRepository) {
|
||||
public ActivateCustomer(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
this.customerRepository = customerRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<CustomerError, Customer> execute(CustomerId customerId, ActorId performedBy) {
|
||||
|
|
@ -30,12 +31,13 @@ public class ActivateCustomer {
|
|||
}
|
||||
customer.activate();
|
||||
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(customer);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(customer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,18 +2,19 @@ package de.effigenix.application.masterdata;
|
|||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class ActivateSupplier {
|
||||
|
||||
private final SupplierRepository supplierRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public ActivateSupplier(SupplierRepository supplierRepository) {
|
||||
public ActivateSupplier(SupplierRepository supplierRepository, UnitOfWork unitOfWork) {
|
||||
this.supplierRepository = supplierRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<SupplierError, Supplier> execute(SupplierId supplierId, ActorId performedBy) {
|
||||
|
|
@ -30,12 +31,13 @@ public class ActivateSupplier {
|
|||
}
|
||||
supplier.activate();
|
||||
|
||||
switch (supplierRepository.save(supplier)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(supplier);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (supplierRepository.save(supplier)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(supplier);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,18 +3,19 @@ package de.effigenix.application.masterdata;
|
|||
import de.effigenix.application.masterdata.command.AddCertificateCommand;
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class AddCertificate {
|
||||
|
||||
private final SupplierRepository supplierRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public AddCertificate(SupplierRepository supplierRepository) {
|
||||
public AddCertificate(SupplierRepository supplierRepository, UnitOfWork unitOfWork) {
|
||||
this.supplierRepository = supplierRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<SupplierError, Supplier> execute(AddCertificateCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -39,12 +40,13 @@ public class AddCertificate {
|
|||
}
|
||||
supplier.addCertificate(certificate);
|
||||
|
||||
switch (supplierRepository.save(supplier)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(supplier);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (supplierRepository.save(supplier)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(supplier);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,18 +4,19 @@ import de.effigenix.application.masterdata.command.AddDeliveryAddressCommand;
|
|||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Address;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class AddDeliveryAddress {
|
||||
|
||||
private final CustomerRepository customerRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public AddDeliveryAddress(CustomerRepository customerRepository) {
|
||||
public AddDeliveryAddress(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
this.customerRepository = customerRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<CustomerError, Customer> execute(AddDeliveryAddressCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -46,12 +47,13 @@ public class AddDeliveryAddress {
|
|||
}
|
||||
customer.addDeliveryAddress(deliveryAddress);
|
||||
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(customer);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(customer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,18 +4,19 @@ import de.effigenix.application.masterdata.command.AddSalesUnitCommand;
|
|||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Money;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class AddSalesUnit {
|
||||
|
||||
private final ArticleRepository articleRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public AddSalesUnit(ArticleRepository articleRepository) {
|
||||
public AddSalesUnit(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
this.articleRepository = articleRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<ArticleError, Article> execute(AddSalesUnitCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -50,12 +51,13 @@ public class AddSalesUnit {
|
|||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
switch (articleRepository.save(article)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(article);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (articleRepository.save(article)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(article);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,18 +3,19 @@ package de.effigenix.application.masterdata;
|
|||
import de.effigenix.application.masterdata.command.AssignSupplierCommand;
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class AssignSupplier {
|
||||
|
||||
private final ArticleRepository articleRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public AssignSupplier(ArticleRepository articleRepository) {
|
||||
public AssignSupplier(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
this.articleRepository = articleRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<ArticleError, Article> execute(AssignSupplierCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -33,12 +34,13 @@ public class AssignSupplier {
|
|||
}
|
||||
article.addSupplierReference(SupplierId.of(cmd.supplierId()));
|
||||
|
||||
switch (articleRepository.save(article)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(article);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (articleRepository.save(article)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(article);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,17 @@ package de.effigenix.application.masterdata;
|
|||
import de.effigenix.application.masterdata.command.CreateArticleCommand;
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Transactional
|
||||
public class CreateArticle {
|
||||
|
||||
private final ArticleRepository articleRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public CreateArticle(ArticleRepository articleRepository) {
|
||||
public CreateArticle(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
this.articleRepository = articleRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<ArticleError, Article> execute(CreateArticleCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -37,12 +38,13 @@ public class CreateArticle {
|
|||
}
|
||||
}
|
||||
|
||||
switch (articleRepository.save(article)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(article);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (articleRepository.save(article)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(article);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,17 @@ package de.effigenix.application.masterdata;
|
|||
import de.effigenix.application.masterdata.command.CreateCustomerCommand;
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Transactional
|
||||
public class CreateCustomer {
|
||||
|
||||
private final CustomerRepository customerRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public CreateCustomer(CustomerRepository customerRepository) {
|
||||
public CreateCustomer(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
this.customerRepository = customerRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<CustomerError, Customer> execute(CreateCustomerCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -38,12 +39,13 @@ public class CreateCustomer {
|
|||
}
|
||||
}
|
||||
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(customer);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(customer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,17 @@ package de.effigenix.application.masterdata;
|
|||
import de.effigenix.application.masterdata.command.CreateProductCategoryCommand;
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Transactional
|
||||
public class CreateProductCategory {
|
||||
|
||||
private final ProductCategoryRepository categoryRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public CreateProductCategory(ProductCategoryRepository categoryRepository) {
|
||||
public CreateProductCategory(ProductCategoryRepository categoryRepository, UnitOfWork unitOfWork) {
|
||||
this.categoryRepository = categoryRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<ProductCategoryError, ProductCategory> execute(CreateProductCategoryCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -34,12 +35,13 @@ public class CreateProductCategory {
|
|||
}
|
||||
}
|
||||
|
||||
switch (categoryRepository.save(category)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new ProductCategoryError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(category);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (categoryRepository.save(category)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new ProductCategoryError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(category);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,17 @@ package de.effigenix.application.masterdata;
|
|||
import de.effigenix.application.masterdata.command.CreateSupplierCommand;
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Transactional
|
||||
public class CreateSupplier {
|
||||
|
||||
private final SupplierRepository supplierRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public CreateSupplier(SupplierRepository supplierRepository) {
|
||||
public CreateSupplier(SupplierRepository supplierRepository, UnitOfWork unitOfWork) {
|
||||
this.supplierRepository = supplierRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<SupplierError, Supplier> execute(CreateSupplierCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -42,12 +43,13 @@ public class CreateSupplier {
|
|||
}
|
||||
|
||||
// 4. Speichern
|
||||
switch (supplierRepository.save(supplier)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(supplier);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (supplierRepository.save(supplier)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(supplier);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,18 +2,19 @@ package de.effigenix.application.masterdata;
|
|||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class DeactivateArticle {
|
||||
|
||||
private final ArticleRepository articleRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public DeactivateArticle(ArticleRepository articleRepository) {
|
||||
public DeactivateArticle(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
this.articleRepository = articleRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<ArticleError, Article> execute(ArticleId articleId, ActorId performedBy) {
|
||||
|
|
@ -30,12 +31,13 @@ public class DeactivateArticle {
|
|||
}
|
||||
article.deactivate();
|
||||
|
||||
switch (articleRepository.save(article)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(article);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (articleRepository.save(article)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(article);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,18 +2,19 @@ package de.effigenix.application.masterdata;
|
|||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class DeactivateCustomer {
|
||||
|
||||
private final CustomerRepository customerRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public DeactivateCustomer(CustomerRepository customerRepository) {
|
||||
public DeactivateCustomer(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
this.customerRepository = customerRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<CustomerError, Customer> execute(CustomerId customerId, ActorId performedBy) {
|
||||
|
|
@ -30,12 +31,13 @@ public class DeactivateCustomer {
|
|||
}
|
||||
customer.deactivate();
|
||||
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(customer);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(customer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,18 +2,19 @@ package de.effigenix.application.masterdata;
|
|||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class DeactivateSupplier {
|
||||
|
||||
private final SupplierRepository supplierRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public DeactivateSupplier(SupplierRepository supplierRepository) {
|
||||
public DeactivateSupplier(SupplierRepository supplierRepository, UnitOfWork unitOfWork) {
|
||||
this.supplierRepository = supplierRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<SupplierError, Supplier> execute(SupplierId supplierId, ActorId performedBy) {
|
||||
|
|
@ -30,12 +31,13 @@ public class DeactivateSupplier {
|
|||
}
|
||||
supplier.deactivate();
|
||||
|
||||
switch (supplierRepository.save(supplier)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(supplier);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (supplierRepository.save(supplier)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(supplier);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,20 +2,21 @@ package de.effigenix.application.masterdata;
|
|||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class DeleteProductCategory {
|
||||
|
||||
private final ProductCategoryRepository categoryRepository;
|
||||
private final ArticleRepository articleRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public DeleteProductCategory(ProductCategoryRepository categoryRepository, ArticleRepository articleRepository) {
|
||||
public DeleteProductCategory(ProductCategoryRepository categoryRepository, ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
this.categoryRepository = categoryRepository;
|
||||
this.articleRepository = articleRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<ProductCategoryError, Void> execute(ProductCategoryId categoryId, ActorId performedBy) {
|
||||
|
|
@ -31,22 +32,24 @@ public class DeleteProductCategory {
|
|||
}
|
||||
}
|
||||
|
||||
switch (articleRepository.findByCategory(categoryId)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ProductCategoryError.RepositoryFailure(err.message())); }
|
||||
case Success(var articles) -> {
|
||||
if (!articles.isEmpty()) {
|
||||
return Result.failure(new ProductCategoryError.CategoryInUse(categoryId));
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (articleRepository.findByCategory(categoryId)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ProductCategoryError.RepositoryFailure(err.message())); }
|
||||
case Success(var articles) -> {
|
||||
if (!articles.isEmpty()) {
|
||||
return Result.failure(new ProductCategoryError.CategoryInUse(categoryId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (categoryRepository.delete(category)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ProductCategoryError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
switch (categoryRepository.delete(category)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ProductCategoryError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(null);
|
||||
return Result.success(null);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,9 @@ package de.effigenix.application.masterdata;
|
|||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public class GetArticle {
|
||||
|
||||
private final ArticleRepository articleRepository;
|
||||
|
|
|
|||
|
|
@ -2,11 +2,9 @@ package de.effigenix.application.masterdata;
|
|||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public class GetCustomer {
|
||||
|
||||
private final CustomerRepository customerRepository;
|
||||
|
|
|
|||
|
|
@ -2,11 +2,9 @@ package de.effigenix.application.masterdata;
|
|||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public class GetSupplier {
|
||||
|
||||
private final SupplierRepository supplierRepository;
|
||||
|
|
|
|||
|
|
@ -2,13 +2,11 @@ package de.effigenix.application.masterdata;
|
|||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public class ListArticles {
|
||||
|
||||
private final ArticleRepository articleRepository;
|
||||
|
|
|
|||
|
|
@ -2,13 +2,11 @@ package de.effigenix.application.masterdata;
|
|||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public class ListCustomers {
|
||||
|
||||
private final CustomerRepository customerRepository;
|
||||
|
|
|
|||
|
|
@ -2,13 +2,11 @@ package de.effigenix.application.masterdata;
|
|||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public class ListProductCategories {
|
||||
|
||||
private final ProductCategoryRepository categoryRepository;
|
||||
|
|
|
|||
|
|
@ -2,13 +2,11 @@ package de.effigenix.application.masterdata;
|
|||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public class ListSuppliers {
|
||||
|
||||
private final SupplierRepository supplierRepository;
|
||||
|
|
|
|||
|
|
@ -3,18 +3,19 @@ package de.effigenix.application.masterdata;
|
|||
import de.effigenix.application.masterdata.command.RateSupplierCommand;
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class RateSupplier {
|
||||
|
||||
private final SupplierRepository supplierRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public RateSupplier(SupplierRepository supplierRepository) {
|
||||
public RateSupplier(SupplierRepository supplierRepository, UnitOfWork unitOfWork) {
|
||||
this.supplierRepository = supplierRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<SupplierError, Supplier> execute(RateSupplierCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -39,12 +40,13 @@ public class RateSupplier {
|
|||
}
|
||||
supplier.rate(rating);
|
||||
|
||||
switch (supplierRepository.save(supplier)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(supplier);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (supplierRepository.save(supplier)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(supplier);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,20 +3,21 @@ package de.effigenix.application.masterdata;
|
|||
import de.effigenix.application.masterdata.command.RemoveCertificateCommand;
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class RemoveCertificate {
|
||||
|
||||
private final SupplierRepository supplierRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public RemoveCertificate(SupplierRepository supplierRepository) {
|
||||
public RemoveCertificate(SupplierRepository supplierRepository, UnitOfWork unitOfWork) {
|
||||
this.supplierRepository = supplierRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<SupplierError, Supplier> execute(RemoveCertificateCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -45,12 +46,13 @@ public class RemoveCertificate {
|
|||
}
|
||||
supplier.removeCertificate(certificate.get());
|
||||
|
||||
switch (supplierRepository.save(supplier)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(supplier);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (supplierRepository.save(supplier)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(supplier);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,18 +3,19 @@ package de.effigenix.application.masterdata;
|
|||
import de.effigenix.application.masterdata.command.RemoveDeliveryAddressCommand;
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class RemoveDeliveryAddress {
|
||||
|
||||
private final CustomerRepository customerRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public RemoveDeliveryAddress(CustomerRepository customerRepository) {
|
||||
public RemoveDeliveryAddress(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
this.customerRepository = customerRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<CustomerError, Customer> execute(RemoveDeliveryAddressCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -33,12 +34,13 @@ public class RemoveDeliveryAddress {
|
|||
}
|
||||
customer.removeDeliveryAddress(cmd.label());
|
||||
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(customer);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(customer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,18 +2,19 @@ package de.effigenix.application.masterdata;
|
|||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class RemoveFrameContract {
|
||||
|
||||
private final CustomerRepository customerRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public RemoveFrameContract(CustomerRepository customerRepository) {
|
||||
public RemoveFrameContract(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
this.customerRepository = customerRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<CustomerError, Customer> execute(CustomerId customerId, ActorId performedBy) {
|
||||
|
|
@ -30,12 +31,13 @@ public class RemoveFrameContract {
|
|||
}
|
||||
customer.removeFrameContract();
|
||||
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(customer);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(customer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,18 +3,19 @@ package de.effigenix.application.masterdata;
|
|||
import de.effigenix.application.masterdata.command.RemoveSalesUnitCommand;
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class RemoveSalesUnit {
|
||||
|
||||
private final ArticleRepository articleRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public RemoveSalesUnit(ArticleRepository articleRepository) {
|
||||
public RemoveSalesUnit(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
this.articleRepository = articleRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<ArticleError, Article> execute(RemoveSalesUnitCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -37,12 +38,13 @@ public class RemoveSalesUnit {
|
|||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
switch (articleRepository.save(article)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(article);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (articleRepository.save(article)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(article);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,18 +3,19 @@ package de.effigenix.application.masterdata;
|
|||
import de.effigenix.application.masterdata.command.RemoveSupplierCommand;
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class RemoveSupplier {
|
||||
|
||||
private final ArticleRepository articleRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public RemoveSupplier(ArticleRepository articleRepository) {
|
||||
public RemoveSupplier(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
this.articleRepository = articleRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<ArticleError, Article> execute(RemoveSupplierCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -33,12 +34,13 @@ public class RemoveSupplier {
|
|||
}
|
||||
article.removeSupplierReference(SupplierId.of(cmd.supplierId()));
|
||||
|
||||
switch (articleRepository.save(article)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(article);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (articleRepository.save(article)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(article);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,20 +4,21 @@ import de.effigenix.application.masterdata.command.SetFrameContractCommand;
|
|||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Money;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class SetFrameContract {
|
||||
|
||||
private final CustomerRepository customerRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public SetFrameContract(CustomerRepository customerRepository) {
|
||||
public SetFrameContract(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
this.customerRepository = customerRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<CustomerError, Customer> execute(SetFrameContractCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -62,12 +63,13 @@ public class SetFrameContract {
|
|||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(customer);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(customer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,18 +3,19 @@ package de.effigenix.application.masterdata;
|
|||
import de.effigenix.application.masterdata.command.SetPreferencesCommand;
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class SetPreferences {
|
||||
|
||||
private final CustomerRepository customerRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public SetPreferences(CustomerRepository customerRepository) {
|
||||
public SetPreferences(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
this.customerRepository = customerRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<CustomerError, Customer> execute(SetPreferencesCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -33,12 +34,13 @@ public class SetPreferences {
|
|||
}
|
||||
customer.setPreferences(cmd.preferences());
|
||||
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(customer);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(customer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,17 @@ package de.effigenix.application.masterdata;
|
|||
import de.effigenix.application.masterdata.command.UpdateArticleCommand;
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Transactional
|
||||
public class UpdateArticle {
|
||||
|
||||
private final ArticleRepository articleRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public UpdateArticle(ArticleRepository articleRepository) {
|
||||
public UpdateArticle(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
this.articleRepository = articleRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<ArticleError, Article> execute(UpdateArticleCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -36,12 +37,13 @@ public class UpdateArticle {
|
|||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
switch (articleRepository.save(article)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(article);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (articleRepository.save(article)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(article);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,17 @@ package de.effigenix.application.masterdata;
|
|||
import de.effigenix.application.masterdata.command.UpdateCustomerCommand;
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Transactional
|
||||
public class UpdateCustomer {
|
||||
|
||||
private final CustomerRepository customerRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public UpdateCustomer(CustomerRepository customerRepository) {
|
||||
public UpdateCustomer(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
this.customerRepository = customerRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<CustomerError, Customer> execute(UpdateCustomerCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -40,12 +41,13 @@ public class UpdateCustomer {
|
|||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(customer);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (customerRepository.save(customer)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(customer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,17 @@ package de.effigenix.application.masterdata;
|
|||
import de.effigenix.application.masterdata.command.UpdateProductCategoryCommand;
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Transactional
|
||||
public class UpdateProductCategory {
|
||||
|
||||
private final ProductCategoryRepository categoryRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public UpdateProductCategory(ProductCategoryRepository categoryRepository) {
|
||||
public UpdateProductCategory(ProductCategoryRepository categoryRepository, UnitOfWork unitOfWork) {
|
||||
this.categoryRepository = categoryRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<ProductCategoryError, ProductCategory> execute(UpdateProductCategoryCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -36,12 +37,13 @@ public class UpdateProductCategory {
|
|||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
switch (categoryRepository.save(category)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new ProductCategoryError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(category);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (categoryRepository.save(category)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new ProductCategoryError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(category);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,18 +4,19 @@ import de.effigenix.application.masterdata.command.UpdateSalesUnitPriceCommand;
|
|||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Money;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.effigenix.shared.common.Result.*;
|
||||
|
||||
@Transactional
|
||||
public class UpdateSalesUnitPrice {
|
||||
|
||||
private final ArticleRepository articleRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public UpdateSalesUnitPrice(ArticleRepository articleRepository) {
|
||||
public UpdateSalesUnitPrice(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
this.articleRepository = articleRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<ArticleError, Article> execute(UpdateSalesUnitPriceCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -44,12 +45,13 @@ public class UpdateSalesUnitPrice {
|
|||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
switch (articleRepository.save(article)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(article);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (articleRepository.save(article)) {
|
||||
case Failure(var err) ->
|
||||
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
|
||||
case Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(article);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,17 @@ package de.effigenix.application.masterdata;
|
|||
import de.effigenix.application.masterdata.command.UpdateSupplierCommand;
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Transactional
|
||||
public class UpdateSupplier {
|
||||
|
||||
private final SupplierRepository supplierRepository;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public UpdateSupplier(SupplierRepository supplierRepository) {
|
||||
public UpdateSupplier(SupplierRepository supplierRepository, UnitOfWork unitOfWork) {
|
||||
this.supplierRepository = supplierRepository;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<SupplierError, Supplier> execute(UpdateSupplierCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -43,12 +44,13 @@ public class UpdateSupplier {
|
|||
}
|
||||
|
||||
// 3. Speichern
|
||||
switch (supplierRepository.save(supplier)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
|
||||
return Result.success(supplier);
|
||||
return unitOfWork.executeAtomically(() -> {
|
||||
switch (supplierRepository.save(supplier)) {
|
||||
case Result.Failure(var err) ->
|
||||
{ return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
|
||||
case Result.Success(var ignored) -> { }
|
||||
}
|
||||
return Result.success(supplier);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,32 +6,34 @@ import de.effigenix.domain.usermanagement.*;
|
|||
import de.effigenix.shared.common.RepositoryError;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.AuthorizationPort;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Use Case: Assign a role to a user.
|
||||
*/
|
||||
@Transactional
|
||||
public class AssignRole {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final RoleRepository roleRepository;
|
||||
private final AuditLogger auditLogger;
|
||||
private final AuthorizationPort authPort;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public AssignRole(
|
||||
UserRepository userRepository,
|
||||
RoleRepository roleRepository,
|
||||
AuditLogger auditLogger,
|
||||
AuthorizationPort authPort
|
||||
AuthorizationPort authPort,
|
||||
UnitOfWork unitOfWork
|
||||
) {
|
||||
this.userRepository = userRepository;
|
||||
this.roleRepository = roleRepository;
|
||||
this.auditLogger = auditLogger;
|
||||
this.authPort = authPort;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<UserError, UserDTO> execute(AssignRoleCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -61,12 +63,13 @@ public class AssignRole {
|
|||
}
|
||||
Role role = optRole.get();
|
||||
return user.assignRole(role)
|
||||
.flatMap(updated -> userRepository.save(updated)
|
||||
.mapError(err -> (UserError) new UserError.RepositoryFailure(err.message()))
|
||||
.map(ignored -> {
|
||||
auditLogger.log(AuditEvent.ROLE_ASSIGNED, updated.id().value(), "Role: " + role.name(), performedBy);
|
||||
return UserDTO.from(updated);
|
||||
}));
|
||||
.flatMap(updated -> unitOfWork.executeAtomically(() ->
|
||||
userRepository.save(updated)
|
||||
.mapError(err -> (UserError) new UserError.RepositoryFailure(err.message()))
|
||||
.map(ignored -> {
|
||||
auditLogger.log(AuditEvent.ROLE_ASSIGNED, updated.id().value(), "Role: " + role.name(), performedBy);
|
||||
return UserDTO.from(updated);
|
||||
})));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import de.effigenix.application.usermanagement.command.AuthenticateCommand;
|
|||
import de.effigenix.application.usermanagement.dto.SessionToken;
|
||||
import de.effigenix.domain.usermanagement.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
|
|
@ -17,24 +17,26 @@ import java.util.Optional;
|
|||
* Returns a JWT session token on success.
|
||||
* Logs all authentication attempts for security auditing.
|
||||
*/
|
||||
@Transactional
|
||||
public class AuthenticateUser {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final PasswordHasher passwordHasher;
|
||||
private final SessionManager sessionManager;
|
||||
private final AuditLogger auditLogger;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public AuthenticateUser(
|
||||
UserRepository userRepository,
|
||||
PasswordHasher passwordHasher,
|
||||
SessionManager sessionManager,
|
||||
AuditLogger auditLogger
|
||||
AuditLogger auditLogger,
|
||||
UnitOfWork unitOfWork
|
||||
) {
|
||||
this.userRepository = userRepository;
|
||||
this.passwordHasher = passwordHasher;
|
||||
this.sessionManager = sessionManager;
|
||||
this.auditLogger = auditLogger;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<UserError, SessionToken> execute(AuthenticateCommand cmd) {
|
||||
|
|
@ -73,11 +75,12 @@ public class AuthenticateUser {
|
|||
|
||||
// 5. Update last login timestamp (immutable)
|
||||
return user.withLastLogin(OffsetDateTime.now(ZoneOffset.UTC))
|
||||
.flatMap(updated -> userRepository.save(updated)
|
||||
.mapError(err -> (UserError) new UserError.RepositoryFailure(err.message()))
|
||||
.map(ignored -> {
|
||||
auditLogger.log(AuditEvent.LOGIN_SUCCESS, updated.id().value(), ActorId.of(updated.id().value()));
|
||||
return token;
|
||||
}));
|
||||
.flatMap(updated -> unitOfWork.executeAtomically(() ->
|
||||
userRepository.save(updated)
|
||||
.mapError(err -> (UserError) new UserError.RepositoryFailure(err.message()))
|
||||
.map(ignored -> {
|
||||
auditLogger.log(AuditEvent.LOGIN_SUCCESS, updated.id().value(), ActorId.of(updated.id().value()));
|
||||
return token;
|
||||
})));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import de.effigenix.application.usermanagement.command.ChangePasswordCommand;
|
|||
import de.effigenix.domain.usermanagement.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.AuthorizationPort;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Use Case: Change user password.
|
||||
|
|
@ -13,24 +13,26 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
* Requires current password verification for security.
|
||||
* Self-service: users can change their own password without PASSWORD_CHANGE permission.
|
||||
*/
|
||||
@Transactional
|
||||
public class ChangePassword {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final PasswordHasher passwordHasher;
|
||||
private final AuditLogger auditLogger;
|
||||
private final AuthorizationPort authPort;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public ChangePassword(
|
||||
UserRepository userRepository,
|
||||
PasswordHasher passwordHasher,
|
||||
AuditLogger auditLogger,
|
||||
AuthorizationPort authPort
|
||||
AuthorizationPort authPort,
|
||||
UnitOfWork unitOfWork
|
||||
) {
|
||||
this.userRepository = userRepository;
|
||||
this.passwordHasher = passwordHasher;
|
||||
this.auditLogger = auditLogger;
|
||||
this.authPort = authPort;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<UserError, Void> execute(ChangePasswordCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -71,12 +73,13 @@ public class ChangePassword {
|
|||
// 5. Hash and update (immutable)
|
||||
PasswordHash newPasswordHash = passwordHasher.hash(cmd.newPassword());
|
||||
return user.changePassword(newPasswordHash)
|
||||
.flatMap(updated -> userRepository.save(updated)
|
||||
.mapError(err -> (UserError) new UserError.RepositoryFailure(err.message()))
|
||||
.map(ignored -> {
|
||||
auditLogger.log(AuditEvent.PASSWORD_CHANGED, updated.id().value(), performedBy);
|
||||
return null;
|
||||
}));
|
||||
.flatMap(updated -> unitOfWork.executeAtomically(() ->
|
||||
userRepository.save(updated)
|
||||
.mapError(err -> (UserError) new UserError.RepositoryFailure(err.message()))
|
||||
.map(ignored -> {
|
||||
auditLogger.log(AuditEvent.PASSWORD_CHANGED, updated.id().value(), performedBy);
|
||||
return null;
|
||||
})));
|
||||
}
|
||||
|
||||
private Result<UserError, User> findUser(UserId userId) {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import de.effigenix.domain.usermanagement.*;
|
|||
import de.effigenix.shared.common.RepositoryError;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.AuthorizationPort;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
|
@ -15,7 +15,6 @@ import java.util.Set;
|
|||
/**
|
||||
* Use Case: Create a new user account.
|
||||
*/
|
||||
@Transactional
|
||||
public class CreateUser {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
|
@ -23,19 +22,22 @@ public class CreateUser {
|
|||
private final PasswordHasher passwordHasher;
|
||||
private final AuditLogger auditLogger;
|
||||
private final AuthorizationPort authPort;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public CreateUser(
|
||||
UserRepository userRepository,
|
||||
RoleRepository roleRepository,
|
||||
PasswordHasher passwordHasher,
|
||||
AuditLogger auditLogger,
|
||||
AuthorizationPort authPort
|
||||
AuthorizationPort authPort,
|
||||
UnitOfWork unitOfWork
|
||||
) {
|
||||
this.userRepository = userRepository;
|
||||
this.roleRepository = roleRepository;
|
||||
this.passwordHasher = passwordHasher;
|
||||
this.auditLogger = auditLogger;
|
||||
this.authPort = authPort;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<UserError, UserDTO> execute(CreateUserCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -99,11 +101,12 @@ public class CreateUser {
|
|||
}
|
||||
|
||||
return User.create(cmd.username(), cmd.email(), passwordHash, roles, cmd.branchId())
|
||||
.flatMap(user -> userRepository.save(user)
|
||||
.mapError(err -> (UserError) new UserError.RepositoryFailure(err.message()))
|
||||
.map(ignored -> {
|
||||
auditLogger.log(AuditEvent.USER_CREATED, user.id().value(), performedBy);
|
||||
return UserDTO.from(user);
|
||||
}));
|
||||
.flatMap(user -> unitOfWork.executeAtomically(() ->
|
||||
userRepository.save(user)
|
||||
.mapError(err -> (UserError) new UserError.RepositoryFailure(err.message()))
|
||||
.map(ignored -> {
|
||||
auditLogger.log(AuditEvent.USER_CREATED, user.id().value(), performedBy);
|
||||
return UserDTO.from(user);
|
||||
})));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,12 +5,10 @@ import de.effigenix.domain.usermanagement.*;
|
|||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import de.effigenix.shared.security.AuthorizationPort;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Use Case: Get a single user by ID.
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public class GetUser {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import de.effigenix.shared.common.Result;
|
|||
import de.effigenix.shared.security.ActorId;
|
||||
import de.effigenix.shared.security.AuthorizationPort;
|
||||
import de.effigenix.shared.security.BranchId;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
|
@ -16,7 +15,6 @@ import java.util.stream.Collectors;
|
|||
/**
|
||||
* Use Case: List all users (with optional branch filtering).
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public class ListUsers {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
|
|
|||
|
|
@ -5,23 +5,24 @@ import de.effigenix.application.usermanagement.dto.UserDTO;
|
|||
import de.effigenix.domain.usermanagement.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.AuthorizationPort;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Use Case: Lock a user account (prevent login).
|
||||
*/
|
||||
@Transactional
|
||||
public class LockUser {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final AuditLogger auditLogger;
|
||||
private final AuthorizationPort authPort;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public LockUser(UserRepository userRepository, AuditLogger auditLogger, AuthorizationPort authPort) {
|
||||
public LockUser(UserRepository userRepository, AuditLogger auditLogger, AuthorizationPort authPort, UnitOfWork unitOfWork) {
|
||||
this.userRepository = userRepository;
|
||||
this.auditLogger = auditLogger;
|
||||
this.authPort = authPort;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<UserError, UserDTO> execute(LockUserCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -38,12 +39,13 @@ public class LockUser {
|
|||
UserId userId = UserId.of(cmd.userId());
|
||||
return findUser(userId)
|
||||
.flatMap(User::lock)
|
||||
.flatMap(updated -> userRepository.save(updated)
|
||||
.mapError(err -> (UserError) new UserError.RepositoryFailure(err.message()))
|
||||
.map(ignored -> {
|
||||
auditLogger.log(AuditEvent.USER_LOCKED, updated.id().value(), performedBy);
|
||||
return UserDTO.from(updated);
|
||||
}));
|
||||
.flatMap(updated -> unitOfWork.executeAtomically(() ->
|
||||
userRepository.save(updated)
|
||||
.mapError(err -> (UserError) new UserError.RepositoryFailure(err.message()))
|
||||
.map(ignored -> {
|
||||
auditLogger.log(AuditEvent.USER_LOCKED, updated.id().value(), performedBy);
|
||||
return UserDTO.from(updated);
|
||||
})));
|
||||
}
|
||||
|
||||
private Result<UserError, User> findUser(UserId userId) {
|
||||
|
|
|
|||
|
|
@ -5,30 +5,32 @@ import de.effigenix.application.usermanagement.dto.UserDTO;
|
|||
import de.effigenix.domain.usermanagement.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.AuthorizationPort;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Use Case: Remove a role from a user.
|
||||
*/
|
||||
@Transactional
|
||||
public class RemoveRole {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final RoleRepository roleRepository;
|
||||
private final AuditLogger auditLogger;
|
||||
private final AuthorizationPort authPort;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public RemoveRole(
|
||||
UserRepository userRepository,
|
||||
RoleRepository roleRepository,
|
||||
AuditLogger auditLogger,
|
||||
AuthorizationPort authPort
|
||||
AuthorizationPort authPort,
|
||||
UnitOfWork unitOfWork
|
||||
) {
|
||||
this.userRepository = userRepository;
|
||||
this.roleRepository = roleRepository;
|
||||
this.auditLogger = auditLogger;
|
||||
this.authPort = authPort;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<UserError, UserDTO> execute(RemoveRoleCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -58,12 +60,13 @@ public class RemoveRole {
|
|||
}
|
||||
Role role = optRole.get();
|
||||
return user.removeRole(role)
|
||||
.flatMap(updated -> userRepository.save(updated)
|
||||
.mapError(err -> (UserError) new UserError.RepositoryFailure(err.message()))
|
||||
.map(ignored -> {
|
||||
auditLogger.log(AuditEvent.ROLE_REMOVED, updated.id().value(), "Role: " + role.name(), performedBy);
|
||||
return UserDTO.from(updated);
|
||||
}));
|
||||
.flatMap(updated -> unitOfWork.executeAtomically(() ->
|
||||
userRepository.save(updated)
|
||||
.mapError(err -> (UserError) new UserError.RepositoryFailure(err.message()))
|
||||
.map(ignored -> {
|
||||
auditLogger.log(AuditEvent.ROLE_REMOVED, updated.id().value(), "Role: " + role.name(), performedBy);
|
||||
return UserDTO.from(updated);
|
||||
})));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,23 +5,24 @@ import de.effigenix.application.usermanagement.dto.UserDTO;
|
|||
import de.effigenix.domain.usermanagement.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.AuthorizationPort;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Use Case: Unlock a user account (allow login).
|
||||
*/
|
||||
@Transactional
|
||||
public class UnlockUser {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final AuditLogger auditLogger;
|
||||
private final AuthorizationPort authPort;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public UnlockUser(UserRepository userRepository, AuditLogger auditLogger, AuthorizationPort authPort) {
|
||||
public UnlockUser(UserRepository userRepository, AuditLogger auditLogger, AuthorizationPort authPort, UnitOfWork unitOfWork) {
|
||||
this.userRepository = userRepository;
|
||||
this.auditLogger = auditLogger;
|
||||
this.authPort = authPort;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<UserError, UserDTO> execute(UnlockUserCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -38,12 +39,13 @@ public class UnlockUser {
|
|||
UserId userId = UserId.of(cmd.userId());
|
||||
return findUser(userId)
|
||||
.flatMap(User::unlock)
|
||||
.flatMap(updated -> userRepository.save(updated)
|
||||
.mapError(err -> (UserError) new UserError.RepositoryFailure(err.message()))
|
||||
.map(ignored -> {
|
||||
auditLogger.log(AuditEvent.USER_UNLOCKED, updated.id().value(), performedBy);
|
||||
return UserDTO.from(updated);
|
||||
}));
|
||||
.flatMap(updated -> unitOfWork.executeAtomically(() ->
|
||||
userRepository.save(updated)
|
||||
.mapError(err -> (UserError) new UserError.RepositoryFailure(err.message()))
|
||||
.map(ignored -> {
|
||||
auditLogger.log(AuditEvent.USER_UNLOCKED, updated.id().value(), performedBy);
|
||||
return UserDTO.from(updated);
|
||||
})));
|
||||
}
|
||||
|
||||
private Result<UserError, User> findUser(UserId userId) {
|
||||
|
|
|
|||
|
|
@ -5,23 +5,24 @@ import de.effigenix.application.usermanagement.dto.UserDTO;
|
|||
import de.effigenix.domain.usermanagement.*;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import de.effigenix.shared.security.ActorId;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.AuthorizationPort;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Use Case: Update user details (email, branch).
|
||||
*/
|
||||
@Transactional
|
||||
public class UpdateUser {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final AuditLogger auditLogger;
|
||||
private final AuthorizationPort authPort;
|
||||
private final UnitOfWork unitOfWork;
|
||||
|
||||
public UpdateUser(UserRepository userRepository, AuditLogger auditLogger, AuthorizationPort authPort) {
|
||||
public UpdateUser(UserRepository userRepository, AuditLogger auditLogger, AuthorizationPort authPort, UnitOfWork unitOfWork) {
|
||||
this.userRepository = userRepository;
|
||||
this.auditLogger = auditLogger;
|
||||
this.authPort = authPort;
|
||||
this.unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public Result<UserError, UserDTO> execute(UpdateUserCommand cmd, ActorId performedBy) {
|
||||
|
|
@ -54,12 +55,13 @@ public class UpdateUser {
|
|||
current = current.flatMap(u -> u.updateBranch(cmd.branchId()));
|
||||
}
|
||||
|
||||
return current.flatMap(updated -> userRepository.save(updated)
|
||||
.mapError(err -> (UserError) new UserError.RepositoryFailure(err.message()))
|
||||
.map(ignored -> {
|
||||
auditLogger.log(AuditEvent.USER_UPDATED, updated.id().value(), performedBy);
|
||||
return UserDTO.from(updated);
|
||||
}));
|
||||
return current.flatMap(updated -> unitOfWork.executeAtomically(() ->
|
||||
userRepository.save(updated)
|
||||
.mapError(err -> (UserError) new UserError.RepositoryFailure(err.message()))
|
||||
.map(ignored -> {
|
||||
auditLogger.log(AuditEvent.USER_UPDATED, updated.id().value(), performedBy);
|
||||
return UserDTO.from(updated);
|
||||
})));
|
||||
}
|
||||
|
||||
private Result<UserError, User> findUser(UserId userId) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import de.effigenix.domain.masterdata.ArticleRepository;
|
|||
import de.effigenix.domain.masterdata.CustomerRepository;
|
||||
import de.effigenix.domain.masterdata.ProductCategoryRepository;
|
||||
import de.effigenix.domain.masterdata.SupplierRepository;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
|
@ -14,13 +15,13 @@ public class MasterDataUseCaseConfiguration {
|
|||
// ==================== Article Use Cases ====================
|
||||
|
||||
@Bean
|
||||
public CreateArticle createArticle(ArticleRepository articleRepository) {
|
||||
return new CreateArticle(articleRepository);
|
||||
public CreateArticle createArticle(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
return new CreateArticle(articleRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UpdateArticle updateArticle(ArticleRepository articleRepository) {
|
||||
return new UpdateArticle(articleRepository);
|
||||
public UpdateArticle updateArticle(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
return new UpdateArticle(articleRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
@ -34,50 +35,50 @@ public class MasterDataUseCaseConfiguration {
|
|||
}
|
||||
|
||||
@Bean
|
||||
public ActivateArticle activateArticle(ArticleRepository articleRepository) {
|
||||
return new ActivateArticle(articleRepository);
|
||||
public ActivateArticle activateArticle(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
return new ActivateArticle(articleRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DeactivateArticle deactivateArticle(ArticleRepository articleRepository) {
|
||||
return new DeactivateArticle(articleRepository);
|
||||
public DeactivateArticle deactivateArticle(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
return new DeactivateArticle(articleRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AddSalesUnit addSalesUnit(ArticleRepository articleRepository) {
|
||||
return new AddSalesUnit(articleRepository);
|
||||
public AddSalesUnit addSalesUnit(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
return new AddSalesUnit(articleRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RemoveSalesUnit removeSalesUnit(ArticleRepository articleRepository) {
|
||||
return new RemoveSalesUnit(articleRepository);
|
||||
public RemoveSalesUnit removeSalesUnit(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
return new RemoveSalesUnit(articleRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UpdateSalesUnitPrice updateSalesUnitPrice(ArticleRepository articleRepository) {
|
||||
return new UpdateSalesUnitPrice(articleRepository);
|
||||
public UpdateSalesUnitPrice updateSalesUnitPrice(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
return new UpdateSalesUnitPrice(articleRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AssignSupplier assignSupplier(ArticleRepository articleRepository) {
|
||||
return new AssignSupplier(articleRepository);
|
||||
public AssignSupplier assignSupplier(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
return new AssignSupplier(articleRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RemoveSupplier removeSupplier(ArticleRepository articleRepository) {
|
||||
return new RemoveSupplier(articleRepository);
|
||||
public RemoveSupplier removeSupplier(ArticleRepository articleRepository, UnitOfWork unitOfWork) {
|
||||
return new RemoveSupplier(articleRepository, unitOfWork);
|
||||
}
|
||||
|
||||
// ==================== ProductCategory Use Cases ====================
|
||||
|
||||
@Bean
|
||||
public CreateProductCategory createProductCategory(ProductCategoryRepository categoryRepository) {
|
||||
return new CreateProductCategory(categoryRepository);
|
||||
public CreateProductCategory createProductCategory(ProductCategoryRepository categoryRepository, UnitOfWork unitOfWork) {
|
||||
return new CreateProductCategory(categoryRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UpdateProductCategory updateProductCategory(ProductCategoryRepository categoryRepository) {
|
||||
return new UpdateProductCategory(categoryRepository);
|
||||
public UpdateProductCategory updateProductCategory(ProductCategoryRepository categoryRepository, UnitOfWork unitOfWork) {
|
||||
return new UpdateProductCategory(categoryRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
@ -88,21 +89,22 @@ public class MasterDataUseCaseConfiguration {
|
|||
@Bean
|
||||
public DeleteProductCategory deleteProductCategory(
|
||||
ProductCategoryRepository categoryRepository,
|
||||
ArticleRepository articleRepository
|
||||
ArticleRepository articleRepository,
|
||||
UnitOfWork unitOfWork
|
||||
) {
|
||||
return new DeleteProductCategory(categoryRepository, articleRepository);
|
||||
return new DeleteProductCategory(categoryRepository, articleRepository, unitOfWork);
|
||||
}
|
||||
|
||||
// ==================== Supplier Use Cases ====================
|
||||
|
||||
@Bean
|
||||
public CreateSupplier createSupplier(SupplierRepository supplierRepository) {
|
||||
return new CreateSupplier(supplierRepository);
|
||||
public CreateSupplier createSupplier(SupplierRepository supplierRepository, UnitOfWork unitOfWork) {
|
||||
return new CreateSupplier(supplierRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UpdateSupplier updateSupplier(SupplierRepository supplierRepository) {
|
||||
return new UpdateSupplier(supplierRepository);
|
||||
public UpdateSupplier updateSupplier(SupplierRepository supplierRepository, UnitOfWork unitOfWork) {
|
||||
return new UpdateSupplier(supplierRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
@ -116,40 +118,40 @@ public class MasterDataUseCaseConfiguration {
|
|||
}
|
||||
|
||||
@Bean
|
||||
public ActivateSupplier activateSupplier(SupplierRepository supplierRepository) {
|
||||
return new ActivateSupplier(supplierRepository);
|
||||
public ActivateSupplier activateSupplier(SupplierRepository supplierRepository, UnitOfWork unitOfWork) {
|
||||
return new ActivateSupplier(supplierRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DeactivateSupplier deactivateSupplier(SupplierRepository supplierRepository) {
|
||||
return new DeactivateSupplier(supplierRepository);
|
||||
public DeactivateSupplier deactivateSupplier(SupplierRepository supplierRepository, UnitOfWork unitOfWork) {
|
||||
return new DeactivateSupplier(supplierRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RateSupplier rateSupplier(SupplierRepository supplierRepository) {
|
||||
return new RateSupplier(supplierRepository);
|
||||
public RateSupplier rateSupplier(SupplierRepository supplierRepository, UnitOfWork unitOfWork) {
|
||||
return new RateSupplier(supplierRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AddCertificate addCertificate(SupplierRepository supplierRepository) {
|
||||
return new AddCertificate(supplierRepository);
|
||||
public AddCertificate addCertificate(SupplierRepository supplierRepository, UnitOfWork unitOfWork) {
|
||||
return new AddCertificate(supplierRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RemoveCertificate removeCertificate(SupplierRepository supplierRepository) {
|
||||
return new RemoveCertificate(supplierRepository);
|
||||
public RemoveCertificate removeCertificate(SupplierRepository supplierRepository, UnitOfWork unitOfWork) {
|
||||
return new RemoveCertificate(supplierRepository, unitOfWork);
|
||||
}
|
||||
|
||||
// ==================== Customer Use Cases ====================
|
||||
|
||||
@Bean
|
||||
public CreateCustomer createCustomer(CustomerRepository customerRepository) {
|
||||
return new CreateCustomer(customerRepository);
|
||||
public CreateCustomer createCustomer(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
return new CreateCustomer(customerRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UpdateCustomer updateCustomer(CustomerRepository customerRepository) {
|
||||
return new UpdateCustomer(customerRepository);
|
||||
public UpdateCustomer updateCustomer(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
return new UpdateCustomer(customerRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
@ -163,37 +165,37 @@ public class MasterDataUseCaseConfiguration {
|
|||
}
|
||||
|
||||
@Bean
|
||||
public ActivateCustomer activateCustomer(CustomerRepository customerRepository) {
|
||||
return new ActivateCustomer(customerRepository);
|
||||
public ActivateCustomer activateCustomer(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
return new ActivateCustomer(customerRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DeactivateCustomer deactivateCustomer(CustomerRepository customerRepository) {
|
||||
return new DeactivateCustomer(customerRepository);
|
||||
public DeactivateCustomer deactivateCustomer(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
return new DeactivateCustomer(customerRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AddDeliveryAddress addDeliveryAddress(CustomerRepository customerRepository) {
|
||||
return new AddDeliveryAddress(customerRepository);
|
||||
public AddDeliveryAddress addDeliveryAddress(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
return new AddDeliveryAddress(customerRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RemoveDeliveryAddress removeDeliveryAddress(CustomerRepository customerRepository) {
|
||||
return new RemoveDeliveryAddress(customerRepository);
|
||||
public RemoveDeliveryAddress removeDeliveryAddress(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
return new RemoveDeliveryAddress(customerRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SetFrameContract setFrameContract(CustomerRepository customerRepository) {
|
||||
return new SetFrameContract(customerRepository);
|
||||
public SetFrameContract setFrameContract(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
return new SetFrameContract(customerRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RemoveFrameContract removeFrameContract(CustomerRepository customerRepository) {
|
||||
return new RemoveFrameContract(customerRepository);
|
||||
public RemoveFrameContract removeFrameContract(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
return new RemoveFrameContract(customerRepository, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SetPreferences setPreferences(CustomerRepository customerRepository) {
|
||||
return new SetPreferences(customerRepository);
|
||||
public SetPreferences setPreferences(CustomerRepository customerRepository, UnitOfWork unitOfWork) {
|
||||
return new SetPreferences(customerRepository, unitOfWork);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package de.effigenix.infrastructure.config;
|
|||
import de.effigenix.application.usermanagement.*;
|
||||
import de.effigenix.domain.usermanagement.RoleRepository;
|
||||
import de.effigenix.domain.usermanagement.UserRepository;
|
||||
import de.effigenix.shared.persistence.UnitOfWork;
|
||||
import de.effigenix.shared.security.AuthorizationPort;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
|
@ -22,9 +23,10 @@ public class UseCaseConfiguration {
|
|||
RoleRepository roleRepository,
|
||||
PasswordHasher passwordHasher,
|
||||
AuditLogger auditLogger,
|
||||
AuthorizationPort authPort
|
||||
AuthorizationPort authPort,
|
||||
UnitOfWork unitOfWork
|
||||
) {
|
||||
return new CreateUser(userRepository, roleRepository, passwordHasher, auditLogger, authPort);
|
||||
return new CreateUser(userRepository, roleRepository, passwordHasher, auditLogger, authPort, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
@ -32,9 +34,10 @@ public class UseCaseConfiguration {
|
|||
UserRepository userRepository,
|
||||
PasswordHasher passwordHasher,
|
||||
SessionManager sessionManager,
|
||||
AuditLogger auditLogger
|
||||
AuditLogger auditLogger,
|
||||
UnitOfWork unitOfWork
|
||||
) {
|
||||
return new AuthenticateUser(userRepository, passwordHasher, sessionManager, auditLogger);
|
||||
return new AuthenticateUser(userRepository, passwordHasher, sessionManager, auditLogger, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
@ -42,18 +45,20 @@ public class UseCaseConfiguration {
|
|||
UserRepository userRepository,
|
||||
PasswordHasher passwordHasher,
|
||||
AuditLogger auditLogger,
|
||||
AuthorizationPort authPort
|
||||
AuthorizationPort authPort,
|
||||
UnitOfWork unitOfWork
|
||||
) {
|
||||
return new ChangePassword(userRepository, passwordHasher, auditLogger, authPort);
|
||||
return new ChangePassword(userRepository, passwordHasher, auditLogger, authPort, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UpdateUser updateUser(
|
||||
UserRepository userRepository,
|
||||
AuditLogger auditLogger,
|
||||
AuthorizationPort authPort
|
||||
AuthorizationPort authPort,
|
||||
UnitOfWork unitOfWork
|
||||
) {
|
||||
return new UpdateUser(userRepository, auditLogger, authPort);
|
||||
return new UpdateUser(userRepository, auditLogger, authPort, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
@ -61,9 +66,10 @@ public class UseCaseConfiguration {
|
|||
UserRepository userRepository,
|
||||
RoleRepository roleRepository,
|
||||
AuditLogger auditLogger,
|
||||
AuthorizationPort authPort
|
||||
AuthorizationPort authPort,
|
||||
UnitOfWork unitOfWork
|
||||
) {
|
||||
return new AssignRole(userRepository, roleRepository, auditLogger, authPort);
|
||||
return new AssignRole(userRepository, roleRepository, auditLogger, authPort, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
@ -71,27 +77,30 @@ public class UseCaseConfiguration {
|
|||
UserRepository userRepository,
|
||||
RoleRepository roleRepository,
|
||||
AuditLogger auditLogger,
|
||||
AuthorizationPort authPort
|
||||
AuthorizationPort authPort,
|
||||
UnitOfWork unitOfWork
|
||||
) {
|
||||
return new RemoveRole(userRepository, roleRepository, auditLogger, authPort);
|
||||
return new RemoveRole(userRepository, roleRepository, auditLogger, authPort, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LockUser lockUser(
|
||||
UserRepository userRepository,
|
||||
AuditLogger auditLogger,
|
||||
AuthorizationPort authPort
|
||||
AuthorizationPort authPort,
|
||||
UnitOfWork unitOfWork
|
||||
) {
|
||||
return new LockUser(userRepository, auditLogger, authPort);
|
||||
return new LockUser(userRepository, auditLogger, authPort, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UnlockUser unlockUser(
|
||||
UserRepository userRepository,
|
||||
AuditLogger auditLogger,
|
||||
AuthorizationPort authPort
|
||||
AuthorizationPort authPort,
|
||||
UnitOfWork unitOfWork
|
||||
) {
|
||||
return new UnlockUser(userRepository, auditLogger, authPort);
|
||||
return new UnlockUser(userRepository, auditLogger, authPort, unitOfWork);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
|
|||
|
|
@ -0,0 +1,239 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence;
|
||||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.Money;
|
||||
import de.effigenix.shared.common.RepositoryError;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.jdbc.core.simple.JdbcClient;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.*;
|
||||
|
||||
@Repository
|
||||
@Profile("!no-db")
|
||||
public class JdbcArticleRepository implements ArticleRepository {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JdbcArticleRepository.class);
|
||||
|
||||
private final JdbcClient jdbc;
|
||||
|
||||
public JdbcArticleRepository(JdbcClient jdbc) {
|
||||
this.jdbc = jdbc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<Article>> findById(ArticleId id) {
|
||||
try {
|
||||
var articleOpt = jdbc.sql("SELECT * FROM articles WHERE id = :id")
|
||||
.param("id", id.value())
|
||||
.query(this::mapArticleRow)
|
||||
.optional();
|
||||
if (articleOpt.isEmpty()) {
|
||||
return Result.success(Optional.empty());
|
||||
}
|
||||
return Result.success(Optional.of(loadChildren(articleOpt.get())));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findById", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Article>> findAll() {
|
||||
try {
|
||||
var articles = jdbc.sql("SELECT * FROM articles ORDER BY name")
|
||||
.query(this::mapArticleRow)
|
||||
.list()
|
||||
.stream()
|
||||
.map(this::loadChildren)
|
||||
.toList();
|
||||
return Result.success(articles);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findAll", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Article>> findByCategory(ProductCategoryId categoryId) {
|
||||
try {
|
||||
var articles = jdbc.sql("SELECT * FROM articles WHERE category_id = :categoryId ORDER BY name")
|
||||
.param("categoryId", categoryId.value())
|
||||
.query(this::mapArticleRow)
|
||||
.list()
|
||||
.stream()
|
||||
.map(this::loadChildren)
|
||||
.toList();
|
||||
return Result.success(articles);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByCategory", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Article>> findByStatus(ArticleStatus status) {
|
||||
try {
|
||||
var articles = jdbc.sql("SELECT * FROM articles WHERE status = :status ORDER BY name")
|
||||
.param("status", status.name())
|
||||
.query(this::mapArticleRow)
|
||||
.list()
|
||||
.stream()
|
||||
.map(this::loadChildren)
|
||||
.toList();
|
||||
return Result.success(articles);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByStatus", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Void> save(Article article) {
|
||||
try {
|
||||
int rows = jdbc.sql("""
|
||||
UPDATE articles
|
||||
SET name = :name, article_number = :articleNumber, category_id = :categoryId,
|
||||
status = :status, updated_at = :updatedAt
|
||||
WHERE id = :id
|
||||
""")
|
||||
.param("id", article.id().value())
|
||||
.param("name", article.name().value())
|
||||
.param("articleNumber", article.articleNumber().value())
|
||||
.param("categoryId", article.categoryId().value())
|
||||
.param("status", article.status().name())
|
||||
.param("updatedAt", article.updatedAt())
|
||||
.update();
|
||||
|
||||
if (rows == 0) {
|
||||
jdbc.sql("""
|
||||
INSERT INTO articles (id, name, article_number, category_id, status, created_at, updated_at)
|
||||
VALUES (:id, :name, :articleNumber, :categoryId, :status, :createdAt, :updatedAt)
|
||||
""")
|
||||
.param("id", article.id().value())
|
||||
.param("name", article.name().value())
|
||||
.param("articleNumber", article.articleNumber().value())
|
||||
.param("categoryId", article.categoryId().value())
|
||||
.param("status", article.status().name())
|
||||
.param("createdAt", article.createdAt())
|
||||
.param("updatedAt", article.updatedAt())
|
||||
.update();
|
||||
}
|
||||
|
||||
saveSalesUnits(article);
|
||||
saveSupplierReferences(article);
|
||||
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in save", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Void> delete(Article article) {
|
||||
try {
|
||||
jdbc.sql("DELETE FROM articles WHERE id = :id")
|
||||
.param("id", article.id().value())
|
||||
.update();
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in delete", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Boolean> existsByArticleNumber(ArticleNumber articleNumber) {
|
||||
try {
|
||||
int count = jdbc.sql("SELECT COUNT(*) FROM articles WHERE article_number = :articleNumber")
|
||||
.param("articleNumber", articleNumber.value())
|
||||
.query(Integer.class)
|
||||
.single();
|
||||
return Result.success(count > 0);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in existsByArticleNumber", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private void saveSalesUnits(Article article) {
|
||||
jdbc.sql("DELETE FROM sales_units WHERE article_id = :articleId")
|
||||
.param("articleId", article.id().value())
|
||||
.update();
|
||||
|
||||
for (SalesUnit su : article.salesUnits()) {
|
||||
jdbc.sql("""
|
||||
INSERT INTO sales_units (id, article_id, unit, price_model, price_amount, price_currency)
|
||||
VALUES (:id, :articleId, :unit, :priceModel, :priceAmount, :priceCurrency)
|
||||
""")
|
||||
.param("id", su.id().value())
|
||||
.param("articleId", article.id().value())
|
||||
.param("unit", su.unit().name())
|
||||
.param("priceModel", su.priceModel().name())
|
||||
.param("priceAmount", su.price().amount())
|
||||
.param("priceCurrency", su.price().currency().getCurrencyCode())
|
||||
.update();
|
||||
}
|
||||
}
|
||||
|
||||
private void saveSupplierReferences(Article article) {
|
||||
jdbc.sql("DELETE FROM article_suppliers WHERE article_id = :articleId")
|
||||
.param("articleId", article.id().value())
|
||||
.update();
|
||||
|
||||
for (SupplierId supplierId : article.supplierReferences()) {
|
||||
jdbc.sql("INSERT INTO article_suppliers (article_id, supplier_id) VALUES (:articleId, :supplierId)")
|
||||
.param("articleId", article.id().value())
|
||||
.param("supplierId", supplierId.value())
|
||||
.update();
|
||||
}
|
||||
}
|
||||
|
||||
private Article loadChildren(Article article) {
|
||||
var salesUnits = jdbc.sql("SELECT * FROM sales_units WHERE article_id = :articleId")
|
||||
.param("articleId", article.id().value())
|
||||
.query(this::mapSalesUnitRow)
|
||||
.list();
|
||||
|
||||
var supplierIds = jdbc.sql("SELECT supplier_id FROM article_suppliers WHERE article_id = :articleId")
|
||||
.param("articleId", article.id().value())
|
||||
.query((rs, rowNum) -> SupplierId.of(rs.getString("supplier_id")))
|
||||
.set();
|
||||
|
||||
return Article.reconstitute(
|
||||
article.id(), article.name(), article.articleNumber(), article.categoryId(),
|
||||
salesUnits, article.status(), supplierIds, article.createdAt(), article.updatedAt()
|
||||
);
|
||||
}
|
||||
|
||||
private Article mapArticleRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return Article.reconstitute(
|
||||
ArticleId.of(rs.getString("id")),
|
||||
new ArticleName(rs.getString("name")),
|
||||
new ArticleNumber(rs.getString("article_number")),
|
||||
ProductCategoryId.of(rs.getString("category_id")),
|
||||
List.of(),
|
||||
ArticleStatus.valueOf(rs.getString("status")),
|
||||
Set.of(),
|
||||
rs.getObject("created_at", OffsetDateTime.class),
|
||||
rs.getObject("updated_at", OffsetDateTime.class)
|
||||
);
|
||||
}
|
||||
|
||||
private SalesUnit mapSalesUnitRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return SalesUnit.reconstitute(
|
||||
SalesUnitId.of(rs.getString("id")),
|
||||
Unit.valueOf(rs.getString("unit")),
|
||||
PriceModel.valueOf(rs.getString("price_model")),
|
||||
new Money(rs.getBigDecimal("price_amount"),
|
||||
java.util.Currency.getInstance(rs.getString("price_currency")))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,382 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence;
|
||||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.jdbc.core.simple.JdbcClient;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.*;
|
||||
|
||||
@Repository
|
||||
@Profile("!no-db")
|
||||
public class JdbcCustomerRepository implements CustomerRepository {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JdbcCustomerRepository.class);
|
||||
|
||||
private final JdbcClient jdbc;
|
||||
|
||||
public JdbcCustomerRepository(JdbcClient jdbc) {
|
||||
this.jdbc = jdbc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<Customer>> findById(CustomerId id) {
|
||||
try {
|
||||
var customerOpt = jdbc.sql("SELECT * FROM customers WHERE id = :id")
|
||||
.param("id", id.value())
|
||||
.query(this::mapCustomerRow)
|
||||
.optional();
|
||||
if (customerOpt.isEmpty()) {
|
||||
return Result.success(Optional.empty());
|
||||
}
|
||||
return Result.success(Optional.of(loadChildren(customerOpt.get())));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findById", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Customer>> findAll() {
|
||||
try {
|
||||
var customers = jdbc.sql("SELECT * FROM customers ORDER BY name")
|
||||
.query(this::mapCustomerRow)
|
||||
.list()
|
||||
.stream()
|
||||
.map(this::loadChildren)
|
||||
.toList();
|
||||
return Result.success(customers);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findAll", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Customer>> findByType(CustomerType type) {
|
||||
try {
|
||||
var customers = jdbc.sql("SELECT * FROM customers WHERE type = :type ORDER BY name")
|
||||
.param("type", type.name())
|
||||
.query(this::mapCustomerRow)
|
||||
.list()
|
||||
.stream()
|
||||
.map(this::loadChildren)
|
||||
.toList();
|
||||
return Result.success(customers);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByType", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Customer>> findByStatus(CustomerStatus status) {
|
||||
try {
|
||||
var customers = jdbc.sql("SELECT * FROM customers WHERE status = :status ORDER BY name")
|
||||
.param("status", status.name())
|
||||
.query(this::mapCustomerRow)
|
||||
.list()
|
||||
.stream()
|
||||
.map(this::loadChildren)
|
||||
.toList();
|
||||
return Result.success(customers);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByStatus", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Void> save(Customer customer) {
|
||||
try {
|
||||
int rows = jdbc.sql("""
|
||||
UPDATE customers
|
||||
SET name = :name, type = :type, phone = :phone, email = :email,
|
||||
contact_person = :contactPerson,
|
||||
billing_street = :billingStreet, billing_house_number = :billingHouseNumber,
|
||||
billing_postal_code = :billingPostalCode, billing_city = :billingCity,
|
||||
billing_country = :billingCountry,
|
||||
payment_due_days = :paymentDueDays, payment_description = :paymentDescription,
|
||||
status = :status, updated_at = :updatedAt
|
||||
WHERE id = :id
|
||||
""")
|
||||
.param("id", customer.id().value())
|
||||
.params(customerParams(customer))
|
||||
.update();
|
||||
|
||||
if (rows == 0) {
|
||||
jdbc.sql("""
|
||||
INSERT INTO customers
|
||||
(id, name, type, phone, email, contact_person,
|
||||
billing_street, billing_house_number, billing_postal_code, billing_city, billing_country,
|
||||
payment_due_days, payment_description, status, created_at, updated_at)
|
||||
VALUES (:id, :name, :type, :phone, :email, :contactPerson,
|
||||
:billingStreet, :billingHouseNumber, :billingPostalCode, :billingCity, :billingCountry,
|
||||
:paymentDueDays, :paymentDescription, :status, :createdAt, :updatedAt)
|
||||
""")
|
||||
.param("id", customer.id().value())
|
||||
.param("createdAt", customer.createdAt())
|
||||
.params(customerParams(customer))
|
||||
.update();
|
||||
}
|
||||
|
||||
saveDeliveryAddresses(customer);
|
||||
savePreferences(customer);
|
||||
saveFrameContract(customer);
|
||||
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in save", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Void> delete(Customer customer) {
|
||||
try {
|
||||
jdbc.sql("DELETE FROM frame_contracts WHERE customer_id = :customerId")
|
||||
.param("customerId", customer.id().value())
|
||||
.update();
|
||||
jdbc.sql("DELETE FROM customers WHERE id = :id")
|
||||
.param("id", customer.id().value())
|
||||
.update();
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in delete", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Boolean> existsByName(CustomerName name) {
|
||||
try {
|
||||
int count = jdbc.sql("SELECT COUNT(*) FROM customers WHERE name = :name")
|
||||
.param("name", name.value())
|
||||
.query(Integer.class)
|
||||
.single();
|
||||
return Result.success(count > 0);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in existsByName", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> customerParams(Customer customer) {
|
||||
var params = new LinkedHashMap<String, Object>();
|
||||
params.put("name", customer.name().value());
|
||||
params.put("type", customer.type().name());
|
||||
params.put("phone", customer.contactInfo() != null ? customer.contactInfo().phone() : null);
|
||||
params.put("email", customer.contactInfo() != null ? customer.contactInfo().email() : null);
|
||||
params.put("contactPerson", customer.contactInfo() != null ? customer.contactInfo().contactPerson() : null);
|
||||
params.put("billingStreet", customer.billingAddress().street());
|
||||
params.put("billingHouseNumber", customer.billingAddress().houseNumber());
|
||||
params.put("billingPostalCode", customer.billingAddress().postalCode());
|
||||
params.put("billingCity", customer.billingAddress().city());
|
||||
params.put("billingCountry", customer.billingAddress().country());
|
||||
params.put("paymentDueDays", customer.paymentTerms() != null ? customer.paymentTerms().paymentDueDays() : null);
|
||||
params.put("paymentDescription", customer.paymentTerms() != null ? customer.paymentTerms().description() : null);
|
||||
params.put("status", customer.status().name());
|
||||
params.put("updatedAt", customer.updatedAt());
|
||||
return params;
|
||||
}
|
||||
|
||||
private void saveDeliveryAddresses(Customer customer) {
|
||||
jdbc.sql("DELETE FROM delivery_addresses WHERE customer_id = :customerId")
|
||||
.param("customerId", customer.id().value())
|
||||
.update();
|
||||
|
||||
for (DeliveryAddress da : customer.deliveryAddresses()) {
|
||||
jdbc.sql("""
|
||||
INSERT INTO delivery_addresses
|
||||
(customer_id, label, street, house_number, postal_code, city, country, contact_person, delivery_notes)
|
||||
VALUES (:customerId, :label, :street, :houseNumber, :postalCode, :city, :country, :contactPerson, :deliveryNotes)
|
||||
""")
|
||||
.param("customerId", customer.id().value())
|
||||
.param("label", da.label())
|
||||
.param("street", da.address().street())
|
||||
.param("houseNumber", da.address().houseNumber())
|
||||
.param("postalCode", da.address().postalCode())
|
||||
.param("city", da.address().city())
|
||||
.param("country", da.address().country())
|
||||
.param("contactPerson", da.contactPerson())
|
||||
.param("deliveryNotes", da.deliveryNotes())
|
||||
.update();
|
||||
}
|
||||
}
|
||||
|
||||
private void savePreferences(Customer customer) {
|
||||
jdbc.sql("DELETE FROM customer_preferences WHERE customer_id = :customerId")
|
||||
.param("customerId", customer.id().value())
|
||||
.update();
|
||||
|
||||
for (CustomerPreference pref : customer.preferences()) {
|
||||
jdbc.sql("INSERT INTO customer_preferences (customer_id, preference) VALUES (:customerId, :preference)")
|
||||
.param("customerId", customer.id().value())
|
||||
.param("preference", pref.name())
|
||||
.update();
|
||||
}
|
||||
}
|
||||
|
||||
private void saveFrameContract(Customer customer) {
|
||||
jdbc.sql("DELETE FROM frame_contracts WHERE customer_id = :customerId")
|
||||
.param("customerId", customer.id().value())
|
||||
.update();
|
||||
|
||||
if (customer.frameContract() != null) {
|
||||
var fc = customer.frameContract();
|
||||
jdbc.sql("""
|
||||
INSERT INTO frame_contracts (id, customer_id, valid_from, valid_until, delivery_rhythm)
|
||||
VALUES (:id, :customerId, :validFrom, :validUntil, :deliveryRhythm)
|
||||
""")
|
||||
.param("id", fc.id().value())
|
||||
.param("customerId", customer.id().value())
|
||||
.param("validFrom", fc.validFrom())
|
||||
.param("validUntil", fc.validUntil())
|
||||
.param("deliveryRhythm", fc.deliveryRhythm().name())
|
||||
.update();
|
||||
|
||||
saveContractLineItems(fc);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveContractLineItems(FrameContract fc) {
|
||||
jdbc.sql("DELETE FROM contract_line_items WHERE frame_contract_id = :fcId")
|
||||
.param("fcId", fc.id().value())
|
||||
.update();
|
||||
|
||||
for (ContractLineItem item : fc.lineItems()) {
|
||||
jdbc.sql("""
|
||||
INSERT INTO contract_line_items
|
||||
(frame_contract_id, article_id, agreed_price_amount, agreed_price_currency, agreed_quantity, unit)
|
||||
VALUES (:fcId, :articleId, :priceAmount, :priceCurrency, :quantity, :unit)
|
||||
""")
|
||||
.param("fcId", fc.id().value())
|
||||
.param("articleId", item.articleId().value())
|
||||
.param("priceAmount", item.agreedPrice().amount())
|
||||
.param("priceCurrency", item.agreedPrice().currency().getCurrencyCode())
|
||||
.param("quantity", item.agreedQuantity())
|
||||
.param("unit", item.unit() != null ? item.unit().name() : null)
|
||||
.update();
|
||||
}
|
||||
}
|
||||
|
||||
private Customer loadChildren(Customer customer) {
|
||||
var deliveryAddresses = jdbc.sql(
|
||||
"SELECT * FROM delivery_addresses WHERE customer_id = :customerId")
|
||||
.param("customerId", customer.id().value())
|
||||
.query(this::mapDeliveryAddressRow)
|
||||
.list();
|
||||
|
||||
var preferences = jdbc.sql(
|
||||
"SELECT preference FROM customer_preferences WHERE customer_id = :customerId")
|
||||
.param("customerId", customer.id().value())
|
||||
.query((rs, rowNum) -> CustomerPreference.valueOf(rs.getString("preference")))
|
||||
.set();
|
||||
|
||||
FrameContract frameContract = loadFrameContract(customer.id().value());
|
||||
|
||||
return Customer.reconstitute(
|
||||
customer.id(), customer.name(), customer.type(), customer.billingAddress(),
|
||||
customer.contactInfo(), customer.paymentTerms(), deliveryAddresses,
|
||||
frameContract, preferences, customer.status(), customer.createdAt(), customer.updatedAt()
|
||||
);
|
||||
}
|
||||
|
||||
private FrameContract loadFrameContract(String customerId) {
|
||||
var fcOpt = jdbc.sql("SELECT * FROM frame_contracts WHERE customer_id = :customerId")
|
||||
.param("customerId", customerId)
|
||||
.query(this::mapFrameContractRow)
|
||||
.optional();
|
||||
|
||||
if (fcOpt.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var fc = fcOpt.get();
|
||||
var lineItems = jdbc.sql(
|
||||
"SELECT * FROM contract_line_items WHERE frame_contract_id = :fcId")
|
||||
.param("fcId", fc.id().value())
|
||||
.query(this::mapContractLineItemRow)
|
||||
.list();
|
||||
|
||||
return FrameContract.reconstitute(fc.id(), fc.validFrom(), fc.validUntil(),
|
||||
fc.deliveryRhythm(), lineItems);
|
||||
}
|
||||
|
||||
private Customer mapCustomerRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
Address billingAddress = new Address(
|
||||
rs.getString("billing_street"),
|
||||
rs.getString("billing_house_number"),
|
||||
rs.getString("billing_postal_code"),
|
||||
rs.getString("billing_city"),
|
||||
rs.getString("billing_country")
|
||||
);
|
||||
|
||||
ContactInfo contactInfo = new ContactInfo(
|
||||
rs.getString("phone"), rs.getString("email"), rs.getString("contact_person"));
|
||||
|
||||
PaymentTerms paymentTerms = null;
|
||||
Integer dueDays = rs.getObject("payment_due_days", Integer.class);
|
||||
if (dueDays != null) {
|
||||
paymentTerms = new PaymentTerms(dueDays, rs.getString("payment_description"));
|
||||
}
|
||||
|
||||
return Customer.reconstitute(
|
||||
CustomerId.of(rs.getString("id")),
|
||||
new CustomerName(rs.getString("name")),
|
||||
CustomerType.valueOf(rs.getString("type")),
|
||||
billingAddress,
|
||||
contactInfo,
|
||||
paymentTerms,
|
||||
List.of(),
|
||||
null,
|
||||
Set.of(),
|
||||
CustomerStatus.valueOf(rs.getString("status")),
|
||||
rs.getObject("created_at", OffsetDateTime.class),
|
||||
rs.getObject("updated_at", OffsetDateTime.class)
|
||||
);
|
||||
}
|
||||
|
||||
private DeliveryAddress mapDeliveryAddressRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
Address address = new Address(
|
||||
rs.getString("street"),
|
||||
rs.getString("house_number"),
|
||||
rs.getString("postal_code"),
|
||||
rs.getString("city"),
|
||||
rs.getString("country")
|
||||
);
|
||||
return new DeliveryAddress(
|
||||
rs.getString("label"), address,
|
||||
rs.getString("contact_person"), rs.getString("delivery_notes")
|
||||
);
|
||||
}
|
||||
|
||||
private FrameContract mapFrameContractRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return FrameContract.reconstitute(
|
||||
FrameContractId.of(rs.getString("id")),
|
||||
rs.getObject("valid_from", LocalDate.class),
|
||||
rs.getObject("valid_until", LocalDate.class),
|
||||
DeliveryRhythm.valueOf(rs.getString("delivery_rhythm")),
|
||||
List.of()
|
||||
);
|
||||
}
|
||||
|
||||
private ContractLineItem mapContractLineItemRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
String unitStr = rs.getString("unit");
|
||||
return new ContractLineItem(
|
||||
ArticleId.of(rs.getString("article_id")),
|
||||
new Money(rs.getBigDecimal("agreed_price_amount"),
|
||||
Currency.getInstance(rs.getString("agreed_price_currency"))),
|
||||
rs.getObject("agreed_quantity", BigDecimal.class),
|
||||
unitStr != null ? Unit.valueOf(unitStr) : null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence;
|
||||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.RepositoryError;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.jdbc.core.simple.JdbcClient;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
@Profile("!no-db")
|
||||
public class JdbcProductCategoryRepository implements ProductCategoryRepository {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JdbcProductCategoryRepository.class);
|
||||
|
||||
private final JdbcClient jdbc;
|
||||
|
||||
public JdbcProductCategoryRepository(JdbcClient jdbc) {
|
||||
this.jdbc = jdbc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<ProductCategory>> findById(ProductCategoryId id) {
|
||||
try {
|
||||
var result = jdbc.sql("SELECT * FROM product_categories WHERE id = :id")
|
||||
.param("id", id.value())
|
||||
.query(this::mapRow)
|
||||
.optional();
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findById", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<ProductCategory>> findAll() {
|
||||
try {
|
||||
var result = jdbc.sql("SELECT * FROM product_categories ORDER BY name")
|
||||
.query(this::mapRow)
|
||||
.list();
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findAll", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Void> save(ProductCategory category) {
|
||||
try {
|
||||
int rows = jdbc.sql("""
|
||||
UPDATE product_categories SET name = :name, description = :description
|
||||
WHERE id = :id
|
||||
""")
|
||||
.param("id", category.id().value())
|
||||
.param("name", category.name().value())
|
||||
.param("description", category.description())
|
||||
.update();
|
||||
|
||||
if (rows == 0) {
|
||||
jdbc.sql("""
|
||||
INSERT INTO product_categories (id, name, description)
|
||||
VALUES (:id, :name, :description)
|
||||
""")
|
||||
.param("id", category.id().value())
|
||||
.param("name", category.name().value())
|
||||
.param("description", category.description())
|
||||
.update();
|
||||
}
|
||||
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in save", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Void> delete(ProductCategory category) {
|
||||
try {
|
||||
jdbc.sql("DELETE FROM product_categories WHERE id = :id")
|
||||
.param("id", category.id().value())
|
||||
.update();
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in delete", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Boolean> existsByName(CategoryName name) {
|
||||
try {
|
||||
int count = jdbc.sql("SELECT COUNT(*) FROM product_categories WHERE name = :name")
|
||||
.param("name", name.value())
|
||||
.query(Integer.class)
|
||||
.single();
|
||||
return Result.success(count > 0);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in existsByName", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private ProductCategory mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return ProductCategory.reconstitute(
|
||||
ProductCategoryId.of(rs.getString("id")),
|
||||
new CategoryName(rs.getString("name")),
|
||||
rs.getString("description")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence;
|
||||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.shared.common.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.jdbc.core.simple.JdbcClient;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
@Profile("!no-db")
|
||||
public class JdbcSupplierRepository implements SupplierRepository {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JdbcSupplierRepository.class);
|
||||
|
||||
private final JdbcClient jdbc;
|
||||
|
||||
public JdbcSupplierRepository(JdbcClient jdbc) {
|
||||
this.jdbc = jdbc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<Supplier>> findById(SupplierId id) {
|
||||
try {
|
||||
var supplierOpt = jdbc.sql("SELECT * FROM suppliers WHERE id = :id")
|
||||
.param("id", id.value())
|
||||
.query(this::mapSupplierRow)
|
||||
.optional();
|
||||
if (supplierOpt.isEmpty()) {
|
||||
return Result.success(Optional.empty());
|
||||
}
|
||||
return Result.success(Optional.of(loadCertificates(supplierOpt.get())));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findById", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Supplier>> findAll() {
|
||||
try {
|
||||
var suppliers = jdbc.sql("SELECT * FROM suppliers ORDER BY name")
|
||||
.query(this::mapSupplierRow)
|
||||
.list()
|
||||
.stream()
|
||||
.map(this::loadCertificates)
|
||||
.toList();
|
||||
return Result.success(suppliers);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findAll", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Supplier>> findByStatus(SupplierStatus status) {
|
||||
try {
|
||||
var suppliers = jdbc.sql("SELECT * FROM suppliers WHERE status = :status ORDER BY name")
|
||||
.param("status", status.name())
|
||||
.query(this::mapSupplierRow)
|
||||
.list()
|
||||
.stream()
|
||||
.map(this::loadCertificates)
|
||||
.toList();
|
||||
return Result.success(suppliers);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByStatus", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Void> save(Supplier supplier) {
|
||||
try {
|
||||
int rows = jdbc.sql("""
|
||||
UPDATE suppliers
|
||||
SET name = :name, phone = :phone, email = :email, contact_person = :contactPerson,
|
||||
street = :street, house_number = :houseNumber, postal_code = :postalCode,
|
||||
city = :city, country = :country,
|
||||
payment_due_days = :paymentDueDays, payment_description = :paymentDescription,
|
||||
quality_score = :qualityScore, delivery_score = :deliveryScore, price_score = :priceScore,
|
||||
status = :status, updated_at = :updatedAt
|
||||
WHERE id = :id
|
||||
""")
|
||||
.param("id", supplier.id().value())
|
||||
.params(supplierParams(supplier))
|
||||
.update();
|
||||
|
||||
if (rows == 0) {
|
||||
jdbc.sql("""
|
||||
INSERT INTO suppliers
|
||||
(id, name, phone, email, contact_person, street, house_number, postal_code, city, country,
|
||||
payment_due_days, payment_description, quality_score, delivery_score, price_score,
|
||||
status, created_at, updated_at)
|
||||
VALUES (:id, :name, :phone, :email, :contactPerson, :street, :houseNumber, :postalCode,
|
||||
:city, :country, :paymentDueDays, :paymentDescription,
|
||||
:qualityScore, :deliveryScore, :priceScore, :status, :createdAt, :updatedAt)
|
||||
""")
|
||||
.param("id", supplier.id().value())
|
||||
.param("createdAt", supplier.createdAt())
|
||||
.params(supplierParams(supplier))
|
||||
.update();
|
||||
}
|
||||
|
||||
saveCertificates(supplier);
|
||||
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in save", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Void> delete(Supplier supplier) {
|
||||
try {
|
||||
jdbc.sql("DELETE FROM suppliers WHERE id = :id")
|
||||
.param("id", supplier.id().value())
|
||||
.update();
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in delete", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Boolean> existsByName(SupplierName name) {
|
||||
try {
|
||||
int count = jdbc.sql("SELECT COUNT(*) FROM suppliers WHERE name = :name")
|
||||
.param("name", name.value())
|
||||
.query(Integer.class)
|
||||
.single();
|
||||
return Result.success(count > 0);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in existsByName", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private java.util.Map<String, Object> supplierParams(Supplier supplier) {
|
||||
var params = new java.util.LinkedHashMap<String, Object>();
|
||||
params.put("name", supplier.name().value());
|
||||
params.put("phone", supplier.contactInfo() != null ? supplier.contactInfo().phone() : null);
|
||||
params.put("email", supplier.contactInfo() != null ? supplier.contactInfo().email() : null);
|
||||
params.put("contactPerson", supplier.contactInfo() != null ? supplier.contactInfo().contactPerson() : null);
|
||||
params.put("street", supplier.address() != null ? supplier.address().street() : null);
|
||||
params.put("houseNumber", supplier.address() != null ? supplier.address().houseNumber() : null);
|
||||
params.put("postalCode", supplier.address() != null ? supplier.address().postalCode() : null);
|
||||
params.put("city", supplier.address() != null ? supplier.address().city() : null);
|
||||
params.put("country", supplier.address() != null ? supplier.address().country() : null);
|
||||
params.put("paymentDueDays", supplier.paymentTerms() != null ? supplier.paymentTerms().paymentDueDays() : null);
|
||||
params.put("paymentDescription", supplier.paymentTerms() != null ? supplier.paymentTerms().description() : null);
|
||||
params.put("qualityScore", supplier.rating() != null ? supplier.rating().qualityScore() : null);
|
||||
params.put("deliveryScore", supplier.rating() != null ? supplier.rating().deliveryScore() : null);
|
||||
params.put("priceScore", supplier.rating() != null ? supplier.rating().priceScore() : null);
|
||||
params.put("status", supplier.status().name());
|
||||
params.put("updatedAt", supplier.updatedAt());
|
||||
return params;
|
||||
}
|
||||
|
||||
private void saveCertificates(Supplier supplier) {
|
||||
jdbc.sql("DELETE FROM quality_certificates WHERE supplier_id = :supplierId")
|
||||
.param("supplierId", supplier.id().value())
|
||||
.update();
|
||||
|
||||
for (QualityCertificate cert : supplier.certificates()) {
|
||||
jdbc.sql("""
|
||||
INSERT INTO quality_certificates (supplier_id, certificate_type, issuer, valid_from, valid_until)
|
||||
VALUES (:supplierId, :certificateType, :issuer, :validFrom, :validUntil)
|
||||
""")
|
||||
.param("supplierId", supplier.id().value())
|
||||
.param("certificateType", cert.certificateType())
|
||||
.param("issuer", cert.issuer())
|
||||
.param("validFrom", cert.validFrom())
|
||||
.param("validUntil", cert.validUntil())
|
||||
.update();
|
||||
}
|
||||
}
|
||||
|
||||
private Supplier loadCertificates(Supplier supplier) {
|
||||
var certificates = jdbc.sql(
|
||||
"SELECT * FROM quality_certificates WHERE supplier_id = :supplierId")
|
||||
.param("supplierId", supplier.id().value())
|
||||
.query(this::mapCertificateRow)
|
||||
.list();
|
||||
|
||||
return Supplier.reconstitute(
|
||||
supplier.id(), supplier.name(), supplier.address(), supplier.contactInfo(),
|
||||
supplier.paymentTerms(), certificates, supplier.rating(), supplier.status(),
|
||||
supplier.createdAt(), supplier.updatedAt()
|
||||
);
|
||||
}
|
||||
|
||||
private Supplier mapSupplierRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
// Address (optional)
|
||||
Address address = null;
|
||||
String street = rs.getString("street");
|
||||
if (street != null) {
|
||||
address = new Address(street, rs.getString("house_number"),
|
||||
rs.getString("postal_code"), rs.getString("city"), rs.getString("country"));
|
||||
}
|
||||
|
||||
// ContactInfo
|
||||
ContactInfo contactInfo = new ContactInfo(
|
||||
rs.getString("phone"), rs.getString("email"), rs.getString("contact_person"));
|
||||
|
||||
// PaymentTerms (optional)
|
||||
PaymentTerms paymentTerms = null;
|
||||
Integer dueDays = rs.getObject("payment_due_days", Integer.class);
|
||||
if (dueDays != null) {
|
||||
paymentTerms = new PaymentTerms(dueDays, rs.getString("payment_description"));
|
||||
}
|
||||
|
||||
// SupplierRating (optional)
|
||||
SupplierRating rating = null;
|
||||
Integer qualityScore = rs.getObject("quality_score", Integer.class);
|
||||
if (qualityScore != null) {
|
||||
rating = new SupplierRating(qualityScore,
|
||||
rs.getInt("delivery_score"), rs.getInt("price_score"));
|
||||
}
|
||||
|
||||
return Supplier.reconstitute(
|
||||
SupplierId.of(rs.getString("id")),
|
||||
new SupplierName(rs.getString("name")),
|
||||
address,
|
||||
contactInfo,
|
||||
paymentTerms,
|
||||
List.of(),
|
||||
rating,
|
||||
SupplierStatus.valueOf(rs.getString("status")),
|
||||
rs.getObject("created_at", OffsetDateTime.class),
|
||||
rs.getObject("updated_at", OffsetDateTime.class)
|
||||
);
|
||||
}
|
||||
|
||||
private QualityCertificate mapCertificateRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return new QualityCertificate(
|
||||
rs.getString("certificate_type"),
|
||||
rs.getString("issuer"),
|
||||
rs.getObject("valid_from", LocalDate.class),
|
||||
rs.getObject("valid_until", LocalDate.class)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
@Table(name = "articles")
|
||||
public class ArticleEntity {
|
||||
|
||||
@Id
|
||||
@Column(name = "id", nullable = false, length = 36)
|
||||
private String id;
|
||||
|
||||
@Column(name = "name", nullable = false, length = 200)
|
||||
private String name;
|
||||
|
||||
@Column(name = "article_number", nullable = false, unique = true, length = 50)
|
||||
private String articleNumber;
|
||||
|
||||
@Column(name = "category_id", nullable = false, length = 36)
|
||||
private String categoryId;
|
||||
|
||||
@Column(name = "status", nullable = false, length = 20)
|
||||
private String status;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private OffsetDateTime createdAt;
|
||||
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private OffsetDateTime updatedAt;
|
||||
|
||||
@OneToMany(mappedBy = "article", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private List<SalesUnitEntity> salesUnits = new ArrayList<>();
|
||||
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "article_suppliers", joinColumns = @JoinColumn(name = "article_id"))
|
||||
@Column(name = "supplier_id")
|
||||
private Set<String> supplierIds = new HashSet<>();
|
||||
|
||||
protected ArticleEntity() {}
|
||||
|
||||
public ArticleEntity(String id, String name, String articleNumber, String categoryId,
|
||||
String status, OffsetDateTime createdAt, OffsetDateTime updatedAt) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.articleNumber = articleNumber;
|
||||
this.categoryId = categoryId;
|
||||
this.status = status;
|
||||
this.createdAt = createdAt;
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
|
||||
public String getId() { return id; }
|
||||
public String getName() { return name; }
|
||||
public String getArticleNumber() { return articleNumber; }
|
||||
public String getCategoryId() { return categoryId; }
|
||||
public String getStatus() { return status; }
|
||||
public OffsetDateTime getCreatedAt() { return createdAt; }
|
||||
public OffsetDateTime getUpdatedAt() { return updatedAt; }
|
||||
public List<SalesUnitEntity> getSalesUnits() { return salesUnits; }
|
||||
public Set<String> getSupplierIds() { return supplierIds; }
|
||||
|
||||
public void setId(String id) { this.id = id; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
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(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; }
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.entity;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Embeddable
|
||||
public class ContractLineItemEmbeddable {
|
||||
|
||||
@Column(name = "article_id", nullable = false, length = 36)
|
||||
private String articleId;
|
||||
|
||||
@Column(name = "agreed_price_amount", nullable = false, precision = 19, scale = 2)
|
||||
private BigDecimal agreedPriceAmount;
|
||||
|
||||
@Column(name = "agreed_price_currency", nullable = false, length = 3)
|
||||
private String agreedPriceCurrency;
|
||||
|
||||
@Column(name = "agreed_quantity", precision = 19, scale = 4)
|
||||
private BigDecimal agreedQuantity;
|
||||
|
||||
@Column(name = "unit", length = 30)
|
||||
private String unit;
|
||||
|
||||
protected ContractLineItemEmbeddable() {}
|
||||
|
||||
public ContractLineItemEmbeddable(String articleId, BigDecimal agreedPriceAmount,
|
||||
String agreedPriceCurrency, BigDecimal agreedQuantity, String unit) {
|
||||
this.articleId = articleId;
|
||||
this.agreedPriceAmount = agreedPriceAmount;
|
||||
this.agreedPriceCurrency = agreedPriceCurrency;
|
||||
this.agreedQuantity = agreedQuantity;
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
public String getArticleId() { return articleId; }
|
||||
public BigDecimal getAgreedPriceAmount() { return agreedPriceAmount; }
|
||||
public String getAgreedPriceCurrency() { return agreedPriceCurrency; }
|
||||
public BigDecimal getAgreedQuantity() { return agreedQuantity; }
|
||||
public String getUnit() { return unit; }
|
||||
}
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
@Table(name = "customers")
|
||||
public class CustomerEntity {
|
||||
|
||||
@Id
|
||||
@Column(name = "id", nullable = false, length = 36)
|
||||
private String id;
|
||||
|
||||
@Column(name = "name", nullable = false, unique = true, length = 200)
|
||||
private String name;
|
||||
|
||||
@Column(name = "type", nullable = false, length = 10)
|
||||
private String type;
|
||||
|
||||
@Column(name = "phone", length = 50)
|
||||
private String phone;
|
||||
|
||||
@Column(name = "email", length = 255)
|
||||
private String email;
|
||||
|
||||
@Column(name = "contact_person", length = 200)
|
||||
private String contactPerson;
|
||||
|
||||
@Column(name = "billing_street", nullable = false, length = 200)
|
||||
private String billingStreet;
|
||||
|
||||
@Column(name = "billing_house_number", length = 20)
|
||||
private String billingHouseNumber;
|
||||
|
||||
@Column(name = "billing_postal_code", nullable = false, length = 20)
|
||||
private String billingPostalCode;
|
||||
|
||||
@Column(name = "billing_city", nullable = false, length = 100)
|
||||
private String billingCity;
|
||||
|
||||
@Column(name = "billing_country", nullable = false, length = 2)
|
||||
private String billingCountry;
|
||||
|
||||
@Column(name = "payment_due_days")
|
||||
private Integer paymentDueDays;
|
||||
|
||||
@Column(name = "payment_description", length = 500)
|
||||
private String paymentDescription;
|
||||
|
||||
@Column(name = "status", nullable = false, length = 20)
|
||||
private String status;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private OffsetDateTime createdAt;
|
||||
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private OffsetDateTime updatedAt;
|
||||
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "delivery_addresses", joinColumns = @JoinColumn(name = "customer_id"))
|
||||
private List<DeliveryAddressEmbeddable> deliveryAddresses = new ArrayList<>();
|
||||
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "customer_preferences", joinColumns = @JoinColumn(name = "customer_id"))
|
||||
@Column(name = "preference")
|
||||
@Enumerated(EnumType.STRING)
|
||||
private Set<de.effigenix.domain.masterdata.CustomerPreference> preferences = new HashSet<>();
|
||||
|
||||
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "id", referencedColumnName = "customer_id", insertable = false, updatable = false)
|
||||
private FrameContractEntity frameContract;
|
||||
|
||||
public CustomerEntity() {}
|
||||
|
||||
public String getId() { return id; }
|
||||
public String getName() { return name; }
|
||||
public String getType() { return type; }
|
||||
public String getPhone() { return phone; }
|
||||
public String getEmail() { return email; }
|
||||
public String getContactPerson() { return contactPerson; }
|
||||
public String getBillingStreet() { return billingStreet; }
|
||||
public String getBillingHouseNumber() { return billingHouseNumber; }
|
||||
public String getBillingPostalCode() { return billingPostalCode; }
|
||||
public String getBillingCity() { return billingCity; }
|
||||
public String getBillingCountry() { return billingCountry; }
|
||||
public Integer getPaymentDueDays() { return paymentDueDays; }
|
||||
public String getPaymentDescription() { return paymentDescription; }
|
||||
public String getStatus() { return status; }
|
||||
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; }
|
||||
|
||||
public void setId(String id) { this.id = id; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
public void setType(String type) { this.type = type; }
|
||||
public void setPhone(String phone) { this.phone = phone; }
|
||||
public void setEmail(String email) { this.email = email; }
|
||||
public void setContactPerson(String contactPerson) { this.contactPerson = contactPerson; }
|
||||
public void setBillingStreet(String billingStreet) { this.billingStreet = billingStreet; }
|
||||
public void setBillingHouseNumber(String billingHouseNumber) { this.billingHouseNumber = billingHouseNumber; }
|
||||
public void setBillingPostalCode(String billingPostalCode) { this.billingPostalCode = billingPostalCode; }
|
||||
public void setBillingCity(String billingCity) { this.billingCity = billingCity; }
|
||||
public void setBillingCountry(String billingCountry) { this.billingCountry = billingCountry; }
|
||||
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(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; }
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.entity;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
|
||||
@Embeddable
|
||||
public class DeliveryAddressEmbeddable {
|
||||
|
||||
@Column(name = "label", length = 100)
|
||||
private String label;
|
||||
|
||||
@Column(name = "street", nullable = false, length = 200)
|
||||
private String street;
|
||||
|
||||
@Column(name = "house_number", length = 20)
|
||||
private String houseNumber;
|
||||
|
||||
@Column(name = "postal_code", nullable = false, length = 20)
|
||||
private String postalCode;
|
||||
|
||||
@Column(name = "city", nullable = false, length = 100)
|
||||
private String city;
|
||||
|
||||
@Column(name = "country", nullable = false, length = 2)
|
||||
private String country;
|
||||
|
||||
@Column(name = "contact_person", length = 200)
|
||||
private String contactPerson;
|
||||
|
||||
@Column(name = "delivery_notes", length = 500)
|
||||
private String deliveryNotes;
|
||||
|
||||
protected DeliveryAddressEmbeddable() {}
|
||||
|
||||
public DeliveryAddressEmbeddable(String label, String street, String houseNumber,
|
||||
String postalCode, String city, String country,
|
||||
String contactPerson, String deliveryNotes) {
|
||||
this.label = label;
|
||||
this.street = street;
|
||||
this.houseNumber = houseNumber;
|
||||
this.postalCode = postalCode;
|
||||
this.city = city;
|
||||
this.country = country;
|
||||
this.contactPerson = contactPerson;
|
||||
this.deliveryNotes = deliveryNotes;
|
||||
}
|
||||
|
||||
public String getLabel() { return label; }
|
||||
public String getStreet() { return street; }
|
||||
public String getHouseNumber() { return houseNumber; }
|
||||
public String getPostalCode() { return postalCode; }
|
||||
public String getCity() { return city; }
|
||||
public String getCountry() { return country; }
|
||||
public String getContactPerson() { return contactPerson; }
|
||||
public String getDeliveryNotes() { return deliveryNotes; }
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table(name = "frame_contracts")
|
||||
public class FrameContractEntity {
|
||||
|
||||
@Id
|
||||
@Column(name = "id", nullable = false, length = 36)
|
||||
private String id;
|
||||
|
||||
@Column(name = "customer_id", nullable = false, unique = true, length = 36)
|
||||
private String customerId;
|
||||
|
||||
@Column(name = "valid_from")
|
||||
private LocalDate validFrom;
|
||||
|
||||
@Column(name = "valid_until")
|
||||
private LocalDate validUntil;
|
||||
|
||||
@Column(name = "delivery_rhythm", nullable = false, length = 20)
|
||||
private String deliveryRhythm;
|
||||
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "contract_line_items", joinColumns = @JoinColumn(name = "frame_contract_id"))
|
||||
private List<ContractLineItemEmbeddable> lineItems = new ArrayList<>();
|
||||
|
||||
protected FrameContractEntity() {}
|
||||
|
||||
public FrameContractEntity(String id, String customerId, LocalDate validFrom,
|
||||
LocalDate validUntil, String deliveryRhythm) {
|
||||
this.id = id;
|
||||
this.customerId = customerId;
|
||||
this.validFrom = validFrom;
|
||||
this.validUntil = validUntil;
|
||||
this.deliveryRhythm = deliveryRhythm;
|
||||
}
|
||||
|
||||
public String getId() { return id; }
|
||||
public String getCustomerId() { return customerId; }
|
||||
public LocalDate getValidFrom() { return validFrom; }
|
||||
public LocalDate getValidUntil() { return validUntil; }
|
||||
public String getDeliveryRhythm() { return deliveryRhythm; }
|
||||
public List<ContractLineItemEmbeddable> getLineItems() { return lineItems; }
|
||||
|
||||
public void setId(String id) { this.id = id; }
|
||||
public void setCustomerId(String customerId) { this.customerId = customerId; }
|
||||
public void setValidFrom(LocalDate validFrom) { this.validFrom = validFrom; }
|
||||
public void setValidUntil(LocalDate validUntil) { this.validUntil = validUntil; }
|
||||
public void setDeliveryRhythm(String deliveryRhythm) { this.deliveryRhythm = deliveryRhythm; }
|
||||
public void setLineItems(List<ContractLineItemEmbeddable> lineItems) { this.lineItems = lineItems; }
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.entity;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "product_categories")
|
||||
public class ProductCategoryEntity {
|
||||
|
||||
@Id
|
||||
@Column(name = "id", nullable = false, length = 36)
|
||||
private String id;
|
||||
|
||||
@Column(name = "name", nullable = false, unique = true, length = 100)
|
||||
private String name;
|
||||
|
||||
@Column(name = "description", columnDefinition = "TEXT")
|
||||
private String description;
|
||||
|
||||
protected ProductCategoryEntity() {}
|
||||
|
||||
public ProductCategoryEntity(String id, String name, String description) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getId() { return id; }
|
||||
public String getName() { return name; }
|
||||
public String getDescription() { return description; }
|
||||
|
||||
public void setId(String id) { this.id = id; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.entity;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Embeddable
|
||||
public class QualityCertificateEmbeddable {
|
||||
|
||||
@Column(name = "certificate_type", nullable = false, length = 100)
|
||||
private String certificateType;
|
||||
|
||||
@Column(name = "issuer", length = 200)
|
||||
private String issuer;
|
||||
|
||||
@Column(name = "valid_from")
|
||||
private LocalDate validFrom;
|
||||
|
||||
@Column(name = "valid_until")
|
||||
private LocalDate validUntil;
|
||||
|
||||
protected QualityCertificateEmbeddable() {}
|
||||
|
||||
public QualityCertificateEmbeddable(String certificateType, String issuer, LocalDate validFrom, LocalDate validUntil) {
|
||||
this.certificateType = certificateType;
|
||||
this.issuer = issuer;
|
||||
this.validFrom = validFrom;
|
||||
this.validUntil = validUntil;
|
||||
}
|
||||
|
||||
public String getCertificateType() { return certificateType; }
|
||||
public String getIssuer() { return issuer; }
|
||||
public LocalDate getValidFrom() { return validFrom; }
|
||||
public LocalDate getValidUntil() { return validUntil; }
|
||||
|
||||
public void setCertificateType(String certificateType) { this.certificateType = certificateType; }
|
||||
public void setIssuer(String issuer) { this.issuer = issuer; }
|
||||
public void setValidFrom(LocalDate validFrom) { this.validFrom = validFrom; }
|
||||
public void setValidUntil(LocalDate validUntil) { this.validUntil = validUntil; }
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Entity
|
||||
@Table(name = "sales_units")
|
||||
public class SalesUnitEntity {
|
||||
|
||||
@Id
|
||||
@Column(name = "id", nullable = false, length = 36)
|
||||
private String id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "article_id", nullable = false)
|
||||
private ArticleEntity article;
|
||||
|
||||
@Column(name = "unit", nullable = false, length = 30)
|
||||
private String unit;
|
||||
|
||||
@Column(name = "price_model", nullable = false, length = 30)
|
||||
private String priceModel;
|
||||
|
||||
@Column(name = "price_amount", nullable = false, precision = 19, scale = 2)
|
||||
private BigDecimal priceAmount;
|
||||
|
||||
@Column(name = "price_currency", nullable = false, length = 3)
|
||||
private String priceCurrency;
|
||||
|
||||
protected SalesUnitEntity() {}
|
||||
|
||||
public SalesUnitEntity(String id, ArticleEntity article, String unit, String priceModel,
|
||||
BigDecimal priceAmount, String priceCurrency) {
|
||||
this.id = id;
|
||||
this.article = article;
|
||||
this.unit = unit;
|
||||
this.priceModel = priceModel;
|
||||
this.priceAmount = priceAmount;
|
||||
this.priceCurrency = priceCurrency;
|
||||
}
|
||||
|
||||
public String getId() { return id; }
|
||||
public ArticleEntity getArticle() { return article; }
|
||||
public String getUnit() { return unit; }
|
||||
public String getPriceModel() { return priceModel; }
|
||||
public BigDecimal getPriceAmount() { return priceAmount; }
|
||||
public String getPriceCurrency() { return priceCurrency; }
|
||||
|
||||
public void setId(String id) { this.id = id; }
|
||||
public void setArticle(ArticleEntity article) { this.article = article; }
|
||||
public void setUnit(String unit) { this.unit = unit; }
|
||||
public void setPriceModel(String priceModel) { this.priceModel = priceModel; }
|
||||
public void setPriceAmount(BigDecimal priceAmount) { this.priceAmount = priceAmount; }
|
||||
public void setPriceCurrency(String priceCurrency) { this.priceCurrency = priceCurrency; }
|
||||
}
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table(name = "suppliers")
|
||||
public class SupplierEntity {
|
||||
|
||||
@Id
|
||||
@Column(name = "id", nullable = false, length = 36)
|
||||
private String id;
|
||||
|
||||
@Column(name = "name", nullable = false, unique = true, length = 200)
|
||||
private String name;
|
||||
|
||||
@Column(name = "phone", length = 50)
|
||||
private String phone;
|
||||
|
||||
@Column(name = "email", length = 255)
|
||||
private String email;
|
||||
|
||||
@Column(name = "contact_person", length = 200)
|
||||
private String contactPerson;
|
||||
|
||||
@Column(name = "street", length = 200)
|
||||
private String street;
|
||||
|
||||
@Column(name = "house_number", length = 20)
|
||||
private String houseNumber;
|
||||
|
||||
@Column(name = "postal_code", length = 20)
|
||||
private String postalCode;
|
||||
|
||||
@Column(name = "city", length = 100)
|
||||
private String city;
|
||||
|
||||
@Column(name = "country", length = 2)
|
||||
private String country;
|
||||
|
||||
@Column(name = "payment_due_days")
|
||||
private Integer paymentDueDays;
|
||||
|
||||
@Column(name = "payment_description", length = 500)
|
||||
private String paymentDescription;
|
||||
|
||||
@Column(name = "quality_score")
|
||||
private Integer qualityScore;
|
||||
|
||||
@Column(name = "delivery_score")
|
||||
private Integer deliveryScore;
|
||||
|
||||
@Column(name = "price_score")
|
||||
private Integer priceScore;
|
||||
|
||||
@Column(name = "status", nullable = false, length = 20)
|
||||
private String status;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private OffsetDateTime createdAt;
|
||||
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private OffsetDateTime updatedAt;
|
||||
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "quality_certificates", joinColumns = @JoinColumn(name = "supplier_id"))
|
||||
private List<QualityCertificateEmbeddable> certificates = new ArrayList<>();
|
||||
|
||||
public SupplierEntity() {}
|
||||
|
||||
public String getId() { return id; }
|
||||
public String getName() { return name; }
|
||||
public String getPhone() { return phone; }
|
||||
public String getEmail() { return email; }
|
||||
public String getContactPerson() { return contactPerson; }
|
||||
public String getStreet() { return street; }
|
||||
public String getHouseNumber() { return houseNumber; }
|
||||
public String getPostalCode() { return postalCode; }
|
||||
public String getCity() { return city; }
|
||||
public String getCountry() { return country; }
|
||||
public Integer getPaymentDueDays() { return paymentDueDays; }
|
||||
public String getPaymentDescription() { return paymentDescription; }
|
||||
public Integer getQualityScore() { return qualityScore; }
|
||||
public Integer getDeliveryScore() { return deliveryScore; }
|
||||
public Integer getPriceScore() { return priceScore; }
|
||||
public String getStatus() { return status; }
|
||||
public OffsetDateTime getCreatedAt() { return createdAt; }
|
||||
public OffsetDateTime getUpdatedAt() { return updatedAt; }
|
||||
public List<QualityCertificateEmbeddable> getCertificates() { return certificates; }
|
||||
|
||||
public void setId(String id) { this.id = id; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
public void setPhone(String phone) { this.phone = phone; }
|
||||
public void setEmail(String email) { this.email = email; }
|
||||
public void setContactPerson(String contactPerson) { this.contactPerson = contactPerson; }
|
||||
public void setStreet(String street) { this.street = street; }
|
||||
public void setHouseNumber(String houseNumber) { this.houseNumber = houseNumber; }
|
||||
public void setPostalCode(String postalCode) { this.postalCode = postalCode; }
|
||||
public void setCity(String city) { this.city = city; }
|
||||
public void setCountry(String country) { this.country = country; }
|
||||
public void setPaymentDueDays(Integer paymentDueDays) { this.paymentDueDays = paymentDueDays; }
|
||||
public void setPaymentDescription(String paymentDescription) { this.paymentDescription = paymentDescription; }
|
||||
public void setQualityScore(Integer qualityScore) { this.qualityScore = qualityScore; }
|
||||
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(OffsetDateTime createdAt) { this.createdAt = createdAt; }
|
||||
public void setUpdatedAt(OffsetDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||
public void setCertificates(List<QualityCertificateEmbeddable> certificates) { this.certificates = certificates; }
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.mapper;
|
||||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.infrastructure.masterdata.persistence.entity.ArticleEntity;
|
||||
import de.effigenix.infrastructure.masterdata.persistence.entity.SalesUnitEntity;
|
||||
import de.effigenix.shared.common.Money;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Currency;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class ArticleMapper {
|
||||
|
||||
public ArticleEntity toEntity(Article article) {
|
||||
var entity = new ArticleEntity(
|
||||
article.id().value(),
|
||||
article.name().value(),
|
||||
article.articleNumber().value(),
|
||||
article.categoryId().value(),
|
||||
article.status().name(),
|
||||
article.createdAt(),
|
||||
article.updatedAt()
|
||||
);
|
||||
|
||||
List<SalesUnitEntity> salesUnitEntities = article.salesUnits().stream()
|
||||
.map(su -> toSalesUnitEntity(su, entity))
|
||||
.collect(Collectors.toList());
|
||||
entity.setSalesUnits(salesUnitEntities);
|
||||
|
||||
Set<String> supplierIds = article.supplierReferences().stream()
|
||||
.map(SupplierId::value)
|
||||
.collect(Collectors.toSet());
|
||||
entity.setSupplierIds(supplierIds);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
public Article toDomain(ArticleEntity entity) {
|
||||
List<SalesUnit> salesUnits = entity.getSalesUnits().stream()
|
||||
.map(this::toDomainSalesUnit)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Set<SupplierId> supplierRefs = entity.getSupplierIds().stream()
|
||||
.map(SupplierId::of)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
return Article.reconstitute(
|
||||
ArticleId.of(entity.getId()),
|
||||
new ArticleName(entity.getName()),
|
||||
new ArticleNumber(entity.getArticleNumber()),
|
||||
ProductCategoryId.of(entity.getCategoryId()),
|
||||
salesUnits,
|
||||
ArticleStatus.valueOf(entity.getStatus()),
|
||||
supplierRefs,
|
||||
entity.getCreatedAt(),
|
||||
entity.getUpdatedAt()
|
||||
);
|
||||
}
|
||||
|
||||
private SalesUnitEntity toSalesUnitEntity(SalesUnit su, ArticleEntity article) {
|
||||
return new SalesUnitEntity(
|
||||
su.id().value(),
|
||||
article,
|
||||
su.unit().name(),
|
||||
su.priceModel().name(),
|
||||
su.price().amount(),
|
||||
su.price().currency().getCurrencyCode()
|
||||
);
|
||||
}
|
||||
|
||||
private SalesUnit toDomainSalesUnit(SalesUnitEntity entity) {
|
||||
return SalesUnit.reconstitute(
|
||||
SalesUnitId.of(entity.getId()),
|
||||
Unit.valueOf(entity.getUnit()),
|
||||
PriceModel.valueOf(entity.getPriceModel()),
|
||||
new Money(entity.getPriceAmount(), Currency.getInstance(entity.getPriceCurrency()))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,138 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.mapper;
|
||||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.infrastructure.masterdata.persistence.entity.*;
|
||||
import de.effigenix.shared.common.Address;
|
||||
import de.effigenix.shared.common.ContactInfo;
|
||||
import de.effigenix.shared.common.Money;
|
||||
import de.effigenix.shared.common.PaymentTerms;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Currency;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class CustomerMapper {
|
||||
|
||||
public CustomerEntity toEntity(Customer customer) {
|
||||
var entity = new CustomerEntity();
|
||||
entity.setId(customer.id().value());
|
||||
entity.setName(customer.name().value());
|
||||
entity.setType(customer.type().name());
|
||||
|
||||
var contact = customer.contactInfo();
|
||||
if (contact != null) {
|
||||
entity.setPhone(contact.phone());
|
||||
entity.setEmail(contact.email());
|
||||
entity.setContactPerson(contact.contactPerson());
|
||||
}
|
||||
|
||||
var billing = customer.billingAddress();
|
||||
entity.setBillingStreet(billing.street());
|
||||
entity.setBillingHouseNumber(billing.houseNumber());
|
||||
entity.setBillingPostalCode(billing.postalCode());
|
||||
entity.setBillingCity(billing.city());
|
||||
entity.setBillingCountry(billing.country());
|
||||
|
||||
var terms = customer.paymentTerms();
|
||||
if (terms != null) {
|
||||
entity.setPaymentDueDays(terms.paymentDueDays());
|
||||
entity.setPaymentDescription(terms.description());
|
||||
}
|
||||
|
||||
entity.setStatus(customer.status().name());
|
||||
entity.setCreatedAt(customer.createdAt());
|
||||
entity.setUpdatedAt(customer.updatedAt());
|
||||
|
||||
entity.setDeliveryAddresses(customer.deliveryAddresses().stream()
|
||||
.map(da -> new DeliveryAddressEmbeddable(
|
||||
da.label(),
|
||||
da.address().street(), da.address().houseNumber(),
|
||||
da.address().postalCode(), da.address().city(), da.address().country(),
|
||||
da.contactPerson(), da.deliveryNotes()))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
entity.setPreferences(customer.preferences());
|
||||
|
||||
// FrameContract is saved separately — not via the @OneToOne mapping
|
||||
// (handled in JpaCustomerRepository)
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
public Customer toDomain(CustomerEntity entity, FrameContractEntity fcEntity) {
|
||||
Address billingAddress = new Address(
|
||||
entity.getBillingStreet(), entity.getBillingHouseNumber(),
|
||||
entity.getBillingPostalCode(), entity.getBillingCity(), entity.getBillingCountry()
|
||||
);
|
||||
|
||||
ContactInfo contactInfo = new ContactInfo(
|
||||
entity.getPhone(), entity.getEmail(), entity.getContactPerson()
|
||||
);
|
||||
|
||||
PaymentTerms paymentTerms = null;
|
||||
if (entity.getPaymentDueDays() != null) {
|
||||
paymentTerms = new PaymentTerms(entity.getPaymentDueDays(), entity.getPaymentDescription());
|
||||
}
|
||||
|
||||
List<DeliveryAddress> deliveryAddresses = entity.getDeliveryAddresses().stream()
|
||||
.map(da -> new DeliveryAddress(
|
||||
da.getLabel(),
|
||||
new Address(da.getStreet(), da.getHouseNumber(),
|
||||
da.getPostalCode(), da.getCity(), da.getCountry()),
|
||||
da.getContactPerson(), da.getDeliveryNotes()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
FrameContract frameContract = null;
|
||||
if (fcEntity != null) {
|
||||
List<ContractLineItem> lineItems = fcEntity.getLineItems().stream()
|
||||
.map(li -> new ContractLineItem(
|
||||
ArticleId.of(li.getArticleId()),
|
||||
new Money(li.getAgreedPriceAmount(), Currency.getInstance(li.getAgreedPriceCurrency())),
|
||||
li.getAgreedQuantity(),
|
||||
li.getUnit() != null ? Unit.valueOf(li.getUnit()) : null))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
frameContract = FrameContract.reconstitute(
|
||||
FrameContractId.of(fcEntity.getId()),
|
||||
fcEntity.getValidFrom(),
|
||||
fcEntity.getValidUntil(),
|
||||
DeliveryRhythm.valueOf(fcEntity.getDeliveryRhythm()),
|
||||
lineItems
|
||||
);
|
||||
}
|
||||
|
||||
return Customer.reconstitute(
|
||||
CustomerId.of(entity.getId()),
|
||||
new CustomerName(entity.getName()),
|
||||
CustomerType.valueOf(entity.getType()),
|
||||
billingAddress,
|
||||
contactInfo,
|
||||
paymentTerms,
|
||||
deliveryAddresses,
|
||||
frameContract,
|
||||
entity.getPreferences(),
|
||||
CustomerStatus.valueOf(entity.getStatus()),
|
||||
entity.getCreatedAt(),
|
||||
entity.getUpdatedAt()
|
||||
);
|
||||
}
|
||||
|
||||
public FrameContractEntity toFrameContractEntity(FrameContract fc, String customerId) {
|
||||
var entity = new FrameContractEntity(
|
||||
fc.id().value(), customerId,
|
||||
fc.validFrom(), fc.validUntil(),
|
||||
fc.deliveryRhythm().name()
|
||||
);
|
||||
entity.setLineItems(fc.lineItems().stream()
|
||||
.map(li -> new ContractLineItemEmbeddable(
|
||||
li.articleId().value(),
|
||||
li.agreedPrice().amount(),
|
||||
li.agreedPrice().currency().getCurrencyCode(),
|
||||
li.agreedQuantity(),
|
||||
li.unit() != null ? li.unit().name() : null))
|
||||
.collect(Collectors.toList()));
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.mapper;
|
||||
|
||||
import de.effigenix.domain.masterdata.CategoryName;
|
||||
import de.effigenix.domain.masterdata.ProductCategory;
|
||||
import de.effigenix.domain.masterdata.ProductCategoryId;
|
||||
import de.effigenix.infrastructure.masterdata.persistence.entity.ProductCategoryEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ProductCategoryMapper {
|
||||
|
||||
public ProductCategoryEntity toEntity(ProductCategory category) {
|
||||
return new ProductCategoryEntity(
|
||||
category.id().value(),
|
||||
category.name().value(),
|
||||
category.description()
|
||||
);
|
||||
}
|
||||
|
||||
public ProductCategory toDomain(ProductCategoryEntity entity) {
|
||||
return ProductCategory.reconstitute(
|
||||
ProductCategoryId.of(entity.getId()),
|
||||
new CategoryName(entity.getName()),
|
||||
entity.getDescription()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.mapper;
|
||||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.infrastructure.masterdata.persistence.entity.QualityCertificateEmbeddable;
|
||||
import de.effigenix.infrastructure.masterdata.persistence.entity.SupplierEntity;
|
||||
import de.effigenix.shared.common.Address;
|
||||
import de.effigenix.shared.common.ContactInfo;
|
||||
import de.effigenix.shared.common.PaymentTerms;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class SupplierMapper {
|
||||
|
||||
public SupplierEntity toEntity(Supplier supplier) {
|
||||
var entity = new SupplierEntity();
|
||||
entity.setId(supplier.id().value());
|
||||
entity.setName(supplier.name().value());
|
||||
|
||||
var contact = supplier.contactInfo();
|
||||
if (contact != null) {
|
||||
entity.setPhone(contact.phone());
|
||||
entity.setEmail(contact.email());
|
||||
entity.setContactPerson(contact.contactPerson());
|
||||
}
|
||||
|
||||
var address = supplier.address();
|
||||
if (address != null) {
|
||||
entity.setStreet(address.street());
|
||||
entity.setHouseNumber(address.houseNumber());
|
||||
entity.setPostalCode(address.postalCode());
|
||||
entity.setCity(address.city());
|
||||
entity.setCountry(address.country());
|
||||
}
|
||||
|
||||
var terms = supplier.paymentTerms();
|
||||
if (terms != null) {
|
||||
entity.setPaymentDueDays(terms.paymentDueDays());
|
||||
entity.setPaymentDescription(terms.description());
|
||||
}
|
||||
|
||||
var rating = supplier.rating();
|
||||
if (rating != null) {
|
||||
entity.setQualityScore(rating.qualityScore());
|
||||
entity.setDeliveryScore(rating.deliveryScore());
|
||||
entity.setPriceScore(rating.priceScore());
|
||||
}
|
||||
|
||||
entity.setStatus(supplier.status().name());
|
||||
entity.setCreatedAt(supplier.createdAt());
|
||||
entity.setUpdatedAt(supplier.updatedAt());
|
||||
|
||||
List<QualityCertificateEmbeddable> certs = supplier.certificates().stream()
|
||||
.map(c -> new QualityCertificateEmbeddable(
|
||||
c.certificateType(), c.issuer(), c.validFrom(), c.validUntil()))
|
||||
.collect(Collectors.toList());
|
||||
entity.setCertificates(certs);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
public Supplier toDomain(SupplierEntity entity) {
|
||||
Address address = null;
|
||||
if (entity.getStreet() != null) {
|
||||
address = new Address(
|
||||
entity.getStreet(), entity.getHouseNumber(),
|
||||
entity.getPostalCode(), entity.getCity(), entity.getCountry()
|
||||
);
|
||||
}
|
||||
|
||||
ContactInfo contactInfo = new ContactInfo(
|
||||
entity.getPhone(), entity.getEmail(), entity.getContactPerson()
|
||||
);
|
||||
|
||||
PaymentTerms paymentTerms = null;
|
||||
if (entity.getPaymentDueDays() != null) {
|
||||
paymentTerms = new PaymentTerms(entity.getPaymentDueDays(), entity.getPaymentDescription());
|
||||
}
|
||||
|
||||
SupplierRating rating = null;
|
||||
if (entity.getQualityScore() != null) {
|
||||
rating = new SupplierRating(
|
||||
entity.getQualityScore(), entity.getDeliveryScore(), entity.getPriceScore()
|
||||
);
|
||||
}
|
||||
|
||||
List<QualityCertificate> certificates = entity.getCertificates().stream()
|
||||
.map(c -> new QualityCertificate(
|
||||
c.getCertificateType(), c.getIssuer(), c.getValidFrom(), c.getValidUntil()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return Supplier.reconstitute(
|
||||
SupplierId.of(entity.getId()),
|
||||
new SupplierName(entity.getName()),
|
||||
address,
|
||||
contactInfo,
|
||||
paymentTerms,
|
||||
certificates,
|
||||
rating,
|
||||
SupplierStatus.valueOf(entity.getStatus()),
|
||||
entity.getCreatedAt(),
|
||||
entity.getUpdatedAt()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.repository;
|
||||
|
||||
import de.effigenix.infrastructure.masterdata.persistence.entity.ArticleEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ArticleJpaRepository extends JpaRepository<ArticleEntity, String> {
|
||||
|
||||
List<ArticleEntity> findByCategoryId(String categoryId);
|
||||
|
||||
List<ArticleEntity> findByStatus(String status);
|
||||
|
||||
boolean existsByArticleNumber(String articleNumber);
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.repository;
|
||||
|
||||
import de.effigenix.infrastructure.masterdata.persistence.entity.CustomerEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CustomerJpaRepository extends JpaRepository<CustomerEntity, String> {
|
||||
|
||||
List<CustomerEntity> findByType(String type);
|
||||
|
||||
List<CustomerEntity> findByStatus(String status);
|
||||
|
||||
boolean existsByName(String name);
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.repository;
|
||||
|
||||
import de.effigenix.infrastructure.masterdata.persistence.entity.FrameContractEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface FrameContractJpaRepository extends JpaRepository<FrameContractEntity, String> {
|
||||
|
||||
Optional<FrameContractEntity> findByCustomerId(String customerId);
|
||||
|
||||
List<FrameContractEntity> findByCustomerIdIn(List<String> customerIds);
|
||||
|
||||
void deleteByCustomerId(String customerId);
|
||||
}
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.repository;
|
||||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.infrastructure.masterdata.persistence.mapper.ArticleMapper;
|
||||
import de.effigenix.shared.common.RepositoryError;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Repository
|
||||
@Profile("!no-db")
|
||||
@Transactional(readOnly = true)
|
||||
public class JpaArticleRepository implements ArticleRepository {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JpaArticleRepository.class);
|
||||
|
||||
private final ArticleJpaRepository jpaRepository;
|
||||
private final ArticleMapper mapper;
|
||||
|
||||
public JpaArticleRepository(ArticleJpaRepository jpaRepository, ArticleMapper mapper) {
|
||||
this.jpaRepository = jpaRepository;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<Article>> findById(ArticleId id) {
|
||||
try {
|
||||
Optional<Article> result = jpaRepository.findById(id.value())
|
||||
.map(mapper::toDomain);
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findById", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Article>> findAll() {
|
||||
try {
|
||||
List<Article> result = jpaRepository.findAll().stream()
|
||||
.map(mapper::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findAll", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Article>> findByCategory(ProductCategoryId categoryId) {
|
||||
try {
|
||||
List<Article> result = jpaRepository.findByCategoryId(categoryId.value()).stream()
|
||||
.map(mapper::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByCategory", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Article>> findByStatus(ArticleStatus status) {
|
||||
try {
|
||||
List<Article> result = jpaRepository.findByStatus(status.name()).stream()
|
||||
.map(mapper::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByStatus", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<RepositoryError, Void> save(Article article) {
|
||||
try {
|
||||
jpaRepository.save(mapper.toEntity(article));
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in save", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<RepositoryError, Void> delete(Article article) {
|
||||
try {
|
||||
jpaRepository.deleteById(article.id().value());
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in delete", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Boolean> existsByArticleNumber(ArticleNumber articleNumber) {
|
||||
try {
|
||||
return Result.success(jpaRepository.existsByArticleNumber(articleNumber.value()));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in existsByArticleNumber", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,138 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.repository;
|
||||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.infrastructure.masterdata.persistence.entity.CustomerEntity;
|
||||
import de.effigenix.infrastructure.masterdata.persistence.entity.FrameContractEntity;
|
||||
import de.effigenix.infrastructure.masterdata.persistence.mapper.CustomerMapper;
|
||||
import de.effigenix.shared.common.RepositoryError;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Repository
|
||||
@Profile("!no-db")
|
||||
@Transactional(readOnly = true)
|
||||
public class JpaCustomerRepository implements CustomerRepository {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JpaCustomerRepository.class);
|
||||
|
||||
private final CustomerJpaRepository jpaRepository;
|
||||
private final FrameContractJpaRepository frameContractJpaRepository;
|
||||
private final CustomerMapper mapper;
|
||||
|
||||
public JpaCustomerRepository(CustomerJpaRepository jpaRepository,
|
||||
FrameContractJpaRepository frameContractJpaRepository,
|
||||
CustomerMapper mapper) {
|
||||
this.jpaRepository = jpaRepository;
|
||||
this.frameContractJpaRepository = frameContractJpaRepository;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<Customer>> findById(CustomerId id) {
|
||||
try {
|
||||
var entityOpt = jpaRepository.findById(id.value());
|
||||
if (entityOpt.isEmpty()) {
|
||||
return Result.success(Optional.empty());
|
||||
}
|
||||
var fcEntity = frameContractJpaRepository.findByCustomerId(id.value()).orElse(null);
|
||||
return Result.success(Optional.of(mapper.toDomain(entityOpt.get(), fcEntity)));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findById", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Customer>> findAll() {
|
||||
try {
|
||||
return Result.success(mapWithFrameContracts(jpaRepository.findAll()));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findAll", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Customer>> findByType(CustomerType type) {
|
||||
try {
|
||||
return Result.success(mapWithFrameContracts(jpaRepository.findByType(type.name())));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByType", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Customer>> findByStatus(CustomerStatus status) {
|
||||
try {
|
||||
return Result.success(mapWithFrameContracts(jpaRepository.findByStatus(status.name())));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByStatus", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private List<Customer> mapWithFrameContracts(List<CustomerEntity> entities) {
|
||||
List<String> customerIds = entities.stream()
|
||||
.map(CustomerEntity::getId)
|
||||
.toList();
|
||||
Map<String, FrameContractEntity> fcMap = frameContractJpaRepository.findByCustomerIdIn(customerIds).stream()
|
||||
.collect(Collectors.toMap(FrameContractEntity::getCustomerId, Function.identity()));
|
||||
return entities.stream()
|
||||
.map(entity -> mapper.toDomain(entity, fcMap.get(entity.getId())))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<RepositoryError, Void> save(Customer customer) {
|
||||
try {
|
||||
jpaRepository.save(mapper.toEntity(customer));
|
||||
|
||||
// Handle FrameContract separately
|
||||
frameContractJpaRepository.deleteByCustomerId(customer.id().value());
|
||||
if (customer.frameContract() != null) {
|
||||
var fcEntity = mapper.toFrameContractEntity(customer.frameContract(), customer.id().value());
|
||||
frameContractJpaRepository.save(fcEntity);
|
||||
}
|
||||
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in save", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<RepositoryError, Void> delete(Customer customer) {
|
||||
try {
|
||||
frameContractJpaRepository.deleteByCustomerId(customer.id().value());
|
||||
jpaRepository.deleteById(customer.id().value());
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in delete", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Boolean> existsByName(CustomerName name) {
|
||||
try {
|
||||
return Result.success(jpaRepository.existsByName(name.value()));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in existsByName", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.repository;
|
||||
|
||||
import de.effigenix.domain.masterdata.CategoryName;
|
||||
import de.effigenix.domain.masterdata.ProductCategory;
|
||||
import de.effigenix.domain.masterdata.ProductCategoryId;
|
||||
import de.effigenix.domain.masterdata.ProductCategoryRepository;
|
||||
import de.effigenix.infrastructure.masterdata.persistence.mapper.ProductCategoryMapper;
|
||||
import de.effigenix.shared.common.RepositoryError;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Repository
|
||||
@Profile("!no-db")
|
||||
@Transactional(readOnly = true)
|
||||
public class JpaProductCategoryRepository implements ProductCategoryRepository {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JpaProductCategoryRepository.class);
|
||||
|
||||
private final ProductCategoryJpaRepository jpaRepository;
|
||||
private final ProductCategoryMapper mapper;
|
||||
|
||||
public JpaProductCategoryRepository(ProductCategoryJpaRepository jpaRepository, ProductCategoryMapper mapper) {
|
||||
this.jpaRepository = jpaRepository;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<ProductCategory>> findById(ProductCategoryId id) {
|
||||
try {
|
||||
Optional<ProductCategory> result = jpaRepository.findById(id.value())
|
||||
.map(mapper::toDomain);
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findById", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<ProductCategory>> findAll() {
|
||||
try {
|
||||
List<ProductCategory> result = jpaRepository.findAll().stream()
|
||||
.map(mapper::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findAll", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<RepositoryError, Void> save(ProductCategory category) {
|
||||
try {
|
||||
jpaRepository.save(mapper.toEntity(category));
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in save", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<RepositoryError, Void> delete(ProductCategory category) {
|
||||
try {
|
||||
jpaRepository.deleteById(category.id().value());
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in delete", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Boolean> existsByName(CategoryName name) {
|
||||
try {
|
||||
return Result.success(jpaRepository.existsByName(name.value()));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in existsByName", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.repository;
|
||||
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.infrastructure.masterdata.persistence.mapper.SupplierMapper;
|
||||
import de.effigenix.shared.common.RepositoryError;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Repository
|
||||
@Profile("!no-db")
|
||||
@Transactional(readOnly = true)
|
||||
public class JpaSupplierRepository implements SupplierRepository {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JpaSupplierRepository.class);
|
||||
|
||||
private final SupplierJpaRepository jpaRepository;
|
||||
private final SupplierMapper mapper;
|
||||
|
||||
public JpaSupplierRepository(SupplierJpaRepository jpaRepository, SupplierMapper mapper) {
|
||||
this.jpaRepository = jpaRepository;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<Supplier>> findById(SupplierId id) {
|
||||
try {
|
||||
Optional<Supplier> result = jpaRepository.findById(id.value())
|
||||
.map(mapper::toDomain);
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findById", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Supplier>> findAll() {
|
||||
try {
|
||||
List<Supplier> result = jpaRepository.findAll().stream()
|
||||
.map(mapper::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findAll", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Supplier>> findByStatus(SupplierStatus status) {
|
||||
try {
|
||||
List<Supplier> result = jpaRepository.findByStatus(status.name()).stream()
|
||||
.map(mapper::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByStatus", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<RepositoryError, Void> save(Supplier supplier) {
|
||||
try {
|
||||
jpaRepository.save(mapper.toEntity(supplier));
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in save", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<RepositoryError, Void> delete(Supplier supplier) {
|
||||
try {
|
||||
jpaRepository.deleteById(supplier.id().value());
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in delete", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Boolean> existsByName(SupplierName name) {
|
||||
try {
|
||||
return Result.success(jpaRepository.existsByName(name.value()));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in existsByName", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.repository;
|
||||
|
||||
import de.effigenix.infrastructure.masterdata.persistence.entity.ProductCategoryEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface ProductCategoryJpaRepository extends JpaRepository<ProductCategoryEntity, String> {
|
||||
|
||||
boolean existsByName(String name);
|
||||
|
||||
Optional<ProductCategoryEntity> findByName(String name);
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
package de.effigenix.infrastructure.masterdata.persistence.repository;
|
||||
|
||||
import de.effigenix.infrastructure.masterdata.persistence.entity.SupplierEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface SupplierJpaRepository extends JpaRepository<SupplierEntity, String> {
|
||||
|
||||
List<SupplierEntity> findByStatus(String status);
|
||||
|
||||
boolean existsByName(String name);
|
||||
}
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
package de.effigenix.infrastructure.usermanagement.persistence;
|
||||
|
||||
import de.effigenix.domain.usermanagement.*;
|
||||
import de.effigenix.shared.common.RepositoryError;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.jdbc.core.simple.JdbcClient;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
|
||||
@Repository
|
||||
@Profile("!no-db")
|
||||
public class JdbcRoleRepository implements RoleRepository {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JdbcRoleRepository.class);
|
||||
|
||||
private final JdbcClient jdbc;
|
||||
|
||||
public JdbcRoleRepository(JdbcClient jdbc) {
|
||||
this.jdbc = jdbc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<Role>> findById(RoleId id) {
|
||||
try {
|
||||
var roleOpt = jdbc.sql("SELECT * FROM roles WHERE id = :id")
|
||||
.param("id", id.value())
|
||||
.query(this::mapRoleRow)
|
||||
.optional();
|
||||
if (roleOpt.isEmpty()) {
|
||||
return Result.success(Optional.empty());
|
||||
}
|
||||
return Result.success(Optional.of(loadPermissions(roleOpt.get())));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findById", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<Role>> findByName(RoleName name) {
|
||||
try {
|
||||
var roleOpt = jdbc.sql("SELECT * FROM roles WHERE name = :name")
|
||||
.param("name", name.name())
|
||||
.query(this::mapRoleRow)
|
||||
.optional();
|
||||
if (roleOpt.isEmpty()) {
|
||||
return Result.success(Optional.empty());
|
||||
}
|
||||
return Result.success(Optional.of(loadPermissions(roleOpt.get())));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByName", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Role>> findAll() {
|
||||
try {
|
||||
var roles = jdbc.sql("SELECT * FROM roles ORDER BY name")
|
||||
.query(this::mapRoleRow)
|
||||
.list()
|
||||
.stream()
|
||||
.map(this::loadPermissions)
|
||||
.toList();
|
||||
return Result.success(roles);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findAll", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Void> save(Role role) {
|
||||
try {
|
||||
int rows = jdbc.sql("""
|
||||
UPDATE roles SET name = :name, description = :description
|
||||
WHERE id = :id
|
||||
""")
|
||||
.param("id", role.id().value())
|
||||
.param("name", role.name().name())
|
||||
.param("description", role.description())
|
||||
.update();
|
||||
|
||||
if (rows == 0) {
|
||||
jdbc.sql("""
|
||||
INSERT INTO roles (id, name, description)
|
||||
VALUES (:id, :name, :description)
|
||||
""")
|
||||
.param("id", role.id().value())
|
||||
.param("name", role.name().name())
|
||||
.param("description", role.description())
|
||||
.update();
|
||||
}
|
||||
|
||||
savePermissions(role);
|
||||
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in save", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Void> delete(Role role) {
|
||||
try {
|
||||
jdbc.sql("DELETE FROM roles WHERE id = :id")
|
||||
.param("id", role.id().value())
|
||||
.update();
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in delete", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Boolean> existsByName(RoleName name) {
|
||||
try {
|
||||
int count = jdbc.sql("SELECT COUNT(*) FROM roles WHERE name = :name")
|
||||
.param("name", name.name())
|
||||
.query(Integer.class)
|
||||
.single();
|
||||
return Result.success(count > 0);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in existsByName", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private void savePermissions(Role role) {
|
||||
jdbc.sql("DELETE FROM role_permissions WHERE role_id = :roleId")
|
||||
.param("roleId", role.id().value())
|
||||
.update();
|
||||
|
||||
for (Permission permission : role.permissions()) {
|
||||
jdbc.sql("INSERT INTO role_permissions (role_id, permission) VALUES (:roleId, :permission)")
|
||||
.param("roleId", role.id().value())
|
||||
.param("permission", permission.name())
|
||||
.update();
|
||||
}
|
||||
}
|
||||
|
||||
private Role loadPermissions(Role role) {
|
||||
var permissions = jdbc.sql("SELECT permission FROM role_permissions WHERE role_id = :roleId")
|
||||
.param("roleId", role.id().value())
|
||||
.query((rs, rowNum) -> Permission.valueOf(rs.getString("permission")))
|
||||
.set();
|
||||
return Role.reconstitute(role.id(), role.name(), permissions, role.description());
|
||||
}
|
||||
|
||||
private Role mapRoleRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return Role.reconstitute(
|
||||
RoleId.of(rs.getString("id")),
|
||||
RoleName.valueOf(rs.getString("name")),
|
||||
Set.of(),
|
||||
rs.getString("description")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
package de.effigenix.infrastructure.usermanagement.persistence;
|
||||
|
||||
import de.effigenix.domain.usermanagement.*;
|
||||
import de.effigenix.shared.common.RepositoryError;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.jdbc.core.simple.JdbcClient;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.*;
|
||||
|
||||
@Repository
|
||||
@Profile("!no-db")
|
||||
public class JdbcUserRepository implements UserRepository {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JdbcUserRepository.class);
|
||||
|
||||
private final JdbcClient jdbc;
|
||||
private final RoleRepository roleRepository;
|
||||
|
||||
public JdbcUserRepository(JdbcClient jdbc, RoleRepository roleRepository) {
|
||||
this.jdbc = jdbc;
|
||||
this.roleRepository = roleRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<User>> findById(UserId id) {
|
||||
try {
|
||||
var userOpt = jdbc.sql("SELECT * FROM users WHERE id = :id")
|
||||
.param("id", id.value())
|
||||
.query(this::mapUserRow)
|
||||
.optional();
|
||||
if (userOpt.isEmpty()) {
|
||||
return Result.success(Optional.empty());
|
||||
}
|
||||
return Result.success(Optional.of(loadRoles(userOpt.get())));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findById", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<User>> findByUsername(String username) {
|
||||
try {
|
||||
var userOpt = jdbc.sql("SELECT * FROM users WHERE username = :username")
|
||||
.param("username", username)
|
||||
.query(this::mapUserRow)
|
||||
.optional();
|
||||
if (userOpt.isEmpty()) {
|
||||
return Result.success(Optional.empty());
|
||||
}
|
||||
return Result.success(Optional.of(loadRoles(userOpt.get())));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByUsername", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<User>> findByEmail(String email) {
|
||||
try {
|
||||
var userOpt = jdbc.sql("SELECT * FROM users WHERE email = :email")
|
||||
.param("email", email)
|
||||
.query(this::mapUserRow)
|
||||
.optional();
|
||||
if (userOpt.isEmpty()) {
|
||||
return Result.success(Optional.empty());
|
||||
}
|
||||
return Result.success(Optional.of(loadRoles(userOpt.get())));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByEmail", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<User>> findByBranchId(String branchId) {
|
||||
try {
|
||||
var users = jdbc.sql("SELECT * FROM users WHERE branch_id = :branchId")
|
||||
.param("branchId", branchId)
|
||||
.query(this::mapUserRow)
|
||||
.list()
|
||||
.stream()
|
||||
.map(this::loadRoles)
|
||||
.toList();
|
||||
return Result.success(users);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByBranchId", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<User>> findByStatus(UserStatus status) {
|
||||
try {
|
||||
var users = jdbc.sql("SELECT * FROM users WHERE status = :status")
|
||||
.param("status", status.name())
|
||||
.query(this::mapUserRow)
|
||||
.list()
|
||||
.stream()
|
||||
.map(this::loadRoles)
|
||||
.toList();
|
||||
return Result.success(users);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByStatus", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<User>> findAll() {
|
||||
try {
|
||||
var users = jdbc.sql("SELECT * FROM users ORDER BY username")
|
||||
.query(this::mapUserRow)
|
||||
.list()
|
||||
.stream()
|
||||
.map(this::loadRoles)
|
||||
.toList();
|
||||
return Result.success(users);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findAll", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Void> save(User user) {
|
||||
try {
|
||||
int rows = jdbc.sql("""
|
||||
UPDATE users
|
||||
SET username = :username, email = :email, password_hash = :passwordHash,
|
||||
branch_id = :branchId, status = :status, last_login = :lastLogin
|
||||
WHERE id = :id
|
||||
""")
|
||||
.param("id", user.id().value())
|
||||
.param("username", user.username())
|
||||
.param("email", user.email())
|
||||
.param("passwordHash", user.passwordHash().value())
|
||||
.param("branchId", user.branchId())
|
||||
.param("status", user.status().name())
|
||||
.param("lastLogin", user.lastLogin())
|
||||
.update();
|
||||
|
||||
if (rows == 0) {
|
||||
jdbc.sql("""
|
||||
INSERT INTO users (id, username, email, password_hash, branch_id, status, created_at, last_login)
|
||||
VALUES (:id, :username, :email, :passwordHash, :branchId, :status, :createdAt, :lastLogin)
|
||||
""")
|
||||
.param("id", user.id().value())
|
||||
.param("username", user.username())
|
||||
.param("email", user.email())
|
||||
.param("passwordHash", user.passwordHash().value())
|
||||
.param("branchId", user.branchId())
|
||||
.param("status", user.status().name())
|
||||
.param("createdAt", user.createdAt())
|
||||
.param("lastLogin", user.lastLogin())
|
||||
.update();
|
||||
}
|
||||
|
||||
saveUserRoles(user);
|
||||
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in save", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Void> delete(User user) {
|
||||
try {
|
||||
jdbc.sql("DELETE FROM users WHERE id = :id")
|
||||
.param("id", user.id().value())
|
||||
.update();
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in delete", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Boolean> existsByUsername(String username) {
|
||||
try {
|
||||
int count = jdbc.sql("SELECT COUNT(*) FROM users WHERE username = :username")
|
||||
.param("username", username)
|
||||
.query(Integer.class)
|
||||
.single();
|
||||
return Result.success(count > 0);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in existsByUsername", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Boolean> existsByEmail(String email) {
|
||||
try {
|
||||
int count = jdbc.sql("SELECT COUNT(*) FROM users WHERE email = :email")
|
||||
.param("email", email)
|
||||
.query(Integer.class)
|
||||
.single();
|
||||
return Result.success(count > 0);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in existsByEmail", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private void saveUserRoles(User user) {
|
||||
jdbc.sql("DELETE FROM user_roles WHERE user_id = :userId")
|
||||
.param("userId", user.id().value())
|
||||
.update();
|
||||
|
||||
for (Role role : user.roles()) {
|
||||
jdbc.sql("INSERT INTO user_roles (user_id, role_id) VALUES (:userId, :roleId)")
|
||||
.param("userId", user.id().value())
|
||||
.param("roleId", role.id().value())
|
||||
.update();
|
||||
}
|
||||
}
|
||||
|
||||
private User loadRoles(User user) {
|
||||
var roleIds = jdbc.sql("SELECT role_id FROM user_roles WHERE user_id = :userId")
|
||||
.param("userId", user.id().value())
|
||||
.query((rs, rowNum) -> rs.getString("role_id"))
|
||||
.list();
|
||||
|
||||
Set<Role> roles = new HashSet<>();
|
||||
for (String roleId : roleIds) {
|
||||
switch (roleRepository.findById(RoleId.of(roleId))) {
|
||||
case Result.Success(var opt) -> opt.ifPresent(roles::add);
|
||||
case Result.Failure(var err) ->
|
||||
logger.trace("Failed to load role {}: {}", roleId, err.message());
|
||||
}
|
||||
}
|
||||
|
||||
return User.reconstitute(
|
||||
user.id(), user.username(), user.email(), user.passwordHash(),
|
||||
roles, user.branchId(), user.status(), user.createdAt(), user.lastLogin()
|
||||
);
|
||||
}
|
||||
|
||||
private User mapUserRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return User.reconstitute(
|
||||
UserId.of(rs.getString("id")),
|
||||
rs.getString("username"),
|
||||
rs.getString("email"),
|
||||
PasswordHash.of(rs.getString("password_hash")),
|
||||
Set.of(),
|
||||
rs.getString("branch_id"),
|
||||
UserStatus.valueOf(rs.getString("status")),
|
||||
rs.getObject("created_at", OffsetDateTime.class),
|
||||
rs.getObject("last_login", OffsetDateTime.class)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
package de.effigenix.infrastructure.usermanagement.persistence.entity;
|
||||
|
||||
import de.effigenix.domain.usermanagement.Permission;
|
||||
import de.effigenix.domain.usermanagement.RoleName;
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* JPA Entity for Role.
|
||||
* Infrastructure layer - NOT part of domain model!
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "roles")
|
||||
public class RoleEntity {
|
||||
|
||||
@Id
|
||||
@Column(name = "id", nullable = false, length = 36)
|
||||
private String id;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "name", nullable = false, unique = true, length = 50)
|
||||
private RoleName name;
|
||||
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "role_permissions", joinColumns = @JoinColumn(name = "role_id"))
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "permission", nullable = false, length = 100)
|
||||
private Set<Permission> permissions = new HashSet<>();
|
||||
|
||||
@Column(name = "description", length = 500)
|
||||
private String description;
|
||||
|
||||
// JPA requires no-arg constructor
|
||||
protected RoleEntity() {
|
||||
}
|
||||
|
||||
public RoleEntity(
|
||||
String id,
|
||||
RoleName name,
|
||||
Set<Permission> permissions,
|
||||
String description
|
||||
) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.permissions = permissions != null ? permissions : new HashSet<>();
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public RoleName getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(RoleName name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Set<Permission> getPermissions() {
|
||||
return permissions;
|
||||
}
|
||||
|
||||
public void setPermissions(Set<Permission> permissions) {
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
package de.effigenix.infrastructure.usermanagement.persistence.entity;
|
||||
|
||||
import de.effigenix.domain.usermanagement.UserStatus;
|
||||
import jakarta.persistence.*;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* JPA Entity for User.
|
||||
* Infrastructure layer - NOT part of domain model!
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "users")
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class UserEntity {
|
||||
|
||||
@Id
|
||||
@Column(name = "id", nullable = false, length = 36)
|
||||
private String id;
|
||||
|
||||
@Column(name = "username", nullable = false, unique = true, length = 100)
|
||||
private String username;
|
||||
|
||||
@Column(name = "email", nullable = false, unique = true, length = 255)
|
||||
private String email;
|
||||
|
||||
@Column(name = "password_hash", nullable = false, length = 60)
|
||||
private String passwordHash;
|
||||
|
||||
@ManyToMany(fetch = FetchType.EAGER)
|
||||
@JoinTable(
|
||||
name = "user_roles",
|
||||
joinColumns = @JoinColumn(name = "user_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "role_id")
|
||||
)
|
||||
private Set<RoleEntity> roles = new HashSet<>();
|
||||
|
||||
@Column(name = "branch_id", length = 36)
|
||||
private String branchId;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "status", nullable = false, length = 20)
|
||||
private UserStatus status;
|
||||
|
||||
@CreatedDate
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private OffsetDateTime createdAt;
|
||||
|
||||
@Column(name = "last_login")
|
||||
private OffsetDateTime lastLogin;
|
||||
|
||||
// JPA requires no-arg constructor
|
||||
protected UserEntity() {
|
||||
}
|
||||
|
||||
public UserEntity(
|
||||
String id,
|
||||
String username,
|
||||
String email,
|
||||
String passwordHash,
|
||||
Set<RoleEntity> roles,
|
||||
String branchId,
|
||||
UserStatus status,
|
||||
OffsetDateTime createdAt,
|
||||
OffsetDateTime lastLogin
|
||||
) {
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
this.email = email;
|
||||
this.passwordHash = passwordHash;
|
||||
this.roles = roles != null ? roles : new HashSet<>();
|
||||
this.branchId = branchId;
|
||||
this.status = status;
|
||||
this.createdAt = createdAt;
|
||||
this.lastLogin = lastLogin;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPasswordHash() {
|
||||
return passwordHash;
|
||||
}
|
||||
|
||||
public void setPasswordHash(String passwordHash) {
|
||||
this.passwordHash = passwordHash;
|
||||
}
|
||||
|
||||
public Set<RoleEntity> getRoles() {
|
||||
return roles;
|
||||
}
|
||||
|
||||
public void setRoles(Set<RoleEntity> roles) {
|
||||
this.roles = roles;
|
||||
}
|
||||
|
||||
public String getBranchId() {
|
||||
return branchId;
|
||||
}
|
||||
|
||||
public void setBranchId(String branchId) {
|
||||
this.branchId = branchId;
|
||||
}
|
||||
|
||||
public UserStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(UserStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public OffsetDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(OffsetDateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public OffsetDateTime getLastLogin() {
|
||||
return lastLogin;
|
||||
}
|
||||
|
||||
public void setLastLogin(OffsetDateTime lastLogin) {
|
||||
this.lastLogin = lastLogin;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
package de.effigenix.infrastructure.usermanagement.persistence.mapper;
|
||||
|
||||
import de.effigenix.domain.usermanagement.Role;
|
||||
import de.effigenix.domain.usermanagement.RoleId;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.RoleEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* Maps between Role domain entity and RoleEntity JPA entity.
|
||||
* Infrastructure Layer - translates between Domain and Persistence layers.
|
||||
*
|
||||
* This is a crucial part of Hexagonal Architecture:
|
||||
* - Domain layer defines pure business logic (Role)
|
||||
* - Infrastructure layer handles persistence (RoleEntity)
|
||||
* - Mapper translates between the two layers
|
||||
*/
|
||||
@Component
|
||||
public class RoleMapper {
|
||||
|
||||
/**
|
||||
* Converts a Role domain entity to a RoleEntity JPA entity.
|
||||
* Used when saving to the database.
|
||||
*/
|
||||
public RoleEntity toEntity(Role role) {
|
||||
if (role == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new RoleEntity(
|
||||
role.id().value(),
|
||||
role.name(),
|
||||
new HashSet<>(role.permissions()),
|
||||
role.description()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a RoleEntity JPA entity to a Role domain entity.
|
||||
* Used when loading from the database.
|
||||
*/
|
||||
public Role toDomain(RoleEntity entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Role.reconstitute(
|
||||
RoleId.of(entity.getId()),
|
||||
entity.getName(),
|
||||
new HashSet<>(entity.getPermissions()),
|
||||
entity.getDescription()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
package de.effigenix.infrastructure.usermanagement.persistence.mapper;
|
||||
|
||||
import de.effigenix.domain.usermanagement.*;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.RoleEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.UserEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Maps between User domain entity and UserEntity JPA entity.
|
||||
* Infrastructure Layer - translates between Domain and Persistence layers.
|
||||
*
|
||||
* This is a crucial part of Hexagonal Architecture:
|
||||
* - Domain layer defines pure business logic (User)
|
||||
* - Infrastructure layer handles persistence (UserEntity)
|
||||
* - Mapper translates between the two layers
|
||||
*/
|
||||
@Component
|
||||
public class UserMapper {
|
||||
|
||||
private final RoleMapper roleMapper;
|
||||
|
||||
public UserMapper(RoleMapper roleMapper) {
|
||||
this.roleMapper = roleMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a User domain entity to a UserEntity JPA entity.
|
||||
* Used when saving to the database.
|
||||
*/
|
||||
public UserEntity toEntity(User user) {
|
||||
if (user == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Set<RoleEntity> roleEntities = user.roles().stream()
|
||||
.map(roleMapper::toEntity)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
return new UserEntity(
|
||||
user.id().value(),
|
||||
user.username(),
|
||||
user.email(),
|
||||
user.passwordHash().value(),
|
||||
roleEntities,
|
||||
user.branchId(),
|
||||
user.status(),
|
||||
user.createdAt(),
|
||||
user.lastLogin()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a UserEntity JPA entity to a User domain entity.
|
||||
* Used when loading from the database.
|
||||
*/
|
||||
public User toDomain(UserEntity entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Set<Role> roles = entity.getRoles() != null
|
||||
? entity.getRoles().stream()
|
||||
.map(roleMapper::toDomain)
|
||||
.collect(Collectors.toSet())
|
||||
: new HashSet<>();
|
||||
|
||||
return User.reconstitute(
|
||||
UserId.of(entity.getId()),
|
||||
entity.getUsername(),
|
||||
entity.getEmail(),
|
||||
PasswordHash.of(entity.getPasswordHash()),
|
||||
roles,
|
||||
entity.getBranchId(),
|
||||
entity.getStatus(),
|
||||
entity.getCreatedAt(),
|
||||
entity.getLastLogin()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
package de.effigenix.infrastructure.usermanagement.persistence.repository;
|
||||
|
||||
import de.effigenix.shared.common.RepositoryError;
|
||||
import de.effigenix.domain.usermanagement.Role;
|
||||
import de.effigenix.domain.usermanagement.RoleId;
|
||||
import de.effigenix.domain.usermanagement.RoleName;
|
||||
import de.effigenix.domain.usermanagement.RoleRepository;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.mapper.RoleMapper;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* JPA Adapter for RoleRepository (Domain Interface).
|
||||
* Infrastructure Layer - implements the Domain's RoleRepository interface.
|
||||
*
|
||||
* This is the Adapter pattern in Hexagonal Architecture:
|
||||
* - Domain defines the interface (RoleRepository)
|
||||
* - Infrastructure implements it (JpaRoleRepository)
|
||||
* - Uses Spring Data JPA (RoleJpaRepository) internally
|
||||
* - Translates between Domain and JPA entities using RoleMapper
|
||||
*
|
||||
* @Transactional ensures database consistency.
|
||||
*/
|
||||
@Repository
|
||||
@Profile("!no-db")
|
||||
@Transactional(readOnly = true)
|
||||
public class JpaRoleRepository implements RoleRepository {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JpaRoleRepository.class);
|
||||
|
||||
private final RoleJpaRepository jpaRepository;
|
||||
private final RoleMapper roleMapper;
|
||||
|
||||
public JpaRoleRepository(RoleJpaRepository jpaRepository, RoleMapper roleMapper) {
|
||||
this.jpaRepository = jpaRepository;
|
||||
this.roleMapper = roleMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<Role>> findById(RoleId id) {
|
||||
try {
|
||||
Optional<Role> result = jpaRepository.findById(id.value())
|
||||
.map(roleMapper::toDomain);
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findById", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<Role>> findByName(RoleName name) {
|
||||
try {
|
||||
Optional<Role> result = jpaRepository.findByName(name)
|
||||
.map(roleMapper::toDomain);
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByName", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<Role>> findAll() {
|
||||
try {
|
||||
List<Role> result = jpaRepository.findAll().stream()
|
||||
.map(roleMapper::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findAll", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<RepositoryError, Void> save(Role role) {
|
||||
try {
|
||||
jpaRepository.save(roleMapper.toEntity(role));
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in save", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<RepositoryError, Void> delete(Role role) {
|
||||
try {
|
||||
jpaRepository.deleteById(role.id().value());
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in delete", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Boolean> existsByName(RoleName name) {
|
||||
try {
|
||||
return Result.success(jpaRepository.existsByName(name));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in existsByName", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
package de.effigenix.infrastructure.usermanagement.persistence.repository;
|
||||
|
||||
import de.effigenix.shared.common.RepositoryError;
|
||||
import de.effigenix.domain.usermanagement.User;
|
||||
import de.effigenix.domain.usermanagement.UserId;
|
||||
import de.effigenix.domain.usermanagement.UserRepository;
|
||||
import de.effigenix.domain.usermanagement.UserStatus;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.mapper.UserMapper;
|
||||
import de.effigenix.shared.common.Result;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* JPA Adapter for UserRepository (Domain Interface).
|
||||
* Infrastructure Layer - implements the Domain's UserRepository interface.
|
||||
*
|
||||
* This is the Adapter pattern in Hexagonal Architecture:
|
||||
* - Domain defines the interface (UserRepository)
|
||||
* - Infrastructure implements it (JpaUserRepository)
|
||||
* - Uses Spring Data JPA (UserJpaRepository) internally
|
||||
* - Translates between Domain and JPA entities using UserMapper
|
||||
*
|
||||
* @Transactional ensures database consistency.
|
||||
*/
|
||||
@Repository
|
||||
@Profile("!no-db")
|
||||
@Transactional(readOnly = true)
|
||||
public class JpaUserRepository implements UserRepository {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JpaUserRepository.class);
|
||||
private final UserJpaRepository jpaRepository;
|
||||
private final UserMapper userMapper;
|
||||
|
||||
public JpaUserRepository(UserJpaRepository jpaRepository, UserMapper userMapper) {
|
||||
this.jpaRepository = jpaRepository;
|
||||
this.userMapper = userMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<User>> findById(UserId id) {
|
||||
try {
|
||||
Optional<User> result = jpaRepository.findById(id.value())
|
||||
.map(userMapper::toDomain);
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findById", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<User>> findByUsername(String username) {
|
||||
try {
|
||||
Optional<User> result = jpaRepository.findByUsername(username)
|
||||
.map(userMapper::toDomain);
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByUsername", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Optional<User>> findByEmail(String email) {
|
||||
try {
|
||||
Optional<User> result = jpaRepository.findByEmail(email)
|
||||
.map(userMapper::toDomain);
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByEmail", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<User>> findByBranchId(String branchId) {
|
||||
try {
|
||||
List<User> result = jpaRepository.findByBranchId(branchId).stream()
|
||||
.map(userMapper::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByBranchId", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<User>> findByStatus(UserStatus status) {
|
||||
try {
|
||||
List<User> result = jpaRepository.findByStatus(status).stream()
|
||||
.map(userMapper::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findByStatus", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, List<User>> findAll() {
|
||||
try {
|
||||
List<User> result = jpaRepository.findAll().stream()
|
||||
.map(userMapper::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in findAll", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<RepositoryError, Void> save(User user) {
|
||||
try {
|
||||
jpaRepository.save(userMapper.toEntity(user));
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in save", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<RepositoryError, Void> delete(User user) {
|
||||
try {
|
||||
jpaRepository.deleteById(user.id().value());
|
||||
return Result.success(null);
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in delete", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Boolean> existsByUsername(String username) {
|
||||
try {
|
||||
return Result.success(jpaRepository.existsByUsername(username));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in existsByUsername", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<RepositoryError, Boolean> existsByEmail(String email) {
|
||||
try {
|
||||
return Result.success(jpaRepository.existsByEmail(email));
|
||||
} catch (Exception e) {
|
||||
logger.trace("Database error in existsByEmail", e);
|
||||
return Result.failure(new RepositoryError.DatabaseError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
package de.effigenix.infrastructure.usermanagement.persistence.repository;
|
||||
|
||||
import de.effigenix.domain.usermanagement.RoleName;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.RoleEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Spring Data JPA Repository for RoleEntity.
|
||||
* Infrastructure Layer - automatically provides CRUD operations.
|
||||
*
|
||||
* Spring Data generates implementations at runtime based on method names.
|
||||
*/
|
||||
@Repository
|
||||
public interface RoleJpaRepository extends JpaRepository<RoleEntity, String> {
|
||||
|
||||
/**
|
||||
* Finds a role by its name.
|
||||
*/
|
||||
Optional<RoleEntity> findByName(RoleName name);
|
||||
|
||||
/**
|
||||
* Checks if a role with the given name exists.
|
||||
*/
|
||||
boolean existsByName(RoleName name);
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
package de.effigenix.infrastructure.usermanagement.persistence.repository;
|
||||
|
||||
import de.effigenix.domain.usermanagement.UserStatus;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.UserEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Spring Data JPA Repository for UserEntity.
|
||||
* Infrastructure Layer - automatically provides CRUD operations.
|
||||
*
|
||||
* Spring Data generates implementations at runtime based on method names.
|
||||
*/
|
||||
@Repository
|
||||
public interface UserJpaRepository extends JpaRepository<UserEntity, String> {
|
||||
|
||||
/**
|
||||
* Finds a user by their username.
|
||||
*/
|
||||
Optional<UserEntity> findByUsername(String username);
|
||||
|
||||
/**
|
||||
* Finds a user by their email.
|
||||
*/
|
||||
Optional<UserEntity> findByEmail(String email);
|
||||
|
||||
/**
|
||||
* Finds all users assigned to a specific branch.
|
||||
*/
|
||||
List<UserEntity> findByBranchId(String branchId);
|
||||
|
||||
/**
|
||||
* Finds all users with a specific status.
|
||||
*/
|
||||
List<UserEntity> findByStatus(UserStatus status);
|
||||
|
||||
/**
|
||||
* Checks if a username already exists.
|
||||
*/
|
||||
boolean existsByUsername(String username);
|
||||
|
||||
/**
|
||||
* Checks if an email already exists.
|
||||
*/
|
||||
boolean existsByEmail(String email);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue