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    }