/*
* The Kuali Financial System, a comprehensive financial management system for higher education.
*
* Copyright 2005-2014 The Kuali Foundation
*
* 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/>.
*/
package org.kuali.kfs.module.tem.businessobject;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.LinkedHashMap;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.kuali.kfs.module.tem.TemConstants;
import org.kuali.kfs.module.tem.TemConstants.TravelParameters;
import org.kuali.kfs.module.tem.TemParameterConstants;
import org.kuali.kfs.module.tem.document.TravelDocument;
import org.kuali.kfs.module.tem.document.service.MileageRateService;
import org.kuali.kfs.module.tem.document.web.struts.TravelFormBase;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.kfs.sys.util.KfsDateUtils;
import org.kuali.rice.core.api.util.type.KualiDecimal;
import org.kuali.rice.coreservice.framework.parameter.ParameterService;
import org.kuali.rice.kns.util.KNSGlobalVariables;
import org.kuali.rice.krad.bo.PersistableBusinessObjectBase;
import org.kuali.rice.krad.util.ObjectUtils;
@Entity
@Table(name = "TEM_PER_DIEM_EXP_T")
public class PerDiemExpense extends PersistableBusinessObjectBase {
@Id
@GeneratedValue(generator = "TEM_PER_DIEM_EXP_ID_SEQ")
@SequenceGenerator(name = "TEM_PER_DIEM_EXP_ID_SEQ", sequenceName = "TEM_PER_DIEM_EXP_ID_SEQ", allocationSize = 5)
@Column(name = "ID", nullable = false)
private Integer id;
private String documentNumber;
private String countryState;
private String county;
private String primaryDestination;
//boolean flag if it gets disabled due to duplicate
private Boolean breakfast = Boolean.TRUE;
private Boolean lunch = Boolean.TRUE;
private Boolean dinner = Boolean.TRUE;
private Boolean personal = Boolean.FALSE;
private Boolean incidentalsWithMealsOnly;
private KualiDecimal breakfastValue = KualiDecimal.ZERO;
private KualiDecimal lunchValue = KualiDecimal.ZERO;
private KualiDecimal dinnerValue = KualiDecimal.ZERO;
private KualiDecimal incidentalsValue = KualiDecimal.ZERO;
private Integer primaryDestinationId;
private PrimaryDestination primaryDest;
private PerDiem perDiem;
private Integer miles = new Integer(0);
private Timestamp mileageDate;
private ExpenseType mileageRateExpenseType;
private String mileageRateExpenseTypeCode;
private String accommodationTypeCode;
private String accommodationName;
private String accommodationPhoneNum;
private String accommodationAddress;
private AccommodationType accommodationType;
private KualiDecimal lodging = KualiDecimal.ZERO;
private boolean prorated = false;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "FDOC_NBR", length = 14, nullable = false)
public String getDocumentNumber() {
return documentNumber;
}
public void setDocumentNumber(String documentNumber) {
this.documentNumber = documentNumber;
}
@Column(name = "COUNTRY", length = 100, nullable = false)
public String getCountryState() {
return countryState;
}
public void setCountryState(String countryState) {
this.countryState = countryState;
}
@Column(name = "COUNTY_CD", length = 100, nullable = false)
public String getCounty() {
return county;
}
public void setCounty(String county) {
this.county = county;
}
@Column(name = "PRI_DEST", length = 100, nullable = false)
public String getPrimaryDestination() {
return primaryDestination;
}
public void setPrimaryDestination(String primaryDestination) {
this.primaryDestination = primaryDestination;
}
@Column(name = "BREAKFAST_IND", nullable = false, length = 1)
public Boolean getBreakfast() {
return breakfast;
}
public void setBreakfast(Boolean breakfast) {
this.breakfast = breakfast;
}
@Column(name = "LUNCH_IND", nullable = false, length = 1)
public Boolean getLunch() {
return lunch;
}
public void setLunch(Boolean lunch) {
this.lunch = lunch;
}
@Column(name = "DINNER_IND", nullable = false, length = 1)
public Boolean getDinner() {
return dinner;
}
public void setDinner(Boolean dinner) {
this.dinner = dinner;
}
/**
* Gets the perDiemId attribute.
*
* @return Returns the perDiemId.
*/
public Integer getPrimaryDestinationId() {
return primaryDestinationId;
}
/**
* Sets the perDiemId attribute value.
*
* @param perDiemId The perDiemId to set.
*/
public void setPrimaryDestinationId(Integer primaryDestinationId) {
this.primaryDestinationId = primaryDestinationId;
}
public PrimaryDestination getPrimaryDest() {
return primaryDest;
}
public void setPrimaryDest(PrimaryDestination primaryDest) {
this.primaryDest = primaryDest;
}
/**
* Gets the perDiem attribute.
*
* @return Returns the perDiem.
*/
/*public PerDiem getPerDiem() {
return perDiem;
}*/
/**
* Sets the perDiem attribute value.
*
* @param perDiem The perDiem to set.
*/
/*public void setPerDiem(PerDiem perDiem) {
this.perDiem = perDiem;
setupCustomPerDiem();
}*/
/**
* This method gets the accommodation type code associated with this day
*
* @return accoomodation type code
*/
@Column(name = "ACCOM_TYP_CD", length = 4)
public String getAccommodationTypeCode() {
return accommodationTypeCode;
}
/**
* This method sets the accommodation type code for this day
*
* @param accommodationTypeCode
*/
public void setAccommodationTypeCode(String accommodationTypeCode) {
this.accommodationTypeCode = accommodationTypeCode;
}
/**
* This method returns the current accommodation Type for this TripDetailEstimate
*
* @return accommodation Type
*/
@ManyToOne
@JoinColumn(name = "ACCOM_TYP_CD")
public AccommodationType getAccommodationType() {
return accommodationType;
}
/**
* This method is only used for when the object is initially populated from OJB
*
* @param accommodationType
*/
public void setAccommodationType(AccommodationType accommodationType) {
this.accommodationType = accommodationType;
}
/**
* This method returns the name of the accommodation for this day
*
* @return accommodation name
*/
@Column(name = "ACCOM_NM")
public String getAccommodationName() {
return accommodationName;
}
/**
* This method sets the accommodation name for this day
*
* @param accommodationName
*/
public void setAccommodationName(String accommodationName) {
this.accommodationName = accommodationName;
}
/**
* This method returns the accommodation's phone
*
* @return the phone number for the accommodation
*/
@Column(name = "ACCOM_PH")
public String getAccommodationPhoneNum() {
return accommodationPhoneNum;
}
/**
* This method sets the accommodation phone number
*
* @param accommodationPhoneNum
*/
public void setAccommodationPhoneNum(String accommodationPhoneNum) {
this.accommodationPhoneNum = accommodationPhoneNum;
}
/**
* This method returns the accommodation's address
*
* @return accommodation's address
*/
@Column(name = "ACCOM_ADDRESS")
public String getAccommodationAddress() {
return accommodationAddress;
}
/**
* This method sets the accommodation's address
*
* @param accommodationAddress
*/
public void setAccommodationAddress(String accommodationAddress) {
this.accommodationAddress = accommodationAddress;
}
/**
* This method gets the lodging cost for this day. This method does not take into account personal expenses. Use getLodgingTotal() for that.
*
* @return lodging cost
*/
@Column(name = "LODGING", precision = 19, scale = 2)
public KualiDecimal getLodging() {
if (ObjectUtils.isNotNull(lodging) && this.lodging.isGreaterThan(KualiDecimal.ZERO)) {
return lodging;
}
return KualiDecimal.ZERO;
}
/**
* @return the amount of lodging, without logic that may force it back to zero
*/
public KualiDecimal getUnfilteredLodging() {
return lodging;
}
/**
* Matching setter for getUnfilteredLoding, functionally equivalent to setLodging
* @param lodging
*/
public void setUnfilteredLodging(KualiDecimal lodging) {
this.lodging = lodging;
}
/**
* This method sets the lodging cost for this day
*
* @param lodging
*/
public void setLodging(KualiDecimal lodging) {
this.lodging = lodging;
}
@Column(name = "MILES", nullable = false)
public Integer getMiles() {
if (ObjectUtils.isNotNull(miles) && miles > 0) {
return miles;
}
return 0;
}
public void setMiles(Integer miles) {
this.miles = miles;
}
public Integer getUnfilteredMiles() {
return miles;
}
public void setUnfilteredMiles(Integer miles) {
this.miles = miles;
}
/**
* Gets the breakfastValue attribute.
*
* @return Returns the breakfastValue.
*/
public KualiDecimal getBreakfastValue() {
if (ObjectUtils.isNotNull(breakfastValue) && this.breakfastValue.isGreaterThan(KualiDecimal.ZERO)) {
return breakfastValue;
}
return KualiDecimal.ZERO;
}
/**
* Sets the breakfastValue attribute value.
*
* @param breakfastValue The breakfastValue to set.
*/
public void setBreakfastValue(KualiDecimal breakfastValue) {
this.breakfastValue = breakfastValue;
}
public KualiDecimal getUnfilteredBreakfastValue() {
return this.breakfastValue;
}
public void setUnfilteredBreakfastValue(KualiDecimal breakfastValue) {
this.breakfastValue = breakfastValue;
}
/**
* Gets the lunchValue attribute.
*
* @return Returns the lunchValue.
*/
public KualiDecimal getLunchValue() {
if (ObjectUtils.isNotNull(lunchValue) && this.lunchValue.isGreaterThan(KualiDecimal.ZERO)) {
return lunchValue;
}
return KualiDecimal.ZERO;
}
/**
* Sets the lunchValue attribute value.
*
* @param lunchValue The lunchValue to set.
*/
public void setLunchValue(KualiDecimal lunchValue) {
this.lunchValue = lunchValue;
}
public KualiDecimal getUnfilteredLunchValue() {
return this.lunchValue;
}
public void setUnfilteredLunchValue(KualiDecimal lunchValue) {
this.lunchValue = lunchValue;
}
/**
* Gets the dinnerValue attribute.
*
* @return Returns the dinnerValue.
*/
public KualiDecimal getDinnerValue() {
if (ObjectUtils.isNotNull(dinnerValue) && this.dinnerValue.isGreaterThan(KualiDecimal.ZERO)) {
return dinnerValue;
}
return KualiDecimal.ZERO;
}
/**
* Sets the dinnerValue attribute value.
*
* @param dinnerValue The dinnerValue to set.
*/
public void setDinnerValue(KualiDecimal dinnerValue) {
this.dinnerValue = dinnerValue;
}
public KualiDecimal getUnfilteredDinnerValue() {
return this.dinnerValue;
}
public void setUnfilteredDinnerValue(KualiDecimal dinnerValue) {
this.dinnerValue = dinnerValue;
}
@ManyToOne
@JoinColumn(name = "MILEAGE_RT_EXP_TYP_CD")
public ExpenseType getMileageRateExpenseType() {
return mileageRateExpenseType;
}
public void setMileageRateExpenseType(ExpenseType mileageRateExpenseType) {
this.mileageRateExpenseType = mileageRateExpenseType;
}
@Column(name = "MILEAGE_RT_EXP_TYP_CD")
public String getMileageRateExpenseTypeCode() {
return mileageRateExpenseTypeCode;
}
public void setMileageRateExpenseTypeCode(String mileageRateExpenseTypeCode) {
this.mileageRateExpenseTypeCode = mileageRateExpenseTypeCode;
}
public MileageRate getMileageRate(java.sql.Date effectiveDate) {
return SpringContext.getBean(MileageRateService.class).findMileageRateByExpenseTypeCodeAndDate(getMileageRateExpenseTypeCode(), effectiveDate);
}
/**
* Determines if the mileage date for this per diem expense matches the range for the given mileage rate
* @param mileageRate the mileage rate to check the mileage date against
* @return true if the mileage date matches, false otherwise
*/
protected boolean isMileageDateWithinMileageRateRange(MileageRate mileageRate) {
final Date fromDate = mileageRate.getActiveFromDate();
final Date toDate = mileageRate.getActiveToDate();
return (KfsDateUtils.isSameDay(fromDate, getMileageDate()) || fromDate.before(getMileageDate())) && (KfsDateUtils.isSameDay(toDate, getMileageDate()) || toDate.after(getMileageDate()));
}
public KualiDecimal getMileageTotal() {
KualiDecimal total = KualiDecimal.ZERO;
if (KNSGlobalVariables.getKualiForm() instanceof TravelFormBase) {
final TravelFormBase travelForm = (TravelFormBase)KNSGlobalVariables.getKualiForm();
if (travelForm == null) {
return KualiDecimal.ZERO;
}
final TravelDocument travelDocument = travelForm.getTravelDocument();
return getMileageTotalForDocument(travelDocument);
}
return total;
}
protected KualiDecimal getMileageTotalForDocument(TravelDocument travelDocument) {
KualiDecimal total = KualiDecimal.ZERO;
if (!personal) {
if (travelDocument == null) {
return KualiDecimal.ZERO;
}
final java.sql.Date effectiveDate = travelDocument.getEffectiveDateForMileageRate(this);
final MileageRate rate = getMileageRate(effectiveDate);
if (ObjectUtils.isNotNull(rate) && ObjectUtils.isNotNull(this.miles) && this.miles > 0) {
total = new KualiDecimal(new BigDecimal(miles).multiply(rate.getRate()));
}
}
return total;
}
public KualiDecimal getDailyTotal() {
KualiDecimal total = KualiDecimal.ZERO;
if (!personal) {
total = total.add(getMileageTotal());
total = total.add(getLodging());
total = total.add(getMealsAndIncidentals());
}
return total;
}
public KualiDecimal getDailyTotalForDocument(TravelDocument travelDoc) {
KualiDecimal total = KualiDecimal.ZERO;
if (!personal) {
total = total.add(getMileageTotalForDocument(travelDoc));
total = total.add(getLodging());
total = total.add(getMealsAndIncidentals());
}
return total;
}
/**
*
* This method gets the mealsTotal with
* @return
*/
public KualiDecimal getMealsTotal() {
KualiDecimal total = KualiDecimal.ZERO;
if (!personal) {
if (breakfast) {
total = total.add(this.getBreakfastValue());
}
if (lunch) {
total = total.add(this.getLunchValue());
}
if (dinner) {
total = total.add(this.getDinnerValue());
}
}
return total;
}
/**
*
* This method gets the Lodging Total if it is not a personal expense.
* @return
*/
public KualiDecimal getLodgingTotal() {
if (!personal) {
return this.getLodging();
}
return KualiDecimal.ZERO;
}
/**
* Retrieve the Mileage date of per diem
*
* CLEANUP: mileage date should be the per diem expense date
*
* @return mileage date
*/
@Column(name = "MLG_DT")
public Timestamp getMileageDate() {
return mileageDate;
}
public KualiDecimal getMealsAndIncidentals() {
KualiDecimal total = KualiDecimal.ZERO;
if (!personal) {
total = total.add(getMealsTotal());
total = total.add(getIncidentalsValue());
}
return total;
}
public static KualiDecimal calculateMealsAndIncidentalsProrated(KualiDecimal total, Integer perDiemPercent) {
KualiDecimal percent = new KualiDecimal(perDiemPercent).divide(new KualiDecimal(100));
total = total.multiply(percent);
return total;
}
/**
*
* This method split mealsAndIncidentals into breakfast, lunch, dinner and incidentals (overriding the existing breakfast, lunch, dinner and incidentals values).
* @param mealsAndIncidentals
*/
public void setMealsAndIncidentals(KualiDecimal mealsAndIncidentals) {
KualiDecimal meal = mealsAndIncidentals.divide(new KualiDecimal(4));
setBreakfastValue(meal);
setLunchValue(meal);
setDinnerValue(meal);
setIncidentalsValue(mealsAndIncidentals.subtract(getMealsTotal()));
}
/**
* This method returns whether or not this is a personal expense or not (true for personal expense, false otherwise)
*
* @return true for personal expense, false otherwise
*/
@Column(name = "PERSONAL", nullable = false, length = 1)
public Boolean getPersonal() {
return personal;
}
/**
* This method sets true if this is a personal expense
*
* @param true for personal expense
*/
public void setPersonal(Boolean personal) {
this.personal = personal;
}
/**
* Assign the Mileage date of per diem
*
* @param mileageDate as Date
*/
public void setMileageDate(final Timestamp mileageDate) {
this.mileageDate = mileageDate;
}
@SuppressWarnings("rawtypes")
protected LinkedHashMap toStringMapper_RICE20_REFACTORME() {
LinkedHashMap map = new LinkedHashMap();
map.put("id", id);
map.put("countryState", this.countryState);
map.put("county", this.county);
map.put("primaryDestination", this.primaryDestination);
return map;
}
public KualiDecimal getDefaultMealsAndIncidentals() {
KualiDecimal total = KualiDecimal.ZERO;
if (!personal && this.perDiem != null) {
if (breakfast) {
total = total.add(this.perDiem.getBreakfast());
}
if (lunch) {
total = total.add(this.perDiem.getLunch());
}
if (dinner) {
total = total.add(this.perDiem.getDinner());
}
// finally add in the incidentals
if (getIncludeIncidentals()) {
total = total.add(this.perDiem.getIncidentals());
}
}
return total;
}
public boolean isCustomPerDiem() {
return primaryDestinationId == null || this.primaryDestinationId == TemConstants.CUSTOM_PRIMARY_DESTINATION_ID;
}
/**
* This method checks for incidentals inclusion to the mealsAndIncidentals calculation.
*
* @return
*/
public Boolean getIncludeIncidentals() {
return !(!breakfast && !lunch && !dinner && getIncidentalsWithMealsOnly());
}
public Boolean getIncidentalsWithMealsOnly() {
if (incidentalsWithMealsOnly == null) {
final boolean incidentalsWithMealsOnlyInd = SpringContext.getBean(ParameterService.class).getParameterValueAsBoolean(TemParameterConstants.TEM_DOCUMENT.class, TravelParameters.INCIDENTALS_WITH_MEALS_IND, Boolean.FALSE);
incidentalsWithMealsOnly = incidentalsWithMealsOnlyInd;
}
return incidentalsWithMealsOnly;
}
public void setIncidentalsWithMealsOnly(Boolean incidentalsWithMealsOnly) {
this.incidentalsWithMealsOnly = incidentalsWithMealsOnly;
}
/**
* This method returns incidentalsValue affected by INCIDENTALS_WITH_MEALS_IND parameter
*
* @return
*/
public KualiDecimal getIncidentalsValue() {
if (getIncludeIncidentals()) {
if (ObjectUtils.isNotNull(incidentalsValue) && this.incidentalsValue.isGreaterThan(KualiDecimal.ZERO)) {
return incidentalsValue;
}
}
return KualiDecimal.ZERO;
}
public void setIncidentalsValue(KualiDecimal incidentalsValue) {
this.incidentalsValue = incidentalsValue;
}
public KualiDecimal getUnfilteredIncidentalsValue() {
return this.incidentalsValue;
}
public void setUnfilteredIncidentalsValue(KualiDecimal incidentalsValue) {
this.incidentalsValue = incidentalsValue;
}
public boolean isProrated() {
if(isCustomPerDiem()){
return false;
}
return prorated;
}
public void setProrated(boolean prorated) {
this.prorated = prorated;
}
/**
* Gets the countryStateText attribute.
*
* @return Returns the countryStateText
*/
public String getCountryStateText() {
return countryState;
}
/**
* Sets the countryStateText attribute.
*
* @param countryStateText The countryStateText to set.
*/
public void setCountryStateText(String countryState) {
this.countryState = countryState;
}
}