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

refactor: konsistentes Result-basiertes Error-Handling im Master Data BC

VO-Factory-Methoden (of/create/tryEuro) für alle Value Objects eingeführt,
die intern IllegalArgumentException fangen und Result<String, T> liefern.
FrameContract.create() liefert jetzt Result statt zu werfen.

Alle 31 Use Cases auf Record-Pattern-Deconstruction umgestellt
(Failure(var err) / Success(var val) statt verbose generischer Typen).
isFailure()/unsafeGetValue() eliminiert.

Aggregate-Factorys bereinigt — VO-Null-Checks entfernt, da Validierung
jetzt in den VO-Factories liegt. ValidationFailure und CertificateNotFound
zu den Error-Interfaces hinzugefügt.

WIP: Aggregate.create() gibt teilweise kein Result mehr zurück —
wird im nächsten Schritt korrigiert.
This commit is contained in:
Sebastian Frick 2026-02-17 23:44:44 +01:00
parent b813fcbcaa
commit 6b341f217b
57 changed files with 853 additions and 658 deletions

View file

@ -1,13 +1,10 @@
package de.effigenix.application.masterdata; package de.effigenix.application.masterdata;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -20,24 +17,25 @@ public class ActivateArticle {
} }
public Result<ArticleError, Article> execute(ArticleId articleId, ActorId performedBy) { public Result<ArticleError, Article> execute(ArticleId articleId, ActorId performedBy) {
Article article;
switch (articleRepository.findById(articleId)) { switch (articleRepository.findById(articleId)) {
case Failure<RepositoryError, Optional<Article>> f -> case Failure(var err) ->
{ return Result.failure(new ArticleError.RepositoryFailure(f.error().message())); } { return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Article>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new ArticleError.ArticleNotFound(articleId)); return Result.failure(new ArticleError.ArticleNotFound(articleId));
} }
Article article = s.value().get(); article = opt.get();
article.activate();
switch (articleRepository.save(article)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new ArticleError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(article);
} }
} }
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);
} }
} }

View file

@ -1,13 +1,10 @@
package de.effigenix.application.masterdata; package de.effigenix.application.masterdata;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -20,24 +17,25 @@ public class ActivateCustomer {
} }
public Result<CustomerError, Customer> execute(CustomerId customerId, ActorId performedBy) { public Result<CustomerError, Customer> execute(CustomerId customerId, ActorId performedBy) {
Customer customer;
switch (customerRepository.findById(customerId)) { switch (customerRepository.findById(customerId)) {
case Failure<RepositoryError, Optional<Customer>> f -> case Failure(var err) ->
{ return Result.failure(new CustomerError.RepositoryFailure(f.error().message())); } { return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Customer>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new CustomerError.CustomerNotFound(customerId)); return Result.failure(new CustomerError.CustomerNotFound(customerId));
} }
Customer customer = s.value().get(); customer = opt.get();
customer.activate();
switch (customerRepository.save(customer)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new CustomerError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(customer);
} }
} }
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);
} }
} }

View file

@ -1,13 +1,10 @@
package de.effigenix.application.masterdata; package de.effigenix.application.masterdata;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -20,24 +17,25 @@ public class ActivateSupplier {
} }
public Result<SupplierError, Supplier> execute(SupplierId supplierId, ActorId performedBy) { public Result<SupplierError, Supplier> execute(SupplierId supplierId, ActorId performedBy) {
Supplier supplier;
switch (supplierRepository.findById(supplierId)) { switch (supplierRepository.findById(supplierId)) {
case Failure<RepositoryError, Optional<Supplier>> f -> case Failure(var err) ->
{ return Result.failure(new SupplierError.RepositoryFailure(f.error().message())); } { return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Supplier>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new SupplierError.SupplierNotFound(supplierId)); return Result.failure(new SupplierError.SupplierNotFound(supplierId));
} }
Supplier supplier = s.value().get(); supplier = opt.get();
supplier.activate();
switch (supplierRepository.save(supplier)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new SupplierError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(supplier);
} }
} }
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);
} }
} }

View file

@ -2,13 +2,10 @@ package de.effigenix.application.masterdata;
import de.effigenix.application.masterdata.command.AddCertificateCommand; import de.effigenix.application.masterdata.command.AddCertificateCommand;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -23,27 +20,31 @@ public class AddCertificate {
public Result<SupplierError, Supplier> execute(AddCertificateCommand cmd, ActorId performedBy) { public Result<SupplierError, Supplier> execute(AddCertificateCommand cmd, ActorId performedBy) {
var supplierId = SupplierId.of(cmd.supplierId()); var supplierId = SupplierId.of(cmd.supplierId());
Supplier supplier;
switch (supplierRepository.findById(supplierId)) { switch (supplierRepository.findById(supplierId)) {
case Failure<RepositoryError, Optional<Supplier>> f -> case Failure(var err) ->
{ return Result.failure(new SupplierError.RepositoryFailure(f.error().message())); } { return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Supplier>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new SupplierError.SupplierNotFound(supplierId)); return Result.failure(new SupplierError.SupplierNotFound(supplierId));
} }
Supplier supplier = s.value().get(); supplier = opt.get();
var certificate = new QualityCertificate(
cmd.certificateType(), cmd.issuer(), cmd.validFrom(), cmd.validUntil());
supplier.addCertificate(certificate);
switch (supplierRepository.save(supplier)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new SupplierError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(supplier);
} }
} }
QualityCertificate certificate;
switch (QualityCertificate.create(cmd.certificateType(), cmd.issuer(), cmd.validFrom(), cmd.validUntil())) {
case Failure(var msg) -> { return Result.failure(new SupplierError.ValidationFailure(msg)); }
case Success(var val) -> certificate = val;
}
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);
} }
} }

View file

@ -3,13 +3,10 @@ package de.effigenix.application.masterdata;
import de.effigenix.application.masterdata.command.AddDeliveryAddressCommand; import de.effigenix.application.masterdata.command.AddDeliveryAddressCommand;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.Address; import de.effigenix.shared.common.Address;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -24,27 +21,37 @@ public class AddDeliveryAddress {
public Result<CustomerError, Customer> execute(AddDeliveryAddressCommand cmd, ActorId performedBy) { public Result<CustomerError, Customer> execute(AddDeliveryAddressCommand cmd, ActorId performedBy) {
var customerId = CustomerId.of(cmd.customerId()); var customerId = CustomerId.of(cmd.customerId());
Customer customer;
switch (customerRepository.findById(customerId)) { switch (customerRepository.findById(customerId)) {
case Failure<RepositoryError, Optional<Customer>> f -> case Failure(var err) ->
{ return Result.failure(new CustomerError.RepositoryFailure(f.error().message())); } { return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Customer>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new CustomerError.CustomerNotFound(customerId)); return Result.failure(new CustomerError.CustomerNotFound(customerId));
} }
Customer customer = s.value().get(); customer = opt.get();
var address = new Address(cmd.street(), cmd.houseNumber(), cmd.postalCode(), cmd.city(), cmd.country());
var deliveryAddress = new DeliveryAddress(cmd.label(), address, cmd.contactPerson(), cmd.deliveryNotes());
customer.addDeliveryAddress(deliveryAddress);
switch (customerRepository.save(customer)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new CustomerError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(customer);
} }
} }
Address address;
switch (Address.create(cmd.street(), cmd.houseNumber(), cmd.postalCode(), cmd.city(), cmd.country())) {
case Failure(var msg) -> { return Result.failure(new CustomerError.ValidationFailure(msg)); }
case Success(var val) -> address = val;
}
DeliveryAddress deliveryAddress;
switch (DeliveryAddress.create(cmd.label(), address, cmd.contactPerson(), cmd.deliveryNotes())) {
case Failure(var msg) -> { return Result.failure(new CustomerError.ValidationFailure(msg)); }
case Success(var val) -> deliveryAddress = val;
}
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);
} }
} }

View file

@ -3,13 +3,10 @@ package de.effigenix.application.masterdata;
import de.effigenix.application.masterdata.command.AddSalesUnitCommand; import de.effigenix.application.masterdata.command.AddSalesUnitCommand;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.Money; import de.effigenix.shared.common.Money;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -24,33 +21,41 @@ public class AddSalesUnit {
public Result<ArticleError, Article> execute(AddSalesUnitCommand cmd, ActorId performedBy) { public Result<ArticleError, Article> execute(AddSalesUnitCommand cmd, ActorId performedBy) {
var articleId = ArticleId.of(cmd.articleId()); var articleId = ArticleId.of(cmd.articleId());
Article article;
switch (articleRepository.findById(articleId)) { switch (articleRepository.findById(articleId)) {
case Failure<RepositoryError, Optional<Article>> f -> case Failure(var err) ->
{ return Result.failure(new ArticleError.RepositoryFailure(f.error().message())); } { return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Article>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new ArticleError.ArticleNotFound(articleId)); return Result.failure(new ArticleError.ArticleNotFound(articleId));
} }
Article article = s.value().get(); article = opt.get();
var suResult = SalesUnit.create(cmd.unit(), cmd.priceModel(), Money.euro(cmd.price()));
if (suResult.isFailure()) {
return Result.failure(suResult.unsafeGetError());
}
var addResult = article.addSalesUnit(suResult.unsafeGetValue());
if (addResult.isFailure()) {
return Result.failure(addResult.unsafeGetError());
}
switch (articleRepository.save(article)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new ArticleError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(article);
} }
} }
Money price;
switch (Money.tryEuro(cmd.price())) {
case Failure(var msg) -> { return Result.failure(new ArticleError.ValidationFailure(msg)); }
case Success(var val) -> price = val;
}
SalesUnit salesUnit;
switch (SalesUnit.create(cmd.unit(), cmd.priceModel(), price)) {
case Failure(var err) -> { return Result.failure(err); }
case Success(var val) -> salesUnit = val;
}
switch (article.addSalesUnit(salesUnit)) {
case Failure(var err) -> { return Result.failure(err); }
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);
} }
} }

