swt23w23/src/main/java/catering/inventory/InventoryMutateForm.java

176 lines
5.7 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (C) 2023 Simon Bruder
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package catering.inventory;
import static org.salespointframework.core.Currencies.EURO;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.javamoney.moneta.Money;
import org.salespointframework.catalog.Product;
import org.salespointframework.inventory.UniqueInventoryItem;
import org.salespointframework.quantity.Quantity;
import org.springframework.data.util.Streamable;
import catering.catalog.Consumable;
import catering.catalog.Rentable;
import catering.order.OrderType;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.PositiveOrZero; // NonNegative in enterprise java
/**
* Abstract class for handling inventory mutations.
*
* It has children for every product type.
*
* The current implementation requires {@link #forProductType(Class)} and {@link #of(Product, UniqueInventoryItem)}
* to also be updated when a new child class is added.
*/
abstract class InventoryMutateForm {
private @NotEmpty String name;
private @NotNull Quantity quantity;
private @NotNull @PositiveOrZero Double retailPrice;
private @NotNull Set<OrderType> orderTypes;
public InventoryMutateForm() {
}
public String getName() {
return name;
}
public Quantity getQuantity() {
return quantity;
}
public Double getRetailPrice() {
return retailPrice;
}
public void setName(String name) {
this.name = name;
}
public Set<OrderType> getOrderTypes() {
return orderTypes;
}
public void setQuantity(Quantity quantity) {
this.quantity = quantity;
}
public void setRetailPrice(Double retailPrice) {
this.retailPrice = retailPrice;
}
public void setOrderTypes(Set<OrderType> orderTypes) {
this.orderTypes = orderTypes;
}
/**
* Creates an empty {@link InventoryMutateForm} for {@link Product}s of the given {@link Class}.
*
* @param <T> a child class of {@link Product}
* @param type the concrete {@link Product} the form should mutate
* @return an object of an {@link InventoryMutateForm} subclass
* @throws IllegalArgumentException if the {@literal type} is not supported
*/
public static <T extends Product> InventoryMutateForm forProductType(Class<T> type) {
// Java cant switch over Class in JDK17 (without preview features)
// See https://openjdk.org/jeps/406 for improvement in higher versions.
if (type.equals(Consumable.class)) {
return new ConsumableMutateForm();
} else if (type.equals(Rentable.class)) {
return new RentableMutateForm();
} else {
throw new IllegalArgumentException(
"InventoryMutateForm::forProductType not supported for given types");
}
}
/**
* Creates a populated {@link InventoryMutateForm} from a given {@link Product} and {@link UniqueInventoryItem}.
*
* @param product an instance of a {@link Product} subclass
* @param item an {@link UniqueInventoryItem} holding a {@link Quantity}
* @return an object of an {@link InventoryMutateForm} subclass
*/
public static InventoryMutateForm of(Product product, UniqueInventoryItem item) {
if (product instanceof Consumable consumable) {
return ConsumableMutateForm.of(consumable, item);
} else if (product instanceof Rentable rentable) {
return RentableMutateForm.of(rentable, item);
} else {
throw new IllegalArgumentException("InventoryMutateForm::ofProductAndItem not supported for given types");
}
}
/**
* Creates a new {@link Product} from a populated {@link InventoryMutateForm}.
*
* @return an instance of a {@link Product} subclass
*/
public abstract Product toProduct();
/**
* Modifies a given {@link Product} to match the values from the {@link InventoryMutateForm}.
*
* As the {@link Quantity} is stored inside of the {@link UniqueInventoryItem},
* it has to be updated manually.
*
* @param product the {@link Product} to be updated
*/
public void modifyProduct(Product product) {
product.setName(getName());
product.setPrice(Money.of(getRetailPrice(), EURO));
// first, remove all categories that are *not* selected
Stream.of(OrderType.class.getEnumConstants())
.filter(Predicate.not(getOrderTypes()::contains))
.map(OrderType::toString)
.forEach(product::removeCategory);
// then, add all categories that *are* selected
getOrderTypes().stream()
.map(OrderType::toString)
.forEach(product::addCategory);
modifyProductPrimitive(product);
}
protected abstract void modifyProductPrimitive(Product product);
/**
* Returns a {@link Set} of {@link OrderType}s from the categories of a
* {@link Product}
*
* @param categories a {@link Streamable} of category {@link String}s
* @return a {@link Set} of all {@link OrderType}s attached to the product
*/
public static Set<OrderType> orderTypesFromCategories(Streamable<String> categories) {
return categories.stream()
.filter(Stream.of(OrderType.class.getEnumConstants())
.map(OrderType::toString)
.collect(Collectors.toSet())::contains)
.map(OrderType::valueOf).collect(Collectors.toSet());
}
}