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    }