View file

@ -2,13 +2,10 @@ package de.effigenix.application.masterdata;
import de.effigenix.application.masterdata.command.AssignSupplierCommand; import de.effigenix.application.masterdata.command.AssignSupplierCommand;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -23,24 +20,25 @@ public class AssignSupplier {
public Result<ArticleError, Article> execute(AssignSupplierCommand cmd, ActorId performedBy) { public Result<ArticleError, Article> execute(AssignSupplierCommand cmd, ActorId performedBy) {
var articleId = ArticleId.of(cmd.articleId()); var articleId = ArticleId.of(cmd.articleId());
Article article;
switch (articleRepository.findById(articleId)) { switch (articleRepository.findById(articleId)) {
case Failure<RepositoryError, Optional<Article>> f -> case Failure(var err) ->
{ return Result.failure(new ArticleError.RepositoryFailure(f.error().message())); } { return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Article>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new ArticleError.ArticleNotFound(articleId)); return Result.failure(new ArticleError.ArticleNotFound(articleId));
} }
Article article = s.value().get(); article = opt.get();
article.addSupplierReference(SupplierId.of(cmd.supplierId()));
switch (articleRepository.save(article)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new ArticleError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(article);
} }
} }
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);
} }
} }

View file

@ -3,7 +3,6 @@ package de.effigenix.application.masterdata;
import de.effigenix.application.masterdata.command.CreateArticleCommand; import de.effigenix.application.masterdata.command.CreateArticleCommand;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.Money; import de.effigenix.shared.common.Money;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -20,41 +19,50 @@ public class CreateArticle {
} }
public Result<ArticleError, Article> execute(CreateArticleCommand cmd, ActorId performedBy) { public Result<ArticleError, Article> execute(CreateArticleCommand cmd, ActorId performedBy) {
// Check uniqueness ArticleNumber articleNumber;
switch (articleRepository.existsByArticleNumber(new ArticleNumber(cmd.articleNumber()))) { switch (ArticleNumber.of(cmd.articleNumber())) {
case Failure<RepositoryError, Boolean> f -> case Failure(var msg) -> { return Result.failure(new ArticleError.ValidationFailure(msg)); }
{ return Result.failure(new ArticleError.RepositoryFailure(f.error().message())); } case Success(var val) -> articleNumber = val;
case Success<RepositoryError, Boolean> s -> { }
if (s.value()) {
switch (articleRepository.existsByArticleNumber(articleNumber)) {
case Failure(var err) ->
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
case Success(var exists) -> {
if (exists) {
return Result.failure(new ArticleError.ArticleNumberAlreadyExists(cmd.articleNumber())); return Result.failure(new ArticleError.ArticleNumberAlreadyExists(cmd.articleNumber()));
} }
} }
} }
// Create initial SalesUnit Money price;
var salesUnitResult = SalesUnit.create(cmd.unit(), cmd.priceModel(), Money.euro(cmd.price())); switch (Money.tryEuro(cmd.price())) {
if (salesUnitResult.isFailure()) { case Failure(var msg) -> { return Result.failure(new ArticleError.ValidationFailure(msg)); }
return Result.failure(salesUnitResult.unsafeGetError()); case Success(var val) -> price = val;
} }
// Create Article SalesUnit salesUnit;
var articleResult = Article.create( switch (SalesUnit.create(cmd.unit(), cmd.priceModel(), price)) {
new ArticleName(cmd.name()), case Failure(var err) -> { return Result.failure(err); }
new ArticleNumber(cmd.articleNumber()), case Success(var val) -> salesUnit = val;
ProductCategoryId.of(cmd.categoryId()),
salesUnitResult.unsafeGetValue()
);
if (articleResult.isFailure()) {
return Result.failure(articleResult.unsafeGetError());
} }
Article article = articleResult.unsafeGetValue(); ArticleName name;
switch (ArticleName.of(cmd.name())) {
case Failure(var msg) -> { return Result.failure(new ArticleError.ValidationFailure(msg)); }
case Success(var val) -> name = val;
}
Article article;
switch (Article.create(name, articleNumber, ProductCategoryId.of(cmd.categoryId()), salesUnit)) {
case Failure(var err) -> { return Result.failure(err); }
case Success(var val) -> article = val;
}
// Save
switch (articleRepository.save(article)) { switch (articleRepository.save(article)) {
case Failure<RepositoryError, Void> f -> case Failure(var err) ->
{ return Result.failure(new ArticleError.RepositoryFailure(f.error().message())); } { return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Void> ignored -> { } case Success(var ignored) -> { }
} }
return Result.success(article); return Result.success(article);

View file

@ -18,33 +18,46 @@ public class CreateCustomer {
} }
public Result<CustomerError, Customer> execute(CreateCustomerCommand cmd, ActorId performedBy) { public Result<CustomerError, Customer> execute(CreateCustomerCommand cmd, ActorId performedBy) {
var name = new CustomerName(cmd.name()); CustomerName name;
switch (CustomerName.of(cmd.name())) {
case Failure(var msg) -> { return Result.failure(new CustomerError.ValidationFailure(msg)); }
case Success(var val) -> name = val;
}
switch (customerRepository.existsByName(name)) { switch (customerRepository.existsByName(name)) {
case Failure<RepositoryError, Boolean> f -> case Failure(var err) ->
{ return Result.failure(new CustomerError.RepositoryFailure(f.error().message())); } { return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Boolean> s -> { case Success(var exists) -> {
if (s.value()) { if (exists) {
return Result.failure(new CustomerError.CustomerNameAlreadyExists(cmd.name())); return Result.failure(new CustomerError.CustomerNameAlreadyExists(cmd.name()));
} }
} }
} }
var address = new Address(cmd.street(), cmd.houseNumber(), cmd.postalCode(), cmd.city(), cmd.country()); Address address;
var contactInfo = new ContactInfo(cmd.phone(), cmd.email(), cmd.contactPerson()); switch (Address.create(cmd.street(), cmd.houseNumber(), cmd.postalCode(), cmd.city(), cmd.country())) {
var paymentTerms = new PaymentTerms(cmd.paymentDueDays(), cmd.paymentDescription()); case Failure(var msg) -> { return Result.failure(new CustomerError.ValidationFailure(msg)); }
case Success(var val) -> address = val;
var result = Customer.create(name, cmd.type(), address, contactInfo, paymentTerms);
if (result.isFailure()) {
return result;
} }
Customer customer = result.unsafeGetValue(); ContactInfo contactInfo;
switch (ContactInfo.create(cmd.phone(), cmd.email(), cmd.contactPerson())) {
case Failure(var msg) -> { return Result.failure(new CustomerError.ValidationFailure(msg)); }
case Success(var val) -> contactInfo = val;
}
PaymentTerms paymentTerms;
switch (PaymentTerms.create(cmd.paymentDueDays(), cmd.paymentDescription())) {
case Failure(var msg) -> { return Result.failure(new CustomerError.ValidationFailure(msg)); }
case Success(var val) -> paymentTerms = val;
}
var customer = Customer.create(name, cmd.type(), address, contactInfo, paymentTerms);
switch (customerRepository.save(customer)) { switch (customerRepository.save(customer)) {
case Failure<RepositoryError, Void> f -> case Failure(var err) ->
{ return Result.failure(new CustomerError.RepositoryFailure(f.error().message())); } { return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Void> ignored -> { } case Success(var ignored) -> { }
} }
return Result.success(customer); return Result.success(customer);

View file

@ -2,7 +2,6 @@ package de.effigenix.application.masterdata;
import de.effigenix.application.masterdata.command.CreateProductCategoryCommand; import de.effigenix.application.masterdata.command.CreateProductCategoryCommand;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -19,29 +18,28 @@ public class CreateProductCategory {
} }
public Result<ProductCategoryError, ProductCategory> execute(CreateProductCategoryCommand cmd, ActorId performedBy) { public Result<ProductCategoryError, ProductCategory> execute(CreateProductCategoryCommand cmd, ActorId performedBy) {
var name = new CategoryName(cmd.name()); CategoryName name;
switch (CategoryName.of(cmd.name())) {
case Failure(var msg) -> { return Result.failure(new ProductCategoryError.ValidationFailure(msg)); }
case Success(var val) -> name = val;
}
switch (categoryRepository.existsByName(name)) { switch (categoryRepository.existsByName(name)) {
case Failure<RepositoryError, Boolean> f -> case Failure(var err) ->
{ return Result.failure(new ProductCategoryError.RepositoryFailure(f.error().message())); } { return Result.failure(new ProductCategoryError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Boolean> s -> { case Success(var exists) -> {
if (s.value()) { if (exists) {
return Result.failure(new ProductCategoryError.CategoryNameAlreadyExists(cmd.name())); return Result.failure(new ProductCategoryError.CategoryNameAlreadyExists(cmd.name()));
} }
} }
} }
var result = ProductCategory.create(name, cmd.description()); var category = ProductCategory.create(name, cmd.description());
if (result.isFailure()) {
return result;
}
ProductCategory category = result.unsafeGetValue();
switch (categoryRepository.save(category)) { switch (categoryRepository.save(category)) {
case Failure<RepositoryError, Void> f -> case Failure(var err) ->
{ return Result.failure(new ProductCategoryError.RepositoryFailure(f.error().message())); } { return Result.failure(new ProductCategoryError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Void> ignored -> { } case Success(var ignored) -> { }
} }
return Result.success(category); return Result.success(category);

View file

@ -18,33 +18,46 @@ public class CreateSupplier {
} }
public Result<SupplierError, Supplier> execute(CreateSupplierCommand cmd, ActorId performedBy) { public Result<SupplierError, Supplier> execute(CreateSupplierCommand cmd, ActorId performedBy) {
var name = new SupplierName(cmd.name()); SupplierName name;
switch (SupplierName.of(cmd.name())) {
case Failure(var msg) -> { return Result.failure(new SupplierError.ValidationFailure(msg)); }
case Success(var val) -> name = val;
}
switch (supplierRepository.existsByName(name)) { switch (supplierRepository.existsByName(name)) {
case Failure<RepositoryError, Boolean> f -> case Failure(var err) ->
{ return Result.failure(new SupplierError.RepositoryFailure(f.error().message())); } { return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Boolean> s -> { case Success(var exists) -> {
if (s.value()) { if (exists) {
return Result.failure(new SupplierError.SupplierNameAlreadyExists(cmd.name())); return Result.failure(new SupplierError.SupplierNameAlreadyExists(cmd.name()));
} }
} }
} }
var address = new Address(cmd.street(), cmd.houseNumber(), cmd.postalCode(), cmd.city(), cmd.country()); Address address;
var contactInfo = new ContactInfo(cmd.phone(), cmd.email(), cmd.contactPerson()); switch (Address.create(cmd.street(), cmd.houseNumber(), cmd.postalCode(), cmd.city(), cmd.country())) {
var paymentTerms = new PaymentTerms(cmd.paymentDueDays(), cmd.paymentDescription()); case Failure(var msg) -> { return Result.failure(new SupplierError.ValidationFailure(msg)); }
case Success(var val) -> address = val;
var result = Supplier.create(name, address, contactInfo, paymentTerms);
if (result.isFailure()) {
return result;
} }
Supplier supplier = result.unsafeGetValue(); ContactInfo contactInfo;
switch (ContactInfo.create(cmd.phone(), cmd.email(), cmd.contactPerson())) {
case Failure(var msg) -> { return Result.failure(new SupplierError.ValidationFailure(msg)); }
case Success(var val) -> contactInfo = val;
}
PaymentTerms paymentTerms;
switch (PaymentTerms.create(cmd.paymentDueDays(), cmd.paymentDescription())) {
case Failure(var msg) -> { return Result.failure(new SupplierError.ValidationFailure(msg)); }
case Success(var val) -> paymentTerms = val;
}
var supplier = Supplier.create(name, address, contactInfo, paymentTerms);
switch (supplierRepository.save(supplier)) { switch (supplierRepository.save(supplier)) {
case Failure<RepositoryError, Void> f -> case Failure(var err) ->
{ return Result.failure(new SupplierError.RepositoryFailure(f.error().message())); } { return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Void> ignored -> { } case Success(var ignored) -> { }
} }
return Result.success(supplier); return Result.success(supplier);

View file

@ -1,13 +1,10 @@
package de.effigenix.application.masterdata; package de.effigenix.application.masterdata;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -20,24 +17,25 @@ public class DeactivateArticle {
} }
public Result<ArticleError, Article> execute(ArticleId articleId, ActorId performedBy) { public Result<ArticleError, Article> execute(ArticleId articleId, ActorId performedBy) {
Article article;
switch (articleRepository.findById(articleId)) { switch (articleRepository.findById(articleId)) {
case Failure<RepositoryError, Optional<Article>> f -> case Failure(var err) ->
{ return Result.failure(new ArticleError.RepositoryFailure(f.error().message())); } { return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Article>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new ArticleError.ArticleNotFound(articleId)); return Result.failure(new ArticleError.ArticleNotFound(articleId));
} }
Article article = s.value().get(); article = opt.get();
article.deactivate();
switch (articleRepository.save(article)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new ArticleError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(article);
} }
} }
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);
} }
} }

View file

@ -1,13 +1,10 @@
package de.effigenix.application.masterdata; package de.effigenix.application.masterdata;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -20,24 +17,25 @@ public class DeactivateCustomer {
} }
public Result<CustomerError, Customer> execute(CustomerId customerId, ActorId performedBy) { public Result<CustomerError, Customer> execute(CustomerId customerId, ActorId performedBy) {
Customer customer;
switch (customerRepository.findById(customerId)) { switch (customerRepository.findById(customerId)) {
case Failure<RepositoryError, Optional<Customer>> f -> case Failure(var err) ->
{ return Result.failure(new CustomerError.RepositoryFailure(f.error().message())); } { return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Customer>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new CustomerError.CustomerNotFound(customerId)); return Result.failure(new CustomerError.CustomerNotFound(customerId));
} }
Customer customer = s.value().get(); customer = opt.get();
customer.deactivate();
switch (customerRepository.save(customer)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new CustomerError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(customer);
} }
} }
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);
} }
} }

