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    }