/*
* This program is part of the OpenLMIS logistics management information system platform software.
* Copyright © 2013 VillageReach
*
* 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 http://www.gnu.org/licenses. For additional information contact info@OpenLMIS.org.
*/
package org.openlmis.rnr.domain;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.openlmis.core.message.OpenLmisMessage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.util.Arrays.asList;
/**
* ProgramRnrTemplate corresponds to Rnr Template for a program and is a container for columns in that Template.
*/
@NoArgsConstructor
public class ProgramRnrTemplate extends Template {
public static final String STOCK_IN_HAND = "stockInHand";
public static final String REMARKS = "remarks";
public static final String QUANTITY_DISPENSED = "quantityDispensed";
public static final String BEGINNING_BALANCE = "beginningBalance";
public static final String QUANTITY_RECEIVED = "quantityReceived";
public static final String QUANTITY_APPROVED = "quantityApproved";
public static final String LOSSES_AND_ADJUSTMENTS = "lossesAndAdjustments";
public static final String STOCK_OUT_DAYS = "stockOutDays";
public static final String NORMALIZED_CONSUMPTION = "normalizedConsumption";
public static final String QUANTITY_REQUESTED = "quantityRequested";
public static final String REASON_FOR_REQUESTED_QUANTITY = "reasonForRequestedQuantity";
public static final String NEW_PATIENT_COUNT = "newPatientCount";
public static final String COST = "cost";
public static final String PRICE = "price";
public static final String TOTAL = "total";
public static final String PRODUCT = "product";
public static final String DISPENSING_UNIT = "dispensingUnit";
public static final String PRODUCT_CODE = "productCode";
public static final String PACKS_TO_SHIP = "packsToShip";
public static final String SKIPPED = "skipped";
public static final String CALCULATED_ORDER_QUANTITY = "calculatedOrderQuantity";
public static final String USER_NEEDS_TO_ENTER_DEPENDENT_FIELD = "user.needs.to.enter.dependent.field";
public static final String INTERDEPENDENT_FIELDS_CAN_NOT_BE_CALCULATED = "error.interdependent.fields.can.not.be.calculated";
public static final String COLUMN_SHOULD_BE_VISIBLE_IF_USER_INPUT = "error.column.should.be.visible.if.user.input";
public static final String USER_NEED_TO_ENTER_REQUESTED_QUANTITY_REASON = "error.user.needs.to.enter.requested.quantity.reason";
final List<String> nonPrintableFullSupplyColumnNames = asList(REMARKS, REASON_FOR_REQUESTED_QUANTITY);
final List<String> printableNonFullSupplyColumnNames = asList(PRODUCT, PRODUCT_CODE, DISPENSING_UNIT, QUANTITY_REQUESTED, PACKS_TO_SHIP, PRICE, COST, QUANTITY_APPROVED);
@Getter
private Map<String, RnrColumn> rnrColumnsMap = new HashMap<>();
private Map<String, OpenLmisMessage> errorMap = new HashMap<>();
@Getter
@Setter
private Long modifiedBy;
@Getter
@Setter
private Boolean applyDefaultZero = false;
public ProgramRnrTemplate(Long programId, List<? extends Column> rnrColumns) {
this.programId = programId;
this.columns = rnrColumns;
for (Column rnrColumn : rnrColumns) {
rnrColumnsMap.put(rnrColumn.getName(), (RnrColumn) rnrColumn);
}
}
public ProgramRnrTemplate(List<? extends Column> programRnrColumns) {
this.columns = programRnrColumns;
for (Column rnrColumn : columns) {
rnrColumnsMap.put(rnrColumn.getName(), (RnrColumn) rnrColumn);
}
}
public boolean columnsVisible(String... rnrColumnNames) {
boolean visible = true;
for (String rnrColumnName : rnrColumnNames) {
visible = (rnrColumnsMap.get(rnrColumnName) != null) && visible && rnrColumnsMap.get(rnrColumnName).getVisible();
}
return visible;
}
public boolean columnsCalculated(String... rnrColumnNames) {
boolean calculated = false;
for (String rnrColumnName : rnrColumnNames) {
calculated = calculated || (rnrColumnsMap.get(rnrColumnName).getSource() == RnRColumnSource.CALCULATED);
}
return calculated;
}
public boolean columnsUserInput(String... rnrColumnNames) {
boolean userInput = false;
for (String rnrColumnName : rnrColumnNames) {
userInput = userInput || (rnrColumnsMap.get(rnrColumnName).getSource() == RnRColumnSource.USER_INPUT);
}
return userInput;
}
public String getRnrColumnLabelFor(String columnName) {
return rnrColumnsMap.get(columnName).getLabel();
}
private boolean areSelectedTogether(String column1, String column2) {
return (columnsVisible(column1) && columnsVisible(column2)) || (!columnsVisible(column1) && !columnsVisible(column2));
}
public Map<String, OpenLmisMessage> validateToSave() {
validateColumnsTobeCheckedIfUserInput();
validateCalculatedColumnHasDependentChecked(STOCK_IN_HAND, QUANTITY_DISPENSED);
validateCalculatedColumnHasDependentChecked(QUANTITY_DISPENSED, STOCK_IN_HAND);
validateQuantityDispensedAndStockInHandCannotBeCalculatedAtSameTime();
validateQuantityRequested();
return errorMap;
}
private void validateColumnsTobeCheckedIfUserInput() {
validateColumnToBeCheckedIfUserInput(STOCK_IN_HAND);
validateColumnToBeCheckedIfUserInput(QUANTITY_DISPENSED);
}
private void validateColumnToBeCheckedIfUserInput(String column) {
if (columnIsUserInput(column) && !columnsVisible(column)) {
errorMap.put(column, new OpenLmisMessage(COLUMN_SHOULD_BE_VISIBLE_IF_USER_INPUT, getRnrColumnLabelFor(column)));
}
}
private boolean columnIsUserInput(String column) {
return !columnsCalculated(column);
}
private void validateQuantityDispensedAndStockInHandCannotBeCalculatedAtSameTime() {
if (columnsCalculated(QUANTITY_DISPENSED) && columnsCalculated(STOCK_IN_HAND)) {
OpenLmisMessage errorMessage = new OpenLmisMessage(INTERDEPENDENT_FIELDS_CAN_NOT_BE_CALCULATED,
getRnrColumnLabelFor(QUANTITY_DISPENSED),
getRnrColumnLabelFor(STOCK_IN_HAND));
errorMap.put(QUANTITY_DISPENSED, errorMessage);
errorMap.put(STOCK_IN_HAND, errorMessage);
}
}
private void validateCalculatedColumnHasDependentChecked(String columnToEvaluate, String dependent) {
if (columnsCalculated(columnToEvaluate) && !columnsVisible(dependent)) {
errorMap.put(columnToEvaluate, new OpenLmisMessage(USER_NEEDS_TO_ENTER_DEPENDENT_FIELD, getRnrColumnLabelFor(dependent), getRnrColumnLabelFor(columnToEvaluate)));
}
}
private void validateQuantityRequested() {
if (!areSelectedTogether(QUANTITY_REQUESTED, REASON_FOR_REQUESTED_QUANTITY)) {
if (columnsVisible(QUANTITY_REQUESTED)) {
errorMap.put(QUANTITY_REQUESTED, new OpenLmisMessage(USER_NEED_TO_ENTER_REQUESTED_QUANTITY_REASON,
getRnrColumnLabelFor(QUANTITY_REQUESTED),
getRnrColumnLabelFor(REASON_FOR_REQUESTED_QUANTITY)));
} else {
errorMap.put(REASON_FOR_REQUESTED_QUANTITY, new OpenLmisMessage(USER_NEED_TO_ENTER_REQUESTED_QUANTITY_REASON,
getRnrColumnLabelFor(REASON_FOR_REQUESTED_QUANTITY),
getRnrColumnLabelFor(QUANTITY_REQUESTED)));
}
}
}
public List<? extends Column> getPrintableColumns(Boolean fullSupply) {
List<RnrColumn> printableRnrColumns = new ArrayList<>();
for (Column rnrColumn : columns) {
if (rnrColumn.getVisible()) {
if (fullSupply && !nonPrintableFullSupplyColumnNames.contains(rnrColumn.getName())) {
printableRnrColumns.add((RnrColumn) rnrColumn);
} else if (!fullSupply && printableNonFullSupplyColumnNames.contains(rnrColumn.getName())) {
printableRnrColumns.add((RnrColumn) rnrColumn);
}
}
}
return printableRnrColumns;
}
}