View file

@ -1,13 +1,10 @@
package de.effigenix.application.masterdata; package de.effigenix.application.masterdata;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -20,24 +17,25 @@ public class DeactivateSupplier {
} }
public Result<SupplierError, Supplier> execute(SupplierId supplierId, ActorId performedBy) { public Result<SupplierError, Supplier> execute(SupplierId supplierId, ActorId performedBy) {
Supplier supplier;
switch (supplierRepository.findById(supplierId)) { switch (supplierRepository.findById(supplierId)) {
case Failure<RepositoryError, Optional<Supplier>> f -> case Failure(var err) ->
{ return Result.failure(new SupplierError.RepositoryFailure(f.error().message())); } { return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Supplier>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new SupplierError.SupplierNotFound(supplierId)); return Result.failure(new SupplierError.SupplierNotFound(supplierId));
} }
Supplier supplier = s.value().get(); supplier = opt.get();
supplier.deactivate();
switch (supplierRepository.save(supplier)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new SupplierError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(supplier);
} }
} }
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);
} }
} }

View file

@ -1,14 +1,10 @@
package de.effigenix.application.masterdata; package de.effigenix.application.masterdata;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -23,36 +19,34 @@ public class DeleteProductCategory {
} }
public Result<ProductCategoryError, Void> execute(ProductCategoryId categoryId, ActorId performedBy) { public Result<ProductCategoryError, Void> execute(ProductCategoryId categoryId, ActorId performedBy) {
// Check category exists ProductCategory category;
switch (categoryRepository.findById(categoryId)) { switch (categoryRepository.findById(categoryId)) {
case Failure<RepositoryError, Optional<ProductCategory>> f -> case Failure(var err) ->
{ return Result.failure(new ProductCategoryError.RepositoryFailure(f.error().message())); } { return Result.failure(new ProductCategoryError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<ProductCategory>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new ProductCategoryError.CategoryNotFound(categoryId)); return Result.failure(new ProductCategoryError.CategoryNotFound(categoryId));
} }
ProductCategory category = s.value().get(); category = opt.get();
// Check no articles are using this category
switch (articleRepository.findByCategory(categoryId)) {
case Failure<RepositoryError, List<Article>> f2 ->
{ return Result.failure(new ProductCategoryError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, List<Article>> s2 -> {
if (!s2.value().isEmpty()) {
return Result.failure(new ProductCategoryError.CategoryInUse(categoryId));
}
}
}
// Delete
switch (categoryRepository.delete(category)) {
case Failure<RepositoryError, Void> f3 ->
{ return Result.failure(new ProductCategoryError.RepositoryFailure(f3.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(null);
} }
} }
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) -> { }
}
return Result.success(null);
} }
} }

View file

