001/* 002 * Copyright 2005 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.ole.fp.document.validation.impl; 017 018import java.text.MessageFormat; 019import java.util.ArrayList; 020import java.util.List; 021import java.util.Set; 022 023import org.apache.commons.lang.StringUtils; 024import org.kuali.ole.fp.businessobject.DisbursementVoucherNonEmployeeTravel; 025import org.kuali.ole.fp.businessobject.DisbursementVoucherWireTransfer; 026import org.kuali.ole.fp.businessobject.options.PaymentReasonValuesFinder; 027import org.kuali.ole.fp.document.DisbursementVoucherConstants; 028import org.kuali.ole.fp.document.DisbursementVoucherDocument; 029import org.kuali.ole.sys.OLEConstants; 030import org.kuali.ole.sys.OLEKeyConstants; 031import org.kuali.ole.sys.OLEPropertyConstants; 032import org.kuali.ole.sys.businessobject.Bank; 033import org.kuali.ole.sys.context.SpringContext; 034import org.kuali.ole.sys.service.BankService; 035import org.kuali.rice.core.api.config.property.ConfigurationService; 036import org.kuali.rice.core.api.util.KeyValue; 037import org.kuali.rice.kns.rules.PromptBeforeValidationBase; 038import org.kuali.rice.krad.document.Document; 039import org.kuali.rice.krad.util.ObjectUtils; 040 041/** 042 * Checks warnings and prompt conditions for dv document. 043 */ 044public class DisbursementVoucherDocumentPreRules extends PromptBeforeValidationBase implements DisbursementVoucherConstants { 045 046 /** 047 * Executes pre-rules for Disbursement Voucher Document 048 * 049 * @param document submitted document 050 * @return true if pre-rules execute successfully 051 * @see org.kuali.rice.kns.rules.PromptBeforeValidationBase#doRules(org.kuali.rice.kns.document.MaintenanceDocument) 052 */ 053 @Override 054 public boolean doPrompts(Document document) { 055 boolean preRulesOK = true; 056 057 DisbursementVoucherDocument dvDocument = (DisbursementVoucherDocument) document; 058 checkSpecialHandlingIndicator(dvDocument); 059 060 preRulesOK &= checkNonEmployeeTravelTabState(dvDocument); 061 062 preRulesOK &= checkWireTransferTabState(dvDocument); 063 064 preRulesOK &= checkForeignDraftTabState(dvDocument); 065 066 preRulesOK &= checkBankCodeActive(dvDocument); 067 068 return preRulesOK; 069 } 070 071 /** 072 * If the special handling name and address 1 fields have value, this will mark the special handling indicator for the user. 073 * 074 * @param dvDocument submitted disbursement voucher document 075 */ 076 protected void checkSpecialHandlingIndicator(DisbursementVoucherDocument dvDocument) { 077 if (StringUtils.isNotBlank(dvDocument.getDvPayeeDetail().getDisbVchrSpecialHandlingPersonName()) && StringUtils.isNotBlank(dvDocument.getDvPayeeDetail().getDisbVchrSpecialHandlingLine1Addr()) && allowTurningOnOfSpecialHandling(dvDocument)) { 078 dvDocument.setDisbVchrSpecialHandlingCode(true); 079 } 080 } 081 082 /** 083 * Allows the automatic turning on of special handling indicator - which will not be allowed at the Campus route level 084 * @param dvDocument the document to allow turning on of special handling for 085 * @return true if special handling can be automatically turned on, false otherwise 086 */ 087 protected boolean allowTurningOnOfSpecialHandling(DisbursementVoucherDocument dvDocument) { 088 Set<String> currentNodes = dvDocument.getDocumentHeader().getWorkflowDocument().getCurrentNodeNames(); 089 return !(currentNodes.contains(DisbursementVoucherConstants.RouteLevelNames.CAMPUS)); 090 } 091 092 /** 093 * This method checks non-employee travel tab state is valid 094 * 095 * @param dvDocument submitted disbursement voucher document 096 * @return true if the state of all the tabs is valid, false otherwise. 097 */ 098 protected boolean checkNonEmployeeTravelTabState(DisbursementVoucherDocument dvDocument) { 099 boolean tabStatesOK = true; 100 101 DisbursementVoucherNonEmployeeTravel dvNonEmplTrav = dvDocument.getDvNonEmployeeTravel(); 102 if (!hasNonEmployeeTravelValues(dvNonEmplTrav)) { 103 return true; 104 } 105 106 String paymentReasonCode = dvDocument.getDvPayeeDetail().getDisbVchrPaymentReasonCode(); 107// List<String> nonEmpltravelPaymentReasonCodes = new ArrayList<String>( SpringContext.getBean(ParameterService.class).getParameterValuesAsString(DisbursementVoucherDocument.class, NONEMPLOYEE_TRAVEL_PAY_REASONS_PARM_NM) ); 108 //Modified for the jira issue OLE-3415 109 List<String> nonEmpltravelPaymentReasonCodes = new ArrayList<String>(); 110 111 if (nonEmpltravelPaymentReasonCodes == null || !nonEmpltravelPaymentReasonCodes.contains(paymentReasonCode) || dvDocument.getDvPayeeDetail().isEmployee()) { 112 String nonEmplTravReasonStr = getValidPaymentReasonsAsString(nonEmpltravelPaymentReasonCodes); 113 114 String paymentReasonName = dvDocument.getDvPayeeDetail().getDisbVchrPaymentReasonName(); 115 Object[] args = { "payment reason", "'" + paymentReasonName + "'", "Non-Employee Travel", nonEmplTravReasonStr }; 116 117 String questionText = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(OLEKeyConstants.QUESTION_CLEAR_UNNEEDED_TAB); 118 questionText = MessageFormat.format(questionText, args); 119 120 boolean clearTab = super.askOrAnalyzeYesNoQuestion(OLEConstants.DisbursementVoucherDocumentConstants.CLEAR_NON_EMPLOYEE_TAB_QUESTION_ID, questionText); 121 if (clearTab) { 122 DisbursementVoucherNonEmployeeTravel blankDvNonEmplTrav = new DisbursementVoucherNonEmployeeTravel(); 123 blankDvNonEmplTrav.setDocumentNumber(dvNonEmplTrav.getDocumentNumber()); 124 blankDvNonEmplTrav.setVersionNumber(dvNonEmplTrav.getVersionNumber()); 125 dvDocument.setDvNonEmployeeTravel(blankDvNonEmplTrav); 126 } 127 else { 128 // return to document if the user doesn't want to clear the Non Employee Travel tab 129 super.event.setActionForwardName(OLEConstants.MAPPING_BASIC); 130 tabStatesOK = false; 131 } 132 } 133 134 return tabStatesOK; 135 } 136 137 /** 138 * Returns true if non-employee travel tab contains any data in any of its fields 139 * 140 * @param dvNonEmplTrav disbursement voucher non employee travel object 141 * @return True if non employee travel tab contains any data in any fields. 142 */ 143 protected boolean hasNonEmployeeTravelValues(DisbursementVoucherNonEmployeeTravel dvNonEmplTrav) { 144 boolean hasValues = false; 145 146 // Checks each explicit field in the tab for user entered values 147 hasValues = hasNonEmployeeTravelGeneralValues(dvNonEmplTrav); 148 149 // Checks per diem section for values 150 if (!hasValues) { 151 hasValues = hasNonEmployeeTravelPerDiemValues(dvNonEmplTrav); 152 } 153 154 if (!hasValues) { 155 hasValues = hasNonEmployeeTravelPersonalVehicleValues(dvNonEmplTrav); 156 } 157 158 if (!hasValues) { 159 hasValues = dvNonEmplTrav.getDvNonEmployeeExpenses().size() > 0; 160 } 161 162 if (!hasValues) { 163 hasValues = dvNonEmplTrav.getDvPrePaidEmployeeExpenses().size() > 0; 164 } 165 166 return hasValues; 167 } 168 169 /** 170 * Returns true if any values are not blank on non employee travel tab 171 * 172 * @param dvNonEmplTrav disbursement voucher non employee travel object 173 * @return True if any values are found in the non employee travel tab 174 */ 175 protected boolean hasNonEmployeeTravelGeneralValues(DisbursementVoucherNonEmployeeTravel dvNonEmplTrav) { 176 return StringUtils.isNotBlank(dvNonEmplTrav.getDisbVchrNonEmpTravelerName()) || StringUtils.isNotBlank(dvNonEmplTrav.getDisbVchrServicePerformedDesc()) || StringUtils.isNotBlank(dvNonEmplTrav.getDvServicePerformedLocName()) || StringUtils.isNotBlank(dvNonEmplTrav.getDvServiceRegularEmprName()) || StringUtils.isNotBlank(dvNonEmplTrav.getDisbVchrTravelFromCityName()) || StringUtils.isNotBlank(dvNonEmplTrav.getDisbVchrTravelFromStateCode()) || StringUtils.isNotBlank(dvNonEmplTrav.getDvTravelFromCountryCode()) || ObjectUtils.isNotNull(dvNonEmplTrav.getDvPerdiemStartDttmStamp()) || StringUtils.isNotBlank(dvNonEmplTrav.getDisbVchrTravelToCityName()) || StringUtils.isNotBlank(dvNonEmplTrav.getDisbVchrTravelToStateCode()) || StringUtils.isNotBlank(dvNonEmplTrav.getDisbVchrTravelToCountryCode()) || ObjectUtils.isNotNull(dvNonEmplTrav.getDvPerdiemEndDttmStamp()); 177 } 178 179 /** 180 * Returns true if non employee travel tab contains data in any of the fields in the per diem section 181 * 182 * @param dvNonEmplTrav disbursement voucher non employee travel object 183 * @return True if non employee travel tab contains data in any of the fields in the per diem section 184 */ 185 protected boolean hasNonEmployeeTravelPerDiemValues(DisbursementVoucherNonEmployeeTravel dvNonEmplTrav) { 186 return StringUtils.isNotBlank(dvNonEmplTrav.getDisbVchrPerdiemCategoryName()) || ObjectUtils.isNotNull(dvNonEmplTrav.getDisbVchrPerdiemRate()) || ObjectUtils.isNotNull(dvNonEmplTrav.getDisbVchrPerdiemCalculatedAmt()) || ObjectUtils.isNotNull(dvNonEmplTrav.getDisbVchrPerdiemActualAmount()) || StringUtils.isNotBlank(dvNonEmplTrav.getDvPerdiemChangeReasonText()); 187 } 188 189 /** 190 * Returns true if non employee travel tab contains data in any of the fields in the personal vehicle section 191 * 192 * @param dvNonEmplTrav disbursement voucher non employee travel object 193 * @return True if non employee travel tab contains data in any of the fields in the personal vehicle section 194 */ 195 protected boolean hasNonEmployeeTravelPersonalVehicleValues(DisbursementVoucherNonEmployeeTravel dvNonEmplTrav) { 196 return StringUtils.isNotBlank(dvNonEmplTrav.getDisbVchrAutoFromCityName()) || StringUtils.isNotBlank(dvNonEmplTrav.getDisbVchrAutoFromStateCode()) || StringUtils.isNotBlank(dvNonEmplTrav.getDisbVchrAutoToCityName()) || StringUtils.isNotBlank(dvNonEmplTrav.getDisbVchrAutoToStateCode()) || ObjectUtils.isNotNull(dvNonEmplTrav.getDisbVchrMileageCalculatedAmt()) || ObjectUtils.isNotNull(dvNonEmplTrav.getDisbVchrPersonalCarAmount()); 197 } 198 199 /** 200 * Returns true if the state of all the tabs is valid, false otherwise. 201 * 202 * @param dvDocument submitted disbursemtn voucher document 203 * @return true if the state of all the tabs is valid, false otherwise. 204 */ 205 protected boolean checkForeignDraftTabState(DisbursementVoucherDocument dvDocument) { 206 boolean tabStatesOK = true; 207 208 DisbursementVoucherWireTransfer dvForeignDraft = dvDocument.getDvWireTransfer(); 209 210 // if payment method is CHECK and wire tab contains data, ask user to clear tab 211 if ((StringUtils.equals(DisbursementVoucherConstants.PAYMENT_METHOD_CHECK, dvDocument.getDisbVchrPaymentMethodCode()) || StringUtils.equals(DisbursementVoucherConstants.PAYMENT_METHOD_WIRE, dvDocument.getDisbVchrPaymentMethodCode())) && hasForeignDraftValues(dvForeignDraft)) { 212 String questionText = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(OLEKeyConstants.QUESTION_CLEAR_UNNEEDED_TAB); 213 214 Object[] args = { "payment method", dvDocument.getDisbVchrPaymentMethodCode(), "Foreign Draft", DisbursementVoucherConstants.PAYMENT_METHOD_DRAFT }; 215 questionText = MessageFormat.format(questionText, args); 216 217 boolean clearTab = super.askOrAnalyzeYesNoQuestion(OLEConstants.DisbursementVoucherDocumentConstants.CLEAR_FOREIGN_DRAFT_TAB_QUESTION_ID, questionText); 218 if (clearTab) { 219 // NOTE: Can't replace with new instance because Wire Transfer uses same object 220 clearForeignDraftValues(dvForeignDraft); 221 } 222 else { 223 // return to document if the user doesn't want to clear the Wire Transfer tab 224 super.event.setActionForwardName(OLEConstants.MAPPING_BASIC); 225 tabStatesOK = false; 226 } 227 } 228 229 return tabStatesOK; 230 } 231 232 /** 233 * Returns true if foreign draft tab contains any data in any fields. NOTE: Currently does not validate based on only required 234 * fields. Checks all fields within tab for data. 235 * 236 * @param dvForeignDraft disbursement foreign draft object 237 * @return True if foreign draft tab contains any data in any fields. 238 */ 239 protected boolean hasForeignDraftValues(DisbursementVoucherWireTransfer dvForeignDraft) { 240 boolean hasValues = false; 241 242 // Checks each explicit field in the tab for user entered values 243 hasValues |= StringUtils.isNotBlank(dvForeignDraft.getDisbursementVoucherForeignCurrencyTypeCode()); 244 hasValues |= StringUtils.isNotBlank(dvForeignDraft.getDisbursementVoucherForeignCurrencyTypeName()); 245 246 return hasValues; 247 } 248 249 /** 250 * This method sets foreign currency type code and name to null for passed in disbursement foreign draft object 251 * 252 * @param dvForeignDraft disbursement foreign draft object 253 */ 254 protected void clearForeignDraftValues(DisbursementVoucherWireTransfer dvForeignDraft) { 255 dvForeignDraft.setDisbursementVoucherForeignCurrencyTypeCode(null); 256 dvForeignDraft.setDisbursementVoucherForeignCurrencyTypeName(null); 257 } 258 259 /** 260 * This method returns true if the state of all the tabs is valid, false otherwise. 261 * 262 * @param dvDocument submitted disbursement voucher document 263 * @return Returns true if the state of all the tabs is valid, false otherwise. 264 */ 265 protected boolean checkWireTransferTabState(DisbursementVoucherDocument dvDocument) { 266 boolean tabStatesOK = true; 267 268 DisbursementVoucherWireTransfer dvWireTransfer = dvDocument.getDvWireTransfer(); 269 270 // if payment method is CHECK and wire tab contains data, ask user to clear tab 271 if ((StringUtils.equals(DisbursementVoucherConstants.PAYMENT_METHOD_CHECK, dvDocument.getDisbVchrPaymentMethodCode()) || StringUtils.equals(DisbursementVoucherConstants.PAYMENT_METHOD_DRAFT, dvDocument.getDisbVchrPaymentMethodCode())) && hasWireTransferValues(dvWireTransfer)) { 272 String questionText = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(OLEKeyConstants.QUESTION_CLEAR_UNNEEDED_TAB); 273 274 Object[] args = { "payment method", dvDocument.getDisbVchrPaymentMethodCode(), "Wire Transfer", DisbursementVoucherConstants.PAYMENT_METHOD_WIRE }; 275 questionText = MessageFormat.format(questionText, args); 276 277 boolean clearTab = super.askOrAnalyzeYesNoQuestion(OLEConstants.DisbursementVoucherDocumentConstants.CLEAR_WIRE_TRANSFER_TAB_QUESTION_ID, questionText); 278 if (clearTab) { 279 // NOTE: Can't replace with new instance because Foreign Draft uses same object 280 clearWireTransferValues(dvWireTransfer); 281 } 282 else { 283 // return to document if the user doesn't want to clear the Wire Transfer tab 284 super.event.setActionForwardName(OLEConstants.MAPPING_BASIC); 285 tabStatesOK = false; 286 } 287 } 288 289 return tabStatesOK; 290 } 291 292 /** 293 * If bank specification is enabled, prompts user to use the continuation bank code when the given bank code is inactive 294 * 295 * @param dvDocument document containing bank code 296 * @return true 297 */ 298 protected boolean checkBankCodeActive(DisbursementVoucherDocument dvDocument) { 299 boolean continueRules = true; 300 301 // if bank specification is not enabled, no need to validate bank 302 if (!SpringContext.getBean(BankService.class).isBankSpecificationEnabled()) { 303 return continueRules; 304 } 305 306 // refresh bank reference so continuation bank can be checked for active status 307 dvDocument.refreshReferenceObject(OLEPropertyConstants.BANK); 308 Bank bank = dvDocument.getBank(); 309 310 // if bank is inactive and continuation is active, prompt user to use continuation bank 311 if (bank != null && !bank.isActive() && bank.getContinuationBank().isActive()) { 312 String questionText = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(OLEKeyConstants.QUESTION_BANK_INACTIVE); 313 questionText = MessageFormat.format(questionText, dvDocument.getDisbVchrBankCode(), bank.getContinuationBankCode()); 314 315 boolean useContinuation = super.askOrAnalyzeYesNoQuestion(OLEConstants.USE_CONTINUATION_BANK_QUESTION, questionText); 316 if (useContinuation) { 317 dvDocument.setDisbVchrBankCode(bank.getContinuationBankCode()); 318 } 319 } 320 321 return continueRules; 322 } 323 324 /** 325 * Returns true if wire transfer tab contains any data in any fields. 326 * 327 * @param dvWireTransfer disbursement voucher wire transfer 328 * @return true if wire transfer tab contains any data in any fields. 329 */ 330 protected boolean hasWireTransferValues(DisbursementVoucherWireTransfer dvWireTransfer) { 331 boolean hasValues = false; 332 333 // Checks each explicit field in the tab for user entered values 334 hasValues |= StringUtils.isNotBlank(dvWireTransfer.getDisbursementVoucherAutomatedClearingHouseProfileNumber()); 335 hasValues |= StringUtils.isNotBlank(dvWireTransfer.getDisbursementVoucherBankName()); 336 hasValues |= StringUtils.isNotBlank(dvWireTransfer.getDisbVchrBankRoutingNumber()); 337 hasValues |= StringUtils.isNotBlank(dvWireTransfer.getDisbVchrBankCityName()); 338 hasValues |= StringUtils.isNotBlank(dvWireTransfer.getDisbVchrBankStateCode()); 339 hasValues |= StringUtils.isNotBlank(dvWireTransfer.getDisbVchrBankCountryCode()); 340 hasValues |= StringUtils.isNotBlank(dvWireTransfer.getDisbVchrPayeeAccountNumber()); 341 hasValues |= StringUtils.isNotBlank(dvWireTransfer.getDisbVchrAttentionLineText()); 342 hasValues |= StringUtils.isNotBlank(dvWireTransfer.getDisbVchrCurrencyTypeName()); 343 hasValues |= StringUtils.isNotBlank(dvWireTransfer.getDisbVchrAdditionalWireText()); 344 hasValues |= StringUtils.isNotBlank(dvWireTransfer.getDisbursementVoucherPayeeAccountName()); 345 346 return hasValues; 347 } 348 349 /** 350 * This method sets all values in the passed in disbursement wire transfer object to null 351 * 352 * @param dvWireTransfer 353 */ 354 protected void clearWireTransferValues(DisbursementVoucherWireTransfer dvWireTransfer) { 355 dvWireTransfer.setDisbursementVoucherAutomatedClearingHouseProfileNumber(null); 356 dvWireTransfer.setDisbursementVoucherBankName(null); 357 dvWireTransfer.setDisbVchrBankRoutingNumber(null); 358 dvWireTransfer.setDisbVchrBankCityName(null); 359 dvWireTransfer.setDisbVchrBankStateCode(null); 360 dvWireTransfer.setDisbVchrBankCountryCode(null); 361 dvWireTransfer.setDisbVchrPayeeAccountNumber(null); 362 dvWireTransfer.setDisbVchrAttentionLineText(null); 363 dvWireTransfer.setDisbVchrCurrencyTypeName(null); 364 dvWireTransfer.setDisbVchrAdditionalWireText(null); 365 dvWireTransfer.setDisbursementVoucherPayeeAccountName(null); 366 } 367 368 /** 369 * put the valid payment reason codes along with their description together 370 * 371 * @param validPaymentReasonCodes the given valid payment reason codes 372 * @return the valid payment reason codes along with their description as a string 373 */ 374 protected String getValidPaymentReasonsAsString(List<String> validPaymentReasonCodes) { 375 List<String> payementReasonString = new ArrayList<String>(); 376 377 if (validPaymentReasonCodes == null || validPaymentReasonCodes.isEmpty()) { 378 return StringUtils.EMPTY; 379 } 380 381 List<KeyValue> reasons = new PaymentReasonValuesFinder().getKeyValues(); 382 for (KeyValue reason : reasons) { 383 if (validPaymentReasonCodes.contains(reason.getKey())) { 384 payementReasonString.add(reason.getValue()); 385 } 386 } 387 388 return payementReasonString.toString(); 389 } 390}