001/* 002 * The Kuali Financial System, a comprehensive financial management system for higher education. 003 * 004 * Copyright 2005-2014 The Kuali Foundation 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU Affero General Public License as 008 * published by the Free Software Foundation, either version 3 of the 009 * License, or (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU Affero General Public License for more details. 015 * 016 * You should have received a copy of the GNU Affero General Public License 017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package org.kuali.kfs.module.tem.dataaccess.impl; 020 021import static org.kuali.kfs.module.tem.TemPropertyConstants.TRAVEL_DOCUMENT_IDENTIFIER; 022 023import java.sql.Timestamp; 024import java.util.ArrayList; 025import java.util.Arrays; 026import java.util.Collection; 027import java.util.Iterator; 028import java.util.List; 029import java.util.Set; 030 031import org.apache.log4j.Logger; 032import org.apache.ojb.broker.query.Criteria; 033import org.apache.ojb.broker.query.Query; 034import org.apache.ojb.broker.query.QueryByCriteria; 035import org.apache.ojb.broker.query.QueryFactory; 036import org.apache.ojb.broker.query.ReportQueryByCriteria; 037import org.kuali.kfs.module.tem.TemConstants; 038import org.kuali.kfs.module.tem.TemPropertyConstants; 039import org.kuali.kfs.module.tem.businessobject.ImportedExpense; 040import org.kuali.kfs.module.tem.businessobject.PerDiem; 041import org.kuali.kfs.module.tem.businessobject.TravelAdvance; 042import org.kuali.kfs.module.tem.dataaccess.TravelDocumentDao; 043import org.kuali.kfs.module.tem.document.TEMReimbursementDocument; 044import org.kuali.kfs.module.tem.document.TravelAuthorizationDocument; 045import org.kuali.kfs.module.tem.document.TravelDocument; 046import org.kuali.kfs.module.tem.document.TravelEntertainmentDocument; 047import org.kuali.kfs.module.tem.document.TravelReimbursementDocument; 048import org.kuali.kfs.module.tem.document.TravelRelocationDocument; 049import org.kuali.kfs.sys.KFSConstants; 050import org.kuali.kfs.sys.KFSPropertyConstants; 051import org.kuali.kfs.sys.KFSConstants.DocumentStatusCodes; 052import org.kuali.kfs.sys.util.TransactionalServiceUtils; 053import org.kuali.rice.core.framework.persistence.ojb.dao.PlatformAwareDaoBaseOjb; 054import org.kuali.rice.krad.util.ObjectUtils; 055import org.kuali.rice.krad.util.OjbCollectionAware; 056 057/** 058 * This class is the OJB implementation of the DocumentDao interface. 059 */ 060public class TravelDocumentDaoOjb extends PlatformAwareDaoBaseOjb implements TravelDocumentDao, OjbCollectionAware { 061 062 public static Logger LOG = Logger.getLogger(TravelDocumentDaoOjb.class); 063 064 @Override 065 public List<TravelDocument> findDocuments(final Class<?> travelDocumentClass, final String travelDocumentNumber) { 066 final Criteria c = new Criteria(); 067 c.addEqualTo(TRAVEL_DOCUMENT_IDENTIFIER, travelDocumentNumber); 068 069 LOG.debug("Creating query for type "+ travelDocumentClass+ " using criteria "+ c); 070 071 final List<TravelDocument> retval = new ArrayList<TravelDocument>(); 072 073 Collection<? extends TravelDocument> documents = getPersistenceBrokerTemplate().getCollectionByQuery(new QueryByCriteria(travelDocumentClass, c)); 074 075 for (Iterator it = documents.iterator(); it.hasNext();) { 076 TravelDocument document = (TravelDocument) it.next(); 077 retval.add(document); 078 } 079 080 return retval; 081 } 082 083 @Override 084 public List<String> findDocumentNumbers(final Class<?> travelDocumentClass, final String travelDocumentNumber) { 085 final Criteria c = new Criteria(); 086 c.addEqualTo(TRAVEL_DOCUMENT_IDENTIFIER, travelDocumentNumber); 087 088 LOG.debug("Creating query for type "+ travelDocumentClass+ " using criteria "+ c); 089 090 final List<String> retval = new ArrayList<String>(); 091 092 Collection<? extends TravelDocument> documents = getPersistenceBrokerTemplate().getCollectionByQuery(new QueryByCriteria(travelDocumentClass, c)); 093 094 for (Iterator it = documents.iterator(); it.hasNext();) { 095 TravelDocument document = (TravelDocument) it.next(); 096 retval.add(document.getDocumentNumber()); 097 } 098 099 return retval; 100 } 101 102 /** 103 * @see org.kuali.kfs.module.tem.dataaccess.TravelDocumentDao#findPerDiem(int, java.sql.Date, java.sql.Date) 104 */ 105 @Override 106 public List<PerDiem> findEffectivePerDiems(int primaryDestinationId, java.sql.Date effectiveDate){ 107 Criteria criteria = new Criteria(); 108 criteria.addEqualTo(TemPropertyConstants.PRIMARY_DESTINATION_ID, new Integer(primaryDestinationId)); 109 110 //Add date criteria so the date falls in a specific range 111 //or their is no "To" date. (Open-ended) 112 Criteria dateBetweenCriteria = new Criteria(); 113 Criteria dateNullCriteria = new Criteria(); 114 115 dateBetweenCriteria.addGreaterOrEqualThan(TemPropertyConstants.PER_DIEM_EFFECTIVE_TO_DATE, effectiveDate); 116 dateBetweenCriteria.addLessOrEqualThan(TemPropertyConstants.PER_DIEM_EFFECTIVE_FROM_DATE, effectiveDate); 117 118 dateNullCriteria.addIsNull(TemPropertyConstants.PER_DIEM_EFFECTIVE_TO_DATE); 119 120 dateBetweenCriteria.addOrCriteria(dateNullCriteria); 121 criteria.addAndCriteria(dateBetweenCriteria); 122 QueryByCriteria query = QueryFactory.newQuery(PerDiem.class, criteria); 123 124 List<PerDiem> possiblePerDiems = new ArrayList<PerDiem>(); 125 possiblePerDiems.addAll(getPersistenceBrokerTemplate().getCollectionByQuery(query)); 126 return possiblePerDiems; 127 } 128 129 /** 130 * @see org.kuali.kfs.module.tem.dataaccess.TravelDocumentDao#getOutstandingTravelAdvanceByInvoice(java.util.Set) 131 */ 132 @Override 133 public List<TravelAdvance> getOutstandingTravelAdvanceByInvoice(Set<String> arInvoiceDocNumbers) { 134 if (ObjectUtils.isNull(arInvoiceDocNumbers) || arInvoiceDocNumbers.isEmpty()) { 135 return new ArrayList<TravelAdvance>(); 136 } 137 138 Criteria criteria = new Criteria(); 139 criteria.addIn(TemPropertyConstants.AR_INVOICE_DOC_NUMBER, arInvoiceDocNumbers); 140 criteria.addIsNull(TemPropertyConstants.TAXABLE_RAMIFICATION_NOTIFICATION_DATE); 141 142 Query query = QueryFactory.newQuery(TravelAdvance.class, criteria); 143 144 return (List<TravelAdvance>)getPersistenceBrokerTemplate().getCollectionByQuery(query); 145 } 146 147 /** 148 * @see org.kuali.kfs.module.tem.dataaccess.TravelDocumentDao#findLatestTaxableRamificationNotificationDate() 149 */ 150 @Override 151 public Object[] findLatestTaxableRamificationNotificationDate() { 152 getPersistenceBrokerTemplate().clearCache(); 153 154 Criteria criteria = new Criteria(); 155 criteria.addNotNull(TemPropertyConstants.TAXABLE_RAMIFICATION_NOTIFICATION_DATE); 156 157 ReportQueryByCriteria query = QueryFactory.newReportQuery(TravelAdvance.class, criteria); 158 159 String selectionField = "max(" + TemPropertyConstants.TAXABLE_RAMIFICATION_NOTIFICATION_DATE + ")"; 160 query.setAttributes(new String[] { selectionField }); 161 query.setDistinct(true); 162 163 Iterator<Object[]> iterator = getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(query); 164 return TransactionalServiceUtils.retrieveFirstAndExhaustIterator(iterator); 165 166 167 } 168 169 /** 170 * @see org.kuali.kfs.module.tem.dataaccess.TravelDocumentDao#getReimbursementDocumentsByHeaderStatus(java.lang.String, boolean) 171 */ 172 @Override 173 public Collection<? extends TEMReimbursementDocument> getReimbursementDocumentsByHeaderStatus(String statusCode, boolean immediatesOnly) { 174 return (Collection<? extends TEMReimbursementDocument>)getTravelDocumentsByHeaderStatus(TravelReimbursementDocument.class, statusCode, immediatesOnly, TemPropertyConstants.TRAVEL_PAYMENT); 175 } 176 177 /** 178 * @see org.kuali.kfs.module.tem.dataaccess.TravelDocumentDao#getRelocationDocumentsByHeaderStatus(java.lang.String, boolean) 179 */ 180 @Override 181 public Collection<? extends TEMReimbursementDocument> getRelocationDocumentsByHeaderStatus(String statusCode, boolean immediatesOnly) { 182 return (Collection<? extends TEMReimbursementDocument>)getTravelDocumentsByHeaderStatus(TravelRelocationDocument.class, statusCode, immediatesOnly, TemPropertyConstants.TRAVEL_PAYMENT); 183 } 184 185 /** 186 * @see org.kuali.kfs.module.tem.dataaccess.TravelDocumentDao#getEntertainmentDocumentsByHeaderStatus(java.lang.String, boolean) 187 */ 188 @Override 189 public Collection<? extends TEMReimbursementDocument> getEntertainmentDocumentsByHeaderStatus(String statusCode, boolean immediatesOnly) { 190 return (Collection<? extends TEMReimbursementDocument>)getTravelDocumentsByHeaderStatus(TravelEntertainmentDocument.class, statusCode, immediatesOnly, TemPropertyConstants.TRAVEL_PAYMENT); 191 } 192 193 /** 194 * @see org.kuali.kfs.module.tem.dataaccess.TravelDocumentDao#getAuthorizationDocumentsByHeaderStatus(java.lang.String, boolean) 195 */ 196 @Override 197 public Collection<? extends TravelAuthorizationDocument> getAuthorizationsAndAmendmentsByHeaderStatus(String statusCode, boolean immediatesOnly) { 198 List<TravelAuthorizationDocument> documents = new ArrayList<TravelAuthorizationDocument>(); 199 documents.addAll((Collection<TravelAuthorizationDocument>)getTravelDocumentsByHeaderStatus(TravelAuthorizationDocument.class, statusCode, immediatesOnly, TemPropertyConstants.ADVANCE_TRAVEL_PAYMENT)); // extents will get travel auth amendments 200 return documents; 201 } 202 203 /** 204 * Do a lookup of reimbursable documents of the given class with the given financial system document header status code and a payment method of "check" (ie, PDP will pay out) 205 * @param documentClazz the class of the document to look up 206 * @param statusCode the status code of the documents to look up 207 * @param immediatesOnly true if only those reimbursable documents 208 * @return a Collection of qualifying documents 209 */ 210 protected Collection<? extends TravelDocument> getTravelDocumentsByHeaderStatus(Class<? extends TravelDocument> documentClazz, String statusCode, boolean immediatesOnly, String travelPaymentProperty) { 211 if (LOG.isDebugEnabled()) { 212 LOG.debug("getReimbursableDocumentsByHeaderStatus() started"); 213 } 214 215 Criteria criteria = new Criteria(); 216 criteria.addEqualTo(KFSPropertyConstants.DOCUMENT_HEADER+"."+KFSPropertyConstants.FINANCIAL_DOCUMENT_STATUS_CODE, statusCode); 217 criteria.addEqualTo(travelPaymentProperty+".paymentMethodCode", KFSConstants.PaymentSourceConstants.PAYMENT_METHOD_CHECK); 218 if (immediatesOnly) { 219 criteria.addEqualTo(travelPaymentProperty+".immediatePaymentIndicator", Boolean.TRUE); 220 } 221 222 return getPersistenceBrokerTemplate().getCollectionByQuery(new QueryByCriteria(documentClazz, criteria)); 223 } 224 225 /** 226 * Retrieves all travel reimbursement documents which have corporate card expenses to extract but which have not yet been extracted 227 * @see org.kuali.kfs.module.tem.dataaccess.TravelDocumentDao#getReimbursementDocumentsNeedingCorporateCardExtraction() 228 */ 229 @Override 230 public Collection<? extends TEMReimbursementDocument> getReimbursementDocumentsNeedingCorporateCardExtraction() { 231 return (Collection<? extends TEMReimbursementDocument>)getUnExtractedCorporateCardTravelDocuments(TravelReimbursementDocument.class); 232 233 } 234 235 /** 236 * Retrieves all entertainment reimbursement documents which have corporate card expenses to extract but which have not yet been extracted 237 * @see org.kuali.kfs.module.tem.dataaccess.TravelDocumentDao#getReimbursementDocumentsNeedingCorporateCardExtraction() 238 */ 239 @Override 240 public Collection<? extends TEMReimbursementDocument> getEntertainmentDocumentsNeedingCorporateCardExtraction() { 241 return (Collection<? extends TEMReimbursementDocument>)getUnExtractedCorporateCardTravelDocuments(TravelEntertainmentDocument.class); 242 243 } 244 245 /** 246 * Retrieves all moving and relocation reimbursement documents which have corporate card expenses to extract but which have not yet been extracted 247 * @see org.kuali.kfs.module.tem.dataaccess.TravelDocumentDao#getReimbursementDocumentsNeedingCorporateCardExtraction() 248 */ 249 @Override 250 public Collection<? extends TEMReimbursementDocument> getRelocationDocumentsNeedingCorporateCardExtraction() { 251 return (Collection<? extends TEMReimbursementDocument>)getUnExtractedCorporateCardTravelDocuments(TravelRelocationDocument.class); 252 253 } 254 255 /** 256 * Retrieves all documents of the given TravelDocument class that a) are extracted or approved by document header, but b) have a null corporate card extraction date and c) actually have corporate card expenses 257 * @param documentClazz the class of the travel documents to retrieve 258 * @return a Collection of matching documents 259 */ 260 protected Collection<? extends TravelDocument> getUnExtractedCorporateCardTravelDocuments(Class<? extends TravelDocument> documentClazz) { 261 Criteria criteria = new Criteria(); 262 263 List<String> statusCodes = new ArrayList<String>(); 264 statusCodes.add(KFSConstants.DocumentStatusCodes.Payments.EXTRACTED); 265 statusCodes.add(KFSConstants.DocumentStatusCodes.APPROVED); 266 criteria.addIn(KFSPropertyConstants.DOCUMENT_HEADER+"."+KFSPropertyConstants.FINANCIAL_DOCUMENT_STATUS_CODE, statusCodes); 267 criteria.addIsNull(TemPropertyConstants.CORPORATE_CARD_PAYMENT_EXTRACT_DATE); 268 269 Criteria expenseCriteria = new Criteria(); 270 expenseCriteria.addEqualTo(TemPropertyConstants.CARD_TYPE, TemConstants.TRAVEL_TYPE_CORP); 271 expenseCriteria.addEqualTo(TemPropertyConstants.EXPENSE_LINE_TYPE_CODE, TemConstants.EXPENSE_IMPORTED); 272 expenseCriteria.addEqualTo(TemPropertyConstants.HISTORICAL_TRAVEL_EXPENSE+"."+TemPropertyConstants.CREDIT_CARD_AGENCY+"."+TemPropertyConstants.PAYMENT_INDICATOR, Boolean.TRUE); 273 ReportQueryByCriteria expensesSubQuery = QueryFactory.newReportQuery(ImportedExpense.class, expenseCriteria); 274 expensesSubQuery.setAttributes(new String[] {KFSPropertyConstants.DOCUMENT_NUMBER}); 275 criteria.addIn(KFSPropertyConstants.DOCUMENT_NUMBER, expensesSubQuery); 276 277 return getPersistenceBrokerTemplate().getCollectionByQuery(new QueryByCriteria(documentClazz, criteria)); 278 } 279 280 281 @Override 282 public Collection<? extends TEMReimbursementDocument> findMatchingTrips (Integer temProfileId ,Timestamp tripBegin, Timestamp tripEnd) { 283 284 285 final Criteria criteria = new Criteria(); 286 final Criteria orEndDateCriteria = new Criteria(); 287 criteria.addEqualTo(TemPropertyConstants.TEM_PROFILE_ID, temProfileId); 288 criteria.addEqualTo(TemPropertyConstants.TRIP_BEGIN_DT, tripBegin); 289 orEndDateCriteria.addEqualTo(TemPropertyConstants.TRIP_END_DT, tripEnd); 290 criteria.addOrCriteria(orEndDateCriteria); 291 criteria.addNotIn("documentHeader.financialDocumentStatusCode", Arrays.asList(DocumentStatusCodes.INITIATED)); 292 293 return getPersistenceBrokerTemplate().getCollectionByQuery(new QueryByCriteria(TravelReimbursementDocument.class, criteria)); 294 295 296 } 297}