@ -1,12 +1,9 @@
package de.effigenix.application.masterdata; package de.effigenix.application.masterdata;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional(readOnly = true) @Transactional(readOnly = true)
@ -20,11 +17,10 @@ public class GetArticle {
public Result<ArticleError, Article> execute(ArticleId articleId) { public Result<ArticleError, Article> execute(ArticleId articleId) {
return switch (articleRepository.findById(articleId)) { return switch (articleRepository.findById(articleId)) {
case Failure<RepositoryError, Optional<Article>> f -> case Failure(var err) ->
Result.failure(new ArticleError.RepositoryFailure(f.error().message())); Result.failure(new ArticleError.RepositoryFailure(err.message()));
case Success<RepositoryError, Optional<Article>> s -> case Success(var opt) ->
s.value() opt.map(Result::<ArticleError, Article>success)
.map(Result::<ArticleError, Article>success)
.orElseGet(() -> Result.failure(new ArticleError.ArticleNotFound(articleId))); .orElseGet(() -> Result.failure(new ArticleError.ArticleNotFound(articleId)));
}; };
} }

View file

@ -1,12 +1,9 @@
package de.effigenix.application.masterdata; package de.effigenix.application.masterdata;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional(readOnly = true) @Transactional(readOnly = true)
@ -20,11 +17,10 @@ public class GetCustomer {
public Result<CustomerError, Customer> execute(CustomerId customerId) { public Result<CustomerError, Customer> execute(CustomerId customerId) {
return switch (customerRepository.findById(customerId)) { return switch (customerRepository.findById(customerId)) {
case Failure<RepositoryError, Optional<Customer>> f -> case Failure(var err) ->
Result.failure(new CustomerError.RepositoryFailure(f.error().message())); Result.failure(new CustomerError.RepositoryFailure(err.message()));
case Success<RepositoryError, Optional<Customer>> s -> case Success(var opt) ->
s.value() opt.map(Result::<CustomerError, Customer>success)
.map(Result::<CustomerError, Customer>success)
.orElseGet(() -> Result.failure(new CustomerError.CustomerNotFound(customerId))); .orElseGet(() -> Result.failure(new CustomerError.CustomerNotFound(customerId)));
}; };
} }

View file

@ -1,12 +1,9 @@
package de.effigenix.application.masterdata; package de.effigenix.application.masterdata;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional(readOnly = true) @Transactional(readOnly = true)
@ -20,11 +17,10 @@ public class GetSupplier {
public Result<SupplierError, Supplier> execute(SupplierId supplierId) { public Result<SupplierError, Supplier> execute(SupplierId supplierId) {
return switch (supplierRepository.findById(supplierId)) { return switch (supplierRepository.findById(supplierId)) {
case Failure<RepositoryError, Optional<Supplier>> f -> case Failure(var err) ->
Result.failure(new SupplierError.RepositoryFailure(f.error().message())); Result.failure(new SupplierError.RepositoryFailure(err.message()));
case Success<RepositoryError, Optional<Supplier>> s -> case Success(var opt) ->
s.value() opt.map(Result::<SupplierError, Supplier>success)
.map(Result::<SupplierError, Supplier>success)
.orElseGet(() -> Result.failure(new SupplierError.SupplierNotFound(supplierId))); .orElseGet(() -> Result.failure(new SupplierError.SupplierNotFound(supplierId)));
}; };
} }

View file

@ -1,7 +1,6 @@
package de.effigenix.application.masterdata; package de.effigenix.application.masterdata;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -20,28 +19,28 @@ public class ListArticles {
public Result<ArticleError, List<Article>> execute() { public Result<ArticleError, List<Article>> execute() {
return switch (articleRepository.findAll()) { return switch (articleRepository.findAll()) {
case Failure<RepositoryError, List<Article>> f -> case Failure(var err) ->
Result.failure(new ArticleError.RepositoryFailure(f.error().message())); Result.failure(new ArticleError.RepositoryFailure(err.message()));
case Success<RepositoryError, List<Article>> s -> case Success(var articles) ->
Result.success(s.value()); Result.success(articles);
}; };
} }
public Result<ArticleError, List<Article>> executeByCategory(ProductCategoryId categoryId) { public Result<ArticleError, List<Article>> executeByCategory(ProductCategoryId categoryId) {
return switch (articleRepository.findByCategory(categoryId)) { return switch (articleRepository.findByCategory(categoryId)) {
case Failure<RepositoryError, List<Article>> f -> case Failure(var err) ->
Result.failure(new ArticleError.RepositoryFailure(f.error().message())); Result.failure(new ArticleError.RepositoryFailure(err.message()));
case Success<RepositoryError, List<Article>> s -> case Success(var articles) ->
Result.success(s.value()); Result.success(articles);
}; };
} }
public Result<ArticleError, List<Article>> executeByStatus(ArticleStatus status) { public Result<ArticleError, List<Article>> executeByStatus(ArticleStatus status) {
return switch (articleRepository.findByStatus(status)) { return switch (articleRepository.findByStatus(status)) {
case Failure<RepositoryError, List<Article>> f -> case Failure(var err) ->
Result.failure(new ArticleError.RepositoryFailure(f.error().message())); Result.failure(new ArticleError.RepositoryFailure(err.message()));
case Success<RepositoryError, List<Article>> s -> case Success(var articles) ->
Result.success(s.value()); Result.success(articles);
}; };
} }
} }

View file

@ -1,7 +1,6 @@
package de.effigenix.application.masterdata; package de.effigenix.application.masterdata;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -20,28 +19,28 @@ public class ListCustomers {
public Result<CustomerError, List<Customer>> execute() { public Result<CustomerError, List<Customer>> execute() {
return switch (customerRepository.findAll()) { return switch (customerRepository.findAll()) {
case Failure<RepositoryError, List<Customer>> f -> case Failure(var err) ->
Result.failure(new CustomerError.RepositoryFailure(f.error().message())); Result.failure(new CustomerError.RepositoryFailure(err.message()));
case Success<RepositoryError, List<Customer>> s -> case Success(var customers) ->
Result.success(s.value()); Result.success(customers);
}; };
} }
public Result<CustomerError, List<Customer>> executeByType(CustomerType type) { public Result<CustomerError, List<Customer>> executeByType(CustomerType type) {
return switch (customerRepository.findByType(type)) { return switch (customerRepository.findByType(type)) {
case Failure<RepositoryError, List<Customer>> f -> case Failure(var err) ->
Result.failure(new CustomerError.RepositoryFailure(f.error().message())); Result.failure(new CustomerError.RepositoryFailure(err.message()));
case Success<RepositoryError, List<Customer>> s -> case Success(var customers) ->
Result.success(s.value()); Result.success(customers);
}; };
} }
public Result<CustomerError, List<Customer>> executeByStatus(CustomerStatus status) { public Result<CustomerError, List<Customer>> executeByStatus(CustomerStatus status) {
return switch (customerRepository.findByStatus(status)) { return switch (customerRepository.findByStatus(status)) {
case Failure<RepositoryError, List<Customer>> f -> case Failure(var err) ->
Result.failure(new CustomerError.RepositoryFailure(f.error().message())); Result.failure(new CustomerError.RepositoryFailure(err.message()));
case Success<RepositoryError, List<Customer>> s -> case Success(var customers) ->
Result.success(s.value()); Result.success(customers);
}; };
} }
} }

View file

@ -1,7 +1,6 @@
package de.effigenix.application.masterdata; package de.effigenix.application.masterdata;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -20,10 +19,10 @@ public class ListProductCategories {
public Result<ProductCategoryError, List<ProductCategory>> execute() { public Result<ProductCategoryError, List<ProductCategory>> execute() {
return switch (categoryRepository.findAll()) { return switch (categoryRepository.findAll()) {
case Failure<RepositoryError, List<ProductCategory>> f -> case Failure(var err) ->
Result.failure(new ProductCategoryError.RepositoryFailure(f.error().message())); Result.failure(new ProductCategoryError.RepositoryFailure(err.message()));
case Success<RepositoryError, List<ProductCategory>> s -> case Success(var categories) ->
Result.success(s.value()); Result.success(categories);
}; };
} }
} }

View file

@ -1,7 +1,6 @@
package de.effigenix.application.masterdata; package de.effigenix.application.masterdata;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -20,19 +19,19 @@ public class ListSuppliers {
public Result<SupplierError, List<Supplier>> execute() { public Result<SupplierError, List<Supplier>> execute() {
return switch (supplierRepository.findAll()) { return switch (supplierRepository.findAll()) {
case Failure<RepositoryError, List<Supplier>> f -> case Failure(var err) ->
Result.failure(new SupplierError.RepositoryFailure(f.error().message())); Result.failure(new SupplierError.RepositoryFailure(err.message()));
case Success<RepositoryError, List<Supplier>> s -> case Success(var suppliers) ->
Result.success(s.value()); Result.success(suppliers);
}; };
} }
public Result<SupplierError, List<Supplier>> executeByStatus(SupplierStatus status) { public Result<SupplierError, List<Supplier>> executeByStatus(SupplierStatus status) {
return switch (supplierRepository.findByStatus(status)) { return switch (supplierRepository.findByStatus(status)) {
case Failure<RepositoryError, List<Supplier>> f -> case Failure(var err) ->
Result.failure(new SupplierError.RepositoryFailure(f.error().message())); Result.failure(new SupplierError.RepositoryFailure(err.message()));
case Success<RepositoryError, List<Supplier>> s -> case Success(var suppliers) ->
Result.success(s.value()); Result.success(suppliers);
}; };
} }
} }

View file

@ -2,13 +2,10 @@ package de.effigenix.application.masterdata;
import de.effigenix.application.masterdata.command.RateSupplierCommand; import de.effigenix.application.masterdata.command.RateSupplierCommand;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -23,30 +20,31 @@ public class RateSupplier {
public Result<SupplierError, Supplier> execute(RateSupplierCommand cmd, ActorId performedBy) { public Result<SupplierError, Supplier> execute(RateSupplierCommand cmd, ActorId performedBy) {
var supplierId = SupplierId.of(cmd.supplierId()); var supplierId = SupplierId.of(cmd.supplierId());
Supplier supplier;
switch (supplierRepository.findById(supplierId)) { switch (supplierRepository.findById(supplierId)) {
case Failure<RepositoryError, Optional<Supplier>> f -> case Failure(var err) ->
{ return Result.failure(new SupplierError.RepositoryFailure(f.error().message())); } { return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Supplier>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new SupplierError.SupplierNotFound(supplierId)); return Result.failure(new SupplierError.SupplierNotFound(supplierId));
} }
Supplier supplier = s.value().get(); supplier = opt.get();
try {
var rating = new SupplierRating(cmd.qualityScore(), cmd.deliveryScore(), cmd.priceScore());
supplier.rate(rating);
} catch (IllegalArgumentException e) {
return Result.failure(new SupplierError.InvalidRating(e.getMessage()));
}
switch (supplierRepository.save(supplier)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new SupplierError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(supplier);
} }
} }
SupplierRating rating;
switch (SupplierRating.create(cmd.qualityScore(), cmd.deliveryScore(), cmd.priceScore())) {
case Failure(var msg) -> { return Result.failure(new SupplierError.InvalidRating(msg)); }
case Success(var val) -> rating = val;
}
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);
} }
} }

View file

@ -2,12 +2,11 @@ package de.effigenix.application.masterdata;
import de.effigenix.application.masterdata.command.RemoveCertificateCommand; import de.effigenix.application.masterdata.command.RemoveCertificateCommand;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional; import java.util.Objects;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@ -23,31 +22,35 @@ public class RemoveCertificate {
public Result<SupplierError, Supplier> execute(RemoveCertificateCommand cmd, ActorId performedBy) { public Result<SupplierError, Supplier> execute(RemoveCertificateCommand cmd, ActorId performedBy) {
var supplierId = SupplierId.of(cmd.supplierId()); var supplierId = SupplierId.of(cmd.supplierId());
Supplier supplier;
switch (supplierRepository.findById(supplierId)) { switch (supplierRepository.findById(supplierId)) {
case Failure<RepositoryError, Optional<Supplier>> f -> case Failure(var err) ->
{ return Result.failure(new SupplierError.RepositoryFailure(f.error().message())); } { return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Supplier>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new SupplierError.SupplierNotFound(supplierId)); return Result.failure(new SupplierError.SupplierNotFound(supplierId));
} }
Supplier supplier = s.value().get(); supplier = opt.get();
// Find matching certificate by type, issuer, and validFrom
supplier.certificates().stream()
.filter(c -> c.certificateType().equals(cmd.certificateType())
&& java.util.Objects.equals(c.issuer(), cmd.issuer())
&& java.util.Objects.equals(c.validFrom(), cmd.validFrom()))
.findFirst()
.ifPresent(supplier::removeCertificate);
switch (supplierRepository.save(supplier)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new SupplierError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(supplier);
} }
} }
var certificate = supplier.certificates().stream()
.filter(c -> c.certificateType().equals(cmd.certificateType())
&& Objects.equals(c.issuer(), cmd.issuer())
&& Objects.equals(c.validFrom(), cmd.validFrom()))
.findFirst();
if (certificate.isEmpty()) {
return Result.failure(new SupplierError.CertificateNotFound(cmd.certificateType()));
}
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);
} }
} }

