1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.ole.gl.batch.service.impl;
17
18 import java.util.ArrayList;
19 import java.util.Date;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23
24 import org.kuali.ole.coa.businessobject.A21SubAccount;
25 import org.kuali.ole.coa.businessobject.Account;
26 import org.kuali.ole.coa.businessobject.IndirectCostRecoveryExclusionAccount;
27 import org.kuali.ole.coa.businessobject.IndirectCostRecoveryExclusionType;
28 import org.kuali.ole.coa.businessobject.ObjectCode;
29 import org.kuali.ole.coa.dataaccess.IndirectCostRecoveryExclusionAccountDao;
30 import org.kuali.ole.coa.dataaccess.IndirectCostRecoveryExclusionTypeDao;
31 import org.kuali.ole.gl.GeneralLedgerConstants;
32 import org.kuali.ole.gl.batch.PosterIndirectCostRecoveryEntriesStep;
33 import org.kuali.ole.gl.batch.service.AccountingCycleCachingService;
34 import org.kuali.ole.gl.batch.service.IndirectCostRecoveryService;
35 import org.kuali.ole.gl.batch.service.PostTransaction;
36 import org.kuali.ole.gl.businessobject.ExpenditureTransaction;
37 import org.kuali.ole.gl.businessobject.Transaction;
38 import org.kuali.ole.sys.Message;
39 import org.kuali.ole.sys.OLEConstants;
40 import org.kuali.ole.sys.OLEPropertyConstants;
41 import org.kuali.ole.sys.context.SpringContext;
42 import org.kuali.ole.sys.service.ReportWriterService;
43 import org.kuali.rice.core.api.parameter.ParameterEvaluatorService;
44 import org.kuali.rice.coreservice.framework.parameter.ParameterService;
45 import org.kuali.rice.krad.service.BusinessObjectService;
46 import org.kuali.rice.krad.service.PersistenceStructureService;
47 import org.kuali.rice.krad.util.ObjectUtils;
48 import org.springframework.transaction.annotation.Transactional;
49 import org.springframework.util.StringUtils;
50
51
52
53
54
55 @Transactional
56 public class PostExpenditureTransaction implements IndirectCostRecoveryService, PostTransaction {
57 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PostExpenditureTransaction.class);
58
59 private static final String INDIRECT_COST_TYPES_PARAMETER = "INDIRECT_COST_TYPES";
60 private static final String INDIRECT_COST_FISCAL_PERIODS_PARAMETER = "INDIRECT_COST_FISCAL_PERIODS";
61 private static final String ICR_EXCLUSIONS_AT_TRANSACTION_AND_TOP_LEVEL_ONLY_PARAMETER_NAME = "ICR_EXCLUSIONS_AT_TRANSACTION_AND_TOP_LEVEL_ONLY_IND";
62
63 private IndirectCostRecoveryExclusionAccountDao indirectCostRecoveryExclusionAccountDao;
64 private IndirectCostRecoveryExclusionTypeDao indirectCostRecoveryExclusionTypeDao;
65 private AccountingCycleCachingService accountingCycleCachingService;
66 private PersistenceStructureService persistenceStructureService;
67 private ParameterService parameterService;
68
69 public void setIndirectCostRecoveryExclusionAccountDao(IndirectCostRecoveryExclusionAccountDao icrea) {
70 indirectCostRecoveryExclusionAccountDao = icrea;
71 }
72
73 public void setIndirectCostRecoveryExclusionTypeDao(IndirectCostRecoveryExclusionTypeDao icrea) {
74 indirectCostRecoveryExclusionTypeDao = icrea;
75 }
76
77
78
79
80 public PostExpenditureTransaction() {
81 super();
82 }
83
84
85
86
87
88
89
90
91
92
93 @Override
94 public boolean isIcrTransaction(Transaction transaction, ReportWriterService reportWriterService) {
95 if (LOG.isDebugEnabled()) {
96 LOG.debug("isIcrTransaction() started");
97 }
98
99
100
101 if (transaction.getObjectType().isFinObjectTypeIcrSelectionIndicator() && SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(PosterIndirectCostRecoveryEntriesStep.class, PostExpenditureTransaction.INDIRECT_COST_FISCAL_PERIODS_PARAMETER, transaction.getUniversityFiscalPeriodCode()).evaluationSucceeds()) {
102
103
104
105 A21SubAccount a21SubAccount = accountingCycleCachingService.getA21SubAccount(transaction.getAccount().getChartOfAccountsCode(), transaction.getAccount().getAccountNumber(), transaction.getSubAccountNumber());
106 String financialIcrSeriesIdentifier;
107 String indirectCostRecoveryTypeCode;
108
109
110 if (a21SubAccount != null) {
111 if (StringUtils.hasText(a21SubAccount.getFinancialIcrSeriesIdentifier()) && StringUtils.hasText(a21SubAccount.getIndirectCostRecoveryTypeCode())) {
112
113 if (!StringUtils.hasText(transaction.getAccount().getFinancialIcrSeriesIdentifier()) || !StringUtils.hasText(transaction.getAccount().getAcctIndirectCostRcvyTypeCd())) {
114 List<Message> warnings = new ArrayList<Message>();
115 warnings.add(new Message("Warning - excluding transaction from Indirect Cost Recovery because Sub-Account is set up for ICR, but Account is not.", Message.TYPE_WARNING));
116 reportWriterService.writeError(transaction, warnings);
117 }
118 }
119
120 if (StringUtils.hasText(a21SubAccount.getFinancialIcrSeriesIdentifier()) && StringUtils.hasText(a21SubAccount.getIndirectCostRecoveryTypeCode())) {
121
122 financialIcrSeriesIdentifier = a21SubAccount.getFinancialIcrSeriesIdentifier();
123 indirectCostRecoveryTypeCode = a21SubAccount.getIndirectCostRecoveryTypeCode();
124 }
125 else {
126
127 financialIcrSeriesIdentifier = transaction.getAccount().getFinancialIcrSeriesIdentifier();
128 indirectCostRecoveryTypeCode = transaction.getAccount().getAcctIndirectCostRcvyTypeCd();
129 }
130 }
131 else {
132
133 financialIcrSeriesIdentifier = transaction.getAccount().getFinancialIcrSeriesIdentifier();
134 indirectCostRecoveryTypeCode = transaction.getAccount().getAcctIndirectCostRcvyTypeCd();
135 }
136
137
138 if (!StringUtils.hasText(financialIcrSeriesIdentifier)) {
139 LOG.debug("isIcrTransaction() Not ICR Account");
140 return false;
141 }
142
143 if ((a21SubAccount != null) && OLEConstants.SubAccountType.COST_SHARE.equals(a21SubAccount.getSubAccountTypeCode())) {
144
145 LOG.debug("isIcrTransaction() A21 subaccounts with type of CS - not posted");
146 return false;
147 }
148
149
150 final boolean selfAndTopLevelOnly = getParameterService().getParameterValueAsBoolean(PosterIndirectCostRecoveryEntriesStep.class, PostExpenditureTransaction.ICR_EXCLUSIONS_AT_TRANSACTION_AND_TOP_LEVEL_ONLY_PARAMETER_NAME);
151 if (excludedByType(indirectCostRecoveryTypeCode, transaction.getFinancialObject(), selfAndTopLevelOnly)) {
152 return false;
153 }
154 if (excludedByAccount(transaction.getAccount(), transaction.getFinancialObject(), selfAndTopLevelOnly)) {
155 return false;
156 }
157
158 return true;
159 }
160 else {
161
162 LOG.debug("isIcrTransaction() invalid period code - not posted");
163 return false;
164 }
165 }
166
167
168
169
170
171
172
173
174 protected boolean excludedByType(String indirectCostRecoveryTypeCode, ObjectCode objectCode, boolean selfAndTopLevelOnly) {
175
176 if ((!StringUtils.hasText(indirectCostRecoveryTypeCode)) || !SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(PosterIndirectCostRecoveryEntriesStep.class, PostExpenditureTransaction.INDIRECT_COST_TYPES_PARAMETER, indirectCostRecoveryTypeCode).evaluationSucceeds()) {
177
178 if (LOG.isDebugEnabled()) {
179 LOG.debug("isIcrTransaction() ICR type is null or excluded by the OLE-GL / Poster Indirect Cost Recoveries Step / INDIRECT_COST_TYPES parameter - not posted");
180 }
181 return true;
182 }
183
184 if (hasExclusionByType(indirectCostRecoveryTypeCode, objectCode)) {
185 return true;
186 }
187
188 ObjectCode currentObjectCode = getReportsToObjectCode(objectCode);
189 while (currentObjectCode != null && !currentObjectCode.isReportingToSelf()) {
190 if (!selfAndTopLevelOnly && hasExclusionByType(indirectCostRecoveryTypeCode, currentObjectCode)) {
191 return true;
192 }
193
194 currentObjectCode = getReportsToObjectCode(currentObjectCode);
195 }
196 if (currentObjectCode != null && hasExclusionByType(indirectCostRecoveryTypeCode, currentObjectCode))
197 {
198 return true;
199 }
200
201 return false;
202 }
203
204
205
206
207
208
209
210 protected boolean hasExclusionByType(String indirectCostRecoveryTypeCode, ObjectCode objectCode) {
211 Map<String, Object> keys = new HashMap<String, Object>();
212 keys.put(OLEPropertyConstants.ACCOUNT_INDIRECT_COST_RECOVERY_TYPE_CODE, indirectCostRecoveryTypeCode);
213 keys.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, objectCode.getChartOfAccountsCode());
214 keys.put(OLEPropertyConstants.FINANCIAL_OBJECT_CODE, objectCode.getFinancialObjectCode());
215 final IndirectCostRecoveryExclusionType excType = SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(IndirectCostRecoveryExclusionType.class, keys);
216 return !ObjectUtils.isNull(excType) && excType.isActive();
217 }
218
219
220
221
222
223
224
225
226 protected boolean excludedByAccount(Account account, ObjectCode objectCode, boolean selfAndTopLevelOnly) {
227 if (hasExclusionByAccount(account, objectCode)) {
228 return true;
229 }
230
231 ObjectCode currentObjectCode = getReportsToObjectCode(objectCode);
232 while (currentObjectCode != null && !currentObjectCode.isReportingToSelf()) {
233 if (!selfAndTopLevelOnly && hasExclusionByAccount(account, currentObjectCode)) {
234 return true;
235 }
236
237 currentObjectCode = getReportsToObjectCode(currentObjectCode);
238 }
239 if (currentObjectCode != null && hasExclusionByAccount(account, currentObjectCode))
240 {
241 return true;
242 }
243
244 return false;
245 }
246
247
248
249
250
251
252
253 protected boolean hasExclusionByAccount(Account account, ObjectCode objectCode) {
254 Map<String, Object> keys = new HashMap<String, Object>();
255 keys.put(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, account.getChartOfAccountsCode());
256 keys.put(OLEPropertyConstants.ACCOUNT_NUMBER, account.getAccountNumber());
257 keys.put(OLEPropertyConstants.FINANCIAL_OBJECT_CHART_OF_ACCOUNT_CODE, objectCode.getChartOfAccountsCode());
258 keys.put(OLEPropertyConstants.FINANCIAL_OBJECT_CODE, objectCode.getFinancialObjectCode());
259 final IndirectCostRecoveryExclusionAccount excAccount = SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(IndirectCostRecoveryExclusionAccount.class, keys);
260
261 return !ObjectUtils.isNull(excAccount);
262 }
263
264
265
266
267
268
269 protected boolean hasValidObjectCodeReportingHierarchy(ObjectCode objectCode) {
270 ObjectCode currentObjectCode = objectCode;
271 while (hasValidReportsToFields(currentObjectCode) && !currentObjectCode.isReportingToSelf()) {
272 currentObjectCode = getReportsToObjectCode(currentObjectCode);
273 if (ObjectUtils.isNull(currentObjectCode) || !currentObjectCode.isActive()) {
274 return false;
275 }
276 }
277 if (!hasValidReportsToFields(currentObjectCode)) {
278 return false;
279 }
280 return true;
281 }
282
283
284
285
286
287
288 protected boolean hasValidReportsToFields(ObjectCode objectCode) {
289 return !org.apache.commons.lang.StringUtils.isBlank(objectCode.getReportsToChartOfAccountsCode()) && !org.apache.commons.lang.StringUtils.isBlank(objectCode.getReportsToFinancialObjectCode());
290 }
291
292
293
294
295
296
297 protected ObjectCode getReportsToObjectCode(ObjectCode objectCode) {
298 return accountingCycleCachingService.getObjectCode(objectCode.getUniversityFiscalYear(), objectCode.getReportsToChartOfAccountsCode(), objectCode.getReportsToFinancialObjectCode());
299 }
300
301
302
303
304
305
306
307
308
309
310
311 @Override
312 public String post(Transaction t, int mode, Date postDate, ReportWriterService posterReportWriterService) {
313 LOG.debug("post() started");
314
315 if (ObjectUtils.isNull(t.getFinancialObject()) || !hasValidObjectCodeReportingHierarchy(t.getFinancialObject())) {
316
317 return GeneralLedgerConstants.ERROR_CODE + ": Warning - excluding transaction from Indirect Cost Recovery because "+t.getUniversityFiscalYear().toString()+"-"+t.getChartOfAccountsCode()+"-"+t.getFinancialObjectCode()+" has an invalid reports to hierarchy (either has an non-existent object or an inactive object)";
318 }
319 else if (isIcrTransaction(t, posterReportWriterService)) {
320 return postTransaction(t, mode);
321 }
322 return GeneralLedgerConstants.EMPTY_CODE;
323 }
324
325
326
327
328
329
330
331
332 protected String postTransaction(Transaction t, int mode) {
333 LOG.debug("postTransaction() started");
334
335 String returnCode = GeneralLedgerConstants.UPDATE_CODE;
336 ExpenditureTransaction et = accountingCycleCachingService.getExpenditureTransaction(t);
337 if (et == null) {
338 LOG.debug("Posting expenditure transation");
339 et = new ExpenditureTransaction(t);
340 returnCode = GeneralLedgerConstants.INSERT_CODE;
341 }
342
343 if (org.apache.commons.lang.StringUtils.isBlank(t.getOrganizationReferenceId())) {
344 et.setOrganizationReferenceId(GeneralLedgerConstants.getDashOrganizationReferenceId());
345 }
346
347 if (OLEConstants.GL_DEBIT_CODE.equals(t.getTransactionDebitCreditCode()) || OLEConstants.GL_BUDGET_CODE.equals(t.getTransactionDebitCreditCode())) {
348 et.setAccountObjectDirectCostAmount(et.getAccountObjectDirectCostAmount().add(t.getTransactionLedgerEntryAmount()));
349 }
350 else {
351 et.setAccountObjectDirectCostAmount(et.getAccountObjectDirectCostAmount().subtract(t.getTransactionLedgerEntryAmount()));
352 }
353
354 if (returnCode.equals(GeneralLedgerConstants.INSERT_CODE)) {
355
356 LOG.info("Inserting a GLEX record. Transaction:"+t);
357 accountingCycleCachingService.insertExpenditureTransaction(et);
358 } else {
359
360 LOG.info("Updating a GLEX record. Transaction:"+t);
361 accountingCycleCachingService.updateExpenditureTransaction(et);
362 }
363
364 return returnCode;
365 }
366
367
368
369
370 @Override
371 public String getDestinationName() {
372 return persistenceStructureService.getTableName(ExpenditureTransaction.class);
373 }
374
375 public void setAccountingCycleCachingService(AccountingCycleCachingService accountingCycleCachingService) {
376 this.accountingCycleCachingService = accountingCycleCachingService;
377 }
378
379 public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) {
380 this.persistenceStructureService = persistenceStructureService;
381 }
382
383
384
385
386
387 public ParameterService getParameterService() {
388 return parameterService;
389 }
390
391
392
393
394
395 public void setParameterService(ParameterService parameterService) {
396 this.parameterService = parameterService;
397 }
398
399 }