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.HashMap;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Map;
24
25 import org.apache.commons.lang.StringUtils;
26 import org.apache.log4j.Logger;
27 import org.kuali.ole.coa.businessobject.Account;
28 import org.kuali.ole.coa.businessobject.SubAccount;
29 import org.kuali.ole.coa.service.SubAccountTrickleDownInactivationService;
30 import org.kuali.ole.sys.OLEKeyConstants;
31 import org.kuali.ole.sys.OLEPropertyConstants;
32 import org.kuali.rice.core.api.config.property.ConfigurationService;
33 import org.kuali.rice.kns.maintenance.Maintainable;
34 import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
35 import org.kuali.rice.krad.bo.DocumentHeader;
36 import org.kuali.rice.krad.bo.Note;
37 import org.kuali.rice.krad.bo.PersistableBusinessObject;
38 import org.kuali.rice.krad.dao.MaintenanceDocumentDao;
39 import org.kuali.rice.krad.maintenance.MaintenanceLock;
40 import org.kuali.rice.krad.service.DocumentHeaderService;
41 import org.kuali.rice.krad.service.NoteService;
42 import org.kuali.rice.krad.util.GlobalVariables;
43 import org.kuali.rice.krad.util.ObjectUtils;
44 import org.springframework.transaction.annotation.Transactional;
45
46 @Transactional
47 public class SubAccountTrickleDownInactivationServiceImpl implements SubAccountTrickleDownInactivationService {
48 private static final Logger LOG = Logger.getLogger(SubAccountTrickleDownInactivationServiceImpl.class);
49
50 protected MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
51 protected MaintenanceDocumentDao maintenanceDocumentDao;
52 protected NoteService noteService;
53 protected ConfigurationService kualiConfigurationService;
54 protected DocumentHeaderService documentHeaderService;
55
56
57
58
59
60
61
62
63
64 public List<MaintenanceLock> generateTrickleDownMaintenanceLocks(Account inactivatedAccount, String documentNumber) {
65 inactivatedAccount.refreshReferenceObject(OLEPropertyConstants.SUB_ACCOUNTS);
66 List<MaintenanceLock> maintenanceLocks = new ArrayList<MaintenanceLock>();
67
68 Maintainable subAccountMaintainable;
69 try {
70 subAccountMaintainable = (Maintainable) maintenanceDocumentDictionaryService.getMaintainableClass(SubAccount.class.getName()).newInstance();
71 subAccountMaintainable.setBoClass(SubAccount.class);
72 subAccountMaintainable.setDocumentNumber(documentNumber);
73 }
74 catch (Exception e) {
75 LOG.error("Unable to instantiate SubAccount Maintainable" , e);
76 throw new RuntimeException("Unable to instantiate SubAccount Maintainable" , e);
77 }
78
79 if (ObjectUtils.isNotNull(inactivatedAccount.getSubAccounts()) && !inactivatedAccount.getSubAccounts().isEmpty()) {
80 for (Iterator<SubAccount> i = inactivatedAccount.getSubAccounts().iterator(); i.hasNext(); ) {
81 SubAccount subAccount = i.next();
82
83 subAccountMaintainable.setBusinessObject(subAccount);
84 maintenanceLocks.addAll(subAccountMaintainable.generateMaintenanceLocks());
85 }
86 }
87 return maintenanceLocks;
88 }
89
90 public void trickleDownInactivateSubAccounts(Account inactivatedAccount, String documentNumber) {
91 List<SubAccount> inactivatedSubAccounts = new ArrayList<SubAccount>();
92 Map<SubAccount, String> alreadyLockedSubAccounts = new HashMap<SubAccount, String>();
93 List<SubAccount> errorPersistingSubAccounts = new ArrayList<SubAccount>();
94
95 Maintainable subAccountMaintainable;
96 try {
97 subAccountMaintainable = (Maintainable) maintenanceDocumentDictionaryService.getMaintainableClass(SubAccount.class.getName()).newInstance();
98 subAccountMaintainable.setBoClass(SubAccount.class);
99 subAccountMaintainable.setDocumentNumber(documentNumber);
100 }
101 catch (Exception e) {
102 LOG.error("Unable to instantiate SubAccount Maintainable" , e);
103 throw new RuntimeException("Unable to instantiate SubAccount Maintainable" , e);
104 }
105
106 inactivatedAccount.refreshReferenceObject(OLEPropertyConstants.SUB_ACCOUNTS);
107 if (ObjectUtils.isNotNull(inactivatedAccount.getSubAccounts()) && !inactivatedAccount.getSubAccounts().isEmpty()) {
108 for (Iterator<SubAccount> i = inactivatedAccount.getSubAccounts().iterator(); i.hasNext(); ) {
109 SubAccount subAccount = i.next();
110 if (subAccount.isActive()) {
111 subAccountMaintainable.setBusinessObject(subAccount);
112 List<MaintenanceLock> subAccountLocks = subAccountMaintainable.generateMaintenanceLocks();
113
114 MaintenanceLock failedLock = verifyAllLocksFromThisDocument(subAccountLocks, documentNumber);
115 if (failedLock != null) {
116
117 alreadyLockedSubAccounts.put(subAccount, failedLock.getDocumentNumber());
118 }
119 else {
120
121 subAccount.setActive(false);
122
123 try {
124 subAccountMaintainable.saveBusinessObject();
125 inactivatedSubAccounts.add(subAccount);
126 }
127 catch (RuntimeException e) {
128 LOG.error("Unable to trickle-down inactivate sub-account " + subAccount.toString(), e);
129 errorPersistingSubAccounts.add(subAccount);
130 }
131 }
132 }
133 }
134
135 addNotesToDocument(documentNumber, inactivatedSubAccounts, alreadyLockedSubAccounts, errorPersistingSubAccounts);
136 }
137 }
138
139 protected void addNotesToDocument(String documentNumber, List<SubAccount> inactivatedSubAccounts, Map<SubAccount, String> alreadyLockedSubAccounts, List<SubAccount> errorPersistingSubAccounts) {
140 if (inactivatedSubAccounts.isEmpty() && alreadyLockedSubAccounts.isEmpty() && errorPersistingSubAccounts.isEmpty()) {
141
142 return;
143 }
144 DocumentHeader noteParent = documentHeaderService.getDocumentHeaderById(documentNumber);
145 Note newNote = new Note();
146
147 addNotes(documentNumber, inactivatedSubAccounts, OLEKeyConstants.SUB_ACCOUNT_TRICKLE_DOWN_INACTIVATION, noteParent, newNote);
148 addNotes(documentNumber, errorPersistingSubAccounts, OLEKeyConstants.SUB_ACCOUNT_TRICKLE_DOWN_INACTIVATION_ERROR_DURING_PERSISTENCE, noteParent, newNote);
149 addMaintenanceLockedNotes(documentNumber, alreadyLockedSubAccounts, OLEKeyConstants.SUB_ACCOUNT_TRICKLE_DOWN_INACTIVATION_RECORD_ALREADY_MAINTENANCE_LOCKED, noteParent, newNote);
150 }
151
152 protected void addMaintenanceLockedNotes(String documentNumber, Map<SubAccount, String> lockedSubAccounts, String messageKey, PersistableBusinessObject noteParent, Note noteTemplate) {
153 for (Map.Entry<SubAccount, String> entry : lockedSubAccounts.entrySet()) {
154 try {
155 SubAccount subAccount = entry.getKey();
156 String subAccountString = subAccount.getChartOfAccountsCode() + " - " + subAccount.getAccountNumber() + " - " + subAccount.getSubAccountNumber();
157 if (StringUtils.isNotBlank(subAccountString)) {
158 String noteTextTemplate = kualiConfigurationService.getPropertyValueAsString(messageKey);
159 String noteText = MessageFormat.format(noteTextTemplate, subAccountString, entry.getValue());
160 Note note = noteService.createNote(noteTemplate, noteParent, GlobalVariables.getUserSession().getPrincipalId());
161 note.setNoteText(noteText);
162 noteService.save(note);
163 }
164 }
165 catch (Exception e) {
166 LOG.error("Unable to create/save notes for document " + documentNumber, e);
167 throw new RuntimeException("Unable to create/save notes for document " + documentNumber, e);
168 }
169 }
170 }
171
172 protected void addNotes(String documentNumber, List<SubAccount> listOfSubAccounts, String messageKey, PersistableBusinessObject noteParent, Note noteTemplate) {
173 for (int i = 0; i < listOfSubAccounts.size(); i += getNumSubAccountsPerNote()) {
174 try {
175 String subAccountString = createSubAccountChunk(listOfSubAccounts, i, i + getNumSubAccountsPerNote());
176 if (StringUtils.isNotBlank(subAccountString)) {
177 String noteTextTemplate = kualiConfigurationService.getPropertyValueAsString(messageKey);
178 String noteText = MessageFormat.format(noteTextTemplate, subAccountString);
179 Note note = noteService.createNote(noteTemplate, noteParent, GlobalVariables.getUserSession().getPrincipalId());
180 note.setNoteText(noteText);
181 note.setNotePostedTimestampToCurrent();
182 noteService.save(note);
183 }
184 }
185 catch (Exception e) {
186 LOG.error("Unable to create/save notes for document " + documentNumber, e);
187 throw new RuntimeException("Unable to create/save notes for document " + documentNumber, e);
188 }
189 }
190 }
191
192 protected String createSubAccountChunk(List<SubAccount> listOfSubAccounts, int startIndex, int endIndex) {
193 StringBuilder buf = new StringBuilder();
194 for (int i = startIndex; i < endIndex && i < listOfSubAccounts.size(); i++) {
195 SubAccount subAccount = listOfSubAccounts.get(i);
196 buf.append(subAccount.getChartOfAccountsCode()).append(" - ").append(subAccount.getAccountNumber()).append(" - ")
197 .append(subAccount.getSubAccountNumber());
198 if (i + 1 < endIndex && i + 1 < listOfSubAccounts.size()) {
199 buf.append(", ");
200 }
201 }
202 return buf.toString();
203 }
204
205 protected int getNumSubAccountsPerNote() {
206 return 20;
207 }
208
209 protected MaintenanceLock verifyAllLocksFromThisDocument(List<MaintenanceLock> maintenanceLocks, String documentNumber) {
210 for (MaintenanceLock maintenanceLock : maintenanceLocks) {
211 String lockingDocNumber = maintenanceDocumentDao.getLockingDocumentNumber(maintenanceLock.getLockingRepresentation(), documentNumber);
212 if (StringUtils.isNotBlank(lockingDocNumber)) {
213 return maintenanceLock;
214 }
215 }
216 return null;
217 }
218
219 public void setMaintenanceDocumentDictionaryService(MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService) {
220 this.maintenanceDocumentDictionaryService = maintenanceDocumentDictionaryService;
221 }
222
223
224
225 public void setMaintenanceDocumentDao(MaintenanceDocumentDao maintenanceDocumentDao) {
226 this.maintenanceDocumentDao = maintenanceDocumentDao;
227 }
228
229
230
231 public void setNoteService(NoteService noteService) {
232 this.noteService = noteService;
233 }
234
235 public void setConfigurationService(ConfigurationService kualiConfigurationService) {
236 this.kualiConfigurationService = kualiConfigurationService;
237 }
238
239 public void setDocumentHeaderService(DocumentHeaderService documentHeaderService) {
240 this.documentHeaderService = documentHeaderService;
241 }
242 }