View file

@ -2,13 +2,10 @@ package de.effigenix.application.masterdata;
import de.effigenix.application.masterdata.command.RemoveDeliveryAddressCommand; import de.effigenix.application.masterdata.command.RemoveDeliveryAddressCommand;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -23,24 +20,25 @@ public class RemoveDeliveryAddress {
public Result<CustomerError, Customer> execute(RemoveDeliveryAddressCommand cmd, ActorId performedBy) { public Result<CustomerError, Customer> execute(RemoveDeliveryAddressCommand cmd, ActorId performedBy) {
var customerId = CustomerId.of(cmd.customerId()); var customerId = CustomerId.of(cmd.customerId());
Customer customer;
switch (customerRepository.findById(customerId)) { switch (customerRepository.findById(customerId)) {
case Failure<RepositoryError, Optional<Customer>> f -> case Failure(var err) ->
{ return Result.failure(new CustomerError.RepositoryFailure(f.error().message())); } { return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Customer>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new CustomerError.CustomerNotFound(customerId)); return Result.failure(new CustomerError.CustomerNotFound(customerId));
} }
Customer customer = s.value().get(); customer = opt.get();
customer.removeDeliveryAddress(cmd.label());
switch (customerRepository.save(customer)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new CustomerError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(customer);
} }
} }
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);
} }
} }

View file

@ -1,13 +1,10 @@
package de.effigenix.application.masterdata; package de.effigenix.application.masterdata;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -20,24 +17,25 @@ public class RemoveFrameContract {
} }
public Result<CustomerError, Customer> execute(CustomerId customerId, ActorId performedBy) { public Result<CustomerError, Customer> execute(CustomerId customerId, ActorId performedBy) {
Customer customer;
switch (customerRepository.findById(customerId)) { switch (customerRepository.findById(customerId)) {
case Failure<RepositoryError, Optional<Customer>> f -> case Failure(var err) ->
{ return Result.failure(new CustomerError.RepositoryFailure(f.error().message())); } { return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Customer>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new CustomerError.CustomerNotFound(customerId)); return Result.failure(new CustomerError.CustomerNotFound(customerId));
} }
Customer customer = s.value().get(); customer = opt.get();
customer.removeFrameContract();
switch (customerRepository.save(customer)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new CustomerError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(customer);
} }
} }
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);
} }
} }

View file

@ -2,13 +2,10 @@ package de.effigenix.application.masterdata;
import de.effigenix.application.masterdata.command.RemoveSalesUnitCommand; import de.effigenix.application.masterdata.command.RemoveSalesUnitCommand;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -23,28 +20,29 @@ public class RemoveSalesUnit {
public Result<ArticleError, Article> execute(RemoveSalesUnitCommand cmd, ActorId performedBy) { public Result<ArticleError, Article> execute(RemoveSalesUnitCommand cmd, ActorId performedBy) {
var articleId = ArticleId.of(cmd.articleId()); var articleId = ArticleId.of(cmd.articleId());
Article article;
switch (articleRepository.findById(articleId)) { switch (articleRepository.findById(articleId)) {
case Failure<RepositoryError, Optional<Article>> f -> case Failure(var err) ->
{ return Result.failure(new ArticleError.RepositoryFailure(f.error().message())); } { return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Article>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new ArticleError.ArticleNotFound(articleId)); return Result.failure(new ArticleError.ArticleNotFound(articleId));
} }
Article article = s.value().get(); article = opt.get();
var removeResult = article.removeSalesUnit(SalesUnitId.of(cmd.salesUnitId()));
if (removeResult.isFailure()) {
return Result.failure(removeResult.unsafeGetError());
}
switch (articleRepository.save(article)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new ArticleError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(article);
} }
} }
switch (article.removeSalesUnit(SalesUnitId.of(cmd.salesUnitId()))) {
case Failure(var err) -> { return Result.failure(err); }
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);
} }
} }

View file

@ -2,13 +2,10 @@ package de.effigenix.application.masterdata;
import de.effigenix.application.masterdata.command.RemoveSupplierCommand; import de.effigenix.application.masterdata.command.RemoveSupplierCommand;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -23,24 +20,25 @@ public class RemoveSupplier {
public Result<ArticleError, Article> execute(RemoveSupplierCommand cmd, ActorId performedBy) { public Result<ArticleError, Article> execute(RemoveSupplierCommand cmd, ActorId performedBy) {
var articleId = ArticleId.of(cmd.articleId()); var articleId = ArticleId.of(cmd.articleId());
Article article;
switch (articleRepository.findById(articleId)) { switch (articleRepository.findById(articleId)) {
case Failure<RepositoryError, Optional<Article>> f -> case Failure(var err) ->
{ return Result.failure(new ArticleError.RepositoryFailure(f.error().message())); } { return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Article>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new ArticleError.ArticleNotFound(articleId)); return Result.failure(new ArticleError.ArticleNotFound(articleId));
} }
Article article = s.value().get(); article = opt.get();
article.removeSupplierReference(SupplierId.of(cmd.supplierId()));
switch (articleRepository.save(article)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new ArticleError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(article);
} }
} }
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);
} }
} }

View file

@ -3,13 +3,11 @@ package de.effigenix.application.masterdata;
import de.effigenix.application.masterdata.command.SetFrameContractCommand; import de.effigenix.application.masterdata.command.SetFrameContractCommand;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.Money; import de.effigenix.shared.common.Money;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional; import java.util.ArrayList;
import java.util.stream.Collectors;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@ -25,41 +23,51 @@ public class SetFrameContract {
public Result<CustomerError, Customer> execute(SetFrameContractCommand cmd, ActorId performedBy) { public Result<CustomerError, Customer> execute(SetFrameContractCommand cmd, ActorId performedBy) {
var customerId = CustomerId.of(cmd.customerId()); var customerId = CustomerId.of(cmd.customerId());
Customer customer;
switch (customerRepository.findById(customerId)) { switch (customerRepository.findById(customerId)) {
case Failure<RepositoryError, Optional<Customer>> f -> case Failure(var err) ->
{ return Result.failure(new CustomerError.RepositoryFailure(f.error().message())); } { return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Customer>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new CustomerError.CustomerNotFound(customerId)); return Result.failure(new CustomerError.CustomerNotFound(customerId));
} }
Customer customer = s.value().get(); customer = opt.get();
var lineItems = cmd.lineItems().stream()
.map(li -> new ContractLineItem(
ArticleId.of(li.articleId()),
Money.euro(li.agreedPrice()),
li.agreedQuantity(),
li.unit()))
.collect(Collectors.toList());
try {
var contract = FrameContract.create(cmd.validFrom(), cmd.validUntil(), cmd.rhythm(), lineItems);
var setResult = customer.setFrameContract(contract);
if (setResult.isFailure()) {
return Result.failure(setResult.unsafeGetError());
}
} catch (IllegalArgumentException e) {
return Result.failure(new CustomerError.InvalidFrameContract(e.getMessage()));
}
switch (customerRepository.save(customer)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new CustomerError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(customer);
} }
} }
var lineItems = new ArrayList<ContractLineItem>();
for (var li : cmd.lineItems()) {
Money price;
switch (Money.tryEuro(li.agreedPrice())) {
case Failure(var msg) -> { return Result.failure(new CustomerError.ValidationFailure(msg)); }
case Success(var val) -> price = val;
}
ContractLineItem item;
switch (ContractLineItem.create(ArticleId.of(li.articleId()), price, li.agreedQuantity(), li.unit())) {
case Failure(var msg) -> { return Result.failure(new CustomerError.ValidationFailure(msg)); }
case Success(var val) -> item = val;
}
lineItems.add(item);
}
FrameContract contract;
switch (FrameContract.create(cmd.validFrom(), cmd.validUntil(), cmd.rhythm(), lineItems)) {
case Failure(var msg) -> { return Result.failure(new CustomerError.InvalidFrameContract(msg)); }
case Success(var val) -> contract = val;
}
switch (customer.setFrameContract(contract)) {
case Failure(var err) -> { return Result.failure(err); }
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);
} }
} }

View file

@ -2,13 +2,10 @@ package de.effigenix.application.masterdata;
import de.effigenix.application.masterdata.command.SetPreferencesCommand; import de.effigenix.application.masterdata.command.SetPreferencesCommand;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -23,24 +20,25 @@ public class SetPreferences {
public Result<CustomerError, Customer> execute(SetPreferencesCommand cmd, ActorId performedBy) { public Result<CustomerError, Customer> execute(SetPreferencesCommand cmd, ActorId performedBy) {
var customerId = CustomerId.of(cmd.customerId()); var customerId = CustomerId.of(cmd.customerId());
Customer customer;
switch (customerRepository.findById(customerId)) { switch (customerRepository.findById(customerId)) {
case Failure<RepositoryError, Optional<Customer>> f -> case Failure(var err) ->
{ return Result.failure(new CustomerError.RepositoryFailure(f.error().message())); } { return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Customer>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new CustomerError.CustomerNotFound(customerId)); return Result.failure(new CustomerError.CustomerNotFound(customerId));
} }
Customer customer = s.value().get(); customer = opt.get();
customer.setPreferences(cmd.preferences());
switch (customerRepository.save(customer)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new CustomerError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(customer);
} }
} }
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);
} }
} }

View file

