package org.openlmis.core.domain; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import org.apache.commons.lang3.StringUtils; import org.openlmis.upload.Importable; import org.openlmis.upload.annotation.ImportField; /** * A StockAdjustmentReason object is a value object that is a reason for a stock adjustment. i.e. a credit or debit * to stock on hand, a transfer, etc. Most importantly, a stock adjustment reason is determined to be either * additive or not. When contained within a stock adjustment, this reason's additive quality would be used to * determine if the quantity of stock adjusted, when summed, contributes to that summation in an additive (+) or * subtractive (-) manner. * * When determining which reasons are available in different areas of the program, the properties {@link #isDefault} * and {@link #inCategory(Category)} are useful. If a reason is a default reason, it is intended to be used across * programs, see {@link StockAdjustmentReasonProgram}. When a reason is in a {@link Category}, the reason is * intended to be used programmatically in that section of the program. */ @EqualsAndHashCode(callSuper=false) public class StockAdjustmentReason extends BaseModel implements Importable { @Getter @ImportField(mandatory = true, name = "Reason Name") private String name; @Getter @ImportField(name = "Description") private String description; @Getter @Setter @ImportField(mandatory = true, name = "Additive", type = "boolean") private Boolean additive; @Setter @ImportField(mandatory = true, type = "int", name = "Display Order") private Integer displayOrder; @Setter @ImportField(name = "Is Default", type = "boolean") private Boolean isDefault; @ImportField(name = "Category", type = "String") private String category; @Deprecated public StockAdjustmentReason() { setCategoryHelper(Category.DEFAULT); // useful for upload configuration, would prefer validity pattern in future } /** * Create a new StockAdjustmentReason. * @param name the globally unique name * @param description a description, the {@link #name} if null. * @param additive if additive then stock adjustments with this reason result in additive summations. * @param displayOrder the order this appears in lists with other StockAdjustmentReason * @param isDefault if true then this reason is a default reason for all programs. * See {@link StockAdjustmentReasonProgram}. * @param category the {@link org.openlmis.core.domain.StockAdjustmentReason.Category} this reason is used within. * {@link org.openlmis.core.domain.StockAdjustmentReason.Category#DEFAULT} if null. * @throws IllegalArgumentException if name is null or blank. */ private StockAdjustmentReason(String name, String description, boolean additive, int displayOrder, boolean isDefault, Category category) { setName(name); setDescription(description); this.additive = additive; this.displayOrder = displayOrder; this.isDefault = isDefault; setCategoryHelper(category); } /** * Creates a new reason with the given name. See {@link #create(String, String)}. * @param name the name of the reason, will also be the description. * @return a new reason. * @throws IllegalArgumentException if name is blank. */ public static StockAdjustmentReason create(String name) { return create(name, name); } /** * Creates an additive, default reason in the {@link org.openlmis.core.domain.StockAdjustmentReason.Category#DEFAULT} * category with a "low" display order". * @param name the name. See {@link #setName(String)}. * @param description the description. See {@link #setDescription(String)}. * @return a new reason * @throws IllegalArgumentException if name is blank. */ public static StockAdjustmentReason create(String name, String description) { return new StockAdjustmentReason(name, description, true, 0, true, Category.DEFAULT); } /** * Sets the globally unique name for this reason * @param name the name * @throws IllegalArgumentException if name is blank */ public void setName(String name) { if (false == StringUtils.isBlank(name)) this.name = name.trim(); else throw new IllegalArgumentException("Name can't be blank"); } /** * Sets the description for this reason, or uses the name if blank. * @param description the description */ public void setDescription(String description) { this.description = StringUtils.isBlank(description) ? this.name : description.trim(); } /** * Sets the {@link Category} that this reason is used within. * @param category the category to use. * @throws NullPointerException if category is unrecognized */ private void setCategoryHelper(Category category) { this.category = (null == category ? Category.DEFAULT : category).toString(); } /** * Sets the {@link org.openlmis.core.domain.StockAdjustmentReason.Category} by parsing the given string. Valid * values are of the form {@link Category#values()}. * @param category the category to set. * @throws NullPointerException if category is unrecognized. */ public void setCategory(String category) { setCategoryHelper(Category.parse(category)); } /** * Determines if this reason is a part of the given {@link org.openlmis.core.domain.StockAdjustmentReason.Category} * @param category the category * @return true if apart of the given category, false otherwise. */ public boolean inCategory(Category category) { if(null == category) return false; return getCategory() == category; } protected final Category getCategory() { return Category.parse(category); } /** * A category concept to {@link StockAdjustmentReason} allow a group of reasons to be grouped programatically * for identifying a reason for specific functionalities of the application (regardless of other groupings). e.g. * some reasons may only be applicable to a feature that deals with national arrival of commodities whereas another * section may only be concerned with the daily transactions at a rural service delivery point. */ public enum Category { DEFAULT, NATIONAL_ARRIVAL; /** * Parses the given String to return a matching Category using {@link #values()}. Cleans the string first * of whitespace and case-sensitivity. * @param category the category string to parse * @return the Category that matches the string, null if no String parses to a Category. */ public static Category parse(String category) { String wCat = StringUtils.trimToEmpty(category).toUpperCase(); Category cat = null; try { cat = valueOf(wCat); } catch (IllegalArgumentException iae) {} return cat; } } }