1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.ole.coa.service.impl;
17
18 import java.text.MessageFormat;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.HashMap;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Map;
25
26 import org.apache.commons.lang.StringUtils;
27 import org.apache.log4j.Logger;
28 import org.kuali.ole.coa.businessobject.Account;
29 import org.kuali.ole.coa.businessobject.ObjectCode;
30 import org.kuali.ole.coa.businessobject.SubObjectCode;
31 import org.kuali.ole.coa.service.SubObjectTrickleDownInactivationService;
32 import org.kuali.ole.sys.OLEKeyConstants;
33 import org.kuali.ole.sys.OLEPropertyConstants;
34 import org.kuali.ole.sys.service.UniversityDateService;
35 import org.kuali.rice.core.api.config.property.ConfigurationService;
36 import org.kuali.rice.kns.maintenance.Maintainable;
37 import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
38 import org.kuali.rice.krad.bo.DocumentHeader;
39 import org.kuali.rice.krad.bo.Note;
40 import org.kuali.rice.krad.bo.PersistableBusinessObject;
41 import org.kuali.rice.krad.dao.MaintenanceDocumentDao;
42 import org.kuali.rice.krad.maintenance.MaintenanceLock;
43 import org.kuali.rice.krad.service.BusinessObjectService;
44 import org.kuali.rice.krad.service.DocumentHeaderService;
45 import org.kuali.rice.krad.service.NoteService;
46 import org.kuali.rice.krad.util.GlobalVariables;
47 import org.springframework.transaction.annotation.Transactional;
48
49 @Transactional
50 public class SubObjectTrickleDownInactivationServiceImpl implements SubObjectTrickleDownInactivationService {
51
52
53 private static final int NO_OF_SUB_OBJECTS_PER_NOTE = 15;
54
55 private static final Logger LOG = Logger.getLogger(SubObjectTrickleDownInactivationServiceImpl.class);
56
57 protected BusinessObjectService businessObjectService;
58 protected MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
59 protected MaintenanceDocumentDao maintenanceDocumentDao;
60 protected NoteService noteService;
61 protected ConfigurationService kualiConfigurationService;
62 protected UniversityDateService universityDateService;
63 protected DocumentHeaderService documentHeaderService;
64
65 public List<MaintenanceLock> generateTrickleDownMaintenanceLocks(Account inactivatedAccount, String documentNumber) {
66 Collection<SubObjectCode> subObjects = getAssociatedSubObjects(inactivatedAccount);
67 List<MaintenanceLock> maintenanceLocks = generateTrickleDownMaintenanceLocks(subObjects, documentNumber);
68 return maintenanceLocks;
69 }
70
71 public List<MaintenanceLock> generateTrickleDownMaintenanceLocks(ObjectCode inactivatedObjectCode, String documentNumber) {
72 Collection<SubObjectCode> subObjects = getAssociatedSubObjects(inactivatedObjectCode);
73 List<MaintenanceLock> maintenanceLocks = generateTrickleDownMaintenanceLocks(subObjects, documentNumber);
74 return maintenanceLocks;
75 }
76
77 public List<MaintenanceLock> generateTrickleDownMaintenanceLocks(Collection<SubObjectCode> subObjects, String documentNumber) {
78 Maintainable subObjectMaintainable = getSubObjectMaintainable(documentNumber);
79 List<MaintenanceLock> maintenanceLocks = new ArrayList<MaintenanceLock>();
80 for (SubObjectCode subObjCd : subObjects) {
81 subObjectMaintainable.setBusinessObject(subObjCd);
82 maintenanceLocks.addAll(subObjectMaintainable.generateMaintenanceLocks());
83 }
84 return maintenanceLocks;
85 }
86
87 protected class TrickleDownInactivationStatus {
88 public List<SubObjectCode> inactivatedSubObjCds;
89 public Map<SubObjectCode, String> alreadyLockedSubObjCds;
90 public List<SubObjectCode> errorPersistingSubObjCds;
91
92 public TrickleDownInactivationStatus() {
93 inactivatedSubObjCds = new ArrayList<SubObjectCode>();
94 alreadyLockedSubObjCds = new HashMap<SubObjectCode, String>();
95 errorPersistingSubObjCds = new ArrayList<SubObjectCode>();
96 }
97 }
98
99 public void trickleDownInactivateSubObjects(Account inactivatedAccount, String documentNumber) {
100 Collection<SubObjectCode> subObjects = getAssociatedSubObjects(inactivatedAccount);
101 TrickleDownInactivationStatus trickleDownInactivationStatus = trickleDownInactivate(subObjects, documentNumber);
102 addNotesToDocument(trickleDownInactivationStatus, documentNumber);
103 }
104
105 public void trickleDownInactivateSubObjects(ObjectCode inactivatedObject, String documentNumber) {
106 Collection<SubObjectCode> subObjects = getAssociatedSubObjects(inactivatedObject);
107 TrickleDownInactivationStatus trickleDownInactivationStatus = trickleDownInactivate(subObjects, documentNumber);
108 addNotesToDocument(trickleDownInactivationStatus, documentNumber);
109 }
110
111 protected TrickleDownInactivationStatus trickleDownInactivate(Collection<SubObjectCode> subObjects, String documentNumber) {
112 TrickleDownInactivationStatus trickleDownInactivationStatus = new TrickleDownInactivationStatus();
113
114 if (subObjects != null && !subObjects.isEmpty()) {
115 Maintainable subObjectMaintainable = getSubObjectMaintainable(documentNumber);
116 for (Iterator<SubObjectCode> i = subObjects.iterator(); i.hasNext(); ) {
117 SubObjectCode subObjCd = i.next();
118 if (subObjCd.isActive()) {
119 subObjectMaintainable.setBusinessObject(subObjCd);
120 List<MaintenanceLock> subAccountLocks = subObjectMaintainable.generateMaintenanceLocks();
121
122 MaintenanceLock failedLock = verifyAllLocksFromThisDocument(subAccountLocks, documentNumber);
123 if (failedLock != null) {
124
125 trickleDownInactivationStatus.alreadyLockedSubObjCds.put(subObjCd, failedLock.getDocumentNumber());
126 }
127 else {
128
129 subObjCd.setActive(false);
130
131 try {
132 subObjectMaintainable.saveBusinessObject();
133 trickleDownInactivationStatus.inactivatedSubObjCds.add(subObjCd);
134 }
135 catch (RuntimeException e) {
136 LOG.error("Unable to trickle-down inactivate sub-account " + subObjCd.toString(), e);
137 trickleDownInactivationStatus.errorPersistingSubObjCds.add(subObjCd);
138 }
139 }
140 }
141 }
142 }
143
144 return trickleDownInactivationStatus;
145 }
146
147 protected void addNotesToDocument(TrickleDownInactivationStatus trickleDownInactivationStatus, String documentNumber) {
148 if (trickleDownInactivationStatus.inactivatedSubObjCds.isEmpty() && trickleDownInactivationStatus.alreadyLockedSubObjCds.isEmpty() && trickleDownInactivationStatus.errorPersistingSubObjCds.isEmpty()) {
149
150 return;
151 }
152 DocumentHeader noteParent = documentHeaderService.getDocumentHeaderById(documentNumber);
153 Note newNote = new Note();
154
155 addNotes(documentNumber, trickleDownInactivationStatus.inactivatedSubObjCds, OLEKeyConstants.SUB_OBJECT_TRICKLE_DOWN_INACTIVATION, noteParent, newNote);
156 addNotes(documentNumber, trickleDownInactivationStatus.errorPersistingSubObjCds, OLEKeyConstants.SUB_OBJECT_TRICKLE_DOWN_INACTIVATION_ERROR_DURING_PERSISTENCE, noteParent, newNote);
157 addMaintenanceLockedNotes(documentNumber, trickleDownInactivationStatus.alreadyLockedSubObjCds, OLEKeyConstants.SUB_OBJECT_TRICKLE_DOWN_INACTIVATION_RECORD_ALREADY_MAINTENANCE_LOCKED, noteParent, newNote);
158 }
159
160 protected MaintenanceLock verifyAllLocksFromThisDocument(List<MaintenanceLock> maintenanceLocks, String documentNumber) {
161 for (MaintenanceLock maintenanceLock : maintenanceLocks) {
162 String lockingDocNumber = maintenanceDocumentDao.getLockingDocumentNumber(maintenanceLock.getLockingRepresentation(), documentNumber);
163 if (StringUtils.isNotBlank(lockingDocNumber)) {
164 return maintenanceLock;
165 }
166 }
167 return null;
168 }
169
170 protected Maintainable getSubObjectMaintainable(String documentNumber) {
171 Maintainable subObjectMaintainable;
172 try {
173 subObjectMaintainable = (Maintainable) maintenanceDocumentDictionaryService.getMaintainableClass(SubObjectCode.class.getName()).newInstance();
174 subObjectMaintainable.setBoClass(SubObjectCode.class);
175 subObjectMaintainable.setDocumentNumber(documentNumber);
176 }
177 catch (Exception e) {
178 LOG.error("Unable to instantiate SubObject Maintainable" , e);
179 throw new RuntimeException("Unable to instantiate SubObject Maintainable" , e);
180 }
181 return subObjectMaintainable;
182 }
183
184 protected Collection<SubObjectCode> getAssociatedSubObjects(Account account) {
185 Map<String, Object> fieldValues = new HashMap<String, Object>();
186 fieldValues.put(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, universityDateService.getCurrentFiscalYear());
187 fieldValues.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, account.getChartOfAccountsCode());
188 fieldValues.put(OLEPropertyConstants.ACCOUNT_NUMBER, account.getAccountNumber());
189 return businessObjectService.findMatching(SubObjectCode.class, fieldValues);
190 }
191
192 protected Collection<SubObjectCode> getAssociatedSubObjects(ObjectCode objectCode) {
193 Map<String, Object> fieldValues = new HashMap<String, Object>();
194 fieldValues.put(OLEPropertyConstants.UNIVERSITY_FISCAL_YEAR, objectCode.getUniversityFiscalYear());
195 fieldValues.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, objectCode.getChartOfAccountsCode());
196 fieldValues.put(OLEPropertyConstants.FINANCIAL_OBJECT_CODE, objectCode.getFinancialObjectCode());
197 return businessObjectService.findMatching(SubObjectCode.class, fieldValues);
198 }
199
200 protected void addNotes(String documentNumber, List<SubObjectCode> listOfSubObjects, String messageKey, PersistableBusinessObject noteParent, Note noteTemplate) {
201 for (int i = 0; i < listOfSubObjects.size(); i += getNumSubObjectsPerNote()) {
202 try {
203 String subAccountString = createSubObjectChunk(listOfSubObjects, i, i + getNumSubObjectsPerNote());
204 if (StringUtils.isNotBlank(subAccountString)) {
205 String noteTextTemplate = kualiConfigurationService.getPropertyValueAsString(messageKey);
206 String noteText = MessageFormat.format(noteTextTemplate, subAccountString);
207 Note note = noteService.createNote(noteTemplate, noteParent, GlobalVariables.getUserSession().getPrincipalId());
208 note.setNoteText(noteText);
209 note.setNotePostedTimestampToCurrent();
210 noteService.save(note);
211 }
212 }
213 catch (Exception e) {
214 LOG.error("Unable to create/save notes for document " + documentNumber, e);
215 throw new RuntimeException("Unable to create/save notes for document " + documentNumber, e);
216 }
217 }
218 }
219
220 protected void addMaintenanceLockedNotes(String documentNumber, Map<SubObjectCode, String> lockedSubObjects, String messageKey, PersistableBusinessObject noteParent, Note noteTemplate) {
221 for (Map.Entry<SubObjectCode, String> entry : lockedSubObjects.entrySet()) {
222 try {
223 SubObjectCode subObjCd = entry.getKey();
224 String subObjectString = subObjCd.getUniversityFiscalYear() + " - " + subObjCd.getChartOfAccountsCode() + " - " + subObjCd.getAccountNumber() + " - " + subObjCd.getFinancialObjectCode() + " - " + subObjCd.getFinancialSubObjectCode();
225 if (StringUtils.isNotBlank(subObjectString)) {
226 String noteTextTemplate = kualiConfigurationService.getPropertyValueAsString(messageKey);
227 String noteText = MessageFormat.format(noteTextTemplate, subObjectString, entry.getValue());
228 Note note = noteService.createNote(noteTemplate, noteParent, GlobalVariables.getUserSession().getPrincipalId());
229 note.setNoteText(noteText);
230 note.setNotePostedTimestampToCurrent();
231 noteService.save(note);
232 }
233 }
234 catch (Exception e) {
235 LOG.error("Unable to create/save notes for document " + documentNumber, e);
236 throw new RuntimeException("Unable to create/save notes for document " + documentNumber, e);
237 }
238 }
239 }
240
241 protected String createSubObjectChunk(List<SubObjectCode> listOfSubObjects, int startIndex, int endIndex) {
242 StringBuilder buf = new StringBuilder();
243 for (int i = startIndex; i < endIndex && i < listOfSubObjects.size(); i++) {
244 SubObjectCode subObjCd = listOfSubObjects.get(i);
245 buf.append(subObjCd.getUniversityFiscalYear()).append(" - ").append(subObjCd.getChartOfAccountsCode()).append(" - ")
246 .append(subObjCd.getAccountNumber()).append(" - ").append(subObjCd.getFinancialObjectCode())
247 .append(" - ").append(subObjCd.getFinancialSubObjectCode());
248 if (i + 1 < endIndex && i + 1 < listOfSubObjects.size()) {
249 buf.append(", ");
250 }
251 }
252 return buf.toString();
253 }
254
255 protected int getNumSubObjectsPerNote() {
256
257
258 return NO_OF_SUB_OBJECTS_PER_NOTE;
259 }
260
261 public void setBusinessObjectService(BusinessObjectService businessObjectService) {
262 this.businessObjectService = businessObjectService;
263 }
264
265 public void setMaintenanceDocumentDictionaryService(MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService) {
266 this.maintenanceDocumentDictionaryService = maintenanceDocumentDictionaryService;
267 }
268
269 public void setMaintenanceDocumentDao(MaintenanceDocumentDao maintenanceDocumentDao) {
270 this.maintenanceDocumentDao = maintenanceDocumentDao;
271 }
272
273 public void setNoteService(NoteService noteService) {
274 this.noteService = noteService;
275 }
276
277 public void setConfigurationService(ConfigurationService kualiConfigurationService) {
278 this.kualiConfigurationService = kualiConfigurationService;
279 }
280
281 public void setUniversityDateService(UniversityDateService universityDateService) {
282 this.universityDateService = universityDateService;
283 }
284
285 public void setDocumentHeaderService(DocumentHeaderService documentHeaderService) {
286 this.documentHeaderService = documentHeaderService;
287 }
288 }