@ -2,13 +2,10 @@ package de.effigenix.application.masterdata;
import de.effigenix.application.masterdata.command.UpdateArticleCommand; import de.effigenix.application.masterdata.command.UpdateArticleCommand;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -23,30 +20,36 @@ public class UpdateArticle {
public Result<ArticleError, Article> execute(UpdateArticleCommand cmd, ActorId performedBy) { public Result<ArticleError, Article> execute(UpdateArticleCommand cmd, ActorId performedBy) {
var articleId = ArticleId.of(cmd.articleId()); var articleId = ArticleId.of(cmd.articleId());
Article article;
switch (articleRepository.findById(articleId)) { switch (articleRepository.findById(articleId)) {
case Failure<RepositoryError, Optional<Article>> f -> case Failure(var err) ->
{ return Result.failure(new ArticleError.RepositoryFailure(f.error().message())); } { return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Article>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new ArticleError.ArticleNotFound(articleId)); return Result.failure(new ArticleError.ArticleNotFound(articleId));
} }
Article article = s.value().get(); article = opt.get();
if (cmd.name() != null) {
article.rename(new ArticleName(cmd.name()));
}
if (cmd.categoryId() != null) {
article.changeCategory(ProductCategoryId.of(cmd.categoryId()));
}
switch (articleRepository.save(article)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new ArticleError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(article);
} }
} }
if (cmd.name() != null) {
ArticleName name;
switch (ArticleName.of(cmd.name())) {
case Failure(var msg) -> { return Result.failure(new ArticleError.ValidationFailure(msg)); }
case Success(var val) -> name = val;
}
article.rename(name);
}
if (cmd.categoryId() != null) {
article.changeCategory(ProductCategoryId.of(cmd.categoryId()));
}
switch (articleRepository.save(article)) {
case Failure(var err) ->
{ return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
case Success(var ignored) -> { }
}
return Result.success(article);
} }
} }

View file

@ -6,8 +6,6 @@ import de.effigenix.shared.common.*;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -22,30 +20,54 @@ public class UpdateCustomer {
public Result<CustomerError, Customer> execute(UpdateCustomerCommand cmd, ActorId performedBy) { public Result<CustomerError, Customer> execute(UpdateCustomerCommand cmd, ActorId performedBy) {
var customerId = CustomerId.of(cmd.customerId()); var customerId = CustomerId.of(cmd.customerId());
Customer customer;
switch (customerRepository.findById(customerId)) { switch (customerRepository.findById(customerId)) {
case Failure<RepositoryError, Optional<Customer>> f -> case Failure(var err) ->
{ return Result.failure(new CustomerError.RepositoryFailure(f.error().message())); } { return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Customer>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new CustomerError.CustomerNotFound(customerId)); return Result.failure(new CustomerError.CustomerNotFound(customerId));
} }
Customer customer = s.value().get(); customer = opt.get();
if (cmd.name() != null) {
customer.updateName(new CustomerName(cmd.name()));
}
customer.updateBillingAddress(new Address(cmd.street(), cmd.houseNumber(), cmd.postalCode(), cmd.city(), cmd.country()));
customer.updateContactInfo(new ContactInfo(cmd.phone(), cmd.email(), cmd.contactPerson()));
customer.updatePaymentTerms(new PaymentTerms(cmd.paymentDueDays(), cmd.paymentDescription()));
switch (customerRepository.save(customer)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new CustomerError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(customer);
} }
} }
if (cmd.name() != null) {
CustomerName name;
switch (CustomerName.of(cmd.name())) {
case Failure(var msg) -> { return Result.failure(new CustomerError.ValidationFailure(msg)); }
case Success(var val) -> name = val;
}
customer.updateName(name);
}
Address address;
switch (Address.create(cmd.street(), cmd.houseNumber(), cmd.postalCode(), cmd.city(), cmd.country())) {
case Failure(var msg) -> { return Result.failure(new CustomerError.ValidationFailure(msg)); }
case Success(var val) -> address = val;
}
customer.updateBillingAddress(address);
ContactInfo contactInfo;
switch (ContactInfo.create(cmd.phone(), cmd.email(), cmd.contactPerson())) {
case Failure(var msg) -> { return Result.failure(new CustomerError.ValidationFailure(msg)); }
case Success(var val) -> contactInfo = val;
}
customer.updateContactInfo(contactInfo);
PaymentTerms paymentTerms;
switch (PaymentTerms.create(cmd.paymentDueDays(), cmd.paymentDescription())) {
case Failure(var msg) -> { return Result.failure(new CustomerError.ValidationFailure(msg)); }
case Success(var val) -> paymentTerms = val;
}
customer.updatePaymentTerms(paymentTerms);
switch (customerRepository.save(customer)) {
case Failure(var err) ->
{ return Result.failure(new CustomerError.RepositoryFailure(err.message())); }
case Success(var ignored) -> { }
}
return Result.success(customer);
} }
} }

View file

@ -2,13 +2,10 @@ package de.effigenix.application.masterdata;
import de.effigenix.application.masterdata.command.UpdateProductCategoryCommand; import de.effigenix.application.masterdata.command.UpdateProductCategoryCommand;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -23,30 +20,36 @@ public class UpdateProductCategory {
public Result<ProductCategoryError, ProductCategory> execute(UpdateProductCategoryCommand cmd, ActorId performedBy) { public Result<ProductCategoryError, ProductCategory> execute(UpdateProductCategoryCommand cmd, ActorId performedBy) {
var categoryId = ProductCategoryId.of(cmd.categoryId()); var categoryId = ProductCategoryId.of(cmd.categoryId());
ProductCategory category;
switch (categoryRepository.findById(categoryId)) { switch (categoryRepository.findById(categoryId)) {
case Failure<RepositoryError, Optional<ProductCategory>> f -> case Failure(var err) ->
{ return Result.failure(new ProductCategoryError.RepositoryFailure(f.error().message())); } { return Result.failure(new ProductCategoryError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<ProductCategory>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new ProductCategoryError.CategoryNotFound(categoryId)); return Result.failure(new ProductCategoryError.CategoryNotFound(categoryId));
} }
ProductCategory category = s.value().get(); category = opt.get();
if (cmd.name() != null) {
category.rename(new CategoryName(cmd.name()));
}
if (cmd.description() != null) {
category.updateDescription(cmd.description());
}
switch (categoryRepository.save(category)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new ProductCategoryError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(category);
} }
} }
if (cmd.name() != null) {
CategoryName name;
switch (CategoryName.of(cmd.name())) {
case Failure(var msg) -> { return Result.failure(new ProductCategoryError.ValidationFailure(msg)); }
case Success(var val) -> name = val;
}
category.rename(name);
}
if (cmd.description() != null) {
category.updateDescription(cmd.description());
}
switch (categoryRepository.save(category)) {
case Failure(var err) ->
{ return Result.failure(new ProductCategoryError.RepositoryFailure(err.message())); }
case Success(var ignored) -> { }
}
return Result.success(category);
} }
} }

View file

@ -3,13 +3,10 @@ package de.effigenix.application.masterdata;
import de.effigenix.application.masterdata.command.UpdateSalesUnitPriceCommand; import de.effigenix.application.masterdata.command.UpdateSalesUnitPriceCommand;
import de.effigenix.domain.masterdata.*; import de.effigenix.domain.masterdata.*;
import de.effigenix.shared.common.Money; import de.effigenix.shared.common.Money;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result; import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -24,29 +21,35 @@ public class UpdateSalesUnitPrice {
public Result<ArticleError, Article> execute(UpdateSalesUnitPriceCommand cmd, ActorId performedBy) { public Result<ArticleError, Article> execute(UpdateSalesUnitPriceCommand cmd, ActorId performedBy) {
var articleId = ArticleId.of(cmd.articleId()); var articleId = ArticleId.of(cmd.articleId());
Article article;
switch (articleRepository.findById(articleId)) { switch (articleRepository.findById(articleId)) {
case Failure<RepositoryError, Optional<Article>> f -> case Failure(var err) ->
{ return Result.failure(new ArticleError.RepositoryFailure(f.error().message())); } { return Result.failure(new ArticleError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Article>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new ArticleError.ArticleNotFound(articleId)); return Result.failure(new ArticleError.ArticleNotFound(articleId));
} }
Article article = s.value().get(); article = opt.get();
var updateResult = article.updateSalesUnitPrice(
SalesUnitId.of(cmd.salesUnitId()), Money.euro(cmd.price()));
if (updateResult.isFailure()) {
return Result.failure(updateResult.unsafeGetError());
}
switch (articleRepository.save(article)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new ArticleError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(article);
} }
} }
Money price;
switch (Money.tryEuro(cmd.price())) {
case Failure(var msg) -> { return Result.failure(new ArticleError.ValidationFailure(msg)); }
case Success(var val) -> price = val;
}
switch (article.updateSalesUnitPrice(SalesUnitId.of(cmd.salesUnitId()), price)) {
case Failure(var err) -> { return Result.failure(err); }
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);
} }
} }

View file

