View Javadoc
1   /*
2    * The Kuali Financial System, a comprehensive financial management system for higher education.
3    * 
4    * Copyright 2005-2014 The Kuali Foundation
5    * 
6    * This program is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU Affero General Public License as
8    * published by the Free Software Foundation, either version 3 of the
9    * License, or (at your option) any later version.
10   * 
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU Affero General Public License for more details.
15   * 
16   * You should have received a copy of the GNU Affero General Public License
17   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  package org.kuali.kfs.module.tem.document.validation.impl;
20  
21  import static org.kuali.kfs.module.tem.TemKeyConstants.ERROR_TA_TRVL_REQ_GRTR_THAN_ZERO;
22  
23  import java.sql.Timestamp;
24  import java.util.Collection;
25  import java.util.Date;
26  import java.util.HashMap;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Set;
30  
31  import org.apache.commons.lang.StringUtils;
32  import org.kuali.kfs.module.tem.TemConstants;
33  import org.kuali.kfs.module.tem.TemConstants.TravelAuthorizationParameters;
34  import org.kuali.kfs.module.tem.TemKeyConstants;
35  import org.kuali.kfs.module.tem.TemPropertyConstants;
36  import org.kuali.kfs.module.tem.TemPropertyConstants.TravelAuthorizationFields;
37  import org.kuali.kfs.module.tem.businessobject.TemProfile;
38  import org.kuali.kfs.module.tem.businessobject.TemProfileAccount;
39  import org.kuali.kfs.module.tem.businessobject.TravelAdvance;
40  import org.kuali.kfs.module.tem.document.TravelAuthorizationDocument;
41  import org.kuali.kfs.module.tem.document.TravelDocument;
42  import org.kuali.kfs.module.tem.document.service.TravelDocumentService;
43  import org.kuali.kfs.module.tem.service.TemProfileService;
44  import org.kuali.kfs.sys.KFSKeyConstants;
45  import org.kuali.kfs.sys.document.validation.GenericValidation;
46  import org.kuali.kfs.sys.document.validation.event.AttributedApproveDocumentEvent;
47  import org.kuali.kfs.sys.document.validation.event.AttributedBlanketApproveDocumentEvent;
48  import org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent;
49  import org.kuali.kfs.sys.document.validation.event.AttributedRouteDocumentEvent;
50  import org.kuali.kfs.sys.util.KfsDateUtils;
51  import org.kuali.rice.core.api.util.type.KualiDecimal;
52  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
53  import org.kuali.rice.kns.document.authorization.TransactionalDocumentAuthorizer;
54  import org.kuali.rice.kns.document.authorization.TransactionalDocumentPresentationController;
55  import org.kuali.rice.krad.document.DocumentAuthorizer;
56  import org.kuali.rice.krad.document.DocumentPresentationController;
57  import org.kuali.rice.krad.service.DocumentDictionaryService;
58  import org.kuali.rice.krad.util.GlobalVariables;
59  import org.kuali.rice.krad.util.KRADPropertyConstants;
60  
61  public class TravelAuthTravelAdvanceValidation extends GenericValidation {
62      protected TemProfileService temProfileService;
63      protected DocumentDictionaryService documentDictionaryService;
64      protected TravelDocumentService travelDocumentService;
65      protected ParameterService parameterService;
66  
67      @Override
68      public boolean validate(AttributedDocumentEvent event) {
69          boolean success = true;
70  
71          TravelAuthorizationDocument document = (TravelAuthorizationDocument)event.getDocument();
72  
73          if (document.getTraveler() == null){
74              GlobalVariables.getMessageMap().putError(TravelAuthorizationFields.TRAVELER_TYPE, TemKeyConstants.ERROR_TA_TRVL_ADV_MISSING_PROFILE);
75              return false;
76          }
77  
78          if (event instanceof AttributedRouteDocumentEvent
79                  || event instanceof AttributedApproveDocumentEvent
80                  || event instanceof AttributedBlanketApproveDocumentEvent){
81              if (document.shouldProcessAdvanceForDocument()) {
82                  success = isTravelAdvanceValid(document, document.getTravelAdvance());
83                  success = success && validateAdvanceAmount((TravelDocument)event.getDocument());
84              }
85          }
86  
87          return success;
88      }
89  
90      private boolean isTravelAdvanceValid(TravelAuthorizationDocument document, TravelAdvance advance) {
91          boolean success = true;
92  
93          GlobalVariables.getMessageMap().addToErrorPath(KRADPropertyConstants.DOCUMENT+"."+TravelAuthorizationFields.TRVL_ADV + ".");
94  
95          if(advance.getTravelAdvanceRequested() != null) {
96              KualiDecimal advReq = advance.getTravelAdvanceRequested();
97              if(advReq.isLessEqual(KualiDecimal.ZERO)) {
98                  success = false;
99              }
100         }
101         else{
102             success = false;
103         }
104 
105         if(!success) {
106             GlobalVariables.getMessageMap().putError(TravelAuthorizationFields.TRVL_ADV_REQUESTED, ERROR_TA_TRVL_REQ_GRTR_THAN_ZERO);
107         }
108 
109         if (canCurrentUserEditDocument(document)) {
110             success = success && validateDueDate(advance, document.getTripEnd());
111         }
112 
113         String travelerID = document.getTraveler().getPrincipalId();
114         Boolean checkPolicy = Boolean.FALSE;
115         if (travelerID != null){
116             //traveler must accept policy, if initiator is arranger, the traveler will have to accept later.
117             checkPolicy = GlobalVariables.getUserSession().getPrincipalId().equals(travelerID);
118         }
119         else{ //Non-kim traveler, arranger accepts policy
120             checkPolicy = Boolean.TRUE;
121         }
122 
123         if (checkPolicy){
124             if (!advance.getTravelAdvancePolicy()){
125                 success = false;
126                 GlobalVariables.getMessageMap().putError(TravelAuthorizationFields.TRVL_ADV_POLICY, TemKeyConstants.ERROR_TA_TRVL_ADV_POLICY);
127             }
128         }
129 
130         boolean testCards = getParameterService().getParameterValueAsBoolean(TravelAuthorizationDocument.class, TravelAuthorizationParameters.CASH_ADVANCE_WARNING_IND);
131         if (testCards){
132             Collection<String> cardTypes = getParameterService().getParameterValuesAsString(TravelAuthorizationDocument.class, TravelAuthorizationParameters.CASH_ADVANCE_CREDIT_CARD_TYPES);
133             Map<String,String> cardTypeMap = new HashMap<String, String>();
134             for (String cardType : cardTypes){
135                 cardTypeMap.put(cardType.toUpperCase(), cardType.toUpperCase());
136             }
137 
138             TemProfile temProfile = document.getTemProfile();
139             if (temProfile == null && travelerID != null){
140                 temProfile = temProfileService.findTemProfileByPrincipalId(travelerID);
141             }
142 
143             if (temProfile != null && temProfile.getAccounts() != null && temProfile.getAccounts().size() > 0){
144                 for (TemProfileAccount account  : temProfile.getAccounts()){
145                     if (cardTypeMap.containsKey(account.getName().toUpperCase())){
146                         if (StringUtils.isBlank(advance.getAdditionalJustification())){
147                             success = false;
148 
149                             GlobalVariables.getMessageMap().putError(TravelAuthorizationFields.TRVL_ADV_ADD_JUST, TemKeyConstants.ERROR_TA_TRVL_ADV_ADD_JUST);
150                         }
151                     }
152                 }
153             }
154         }
155 
156         GlobalVariables.getMessageMap().removeFromErrorPath(KRADPropertyConstants.DOCUMENT+"."+TravelAuthorizationFields.TRVL_ADV + ".");
157 
158         return success;
159     }
160 
161     /**
162      * Runs a number of rules against the due date of the advance: whether it has been filled it, that it's not in the past, that both it and the trip end must be filled in, and that the advance's due date is before the end of hte trip
163      * @param advance the travel advance to validate
164      * @param tripEnd the specified end of the trip
165      * @return true if the advance passed this gauntlet of validations, false otherwise
166      */
167     protected boolean validateDueDate(TravelAdvance advance, Timestamp tripEnd) {
168         boolean success = true;
169 
170         if (advance.getDueDate() != null) {
171             Date dueDate = KfsDateUtils.clearTimeFields(advance.getDueDate());
172             Date today = KfsDateUtils.clearTimeFields(new Date());
173 
174             if (dueDate != null && dueDate.before(today)) {
175                 GlobalVariables.getMessageMap().putError(TravelAuthorizationFields.TRVL_ADV_DUE_DATE, KFSKeyConstants.ERROR_CUSTOM, "The Payment Due Date cannot be in the past.");
176                 success = false;
177             }
178         }
179 
180         if (advance.getDueDate() != null && tripEnd == null){
181             GlobalVariables.getMessageMap().putError(TemPropertyConstants.TRIP_END_DT, TemKeyConstants.ERROR_TA_TRVL_TRIP_END_MISSING);
182             success = false;
183         }
184         else if (advance.getDueDate() != null && advance.getDueDate().after(tripEnd)) {
185             GlobalVariables.getMessageMap().putError(TravelAuthorizationFields.TRVL_ADV_DUE_DATE, TemKeyConstants.ERROR_TA_TRVL_ADV_DUE_DATE_INVALID);
186             success = false;
187         }
188         return success;
189     }
190 
191     protected boolean validateAdvanceAmount(TravelDocument  document ) {
192         boolean success = true;
193         TravelAuthorizationDocument travelAuthorizationDocument = (TravelAuthorizationDocument)document;
194         KualiDecimal totalAdvanceRequested = KualiDecimal.ZERO;
195         GlobalVariables.getMessageMap().addToErrorPath(KRADPropertyConstants.DOCUMENT+"."+TravelAuthorizationFields.TRVL_ADV + ".");
196 
197         totalAdvanceRequested = totalAdvanceRequested.add(travelAuthorizationDocument.getAdvanceTotal());
198 
199         // get total advance requested on TAA and TAC
200         List<TravelAdvance> advances = travelDocumentService.getTravelAdvancesForTrip(document.getTravelDocumentIdentifier());
201        for (TravelAdvance advance : advances) {
202            totalAdvanceRequested = totalAdvanceRequested.add(advance.getTravelAdvanceRequested());
203        }
204 
205 
206 
207        KualiDecimal totalTripAmount = travelAuthorizationDocument.getEncumbranceTotal();
208        if(totalAdvanceRequested.isGreaterThan(totalTripAmount)) {
209            GlobalVariables.getMessageMap().putError(TravelAuthorizationFields.TRVL_ADV, TemKeyConstants.ERROR_TA_TRVL_ADV_EXCCED_TOTAL_TRIP_AMOUNT);
210            success = false;
211        }
212 
213 
214 
215        return success;
216 
217     }
218 
219     /**
220      * Uses the presentation controller and the authorizer for the travel auth doc to determine if the current user can edit the doc and if they have full edit edit mode
221      * @return true if the doc is editable for the current user, false otherwise
222      */
223     protected boolean canCurrentUserEditDocument(TravelAuthorizationDocument doc) {
224         // i hope no one tries to run this validation against something which isn't a TravelAuthDoc.  I mean...even if they do, they won't for very long
225         final String documentTypeName = getDocumentDictionaryService().getDocumentTypeByClass(doc.getClass());
226         final DocumentPresentationController presController = getDocumentDictionaryService().getDocumentPresentationController(documentTypeName);
227         final DocumentAuthorizer authorizer = getDocumentDictionaryService().getDocumentAuthorizer(documentTypeName);
228         final Set<String> presControllerEditModes = ((TransactionalDocumentPresentationController)presController).getEditModes(doc);
229         final Set<String> editModes = ((TransactionalDocumentAuthorizer)authorizer).getEditModes(doc, GlobalVariables.getUserSession().getPerson(), presControllerEditModes);
230         return editModes.contains(TemConstants.TravelEditMode.FULL_ENTRY) && presController.canEdit(doc) && authorizer.canEdit(doc, GlobalVariables.getUserSession().getPerson());
231     }
232 
233     public TemProfileService getTemProfileService() {
234         return temProfileService;
235     }
236 
237     public void setTemProfileService(TemProfileService temProfileService) {
238         this.temProfileService = temProfileService;
239     }
240 
241     /**
242      * @return the injected implementation of the DocumentDictionaryService
243      */
244     public DocumentDictionaryService getDocumentDictionaryService() {
245         return this.documentDictionaryService;
246     }
247 
248     /**
249      * Injects an implementation of the document dictionary service
250      * @param documentDictionaryService an implementation of the document dictionary service to inject
251      */
252     public void setDocumentDictionaryService(DocumentDictionaryService documentDictionaryService) {
253         this.documentDictionaryService = documentDictionaryService;
254     }
255 
256     public void setTravelDocumentService(TravelDocumentService travelDocumentService) {
257         this.travelDocumentService = travelDocumentService;
258     }
259 
260     public ParameterService getParameterService() {
261         return parameterService;
262     }
263 
264     public void setParameterService(ParameterService parameterService) {
265         this.parameterService = parameterService;
266     }
267 }