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