@ -6,8 +6,6 @@ import de.effigenix.shared.common.*;
import de.effigenix.shared.security.ActorId; import de.effigenix.shared.security.ActorId;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static de.effigenix.shared.common.Result.*; import static de.effigenix.shared.common.Result.*;
@Transactional @Transactional
@ -22,30 +20,54 @@ public class UpdateSupplier {
public Result<SupplierError, Supplier> execute(UpdateSupplierCommand cmd, ActorId performedBy) { public Result<SupplierError, Supplier> execute(UpdateSupplierCommand cmd, ActorId performedBy) {
var supplierId = SupplierId.of(cmd.supplierId()); var supplierId = SupplierId.of(cmd.supplierId());
Supplier supplier;
switch (supplierRepository.findById(supplierId)) { switch (supplierRepository.findById(supplierId)) {
case Failure<RepositoryError, Optional<Supplier>> f -> case Failure(var err) ->
{ return Result.failure(new SupplierError.RepositoryFailure(f.error().message())); } { return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
case Success<RepositoryError, Optional<Supplier>> s -> { case Success(var opt) -> {
if (s.value().isEmpty()) { if (opt.isEmpty()) {
return Result.failure(new SupplierError.SupplierNotFound(supplierId)); return Result.failure(new SupplierError.SupplierNotFound(supplierId));
} }
Supplier supplier = s.value().get(); supplier = opt.get();
if (cmd.name() != null) {
supplier.updateName(new SupplierName(cmd.name()));
}
supplier.updateAddress(new Address(cmd.street(), cmd.houseNumber(), cmd.postalCode(), cmd.city(), cmd.country()));
supplier.updateContactInfo(new ContactInfo(cmd.phone(), cmd.email(), cmd.contactPerson()));
supplier.updatePaymentTerms(new PaymentTerms(cmd.paymentDueDays(), cmd.paymentDescription()));
switch (supplierRepository.save(supplier)) {
case Failure<RepositoryError, Void> f2 ->
{ return Result.failure(new SupplierError.RepositoryFailure(f2.error().message())); }
case Success<RepositoryError, Void> ignored -> { }
}
return Result.success(supplier);
} }
} }
if (cmd.name() != null) {
SupplierName name;
switch (SupplierName.of(cmd.name())) {
case Failure(var msg) -> { return Result.failure(new SupplierError.ValidationFailure(msg)); }
case Success(var val) -> name = val;
}
supplier.updateName(name);
}
Address address;
switch (Address.create(cmd.street(), cmd.houseNumber(), cmd.postalCode(), cmd.city(), cmd.country())) {
case Failure(var msg) -> { return Result.failure(new SupplierError.ValidationFailure(msg)); }
case Success(var val) -> address = val;
}
supplier.updateAddress(address);
ContactInfo contactInfo;
switch (ContactInfo.create(cmd.phone(), cmd.email(), cmd.contactPerson())) {
case Failure(var msg) -> { return Result.failure(new SupplierError.ValidationFailure(msg)); }
case Success(var val) -> contactInfo = val;
}
supplier.updateContactInfo(contactInfo);
PaymentTerms paymentTerms;
switch (PaymentTerms.create(cmd.paymentDueDays(), cmd.paymentDescription())) {
case Failure(var msg) -> { return Result.failure(new SupplierError.ValidationFailure(msg)); }
case Success(var val) -> paymentTerms = val;
}
supplier.updatePaymentTerms(paymentTerms);
switch (supplierRepository.save(supplier)) {
case Failure(var err) ->
{ return Result.failure(new SupplierError.RepositoryFailure(err.message())); }
case Success(var ignored) -> { }
}
return Result.success(supplier);
} }
} }

View file

@ -55,7 +55,7 @@ public class Article {
ProductCategoryId categoryId, ProductCategoryId categoryId,
SalesUnit initialSalesUnit SalesUnit initialSalesUnit
) { ) {
if (name == null || articleNumber == null || categoryId == null || initialSalesUnit == null) { if (initialSalesUnit == null) {
return Result.failure(new ArticleError.MinimumSalesUnitRequired()); return Result.failure(new ArticleError.MinimumSalesUnitRequired());
} }
var now = LocalDateTime.now(); var now = LocalDateTime.now();

View file

@ -40,6 +40,10 @@ public sealed interface ArticleError {
@Override public String message() { return "Invalid price: " + reason; } @Override public String message() { return "Invalid price: " + reason; }
} }
record ValidationFailure(String message) implements ArticleError {
@Override public String code() { return "VALIDATION_ERROR"; }
}
record Unauthorized(String message) implements ArticleError { record Unauthorized(String message) implements ArticleError {
@Override public String code() { return "UNAUTHORIZED"; } @Override public String code() { return "UNAUTHORIZED"; }
} }

View file

@ -1,5 +1,7 @@
package de.effigenix.domain.masterdata; package de.effigenix.domain.masterdata;
import de.effigenix.shared.common.Result;
public record ArticleName(String value) { public record ArticleName(String value) {
public ArticleName { public ArticleName {
@ -10,4 +12,12 @@ public record ArticleName(String value) {
throw new IllegalArgumentException("ArticleName must not exceed 200 characters"); throw new IllegalArgumentException("ArticleName must not exceed 200 characters");
} }
} }
public static Result<String, ArticleName> of(String value) {
try {
return Result.success(new ArticleName(value));
} catch (IllegalArgumentException e) {
return Result.failure(e.getMessage());
}
}
} }

View file

@ -1,5 +1,7 @@
package de.effigenix.domain.masterdata; package de.effigenix.domain.masterdata;
import de.effigenix.shared.common.Result;
public record ArticleNumber(String value) { public record ArticleNumber(String value) {
public ArticleNumber { public ArticleNumber {
@ -10,4 +12,12 @@ public record ArticleNumber(String value) {
throw new IllegalArgumentException("ArticleNumber must not exceed 50 characters"); throw new IllegalArgumentException("ArticleNumber must not exceed 50 characters");
} }
} }
public static Result<String, ArticleNumber> of(String value) {
try {
return Result.success(new ArticleNumber(value));
} catch (IllegalArgumentException e) {
return Result.failure(e.getMessage());
}
}
} }

View file

@ -1,5 +1,7 @@
package de.effigenix.domain.masterdata; package de.effigenix.domain.masterdata;
import de.effigenix.shared.common.Result;
public record CategoryName(String value) { public record CategoryName(String value) {
public CategoryName { public CategoryName {
@ -10,4 +12,12 @@ public record CategoryName(String value) {
throw new IllegalArgumentException("CategoryName must not exceed 100 characters"); throw new IllegalArgumentException("CategoryName must not exceed 100 characters");
} }
} }
public static Result<String, CategoryName> of(String value) {
try {
return Result.success(new CategoryName(value));
} catch (IllegalArgumentException e) {
return Result.failure(e.getMessage());
}
}
} }

View file

@ -1,6 +1,7 @@
package de.effigenix.domain.masterdata; package de.effigenix.domain.masterdata;
import de.effigenix.shared.common.Money; import de.effigenix.shared.common.Money;
import de.effigenix.shared.common.Result;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -25,4 +26,13 @@ public record ContractLineItem(
throw new IllegalArgumentException("Agreed quantity must be positive when set"); throw new IllegalArgumentException("Agreed quantity must be positive when set");
} }
} }
public static Result<String, ContractLineItem> create(
ArticleId articleId, Money agreedPrice, BigDecimal agreedQuantity, Unit unit) {
try {
return Result.success(new ContractLineItem(articleId, agreedPrice, agreedQuantity, unit));
} catch (IllegalArgumentException e) {
return Result.failure(e.getMessage());
}
}
} }

View file

@ -60,21 +60,18 @@ public class Customer {
this.updatedAt = updatedAt; this.updatedAt = updatedAt;
} }
public static Result<CustomerError, Customer> create( public static Customer create(
CustomerName name, CustomerName name,
CustomerType type, CustomerType type,
Address billingAddress, Address billingAddress,
ContactInfo contactInfo, ContactInfo contactInfo,
PaymentTerms paymentTerms PaymentTerms paymentTerms
) { ) {
if (name == null || type == null || billingAddress == null) {
return Result.failure(new CustomerError.CustomerNotFound(CustomerId.of("N/A")));
}
var now = LocalDateTime.now(); var now = LocalDateTime.now();
return Result.success(new Customer( return new Customer(
CustomerId.generate(), name, type, billingAddress, contactInfo, paymentTerms, CustomerId.generate(), name, type, billingAddress, contactInfo, paymentTerms,
List.of(), null, Set.of(), CustomerStatus.ACTIVE, now, now List.of(), null, Set.of(), CustomerStatus.ACTIVE, now, now
)); );
} }
public static Customer reconstitute( public static Customer reconstitute(

View file

@ -30,6 +30,10 @@ public sealed interface CustomerError {
@Override public String message() { return "Duplicate line item for article '" + articleId.value() + "'"; } @Override public String message() { return "Duplicate line item for article '" + articleId.value() + "'"; }
} }
record ValidationFailure(String message) implements CustomerError {
@Override public String code() { return "VALIDATION_ERROR"; }
}
record Unauthorized(String message) implements CustomerError { record Unauthorized(String message) implements CustomerError {
@Override public String code() { return "UNAUTHORIZED"; } @Override public String code() { return "UNAUTHORIZED"; }
} }

View file

@ -1,5 +1,7 @@
package de.effigenix.domain.masterdata; package de.effigenix.domain.masterdata;
import de.effigenix.shared.common.Result;
public record CustomerName(String value) { public record CustomerName(String value) {
public CustomerName { public CustomerName {
@ -10,4 +12,12 @@ public record CustomerName(String value) {
throw new IllegalArgumentException("CustomerName must not exceed 200 characters"); throw new IllegalArgumentException("CustomerName must not exceed 200 characters");
} }
} }
public static Result<String, CustomerName> of(String value) {
try {
return Result.success(new CustomerName(value));
} catch (IllegalArgumentException e) {
return Result.failure(e.getMessage());
}
}
} }

View file

