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 for (Map.Entry<String, Integer> entry : earnCodePercent.entrySet()) {
138 //while (itr.hasNext()) {
139 String earnCode = entry.getKey();
140 if (entry.getValue() != 100) {
141 if (invalidEarnCodes == null) {
142 invalidEarnCodes = new HashSet<String>();
143 }
144 invalidEarnCodes.add(earnCode);
145 valid = false;
146 }
147 }
148 if (!valid) {
149 int index = 0;
150 for (AssignmentAccount account : assignmentAccounts) {
151 if (invalidEarnCodes.contains(account.getEarnCode())) {
152 this.putFieldError("assignmentAccounts[" + index
153 + "].percent", "error.percentage.earncode");
154 }
155 index++;
156 }
157 }
158 }
159 return valid;
160 }
161
162 protected boolean validateEarnCode(AssignmentAccount assignmentAccount) {
163 boolean valid = false;
164 LOG.debug("Validating EarnCode: " + assignmentAccount.getEarnCode());
165 Date date = new Date(Calendar.getInstance().getTimeInMillis());
166 EarnCode earnCode = TkServiceLocator.getEarnCodeService().getEarnCode(
167 assignmentAccount.getEarnCode(), date);
168 if (earnCode != null) {
169
170 valid = true;
171 LOG.debug("found earnCode.");
172 } else {
173 this.putGlobalError("error.existence", "earn code '"
174 + assignmentAccount.getEarnCode() + "'");
175 }
176 return valid;
177 }
178
179 protected boolean validateRegPayEarnCode(Assignment assignment) {
180 boolean valid = false;
181 int index = 0;
182 LOG.debug("Validating Regular pay EarnCodes: " + assignment.getAssignmentAccounts().size());
183 for(AssignmentAccount assignmentAccount : assignment.getAssignmentAccounts()){
184 if(assignment.getJobNumber()!=null && assignment.getPrincipalId()!=null){
185 Job job = TkServiceLocator.getJobService().getJob(assignment.getPrincipalId(), assignment.getJobNumber(), assignment.getEffectiveDate(), false);
186 if(job !=null){
187 PayType payType = TkServiceLocator.getPayTypeService().getPayType(job.getHrPayType(), assignment.getEffectiveDate());
188 if(StringUtils.equals(assignmentAccount.getEarnCode(), payType.getRegEarnCode())){
189 valid = true;
190 break;
191 }
192
193 }
194 }
195 index++;
196 }
197 if(!valid) {
198 this.putFieldError("assignmentAccounts", "earncode.regular.pay.required");
199 }
200 return valid;
201 }
202
203 protected boolean validateAccount(AssignmentAccount assignmentAccount) {
204 boolean valid = false;
205 LOG.debug("Validating Account: " + assignmentAccount.getAccountNbr());
206 Map<String, String> fields = new HashMap<String, String>();
207 fields.put("accountNumber", assignmentAccount.getAccountNbr());
208 Collection account = KRADServiceLocator.getBusinessObjectService()
209 .findMatching(Account.class, fields);
210 valid = account.size() > 0;
211 if (!valid) {
212 this.putGlobalError("error.existence", "Account Number '"
213 + assignmentAccount.getAccountNbr() + "'");
214 }
215 return valid;
216 }
217
218 protected boolean validateObjectCode(AssignmentAccount assignmentAccount) {
219 boolean valid = false;
220 LOG.debug("Validating ObjectCode: "
221 + assignmentAccount.getFinObjectCd());
222 Map<String, String> fields = new HashMap<String, String>();
223 fields.put("financialObjectCode", assignmentAccount.getFinObjectCd());
224 Collection objectCode = KRADServiceLocator.getBusinessObjectService()
225 .findMatching(ObjectCode.class, fields);
226 valid = objectCode.size() > 0;
227 if (!valid) {
228 this.putGlobalError("error.existence", "Object Code '"
229 + assignmentAccount.getFinObjectCd() + "'");
230 }
231 return valid;
232 }
233
234 protected boolean validateSubObjectCode(AssignmentAccount assignmentAccount) {
235 boolean valid = false;
236 LOG.debug("Validating SubObjectCode: "
237 + assignmentAccount.getFinSubObjCd());
238 if (assignmentAccount.getFinSubObjCd() != null) {
239 Map<String, String> fields = new HashMap<String, String>();
240 fields.put("financialSubObjectCode", assignmentAccount
241 .getFinSubObjCd());
242 Collection subObjectCode = KRADServiceLocator.getBusinessObjectService()
243 .findMatching(SubObjectCode.class, fields);
244 valid = subObjectCode.size() > 0;
245 if (!valid) {
246 this.putGlobalError("error.existence", "SubObject Code '"
247 + assignmentAccount.getFinSubObjCd() + "'");
248 }
249 } else {
250 valid = true;
251 }
252 return valid;
253 }
254
255 protected boolean validateHasAccounts(Assignment assign){
256 if(assign.getAssignmentAccounts().isEmpty()){
257 this.putGlobalError("error.assign.must.have.one.or.more.account");
258 return false;
259 }
260 return true;
261 }
262
263 protected boolean validateActiveFlag(Assignment assign){
264 if(!assign.isActive()) {
265 List<TimeBlock> tbList = TkServiceLocator.getTimeBlockService().getTimeBlocksForAssignment(assign);
266 if(!tbList.isEmpty()) {
267 Date tbEndDate = tbList.get(0).getEndDate();
268 for(TimeBlock tb : tbList) {
269 if(tb.getEndDate().after(tbEndDate)) {
270 tbEndDate = tb.getEndDate(); // get the max end date
271 }
272 }
273 if(tbEndDate.equals(assign.getEffectiveDate()) || tbEndDate.after(assign.getEffectiveDate())) {
274 this.putFieldError("active", "error.assignment.timeblock.existence", tbEndDate.toString());
275 return false;
276 }
277 }
278 }
279 return true;
280 }
281
282 /**
283 * It looks like the method that calls this class doesn't actually care
284 * about the return type.
285 */
286 @Override
287 protected boolean processCustomRouteDocumentBusinessRules(
288 MaintenanceDocument document) {
289 boolean valid = false;
290 LOG.debug("entering custom validation for DeptLunchRule");
291 PersistableBusinessObject pbo = (PersistableBusinessObject) this.getNewBo();
292 if (pbo instanceof Assignment) {
293 Assignment assignment = (Assignment) pbo;
294 if (assignment != null) {
295 valid = true;
296 valid &= this.validateWorkArea(assignment);
297 valid &= this.validateTask(assignment);
298 valid &= this.validateJob(assignment);
299 valid &= this.validateDepartment(assignment);
300 valid &= this.validatePercentagePerEarnCode(assignment);
301 valid &= this.validateHasAccounts(assignment);
302 valid &= this.validateActiveFlag(assignment);
303 if(!assignment.getAssignmentAccounts().isEmpty()) {
304 valid &= this.validateRegPayEarnCode(assignment);
305 }
306 }
307 }
308
309 return valid;
310 }
311
312 @Override
313 public boolean processCustomAddCollectionLineBusinessRules(
314 MaintenanceDocument document, String collectionName,
315 PersistableBusinessObject line) {
316 boolean valid = false;
317 LOG.debug("entering custom validation for DeptLunchRule");
318 PersistableBusinessObject pbo = line;
319 if (pbo instanceof AssignmentAccount) {
320
321 AssignmentAccount assignmentAccount = (AssignmentAccount) pbo;
322 if (assignmentAccount != null) {
323 valid = true;
324 valid &= this.validateEarnCode(assignmentAccount);
325 valid &= this.validateAccount(assignmentAccount);
326 valid &= this.validateObjectCode(assignmentAccount);
327 valid &= this.validateSubObjectCode(assignmentAccount);
328 }
329 }
330 return valid;
331 }
332
333 }