1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.kpme.pm.position.web;
17
18 import java.beans.IntrospectionException;
19 import java.beans.Introspector;
20 import java.beans.PropertyDescriptor;
21 import java.math.BigDecimal;
22 import java.util.*;
23
24 import org.apache.commons.collections.CollectionUtils;
25 import org.apache.commons.lang.StringUtils;
26 import org.kuali.kpme.core.api.department.Department;
27 import org.kuali.kpme.core.bo.HrBusinessObject;
28 import org.kuali.kpme.core.bo.HrDataObjectMaintainableImpl;
29 import org.kuali.kpme.core.bo.derived.HrBusinessObjectDerived;
30 import org.kuali.kpme.core.departmentaffiliation.DepartmentAffiliationBo;
31 import org.kuali.kpme.core.service.HrServiceLocator;
32 import org.kuali.kpme.core.util.ValidationUtils;
33 import org.kuali.kpme.pm.position.PositionBo;
34 import org.kuali.kpme.pm.position.PositionDutyBo;
35 import org.kuali.kpme.pm.position.PositionQualificationBo;
36 import org.kuali.kpme.pm.position.PstnFlagBo;
37 import org.kuali.kpme.pm.position.funding.PositionFundingBo;
38 import org.kuali.kpme.pm.positiondepartment.PositionDepartmentBo;
39 import org.kuali.kpme.pm.positionresponsibility.PositionResponsibilityBo;
40 import org.kuali.kpme.pm.service.base.PmServiceLocator;
41 import org.kuali.rice.kew.api.document.DocumentStatus;
42 import org.kuali.rice.kew.api.exception.WorkflowException;
43 import org.kuali.rice.kim.api.identity.principal.EntityNamePrincipalName;
44 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
45 import org.kuali.rice.kns.service.KNSServiceLocator;
46 import org.kuali.rice.krad.bo.DocumentHeader;
47 import org.kuali.rice.krad.bo.Note;
48 import org.kuali.rice.krad.maintenance.MaintenanceDocument;
49 import org.kuali.rice.krad.service.KRADServiceLocator;
50 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
51 import org.kuali.rice.krad.uif.container.CollectionGroup;
52 import org.kuali.rice.krad.uif.view.View;
53 import org.kuali.rice.krad.uif.view.ViewModel;
54 import org.kuali.rice.krad.util.GlobalVariables;
55 import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
56
57 public class PositionMaintainableServiceImpl extends HrDataObjectMaintainableImpl {
58
59 private static final long serialVersionUID = 1L;
60
61 @Override
62 public HrBusinessObject getObjectById(String id) {
63 return PositionBo.from(PmServiceLocator.getPositionService().getPosition(id));
64 }
65
66 @Override
67 public void customInactiveSaveLogicNewEffective(HrBusinessObject oldHrObj) {
68 PositionBo bo = (PositionBo)oldHrObj;
69 bo.setDepartmentList(null);
70 bo.setDutyList(null);
71 bo.setPositionResponsibilityList(null);
72 bo.setQualificationList(null);
73 bo.setFlagList(null);
74 bo.setFundingList(null);
75 bo.setRequiredQualList(null);
76 }
77
78 @Override
79 public void customSaveLogic(HrBusinessObject hrObj){
80 PositionBo aPosition = (PositionBo) hrObj;
81 for(PositionQualificationBo aQual : aPosition.getQualificationList()) {
82 aQual.setHrPositionId(aPosition.getHrPositionId());
83 aQual.setPmQualificationId(null);
84 }
85 for(PositionDutyBo aDuty : aPosition.getDutyList()) {
86 aDuty.setHrPositionId(aPosition.getHrPositionId());
87 aDuty.setPmDutyId(null);
88 }
89 for(PstnFlagBo aFlag : aPosition.getFlagList()) {
90 aFlag.setHrPositionId(aPosition.getHrPositionId());
91 aFlag.setPmFlagId(null);
92 }
93 for(PositionFundingBo aFunding : aPosition.getFundingList()) {
94 aFunding.setHrPositionId(aPosition.getHrPositionId());
95 aFunding.setPmPositionFunctionId(null);
96 }
97 for(PositionDepartmentBo aDepartment : aPosition.getDepartmentList()) {
98 aDepartment.setHrPositionId(aPosition.getHrPositionId());
99 aDepartment.setPmPositionDeptId(null);
100 }
101 for(PositionResponsibilityBo aResponsibility : aPosition.getPositionResponsibilityList()) {
102 aResponsibility.setHrPositionId(aPosition.getHrPositionId());
103 aResponsibility.setPositionResponsibilityId(null);
104 }
105
106
107
108
109 if (aPosition.getDepartmentList() != null) {
110 for(PositionDepartmentBo aPositionDepartment : aPosition.getDepartmentList()) {
111 if(aPositionDepartment != null && aPositionDepartment.getDeptAffl() != null) {
112 DepartmentAffiliationBo pda = (DepartmentAffiliationBo)aPositionDepartment.getDeptAfflObj();
113 if (pda.isPrimaryIndicator()) {
114 aPosition.setGroupKeyCode(aPositionDepartment.getGroupKeyCode());
115 break;
116 }
117 }
118 }
119 }
120
121 }
122
123 @Override
124 protected boolean performAddLineValidation(ViewModel viewModel, Object newLine, String collectionId,
125 String collectionPath) {
126 boolean isValid = super.performAddLineValidation(viewModel, newLine, collectionId, collectionPath);
127 if (viewModel instanceof MaintenanceDocumentForm) {
128 MaintenanceDocumentForm maintenanceForm = (MaintenanceDocumentForm) viewModel;
129 MaintenanceDocument document = maintenanceForm.getDocument();
130 if (document.getNewMaintainableObject().getDataObject() instanceof PositionBo) {
131 PositionBo aPosition = (PositionBo) document.getNewMaintainableObject().getDataObject();
132
133 if (newLine instanceof PositionDutyBo) {
134 PositionDutyBo pd = (PositionDutyBo) newLine;
135 boolean results = this.validateDutyListPercentage(pd, aPosition);
136 if(!results) {
137 return false;
138 }
139 }
140
141 if (newLine instanceof PositionFundingBo) {
142 PositionFundingBo pf = (PositionFundingBo) newLine;
143 boolean results = this.validateAddFundingLine(pf, aPosition);
144 if(!results) {
145 return false;
146 }
147 }
148
149
150 if(newLine instanceof PositionResponsibilityBo) {
151 PositionResponsibilityBo pr = (PositionResponsibilityBo) newLine;
152 boolean results = this.validatePositionResponsibilityListPercentage(pr, aPosition);
153 if(!results) {
154 return false;
155 }
156 }
157
158
159 if(newLine instanceof PositionDepartmentBo) {
160 PositionDepartmentBo pd = (PositionDepartmentBo) newLine;
161 boolean results = this.validateAdditionalDepartmentList(pd,aPosition);
162 if(!results){
163 return false;
164 }
165 }
166 }
167 }
168
169 return isValid;
170 }
171
172 private boolean validateAdditionalDepartmentList(PositionDepartmentBo pd,
173 PositionBo aPosition) {
174
175
176 if(aPosition.getEffectiveLocalDate()!=null && pd != null){
177 Department department = HrServiceLocator.getDepartmentService().getDepartment(pd.getDepartment(), pd.getGroupKeyCode(), aPosition.getEffectiveLocalDate());
178 if(department == null){
179 GlobalVariables.getMessageMap().putError("newCollectionLines['document.newMaintainableObject.dataObject.departmentList'].department", "error.existence", "Position Department '" + pd.getDepartment() + "'");
180 return false;
181 }
182 }
183
184 return true;
185 }
186
187 private boolean validateDutyListPercentage(PositionDutyBo pd, PositionBo aPosition) {
188 if(CollectionUtils.isNotEmpty(aPosition.getDutyList()) && pd.getPercentage() != null) {
189 BigDecimal sum = pd.getPercentage();
190 for(PositionDutyBo aDuty : aPosition.getDutyList()) {
191 if(aDuty != null && aDuty.getPercentage() != null) {
192 sum = sum.add(aDuty.getPercentage());
193 }
194 }
195 if(sum.compareTo(new BigDecimal(100)) > 0) {
196 GlobalVariables.getMessageMap().putError("newCollectionLines['document.newMaintainableObject.dataObject.dutyList'].percentage", "duty.percentage.exceedsMaximum", sum.toString());
197 return false;
198 }
199 }
200 return true;
201 }
202
203 private boolean validatePositionResponsibilityListPercentage(PositionResponsibilityBo pd, PositionBo aPosition) {
204 if(CollectionUtils.isNotEmpty(aPosition.getPositionResponsibilityList()) && pd.getPercentTime() != null) {
205 BigDecimal sum = pd.getPercentTime();
206 for(PositionResponsibilityBo aResponsibility : aPosition.getPositionResponsibilityList()) {
207 if(aResponsibility != null && aResponsibility.getPercentTime() != null) {
208 sum = sum.add(aResponsibility.getPercentTime());
209 }
210 }
211 if(sum.compareTo(new BigDecimal(100)) > 0) {
212 GlobalVariables.getMessageMap().putError("newCollectionLines['document.newMaintainableObject.dataObject.positionResponsibilityList'].percentTime", "responsibility.percenttime.exceedsMaximum", sum.toString());
213 return false;
214 }
215 }
216 return true;
217 }
218
219 protected boolean validateAddFundingLine(PositionFundingBo pf, PositionBo aPosition) {
220 if(StringUtils.isNotEmpty(pf.getAccount())) {
221 boolean results = ValidationUtils.validateAccount(pf.getChart(), pf.getAccount());
222 if(!results) {
223 GlobalVariables.getMessageMap().putError("newCollectionLines['document.newMaintainableObject.dataObject.fundingList'].account","error.existence", "Account '" + pf.getAccount() + "'");
224 return results;
225 }
226 }
227 if(StringUtils.isNotEmpty(pf.getSubAccount())) {
228 boolean results = ValidationUtils.validateSubAccount(pf.getSubAccount(), pf.getAccount(), pf.getChart());
229 if(!results) {
230 GlobalVariables.getMessageMap().putError("newCollectionLines['document.newMaintainableObject.dataObject.fundingList'].subAccount","error.existence", "Sub Account '" + pf.getSubAccount() + "'");
231 return results;
232 }
233 }
234 if(StringUtils.isNotEmpty(pf.getObjectCode())) {
235 boolean results = ValidationUtils.validateObjectCode(pf.getObjectCode(), pf.getChart(), null);
236 if(!results) {
237 GlobalVariables.getMessageMap().putError("newCollectionLines['document.newMaintainableObject.dataObject.fundingList'].objectCode","error.existence", "Object Code '" + pf.getObjectCode() + "'");
238 return results;
239 }
240 }
241 if(StringUtils.isNotEmpty(pf.getSubObjectCode())) {
242 boolean results = ValidationUtils.validateSubObjectCode(null,
243 pf.getChart(),
244 pf.getAccount(),
245 pf.getObjectCode(),
246 pf.getSubObjectCode());
247 if(!results) {
248 GlobalVariables.getMessageMap().putError("newCollectionLines['document.newMaintainableObject.dataObject.fundingList'].subObjectCode","error.existence", "Sub Object Code '" + pf.getSubObjectCode() + "'");
249 return results;
250 }
251 }
252 return true;
253
254 }
255
256
257
258
259 @Override
260 public void processAfterEdit(MaintenanceDocument document, Map<String, String[]> requestParameters) {
261 document.getDocumentHeader().setDocumentDescription("Edit Position");
262 super.processAfterEdit(document, requestParameters);
263 }
264
265
266 protected void setupNewPositionRecord(MaintenanceDocument document) {
267 PositionBo aPosition = (PositionBo) document.getNewMaintainableObject().getDataObject();
268 aPosition.setProcess("New");
269 String positionNumber = KNSServiceLocator.getSequenceAccessorService().getNextAvailableSequenceNumber("hr_position_s", PositionBo.class).toString();
270 aPosition.setPositionNumber(positionNumber);
271
272 document.getDocumentHeader().setDocumentDescription("New Position");
273 }
274
275
276 @Override
277 public void processAfterNew(MaintenanceDocument document, Map<String, String[]> requestParameters) {
278 setupNewPositionRecord(document);
279 super.processAfterNew(document, requestParameters);
280 }
281
282 @Override
283 public void processAfterCopy(MaintenanceDocument document, Map<String, String[]> parameters) {
284 setupNewPositionRecord(document);
285 super.processAfterCopy(document, parameters);
286 }
287
288 @Override
289 public String getDocumentTitle(MaintenanceDocument document) {
290 String docTitle = document.getDocumentHeader().getDocumentDescription();
291 return docTitle;
292 }
293
294 @Override
295 public void doRouteStatusChange(DocumentHeader documentHeader) {
296
297 String docDescription = null;
298 PositionBo position = (PositionBo)this.getDataObject();
299 DocumentStatus documentStatus = documentHeader.getWorkflowDocument().getStatus();
300
301
302 if (StringUtils.isEmpty(position.getPositionNumber())) {
303 docDescription = "Process: " + position.getProcess() + " Position Status: " + position.getPositionStatus();
304 } else {
305 docDescription = "Process: " + position.getProcess() + " Position Number: " + position.getPositionNumber() + " Position Status: " + position.getPositionStatus();
306 }
307
308 if (DocumentStatus.ENROUTE.equals(documentStatus)) {
309 try {
310 MaintenanceDocument md = (MaintenanceDocument)KRADServiceLocatorWeb.getDocumentService().getByDocumentHeaderId(documentHeader.getDocumentNumber());
311 md.getDocumentHeader().setDocumentDescription(docDescription);
312 md.getNewMaintainableObject().setDataObject(position);
313 KRADServiceLocatorWeb.getDocumentService().saveDocument(md);
314 } catch (WorkflowException e) {
315 LOG.error("caught exception while handling doRouteStatusChange -> documentService.getByDocumentHeaderId(" + documentHeader.getDocumentNumber() + "). ", e);
316 throw new RuntimeException("caught exception while handling doRouteStatusChange -> documentService.getByDocumentHeaderId(" + documentHeader.getDocumentNumber() + "). ", e);
317 }
318 }
319 }
320
321
322 @Override
323 public void prepareForSave() {
324 PositionBo position = (PositionBo)this.getDataObject();
325 boolean hasPrimaryDepartment = false;
326 for (PositionDepartmentBo positionDepartment : position.getDepartmentList()) {
327 if (positionDepartment.getDeptAfflObj().isPrimaryIndicator()) {
328 hasPrimaryDepartment=true;
329 positionDepartment.setDepartment(position.getPrimaryDepartment());
330 positionDepartment.setGroupKeyCode(position.getGroupKeyCode());
331
332
333 positionDepartment.setDeptAffl(HrServiceLocator.getDepartmentAffiliationService().getPrimaryAffiliation().getDeptAfflType());
334 }
335 }
336
337
338 if (!hasPrimaryDepartment && StringUtils.isNotEmpty(position.getPrimaryDepartment())) {
339 PositionDepartmentBo primaryDepartment = new PositionDepartmentBo();
340 primaryDepartment.setDepartment(position.getPrimaryDepartment());
341 primaryDepartment.setGroupKeyCode(position.getGroupKeyCode());
342
343
344 primaryDepartment.setDeptAffl(HrServiceLocator.getDepartmentAffiliationService().getPrimaryAffiliation().getDeptAfflType());
345 position.getDepartmentList().add(primaryDepartment);
346 }
347
348
349 try {
350 MaintenanceDocument maintenanceDocument = (MaintenanceDocument) KRADServiceLocatorWeb.getDocumentService().getByDocumentHeaderId(this.getDocumentNumber());
351 if (maintenanceDocument != null && maintenanceDocument.getNewMaintainableObject().getDataObject() instanceof PositionBo) {
352 PositionBo previousPosition = (PositionBo) maintenanceDocument.getNewMaintainableObject().getDataObject();
353 recordEnrouteChanges(previousPosition,maintenanceDocument.getNoteTarget().getObjectId());
354 }
355 } catch (Exception e) {
356 e.printStackTrace();
357 }
358
359 super.prepareForSave();
360
361
362 }
363
364 private void recordEnrouteChanges(PositionBo previousPosition, String noteTarget) {
365
366 List<String> noCompareFields = new ArrayList<String>();
367 noCompareFields.add("process");
368 noCompareFields.add("requiredQualList");
369
370 List<Note> noteList = new ArrayList<Note>();
371 PositionBo currentPosition = (PositionBo) this.getDataObject();
372
373 EntityNamePrincipalName approver = KimApiServiceLocator.getIdentityService().getDefaultNamesForPrincipalId(currentPosition.getUserPrincipalId());
374
375
376 try {
377 for (PropertyDescriptor pd : Introspector.getBeanInfo(PositionBo.class).getPropertyDescriptors()) {
378
379 if (pd.getReadMethod() != null && !noCompareFields.contains(pd.getName())) {
380 try {
381 Object currentObject = pd.getReadMethod().invoke(currentPosition);
382 Object previousObject = pd.getReadMethod().invoke(previousPosition);
383 if (currentObject instanceof Collection) {
384 if (!compareCollections(currentObject,previousObject)) {
385 String noteText = approver.getPrincipalName() + " changed " + pd.getDisplayName() + " from '" + previousObject.toString() + "' to '" + currentObject.toString() + "'";
386 noteList.add(createNote(noteText,noteTarget,currentPosition.getUserPrincipalId()));
387 }
388 } else {
389 if (!(currentObject == null ? previousObject == null : currentObject.equals(previousObject))){
390 String noteText = approver.getPrincipalName() + " changed " + pd.getDisplayName() + " from '" + previousObject.toString() + "' to '" + currentObject.toString() + "'";
391 noteList.add(createNote(noteText,noteTarget,currentPosition.getUserPrincipalId()));
392 }
393 }
394
395 } catch (Exception e) {
396 e.printStackTrace();
397 }
398 }
399 }
400 } catch (IntrospectionException e) {
401 e.printStackTrace();
402 }
403
404 KRADServiceLocator.getNoteService().saveNoteList(noteList);
405 }
406
407 @SuppressWarnings("rawtypes")
408 public boolean compareCollections(Object coll1, Object coll2) {
409 if (coll1 == coll2)
410 return true;
411
412 if (coll1 instanceof List && coll2 instanceof List) {
413 ListIterator list1 = ((List) coll1).listIterator();
414 ListIterator list2 = ((List) coll2).listIterator();
415 while (list1.hasNext() && list2.hasNext()) {
416 Object o1 = list1.next();
417 Object o2 = list2.next();
418
419 if (o1 instanceof HrBusinessObjectDerived && o1 instanceof HrBusinessObjectDerived) {
420 HrBusinessObjectDerived hrObj1 = (HrBusinessObjectDerived) o1;
421 HrBusinessObjectDerived hrObj2 = (HrBusinessObjectDerived) o2;
422 if (!(hrObj1 == null ? hrObj2 == null : hrObj1.isEquivalentTo(hrObj2)))
423 return false;
424 } else {
425 if (!(o1 == null ? o2 == null : o1.equals(o2)))
426 return false;
427 }
428 }
429
430 return !(list1.hasNext() || list2.hasNext());
431 } else {
432
433 return coll1.equals(coll2);
434 }
435 }
436
437 private Note createNote(String noteText, String noteTarget, String principalId) {
438 Note note = new Note();
439 note.setRemoteObjectIdentifier(noteTarget);
440 note.setNoteText(StringUtils.abbreviate(noteText,800));
441 note.setAuthorUniversalIdentifier(principalId);
442 note.setNotePostedTimestampToCurrent();
443 return note;
444 }
445
446 }