001 /** 002 * Copyright 2004-2013 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 */ 016 package org.kuali.hr.time.assignment.validation; 017 018 import java.sql.Date; 019 import java.util.Calendar; 020 import java.util.Collection; 021 import java.util.HashMap; 022 import java.util.HashSet; 023 import java.util.Iterator; 024 import java.util.List; 025 import java.util.Map; 026 import java.util.Set; 027 028 import org.apache.commons.lang.StringUtils; 029 import org.apache.commons.lang.time.DateUtils; 030 import org.kuali.hr.job.Job; 031 import org.kuali.hr.time.assignment.Assignment; 032 import org.kuali.hr.time.assignment.AssignmentAccount; 033 import org.kuali.hr.time.earncode.EarnCode; 034 import org.kuali.hr.time.paytype.PayType; 035 import org.kuali.hr.time.service.base.TkServiceLocator; 036 import org.kuali.hr.time.task.Task; 037 import org.kuali.hr.time.timeblock.TimeBlock; 038 import org.kuali.hr.time.util.TKUtils; 039 import org.kuali.hr.time.util.ValidationUtils; 040 import org.kuali.kfs.coa.businessobject.Account; 041 import org.kuali.kfs.coa.businessobject.ObjectCode; 042 import org.kuali.kfs.coa.businessobject.SubObjectCode; 043 import org.kuali.rice.kns.document.MaintenanceDocument; 044 import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase; 045 import org.kuali.rice.krad.bo.PersistableBusinessObject; 046 import org.kuali.rice.krad.service.KRADServiceLocator; 047 import org.kuali.rice.krad.util.GlobalVariables; 048 049 public class AssignmentRule extends MaintenanceDocumentRuleBase { 050 051 protected boolean validateWorkArea(Assignment assignment) { 052 boolean valid = true; 053 if (assignment.getWorkArea() != null) { 054 if (!ValidationUtils.validateWorkArea(assignment.getWorkArea(), 055 assignment.getEffectiveDate())) { 056 this.putFieldError("workArea", "error.existence", "workArea '" 057 + assignment.getWorkArea() + "'"); 058 valid = false; 059 } else { 060 int count = TkServiceLocator.getWorkAreaService().getWorkAreaCount(assignment.getDept(), assignment.getWorkArea()); 061 valid = (count > 0); 062 if (!valid) { 063 this.putFieldError("workArea", "dept.workarea.invalid.sync"); 064 } 065 } 066 } 067 return valid; 068 } 069 070 protected boolean validateTask(Assignment assignment) { 071 boolean valid = true; 072 //task by default is zero so if non zero validate against existing taskss 073 if (assignment.getTask() != null && !assignment.getTask().equals(0L)) { 074 Task task = TkServiceLocator.getTaskService().getTask(assignment.getTask(), assignment.getEffectiveDate()); 075 if(task != null) { 076 if(task.getWorkArea() == null || !task.getWorkArea().equals(assignment.getWorkArea())) { 077 this.putFieldError("task", "task.workarea.invalid.sync"); 078 valid = false; 079 } 080 } 081 } 082 return valid; 083 } 084 085 protected boolean validateDepartment(Assignment assignment) { 086 boolean valid = true; 087 if (assignment.getDept() != null) { 088 int count = TkServiceLocator.getJobService().getJobCount(null, assignment.getJobNumber(), assignment.getDept()); 089 valid = (count > 0); 090 if (!valid) { 091 this.putFieldError("dept", "dept.jobnumber.invalid.sync"); 092 } 093 094 } 095 return valid; 096 } 097 098 protected boolean validateJob(Assignment assignment) { 099 boolean valid = false; 100 LOG.debug("Validating job: " + assignment.getPrincipalId() +" Job number: "+assignment.getJobNumber()); 101 Job job = TkServiceLocator.getJobService().getJob( 102 assignment.getPrincipalId(), assignment.getJobNumber(), 103 assignment.getEffectiveDate(), false); 104 // Job job = 105 // KNSServiceLocator.getBusinessObjectService().findBySinglePrimaryKey(Job.class, 106 // assignment.getJob().getHrJobId()); 107 if (job != null) { 108 valid = true; 109 110 LOG.debug("found job."); 111 } else { 112 this.putFieldError("jobNumber", "error.existence", "jobNumber '" 113 + assignment.getJobNumber() + "'"); 114 } 115 return valid; 116 } 117 118 protected boolean validatePercentagePerEarnCode(Assignment assignment) { 119 boolean valid = true; 120 LOG.debug("Validating PercentagePerEarnCode: "); 121 List<AssignmentAccount> assignmentAccounts = assignment 122 .getAssignmentAccounts(); 123 Set<String> invalidEarnCodes = null; 124 if (assignmentAccounts != null && assignment.isActive()) { 125 Map<String, Integer> earnCodePercent = new HashMap<String, Integer>(); 126 for (AssignmentAccount account : assignmentAccounts) { 127 if (account.getPercent() != null && account.isActive()) { 128 int percent = 0; 129 if (earnCodePercent.containsKey(account.getEarnCode())) { 130 percent = earnCodePercent.get(account.getEarnCode()); 131 } 132 percent += account.getPercent().toBigInteger().intValue(); 133 earnCodePercent.put(account.getEarnCode(), percent); 134 } 135 } 136 Iterator<String> itr = earnCodePercent.keySet().iterator(); 137 while (itr.hasNext()) { 138 String earnCode = itr.next(); 139 if (earnCodePercent.get(earnCode) != 100) { 140 if (invalidEarnCodes == null) { 141 invalidEarnCodes = new HashSet<String>(); 142 } 143 invalidEarnCodes.add(earnCode); 144 valid = false; 145 } 146 } 147 if (!valid) { 148 int index = 0; 149 for (AssignmentAccount account : assignmentAccounts) { 150 if (invalidEarnCodes.contains(account.getEarnCode())) { 151 this.putFieldError("assignmentAccounts[" + index 152 + "].percent", "error.percentage.earncode"); 153 } 154 index++; 155 } 156 } 157 } 158 return valid; 159 } 160 161 protected boolean validateEarnCode(AssignmentAccount assignmentAccount) { 162 boolean valid = false; 163 LOG.debug("Validating EarnCode: " + assignmentAccount.getEarnCode()); 164 Date date = new Date(Calendar.getInstance().getTimeInMillis()); 165 EarnCode earnCode = TkServiceLocator.getEarnCodeService().getEarnCode( 166 assignmentAccount.getEarnCode(), date); 167 if (earnCode != null) { 168 169 valid = true; 170 LOG.debug("found earnCode."); 171 } else { 172 this.putGlobalError("error.existence", "earn code '" 173 + assignmentAccount.getEarnCode() + "'"); 174 } 175 return valid; 176 } 177 178 protected boolean validateRegPayEarnCode(Assignment assignment) { 179 boolean valid = false; 180 int index = 0; 181 LOG.debug("Validating Regular pay EarnCodes: " + assignment.getAssignmentAccounts().size()); 182 for(AssignmentAccount assignmentAccount : assignment.getAssignmentAccounts()){ 183 if(assignment.getJobNumber()!=null && assignment.getPrincipalId()!=null){ 184 Job job = TkServiceLocator.getJobService().getJob(assignment.getPrincipalId(), assignment.getJobNumber(), assignment.getEffectiveDate(), false); 185 if(job !=null){ 186 PayType payType = TkServiceLocator.getPayTypeService().getPayType(job.getHrPayType(), assignment.getEffectiveDate()); 187 if(StringUtils.equals(assignmentAccount.getEarnCode(), payType.getRegEarnCode())){ 188 valid = true; 189 break; 190 } 191 192 } 193 } 194 index++; 195 } 196 if(!valid) { 197 this.putFieldError("assignmentAccounts", "earncode.regular.pay.required"); 198 } 199 return valid; 200 } 201 202 protected boolean validateAccount(AssignmentAccount assignmentAccount) { 203 boolean valid = false; 204 LOG.debug("Validating Account: " + assignmentAccount.getAccountNbr()); 205 Map<String, String> fields = new HashMap<String, String>(); 206 fields.put("accountNumber", assignmentAccount.getAccountNbr()); 207 Collection account = KRADServiceLocator.getBusinessObjectService() 208 .findMatching(Account.class, fields); 209 valid = account.size() > 0; 210 if (!valid) { 211 this.putGlobalError("error.existence", "Account Number '" 212 + assignmentAccount.getAccountNbr() + "'"); 213 } 214 return valid; 215 } 216 217 protected boolean validateObjectCode(AssignmentAccount assignmentAccount) { 218 boolean valid = false; 219 LOG.debug("Validating ObjectCode: " 220 + assignmentAccount.getFinObjectCd()); 221 Map<String, String> fields = new HashMap<String, String>(); 222 fields.put("financialObjectCode", assignmentAccount.getFinObjectCd()); 223 Collection objectCode = KRADServiceLocator.getBusinessObjectService() 224 .findMatching(ObjectCode.class, fields); 225 valid = objectCode.size() > 0; 226 if (!valid) { 227 this.putGlobalError("error.existence", "Object Code '" 228 + assignmentAccount.getFinObjectCd() + "'"); 229 } 230 return valid; 231 } 232 233 protected boolean validateSubObjectCode(AssignmentAccount assignmentAccount) { 234 boolean valid = false; 235 LOG.debug("Validating SubObjectCode: " 236 + assignmentAccount.getFinSubObjCd()); 237 if (assignmentAccount.getFinSubObjCd() != null) { 238 Map<String, String> fields = new HashMap<String, String>(); 239 fields.put("financialSubObjectCode", assignmentAccount 240 .getFinSubObjCd()); 241 Collection subObjectCode = KRADServiceLocator.getBusinessObjectService() 242 .findMatching(SubObjectCode.class, fields); 243 valid = subObjectCode.size() > 0; 244 if (!valid) { 245 this.putGlobalError("error.existence", "SubObject Code '" 246 + assignmentAccount.getFinSubObjCd() + "'"); 247 } 248 } else { 249 valid = true; 250 } 251 return valid; 252 } 253 254 protected boolean validateHasAccounts(Assignment assign){ 255 if(assign.getAssignmentAccounts().isEmpty()){ 256 this.putGlobalError("error.assign.must.have.one.or.more.account"); 257 return false; 258 } 259 return true; 260 } 261 262 protected boolean validateActiveFlag(Assignment assign){ 263 if(!assign.isActive()) { 264 List<TimeBlock> tbList = TkServiceLocator.getTimeBlockService().getTimeBlocksForAssignment(assign); 265 if(!tbList.isEmpty()) { 266 Date tbEndDate = tbList.get(0).getEndDate(); 267 for(TimeBlock tb : tbList) { 268 if(tb.getEndDate().after(tbEndDate)) { 269 tbEndDate = tb.getEndDate(); // get the max end date 270 } 271 } 272 if(tbEndDate.equals(assign.getEffectiveDate()) || tbEndDate.after(assign.getEffectiveDate())) { 273 this.putFieldError("active", "error.assignment.timeblock.existence", tbEndDate.toString()); 274 return false; 275 } 276 } 277 } 278 return true; 279 } 280 281 /** 282 * It looks like the method that calls this class doesn't actually care 283 * about the return type. 284 */ 285 @Override 286 protected boolean processCustomRouteDocumentBusinessRules( 287 MaintenanceDocument document) { 288 boolean valid = false; 289 LOG.debug("entering custom validation for DeptLunchRule"); 290 PersistableBusinessObject pbo = (PersistableBusinessObject) this.getNewBo(); 291 if (pbo instanceof Assignment) { 292 Assignment assignment = (Assignment) pbo; 293 if (assignment != null) { 294 valid = true; 295 valid &= this.validateWorkArea(assignment); 296 valid &= this.validateTask(assignment); 297 valid &= this.validateJob(assignment); 298 valid &= this.validateDepartment(assignment); 299 valid &= this.validatePercentagePerEarnCode(assignment); 300 valid &= this.validateHasAccounts(assignment); 301 valid &= this.validateActiveFlag(assignment); 302 if(!assignment.getAssignmentAccounts().isEmpty()) { 303 valid &= this.validateRegPayEarnCode(assignment); 304 } 305 } 306 } 307 308 return valid; 309 } 310 311 @Override 312 public boolean processCustomAddCollectionLineBusinessRules( 313 MaintenanceDocument document, String collectionName, 314 PersistableBusinessObject line) { 315 boolean valid = false; 316 LOG.debug("entering custom validation for DeptLunchRule"); 317 PersistableBusinessObject pbo = line; 318 if (pbo instanceof AssignmentAccount) { 319 320 AssignmentAccount assignmentAccount = (AssignmentAccount) pbo; 321 if (assignmentAccount != null) { 322 valid = true; 323 valid &= this.validateEarnCode(assignmentAccount); 324 valid &= this.validateAccount(assignmentAccount); 325 valid &= this.validateObjectCode(assignmentAccount); 326 valid &= this.validateSubObjectCode(assignmentAccount); 327 } 328 } 329 return valid; 330 } 331 332 }