@ -1,6 +1,7 @@
package de.effigenix.domain.masterdata; package de.effigenix.domain.masterdata;
import de.effigenix.shared.common.Address; import de.effigenix.shared.common.Address;
import de.effigenix.shared.common.Result;
/** /**
* Value Object representing a labeled delivery address. * Value Object representing a labeled delivery address.
@ -17,4 +18,13 @@ public record DeliveryAddress(
throw new IllegalArgumentException("Address must not be null"); throw new IllegalArgumentException("Address must not be null");
} }
} }
public static Result<String, DeliveryAddress> create(
String label, Address address, String contactPerson, String deliveryNotes) {
try {
return Result.success(new DeliveryAddress(label, address, contactPerson, deliveryNotes));
} catch (IllegalArgumentException e) {
return Result.failure(e.getMessage());
}
}
} }

View file

@ -1,6 +1,7 @@
package de.effigenix.domain.masterdata; package de.effigenix.domain.masterdata;
import de.effigenix.shared.common.Money; import de.effigenix.shared.common.Money;
import de.effigenix.shared.common.Result;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
@ -39,26 +40,26 @@ public class FrameContract {
this.lineItems = new ArrayList<>(lineItems); this.lineItems = new ArrayList<>(lineItems);
} }
public static FrameContract create( public static Result<String, FrameContract> create(
LocalDate validFrom, LocalDate validFrom,
LocalDate validUntil, LocalDate validUntil,
DeliveryRhythm deliveryRhythm, DeliveryRhythm deliveryRhythm,
List<ContractLineItem> lineItems List<ContractLineItem> lineItems
) { ) {
if (validFrom != null && validUntil != null && validUntil.isBefore(validFrom)) { if (validFrom != null && validUntil != null && validUntil.isBefore(validFrom)) {
throw new IllegalArgumentException("validUntil must not be before validFrom"); return Result.failure("validUntil must not be before validFrom");
} }
if (lineItems == null || lineItems.isEmpty()) { if (lineItems == null || lineItems.isEmpty()) {
throw new IllegalArgumentException("FrameContract must have at least one line item"); return Result.failure("FrameContract must have at least one line item");
} }
long distinctArticles = lineItems.stream() long distinctArticles = lineItems.stream()
.map(ContractLineItem::articleId) .map(ContractLineItem::articleId)
.distinct() .distinct()
.count(); .count();
if (distinctArticles != lineItems.size()) { if (distinctArticles != lineItems.size()) {
throw new IllegalArgumentException("Duplicate ArticleIds in line items"); return Result.failure("Duplicate ArticleIds in line items");
} }
return new FrameContract(FrameContractId.generate(), validFrom, validUntil, deliveryRhythm, lineItems); return Result.success(new FrameContract(FrameContractId.generate(), validFrom, validUntil, deliveryRhythm, lineItems));
} }
public static FrameContract reconstitute( public static FrameContract reconstitute(

View file

@ -1,7 +1,5 @@
package de.effigenix.domain.masterdata; package de.effigenix.domain.masterdata;
import de.effigenix.shared.common.Result;
/** /**
* Mini-Aggregate for product categories. * Mini-Aggregate for product categories.
* DB-based entity, dynamically extendable by users. * DB-based entity, dynamically extendable by users.
@ -18,11 +16,8 @@ public class ProductCategory {
this.description = description; this.description = description;
} }
public static Result<ProductCategoryError, ProductCategory> create(CategoryName name, String description) { public static ProductCategory create(CategoryName name, String description) {
if (name == null) { return new ProductCategory(ProductCategoryId.generate(), name, description);
return Result.failure(new ProductCategoryError.InvalidCategoryName("Name must not be null"));
}
return Result.success(new ProductCategory(ProductCategoryId.generate(), name, description));
} }
public static ProductCategory reconstitute(ProductCategoryId id, CategoryName name, String description) { public static ProductCategory reconstitute(ProductCategoryId id, CategoryName name, String description) {

View file

@ -25,6 +25,10 @@ public sealed interface ProductCategoryError {
@Override public String message() { return "Invalid category name: " + reason; } @Override public String message() { return "Invalid category name: " + reason; }
} }
record ValidationFailure(String message) implements ProductCategoryError {
@Override public String code() { return "VALIDATION_ERROR"; }
}
record Unauthorized(String message) implements ProductCategoryError { record Unauthorized(String message) implements ProductCategoryError {
@Override public String code() { return "UNAUTHORIZED"; } @Override public String code() { return "UNAUTHORIZED"; }
} }

View file

@ -1,5 +1,7 @@
package de.effigenix.domain.masterdata; package de.effigenix.domain.masterdata;
import de.effigenix.shared.common.Result;
import java.time.LocalDate; import java.time.LocalDate;
/** /**
@ -22,6 +24,15 @@ public record QualityCertificate(
} }
} }
public static Result<String, QualityCertificate> create(
String certificateType, String issuer, LocalDate validFrom, LocalDate validUntil) {
try {
return Result.success(new QualityCertificate(certificateType, issuer, validFrom, validUntil));
} catch (IllegalArgumentException e) {
return Result.failure(e.getMessage());
}
}
public boolean isExpired() { public boolean isExpired() {
return validUntil != null && validUntil.isBefore(LocalDate.now()); return validUntil != null && validUntil.isBefore(LocalDate.now());
} }

View file

@ -3,7 +3,6 @@ package de.effigenix.domain.masterdata;
import de.effigenix.shared.common.Address; import de.effigenix.shared.common.Address;
import de.effigenix.shared.common.ContactInfo; import de.effigenix.shared.common.ContactInfo;
import de.effigenix.shared.common.PaymentTerms; import de.effigenix.shared.common.PaymentTerms;
import de.effigenix.shared.common.Result;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
@ -55,20 +54,17 @@ public class Supplier {
this.updatedAt = updatedAt; this.updatedAt = updatedAt;
} }
public static Result<SupplierError, Supplier> create( public static Supplier create(
SupplierName name, SupplierName name,
Address address, Address address,
ContactInfo contactInfo, ContactInfo contactInfo,
PaymentTerms paymentTerms PaymentTerms paymentTerms
) { ) {
if (name == null || address == null || paymentTerms == null) {
return Result.failure(new SupplierError.SupplierNotFound(SupplierId.of("N/A")));
}
var now = LocalDateTime.now(); var now = LocalDateTime.now();
return Result.success(new Supplier( return new Supplier(
SupplierId.generate(), name, address, contactInfo, paymentTerms, SupplierId.generate(), name, address, contactInfo, paymentTerms,
List.of(), null, SupplierStatus.ACTIVE, now, now List.of(), null, SupplierStatus.ACTIVE, now, now
)); );
} }
public static Supplier reconstitute( public static Supplier reconstitute(

View file

@ -20,6 +20,15 @@ public sealed interface SupplierError {
@Override public String message() { return "Invalid rating: " + reason; } @Override public String message() { return "Invalid rating: " + reason; }
} }
record ValidationFailure(String message) implements SupplierError {
@Override public String code() { return "VALIDATION_ERROR"; }
}
record CertificateNotFound(String certificateType) implements SupplierError {
@Override public String code() { return "CERTIFICATE_NOT_FOUND"; }
@Override public String message() { return "Certificate of type '" + certificateType + "' not found"; }
}
record Unauthorized(String message) implements SupplierError { record Unauthorized(String message) implements SupplierError {
@Override public String code() { return "UNAUTHORIZED"; } @Override public String code() { return "UNAUTHORIZED"; }
} }

View file

@ -1,5 +1,7 @@
package de.effigenix.domain.masterdata; package de.effigenix.domain.masterdata;
import de.effigenix.shared.common.Result;
public record SupplierName(String value) { public record SupplierName(String value) {
public SupplierName { public SupplierName {
@ -10,4 +12,12 @@ public record SupplierName(String value) {
throw new IllegalArgumentException("SupplierName must not exceed 200 characters"); throw new IllegalArgumentException("SupplierName must not exceed 200 characters");
} }
} }
public static Result<String, SupplierName> of(String value) {
try {
return Result.success(new SupplierName(value));
} catch (IllegalArgumentException e) {
return Result.failure(e.getMessage());
}
}
} }

View file

@ -1,5 +1,7 @@
package de.effigenix.domain.masterdata; package de.effigenix.domain.masterdata;
import de.effigenix.shared.common.Result;
/** /**
* Value Object representing a supplier rating with three scores (1-5). * Value Object representing a supplier rating with three scores (1-5).
*/ */
@ -11,6 +13,14 @@ public record SupplierRating(int qualityScore, int deliveryScore, int priceScore
validateScore("priceScore", priceScore); validateScore("priceScore", priceScore);
} }
public static Result<String, SupplierRating> create(int qualityScore, int deliveryScore, int priceScore) {
try {
return Result.success(new SupplierRating(qualityScore, deliveryScore, priceScore));
} catch (IllegalArgumentException e) {
return Result.failure(e.getMessage());
}
}
public double averageScore() { public double averageScore() {
return (qualityScore + deliveryScore + priceScore) / 3.0; return (qualityScore + deliveryScore + priceScore) / 3.0;
} }

View file

@ -30,4 +30,13 @@ public record Address(
} }
// houseNumber is optional (nullable) // houseNumber is optional (nullable)
} }
public static Result<String, Address> create(
String street, String houseNumber, String postalCode, String city, String country) {
try {
return Result.success(new Address(street, houseNumber, postalCode, city, country));
} catch (IllegalArgumentException e) {
return Result.failure(e.getMessage());
}
}
} }

View file

@ -17,6 +17,14 @@ public record ContactInfo(
} }
} }
public static Result<String, ContactInfo> create(String phone, String email, String contactPerson) {
try {
return Result.success(new ContactInfo(phone, email, contactPerson));
} catch (IllegalArgumentException e) {
return Result.failure(e.getMessage());
}
}
private static boolean isValidEmail(String email) { private static boolean isValidEmail(String email) {
return email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$"); return email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$");
} }

View file

@ -26,6 +26,14 @@ public record Money(BigDecimal amount, Currency currency) {
return new Money(amount.setScale(2, RoundingMode.HALF_UP), Currency.getInstance("EUR")); return new Money(amount.setScale(2, RoundingMode.HALF_UP), Currency.getInstance("EUR"));
} }
public static Result<String, Money> tryEuro(BigDecimal amount) {
try {
return Result.success(euro(amount));
} catch (IllegalArgumentException e) {
return Result.failure(e.getMessage());
}
}
public static Money zero() { public static Money zero() {
return new Money(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP), Currency.getInstance("EUR")); return new Money(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP), Currency.getInstance("EUR"));
} }

View file

@ -11,4 +11,12 @@ public record PaymentTerms(int paymentDueDays, String description) {
throw new IllegalArgumentException("Payment due days must not be negative"); throw new IllegalArgumentException("Payment due days must not be negative");
} }
} }
public static Result<String, PaymentTerms> create(int dueDays, String description) {
try {
return Result.success(new PaymentTerms(dueDays, description));
} catch (IllegalArgumentException e) {
return Result.failure(e.getMessage());
}
}
} }