/* * 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 . */ package catering.inventory; import static org.salespointframework.core.Currencies.EURO; import org.javamoney.moneta.Money; import org.salespointframework.catalog.Product; import org.salespointframework.inventory.UniqueInventoryItem; import org.salespointframework.quantity.Quantity; import catering.catalog.Consumable; import catering.catalog.Rentable; 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; 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 void setQuantity(Quantity quantity) { this.quantity = quantity; } public void setRetailPrice(Double retailPrice) { this.retailPrice = retailPrice; } /** * Creates an empty {@link InventoryMutateForm} for {@link Product}s of the given {@link Class}. * * @param 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 InventoryMutateForm forProductType(Class type) { // Java can’t 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)); modifyProductPrimitive(product); } protected abstract void modifyProductPrimitive(Product product); }