001    /*
002     * Copyright 2011 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.kfs.module.bc.document.service.impl;
017    
018    
019    import java.io.BufferedReader;
020    import java.io.ByteArrayOutputStream;
021    import java.io.IOException;
022    import java.io.InputStream;
023    import java.io.InputStreamReader;
024    import java.util.ArrayList;
025    import java.util.HashMap;
026    import java.util.List;
027    import java.util.Map;
028    
029    import org.apache.commons.lang.StringUtils;
030    import org.kuali.kfs.coa.businessobject.ObjectCode;
031    import org.kuali.kfs.coa.businessobject.SubObjectCode;
032    import org.kuali.kfs.integration.ld.LaborLedgerObject;
033    import org.kuali.kfs.integration.ld.LaborModuleService;
034    import org.kuali.kfs.module.bc.BCConstants;
035    import org.kuali.kfs.module.bc.BCConstants.RequestImportFileType;
036    import org.kuali.kfs.module.bc.businessobject.BudgetConstructionFundingLock;
037    import org.kuali.kfs.module.bc.businessobject.BudgetConstructionHeader;
038    import org.kuali.kfs.module.bc.businessobject.BudgetConstructionLockStatus;
039    import org.kuali.kfs.module.bc.businessobject.BudgetConstructionMonthly;
040    import org.kuali.kfs.module.bc.businessobject.BudgetConstructionRequestMove;
041    import org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionGeneralLedger;
042    import org.kuali.kfs.module.bc.document.BudgetConstructionDocument;
043    import org.kuali.kfs.module.bc.document.dataaccess.ImportRequestDao;
044    import org.kuali.kfs.module.bc.document.service.BenefitsCalculationService;
045    import org.kuali.kfs.module.bc.document.service.BudgetDocumentService;
046    import org.kuali.kfs.module.bc.document.service.BudgetParameterService;
047    import org.kuali.kfs.module.bc.document.service.BudgetRequestImportService;
048    import org.kuali.kfs.module.bc.document.service.LockService;
049    import org.kuali.kfs.module.bc.util.BudgetParameterFinder;
050    import org.kuali.kfs.module.bc.util.ImportRequestFileParsingHelper;
051    import org.kuali.kfs.sys.KFSConstants;
052    import org.kuali.kfs.sys.KFSPropertyConstants;
053    import org.kuali.kfs.sys.context.SpringContext;
054    import org.kuali.kfs.sys.service.NonTransactional;
055    import org.kuali.kfs.sys.service.OptionsService;
056    import org.kuali.rice.kew.exception.WorkflowException;
057    import org.kuali.rice.kim.bo.Person;
058    import org.kuali.rice.kim.util.KimConstants;
059    import org.kuali.rice.kns.document.authorization.TransactionalDocumentAuthorizer;
060    import org.kuali.rice.kns.service.BusinessObjectService;
061    import org.kuali.rice.kns.service.DictionaryValidationService;
062    import org.kuali.rice.kns.service.DocumentHelperService;
063    import org.kuali.rice.kns.service.DocumentService;
064    import org.kuali.rice.kns.util.KNSConstants;
065    import org.kuali.rice.kns.util.KualiInteger;
066    import org.springframework.transaction.annotation.Transactional;
067    
068    import com.lowagie.text.Document;
069    import com.lowagie.text.DocumentException;
070    import com.lowagie.text.Paragraph;
071    import com.lowagie.text.pdf.PdfWriter;
072    
073    /**
074     * Contains services relevent to the budget construction import request process
075     */
076    
077    public class BudgetRequestImportServiceImpl implements BudgetRequestImportService {
078        private BusinessObjectService businessObjectService;
079        private ImportRequestDao importRequestDao;
080        private DictionaryValidationService dictionaryValidationService;
081        private LockService lockService;
082        private BudgetDocumentService budgetDocumentService;
083        private LaborModuleService laborModuleService;
084        private BudgetParameterService budgetParameterService;
085        private OptionsService optionsService;
086        private DocumentHelperService documentHelperService;
087        private DocumentService documentService;
088        
089        private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory.getLog(BudgetRequestImportServiceImpl.class);
090    
091        /**
092         * @see org.kuali.kfs.module.bc.document.service.BudgetRequestImportService#generatePdf(java.util.List, java.io.ByteArrayOutputStream)
093         */
094        @NonTransactional
095        public void generatePdf(List<String> errorMessages, ByteArrayOutputStream baos) throws DocumentException {
096            Document document = new Document();
097            PdfWriter.getInstance(document, baos);
098            document.open();
099    
100            for (String error : errorMessages) {
101                document.add(new Paragraph(error));
102            }
103    
104            document.close();
105        }
106    
107        /**
108         * @see org.kuali.kfs.module.bc.document.service.BudgetRequestImportService#processImportFile(java.io.InputStream, java.lang.String,
109         *      java.lang.String, java.lang.String)
110         */
111        @Transactional
112        public List processImportFile(InputStream fileImportStream, String principalId, String fieldSeperator, String textDelimiter, String fileType, Integer budgetYear) throws IOException {
113            List fileErrorList = new ArrayList();
114            
115            deleteBudgetConstructionMoveRecords(principalId);
116    
117            BudgetConstructionRequestMove budgetConstructionRequestMove = new BudgetConstructionRequestMove();
118    
119            BufferedReader fileReader = new BufferedReader(new InputStreamReader(fileImportStream));
120            int currentLine = 1;
121            while (fileReader.ready()) {
122                String line = StringUtils.strip(fileReader.readLine());
123                boolean isAnnualFile = (fileType.equalsIgnoreCase(RequestImportFileType.ANNUAL.toString())) ? true : false;
124    
125                if (StringUtils.isNotBlank(line)) {
126                    budgetConstructionRequestMove = ImportRequestFileParsingHelper.parseLine(line, fieldSeperator, textDelimiter, isAnnualFile);
127    
128                    // check if there were errors parsing the line
129                    if (budgetConstructionRequestMove == null) {
130                        fileErrorList.add(BCConstants.REQUEST_IMPORT_FILE_PROCESSING_ERROR_MESSAGE_GENERIC + " " + currentLine + ".");
131                        // clean out table since file processing has stopped
132                        deleteBudgetConstructionMoveRecords(principalId);
133                        return fileErrorList;
134                    }
135    
136                    String lineValidationError = validateLine(budgetConstructionRequestMove, currentLine, isAnnualFile);
137    
138                    if ( StringUtils.isNotEmpty(lineValidationError) ) {
139                        fileErrorList.add(lineValidationError);
140                        // clean out table since file processing has stopped
141                        deleteBudgetConstructionMoveRecords(principalId);
142                        return fileErrorList;
143                    }
144    
145                    // set default values
146                    if (StringUtils.isBlank(budgetConstructionRequestMove.getSubAccountNumber())) {
147                        budgetConstructionRequestMove.setSubAccountNumber(KFSConstants.getDashSubAccountNumber());
148                    }
149    
150                    if (StringUtils.isBlank(budgetConstructionRequestMove.getFinancialSubObjectCode())) {
151                        budgetConstructionRequestMove.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode());
152                    }
153                    //set object type code
154                    List revenueObjectTypesParamValues = BudgetParameterFinder.getRevenueObjectTypes();
155                    List expenditureObjectTypesParamValues = BudgetParameterFinder.getExpenditureObjectTypes();
156                    ObjectCode objectCode = getObjectCode(budgetConstructionRequestMove, budgetYear);
157                    if (objectCode != null) {
158                        if ( expenditureObjectTypesParamValues.contains(objectCode.getFinancialObjectTypeCode()) ) {
159                            budgetConstructionRequestMove.setFinancialObjectTypeCode(optionsService.getOptions(budgetYear).getFinObjTypeExpenditureexpCd());
160                        } else if ( revenueObjectTypesParamValues.contains(objectCode.getFinancialObjectTypeCode()) ) {
161                            budgetConstructionRequestMove.setFinancialObjectTypeCode(optionsService.getOptions(budgetYear).getFinObjectTypeIncomecashCode());
162                        }
163                    }
164                    
165                    //check for duplicate key exception, since it requires a different error message
166                    Map searchCriteria = new HashMap();
167                    searchCriteria.put("principalId", principalId);
168                    searchCriteria.put("chartOfAccountsCode", budgetConstructionRequestMove.getChartOfAccountsCode());
169                    searchCriteria.put("accountNumber", budgetConstructionRequestMove.getAccountNumber());
170                    searchCriteria.put("subAccountNumber", budgetConstructionRequestMove.getSubAccountNumber());
171                    searchCriteria.put("financialObjectCode", budgetConstructionRequestMove.getFinancialObjectCode());
172                    searchCriteria.put("financialSubObjectCode", budgetConstructionRequestMove.getFinancialSubObjectCode());
173                    if ( this.businessObjectService.countMatching(BudgetConstructionRequestMove.class, searchCriteria) != 0 ) {
174                        LOG.error("Move table store error, import aborted");
175                        fileErrorList.add("Duplicate Key for " + budgetConstructionRequestMove.getErrorLinePrefixForLogFile());
176                        fileErrorList.add("Move table store error, import aborted");
177                        deleteBudgetConstructionMoveRecords(principalId);
178                        
179                        return fileErrorList;
180                    }
181                    try {
182                        budgetConstructionRequestMove.setPrincipalId(principalId);
183                        importRequestDao.save(budgetConstructionRequestMove, false);
184                    }
185                    catch (RuntimeException e) {
186                        LOG.error("Move table store error, import aborted");
187                        fileErrorList.add("Move table store error, import aborted");
188                        return fileErrorList;
189                    }
190                }
191    
192                currentLine++;
193            }
194    
195            return fileErrorList;
196        }
197    
198    
199        /**
200         * Sets the business object service
201         * 
202         * @param businessObjectService
203         */
204        @NonTransactional
205        public void setBusinessObjectService(BusinessObjectService businessObjectService) {
206            this.businessObjectService = businessObjectService;
207        }
208    
209        /**
210         * @see org.kuali.kfs.module.bc.document.service.BudgetRequestImportService#validateData()
211         */
212        @Transactional
213        public List<String> validateData(Integer budgetYear, String principalId) {
214            Map searchCriteria = new HashMap();
215            searchCriteria.put("principalId", principalId);
216            List<BudgetConstructionRequestMove> dataToValidateList = new ArrayList<BudgetConstructionRequestMove>(businessObjectService.findMatching(BudgetConstructionRequestMove.class, searchCriteria));
217            List<String> errorMessages = new ArrayList<String>();
218    
219            Map<String, BudgetConstructionHeader> retrievedHeaders = new HashMap<String, BudgetConstructionHeader>();
220            
221            for (BudgetConstructionRequestMove record : dataToValidateList) {
222                boolean validLine = true;
223                //KFSMI-798 - refreshNonUpdatableReferences() used instead of refresh(), 
224                //BudgetConstructionRequestMove does not have any updatable references            
225                record.refreshNonUpdateableReferences();
226    
227                String accountKey = record.getChartOfAccountsCode() + record.getAccountNumber();
228                BudgetConstructionHeader budgetConstructionHeader = null;
229                if (retrievedHeaders.containsKey(accountKey)) {
230                    budgetConstructionHeader = retrievedHeaders.get(accountKey);
231                }
232                else {
233                    budgetConstructionHeader = importRequestDao.getHeaderRecord(record, budgetYear);
234                    retrievedHeaders.put(accountKey, budgetConstructionHeader);
235                }
236                
237                SubObjectCode subObjectCode = getSubObjectCode(record, budgetYear);
238                String code = record.getFinancialObjectTypeCode();
239                LaborLedgerObject laborObject = this.laborModuleService.retrieveLaborLedgerObject(budgetYear, record.getChartOfAccountsCode(), record.getFinancialObjectCode());
240                ObjectCode objectCode = getObjectCode(record, budgetYear);
241                
242                if (budgetConstructionHeader == null) {
243                    record.setRequestUpdateErrorCode(BCConstants.RequestImportErrorCode.DATA_VALIDATION_NO_BUDGETED_ACCOUNT_SUB_ACCOUNT_ERROR_CODE.getErrorCode());
244                    errorMessages.add(record.getErrorLinePrefixForLogFile() + " " + BCConstants.RequestImportErrorCode.DATA_VALIDATION_NO_BUDGETED_ACCOUNT_SUB_ACCOUNT_ERROR_CODE.getMessage());
245                }
246                
247                else if (!record.getAccount().isActive()) {
248                    record.setRequestUpdateErrorCode(BCConstants.RequestImportErrorCode.DATA_VALIDATION_ACCOUNT_CLOSED_ERROR_CODE.getErrorCode());
249                    errorMessages.add(record.getErrorLinePrefixForLogFile() + " " + BCConstants.RequestImportErrorCode.DATA_VALIDATION_ACCOUNT_CLOSED_ERROR_CODE.getMessage());
250                }
251    
252                else if (record.getAccount().isExpired()) {
253                    record.setRequestUpdateErrorCode(BCConstants.RequestImportErrorCode.DATA_VALIDATION_ACCOUNT_EXPIRED_ERROR_CODE.getErrorCode());
254                    errorMessages.add(record.getErrorLinePrefixForLogFile() + " " + BCConstants.RequestImportErrorCode.DATA_VALIDATION_ACCOUNT_EXPIRED_ERROR_CODE.getMessage());
255                }
256    
257                else if (!record.getSubAccountNumber().equalsIgnoreCase(KFSConstants.getDashSubAccountNumber()) && !record.getSubAccount().isActive()) {
258                    record.setRequestUpdateErrorCode(BCConstants.RequestImportErrorCode.DATA_VALIDATION_SUB_ACCOUNT_INACTIVE_ERROR_CODE.getErrorCode());
259                    errorMessages.add(record.getErrorLinePrefixForLogFile() + " " + BCConstants.RequestImportErrorCode.DATA_VALIDATION_SUB_ACCOUNT_INACTIVE_ERROR_CODE.getMessage());
260                }
261    
262                // null object type
263                else if (StringUtils.isBlank(record.getFinancialObjectTypeCode())) {
264                    record.setRequestUpdateErrorCode(BCConstants.RequestImportErrorCode.DATA_VALIDATION_OBJECT_TYPE_NULL_ERROR_CODE.getErrorCode());
265                    errorMessages.add(record.getErrorLinePrefixForLogFile() + " " + BCConstants.RequestImportErrorCode.DATA_VALIDATION_OBJECT_TYPE_INVALID_ERROR_CODE.getMessage());
266                }
267    
268                // inactive object code
269                else if (objectCode != null && !objectCode.isActive()) {
270                    record.setRequestUpdateErrorCode(BCConstants.RequestImportErrorCode.DATA_VALIDATION_OBJECT_CODE_INACTIVE_ERROR_CODE.getErrorCode());
271                    errorMessages.add(record.getErrorLinePrefixForLogFile() + " " + BCConstants.RequestImportErrorCode.DATA_VALIDATION_OBJECT_CODE_INACTIVE_ERROR_CODE.getMessage());
272                }
273    
274                // compensation object codes COMP
275                else if (laborObject != null && (laborObject.isDetailPositionRequiredIndicator() || laborObject.getFinancialObjectFringeOrSalaryCode().equals(BCConstants.LABOR_OBJECT_FRINGE_CODE))) {
276                    record.setRequestUpdateErrorCode(BCConstants.RequestImportErrorCode.DATA_VALIDATION_COMPENSATION_OBJECT_CODE_ERROR_CODE.getErrorCode());
277                    errorMessages.add(record.getErrorLinePrefixForLogFile() + " " + BCConstants.RequestImportErrorCode.DATA_VALIDATION_COMPENSATION_OBJECT_CODE_ERROR_CODE.getMessage());
278                }
279    
280                // no wage accounts CMPA
281                else if (!record.getAccount().getSubFundGroup().isSubFundGroupWagesIndicator() && laborObject != null) {
282                    record.setRequestUpdateErrorCode(BCConstants.RequestImportErrorCode.DATA_VALIDATION_NO_WAGE_ACCOUNT_ERROR_CODE.getErrorCode());
283                    errorMessages.add(record.getErrorLinePrefixForLogFile() + " " + BCConstants.RequestImportErrorCode.DATA_VALIDATION_NO_WAGE_ACCOUNT_ERROR_CODE.getMessage());
284                }
285    
286                // invalid sub-object code NOSO
287                else if (!record.getFinancialSubObjectCode().equalsIgnoreCase(KFSConstants.getDashFinancialSubObjectCode()) && subObjectCode == null) {
288                    record.setRequestUpdateErrorCode(BCConstants.RequestImportErrorCode.DATA_VALIDATION_SUB_OBJECT_INVALID_ERROR_CODE.getErrorCode());
289                    errorMessages.add(record.getErrorLinePrefixForLogFile() + " " + BCConstants.RequestImportErrorCode.DATA_VALIDATION_SUB_OBJECT_INVALID_ERROR_CODE.getMessage());
290                }
291                
292                // inactive sub-object code
293                else if (!record.getFinancialSubObjectCode().equalsIgnoreCase(KFSConstants.getDashFinancialSubObjectCode()) && !subObjectCode.isActive()) {
294                    record.setRequestUpdateErrorCode(BCConstants.RequestImportErrorCode.DATA_VALIDATION_SUB_OBJECT_INACTIVE_ERROR_CODE.getErrorCode());
295                    errorMessages.add(record.getErrorLinePrefixForLogFile() + " " + BCConstants.RequestImportErrorCode.DATA_VALIDATION_SUB_OBJECT_INACTIVE_ERROR_CODE.getMessage());
296                }
297    
298                importRequestDao.save(record, true);
299            }
300    
301            return errorMessages;
302        }
303    
304        /**
305         * @see org.kuali.kfs.module.bc.document.service.BudgetRequestImportService#loadBudget()
306         */
307        @Transactional
308        public List<String> loadBudget(Person user, String fileType, Integer budgetYear) throws Exception {
309            List<BudgetConstructionRequestMove> recordsToLoad = importRequestDao.findAllNonErrorCodeRecords(user.getPrincipalId());
310            List<String> errorMessages = new ArrayList<String>();
311            Map<String, BudgetConstructionRequestMove> recordMap = new HashMap<String, BudgetConstructionRequestMove>();
312            
313            for (BudgetConstructionRequestMove recordToLoad : recordsToLoad) {
314                BudgetConstructionHeader header = importRequestDao.getHeaderRecord(recordToLoad, budgetYear);
315    
316                if (recordMap.containsKey(recordToLoad.getSubAccountingString())) {
317                    BudgetConstructionRequestMove temp = recordMap.get(recordToLoad.getSubAccountingString());
318    
319                    recordToLoad.setHasAccess(temp.getHasAccess());
320                    recordToLoad.setHasLock(temp.getHasLock());
321                    recordToLoad.setRequestUpdateErrorCode(temp.getRequestUpdateErrorCode());
322                }
323                else {
324                    boolean hasAccess = false;
325                    if (header != null) {
326                        BudgetConstructionDocument document;
327                        try {
328                            document = (BudgetConstructionDocument) documentService.getByDocumentHeaderId(header.getDocumentNumber());
329                        }
330                        catch (WorkflowException e) {
331                            throw new RuntimeException("Fail to retrieve budget document for doc id " + header.getDocumentNumber());
332                        }
333    
334                        TransactionalDocumentAuthorizer documentAuthorizer = (TransactionalDocumentAuthorizer) getDocumentHelperService().getDocumentAuthorizer(document);
335                        hasAccess = documentAuthorizer.isAuthorizedByTemplate(document, KNSConstants.KNS_NAMESPACE, KimConstants.PermissionTemplateNames.EDIT_DOCUMENT, user.getPrincipalId());
336                    }
337    
338                    if (hasAccess) {
339                        recordToLoad.setHasAccess(true);
340                    }
341                    else {
342                        recordToLoad.setRequestUpdateErrorCode(BCConstants.RequestImportErrorCode.UPDATE_ERROR_CODE_NO_ACCESS_TO_BUDGET_ACCOUNT.getErrorCode());
343                        errorMessages.add(recordToLoad.getErrorLinePrefixForLogFile() + " " + BCConstants.RequestImportErrorCode.UPDATE_ERROR_CODE_NO_ACCESS_TO_BUDGET_ACCOUNT.getMessage());
344                    }
345    
346                    if (recordToLoad.getHasAccess()) {
347                        BudgetConstructionLockStatus lockStatus = this.lockService.lockAccountAndCommit(header, user.getPrincipalId());
348                        if (lockStatus.getLockStatus().equals(BCConstants.LockStatus.SUCCESS)) {
349                            recordToLoad.setHasLock(true);
350                        } else {
351                            recordToLoad.setRequestUpdateErrorCode(BCConstants.RequestImportErrorCode.UPDATE_ERROR_CODE_BUDGET_ACCOUNT_LOCKED.getErrorCode());
352                            errorMessages.add(recordToLoad.getErrorLinePrefixForLogFile() + " " + BCConstants.RequestImportErrorCode.UPDATE_ERROR_CODE_BUDGET_ACCOUNT_LOCKED.getMessage());
353                        }
354                    }
355    
356                    recordMap.put(recordToLoad.getSubAccountingString(), recordToLoad);
357                }
358                
359                //since error codes are copied based on the locking key, the previous records error code from the updateBudgetAmounts may have been copied to this record and should be ignored.
360                String updateAmountPreviousErrorMessage =BCConstants.RequestImportErrorCode.UPDATE_ERROR_CODE_MONTHLY_BUDGET_DELETED.getErrorCode();
361                if (recordToLoad.getHasAccess() && recordToLoad.getHasLock() && 
362                        ( StringUtils.isBlank(recordToLoad.getRequestUpdateErrorCode()) || recordToLoad.getRequestUpdateErrorCode().endsWith(updateAmountPreviousErrorMessage)) ) {
363                    String updateBudgetAmountErrorMessage = updateBudgetAmounts(fileType, recordToLoad, header, budgetYear);
364                    if (!StringUtils.isEmpty(updateBudgetAmountErrorMessage))
365                        errorMessages.add(recordToLoad.getErrorLinePrefixForLogFile() + " " + updateBudgetAmountErrorMessage);
366                }
367    
368                importRequestDao.save(recordToLoad, true);
369            }
370    
371            for (String key : recordMap.keySet()) {
372                BudgetConstructionRequestMove record = recordMap.get(key);
373                BudgetConstructionHeader header = importRequestDao.getHeaderRecord(record, budgetYear);
374                if (record.getHasAccess() && record.getHasLock() && StringUtils.isBlank(record.getRequestUpdateErrorCode())) {
375                    udpateBenefits(fileType, header);
376                }
377    
378                if (record.getHasLock() && header != null) {
379                    this.lockService.unlockAccount(header);
380                }
381            }
382    
383            deleteBudgetConstructionMoveRecords(user.getPrincipalId());
384            return errorMessages;
385        }
386    
387        /**
388         * @see org.kuali.kfs.module.bc.document.service.BudgetRequestImportService#getImportRequestDao()
389         */
390        @NonTransactional
391        public ImportRequestDao getImportRequestDao() {
392            return this.importRequestDao;
393        }
394    
395        /**
396         * @see org.kuali.kfs.module.bc.document.service.BudgetRequestImportService#setImportRequestDao(org.kuali.kfs.module.bc.document.dataaccess.ImportRequestDao)
397         */
398        @NonTransactional
399        public void setImportRequestDao(ImportRequestDao dao) {
400            this.importRequestDao = dao;
401    
402        }
403    
404        /**
405         * updates budget amounts
406         * 
407         * @param fileType
408         * @param importLine
409         * @return error message
410         */
411        protected String updateBudgetAmounts(String fileType, BudgetConstructionRequestMove importLine, BudgetConstructionHeader header, Integer budgetYear) {
412            String errorMessage = "";
413            
414            //set primary key values
415            PendingBudgetConstructionGeneralLedger pendingEntry = new PendingBudgetConstructionGeneralLedger();
416            pendingEntry.setDocumentNumber(header.getDocumentNumber());
417            pendingEntry.setUniversityFiscalYear(budgetYear);
418            pendingEntry.setChartOfAccountsCode(importLine.getChartOfAccountsCode());
419            pendingEntry.setAccountNumber(importLine.getAccountNumber());
420            pendingEntry.setSubAccountNumber(importLine.getSubAccountNumber());
421            pendingEntry.setFinancialObjectCode(importLine.getFinancialObjectCode());
422            pendingEntry.setFinancialSubObjectCode(importLine.getFinancialSubObjectCode());
423            pendingEntry.setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_BASE_BUDGET);
424            pendingEntry.setFinancialObjectTypeCode(importLine.getFinancialObjectTypeCode());
425            
426            //if entry already exists, use existing entry
427            PendingBudgetConstructionGeneralLedger retrievedPendingEntry = (PendingBudgetConstructionGeneralLedger) businessObjectService.retrieve(pendingEntry);
428            if (retrievedPendingEntry != null) pendingEntry = retrievedPendingEntry;
429            else pendingEntry.setFinancialBeginningBalanceLineAmount(new KualiInteger(0));
430                
431            if (fileType.equalsIgnoreCase(BCConstants.RequestImportFileType.ANNUAL.toString())) {
432                List<BudgetConstructionMonthly> monthlyRecords = pendingEntry.getBudgetConstructionMonthly();
433    
434                if (!monthlyRecords.isEmpty()) {
435                    importLine.setRequestUpdateErrorCode(BCConstants.RequestImportErrorCode.UPDATE_ERROR_CODE_MONTHLY_BUDGET_DELETED.getErrorCode());
436                    errorMessage = BCConstants.RequestImportErrorCode.UPDATE_ERROR_CODE_MONTHLY_BUDGET_DELETED.getMessage();
437                    for (BudgetConstructionMonthly monthlyRecord : monthlyRecords) {
438                        businessObjectService.delete(monthlyRecord);
439                    }
440                    
441                    importRequestDao.save(importLine, true);
442                }
443    
444                pendingEntry.setAccountLineAnnualBalanceAmount(importLine.getAccountLineAnnualBalanceAmount());
445                this.businessObjectService.save(pendingEntry);
446            }
447            else if (fileType.equalsIgnoreCase(BCConstants.RequestImportFileType.MONTHLY.toString())) {
448                
449                //calculate account line annual balance amount
450                KualiInteger annualAmount = new KualiInteger(0);
451                annualAmount = annualAmount.add(importLine.getFinancialDocumentMonth1LineAmount());
452                annualAmount = annualAmount.add(importLine.getFinancialDocumentMonth2LineAmount());
453                annualAmount = annualAmount.add(importLine.getFinancialDocumentMonth3LineAmount());
454                annualAmount = annualAmount.add(importLine.getFinancialDocumentMonth4LineAmount());
455                annualAmount = annualAmount.add(importLine.getFinancialDocumentMonth5LineAmount());
456                annualAmount = annualAmount.add(importLine.getFinancialDocumentMonth6LineAmount());
457                annualAmount = annualAmount.add(importLine.getFinancialDocumentMonth7LineAmount());
458                annualAmount = annualAmount.add(importLine.getFinancialDocumentMonth8LineAmount());
459                annualAmount = annualAmount.add(importLine.getFinancialDocumentMonth9LineAmount());
460                annualAmount = annualAmount.add(importLine.getFinancialDocumentMonth10LineAmount());
461                annualAmount = annualAmount.add(importLine.getFinancialDocumentMonth11LineAmount());
462                annualAmount = annualAmount.add(importLine.getFinancialDocumentMonth12LineAmount());
463                pendingEntry.setAccountLineAnnualBalanceAmount(annualAmount);
464                
465                
466                //set primary key values
467                BudgetConstructionMonthly monthlyEntry = new BudgetConstructionMonthly();
468                monthlyEntry.setDocumentNumber(header.getDocumentNumber());
469                monthlyEntry.setUniversityFiscalYear(budgetYear);
470                monthlyEntry.setChartOfAccountsCode(importLine.getChartOfAccountsCode());
471                monthlyEntry.setAccountNumber(importLine.getAccountNumber());
472                monthlyEntry.setSubAccountNumber(importLine.getSubAccountNumber());
473                monthlyEntry.setFinancialObjectCode(importLine.getFinancialObjectCode());
474                monthlyEntry.setFinancialSubObjectCode(importLine.getFinancialSubObjectCode());
475                monthlyEntry.setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_BASE_BUDGET);
476                monthlyEntry.setFinancialObjectTypeCode(importLine.getFinancialObjectTypeCode());
477                
478                //if entry already exists, use existing entry
479                BudgetConstructionMonthly retrievedMonthlyEntry = (BudgetConstructionMonthly) businessObjectService.retrieve(monthlyEntry);
480                if (retrievedMonthlyEntry != null) {
481                    monthlyEntry = retrievedMonthlyEntry;
482                    //monthlyEntry.getPendingBudgetConstructionGeneralLedger().setAccountLineAnnualBalanceAmount(annualAmount);
483                }
484                /*else {
485                    pendingEntry.setAccountLineAnnualBalanceAmount(annualAmount);
486                    monthlyEntry.setPendingBudgetConstructionGeneralLedger(pendingEntry);
487                }*/
488                
489                monthlyEntry.setFinancialDocumentMonth1LineAmount(importLine.getFinancialDocumentMonth1LineAmount());
490                monthlyEntry.setFinancialDocumentMonth2LineAmount(importLine.getFinancialDocumentMonth2LineAmount());
491                monthlyEntry.setFinancialDocumentMonth3LineAmount(importLine.getFinancialDocumentMonth3LineAmount());
492                monthlyEntry.setFinancialDocumentMonth4LineAmount(importLine.getFinancialDocumentMonth4LineAmount());
493                monthlyEntry.setFinancialDocumentMonth5LineAmount(importLine.getFinancialDocumentMonth5LineAmount());
494                monthlyEntry.setFinancialDocumentMonth6LineAmount(importLine.getFinancialDocumentMonth6LineAmount());
495                monthlyEntry.setFinancialDocumentMonth7LineAmount(importLine.getFinancialDocumentMonth7LineAmount());
496                monthlyEntry.setFinancialDocumentMonth8LineAmount(importLine.getFinancialDocumentMonth8LineAmount());
497                monthlyEntry.setFinancialDocumentMonth9LineAmount(importLine.getFinancialDocumentMonth9LineAmount());
498                monthlyEntry.setFinancialDocumentMonth10LineAmount(importLine.getFinancialDocumentMonth10LineAmount());
499                monthlyEntry.setFinancialDocumentMonth11LineAmount(importLine.getFinancialDocumentMonth11LineAmount());
500                monthlyEntry.setFinancialDocumentMonth12LineAmount(importLine.getFinancialDocumentMonth12LineAmount());
501                
502                this.businessObjectService.save(pendingEntry);
503                this.businessObjectService.save(monthlyEntry);
504                
505            }
506    
507            return errorMessage;
508        }
509    
510        /**
511         * Updates benefits
512         * 
513         * @param fileType
514         * @param importLine
515         */
516        protected void udpateBenefits(String fileType, BudgetConstructionHeader header) {
517            BenefitsCalculationService benefitsCalculationService = SpringContext.getBean(BenefitsCalculationService.class);
518    
519            benefitsCalculationService.calculateAnnualBudgetConstructionGeneralLedgerBenefits(header.getDocumentNumber(), header.getUniversityFiscalYear(), header.getChartOfAccountsCode(), header.getAccountNumber(), header.getSubAccountNumber());
520    
521            if (fileType.equalsIgnoreCase(BCConstants.RequestImportFileType.MONTHLY.toString())) {
522                benefitsCalculationService.calculateMonthlyBudgetConstructionGeneralLedgerBenefits(header.getDocumentNumber(), header.getUniversityFiscalYear(), header.getChartOfAccountsCode(), header.getAccountNumber(), header.getSubAccountNumber());
523            }
524        }
525    
526        /**
527         * Checks line validations and returns error messages for line
528         * 
529         * @param budgetConstructionRequestMove
530         * @param lineNumber
531         * @param isAnnual
532         * @return
533         */
534    
535        protected String validateLine(BudgetConstructionRequestMove budgetConstructionRequestMove, int lineNumber, boolean isAnnual) {
536            
537            if ( !this.dictionaryValidationService.isBusinessObjectValid(budgetConstructionRequestMove)) {
538                return BCConstants.REQUEST_IMPORT_FILE_PROCESSING_ERROR_MESSAGE_GENERIC + " " + lineNumber + ".";
539            }
540    
541            if (isAnnual) {
542                if (budgetConstructionRequestMove.getAccountLineAnnualBalanceAmount().compareTo(new KualiInteger(999999999)) >= 0 || budgetConstructionRequestMove.getAccountLineAnnualBalanceAmount().compareTo(new KualiInteger(-999999999)) <= 0) {
543                    return BCConstants.REQUEST_IMPORT_FILE_PROCESSING_ERROR_MESSAGE_GENERIC + " " + lineNumber + ".";
544                }
545            }
546    
547            if (!isAnnual) {
548    
549                if (budgetConstructionRequestMove.getFinancialDocumentMonth1LineAmount().compareTo(new KualiInteger(999999999)) >= 0 || budgetConstructionRequestMove.getFinancialDocumentMonth1LineAmount().compareTo(new KualiInteger(-999999999)) <= 0) {
550                    return BCConstants.REQUEST_IMPORT_FILE_PROCESSING_ERROR_MESSAGE_GENERIC + " " + lineNumber + ".";
551                }
552                if (budgetConstructionRequestMove.getFinancialDocumentMonth2LineAmount().compareTo(new KualiInteger(999999999)) >= 0 || budgetConstructionRequestMove.getFinancialDocumentMonth2LineAmount().compareTo(new KualiInteger(-999999999)) <= 0) {
553                    return BCConstants.REQUEST_IMPORT_FILE_PROCESSING_ERROR_MESSAGE_GENERIC + " " + lineNumber + ".";
554                }
555                if (budgetConstructionRequestMove.getFinancialDocumentMonth3LineAmount().compareTo(new KualiInteger(999999999)) >= 0 || budgetConstructionRequestMove.getFinancialDocumentMonth3LineAmount().compareTo(new KualiInteger(-999999999)) <= 0) {
556                    return BCConstants.REQUEST_IMPORT_FILE_PROCESSING_ERROR_MESSAGE_GENERIC + " " + lineNumber + ".";
557                }
558                if (budgetConstructionRequestMove.getFinancialDocumentMonth4LineAmount().compareTo(new KualiInteger(999999999)) >= 0 || budgetConstructionRequestMove.getFinancialDocumentMonth4LineAmount().compareTo(new KualiInteger(-999999999)) <= 0) {
559                    return BCConstants.REQUEST_IMPORT_FILE_PROCESSING_ERROR_MESSAGE_GENERIC + " " + lineNumber + ".";
560                }
561                if (budgetConstructionRequestMove.getFinancialDocumentMonth5LineAmount().compareTo(new KualiInteger(999999999)) >= 0 || budgetConstructionRequestMove.getFinancialDocumentMonth5LineAmount().compareTo(new KualiInteger(-999999999)) <= 0) {
562                    return BCConstants.REQUEST_IMPORT_FILE_PROCESSING_ERROR_MESSAGE_GENERIC + " " + lineNumber + ".";
563                }
564                if (budgetConstructionRequestMove.getFinancialDocumentMonth6LineAmount().compareTo(new KualiInteger(999999999)) >= 0 || budgetConstructionRequestMove.getFinancialDocumentMonth6LineAmount().compareTo(new KualiInteger(-999999999)) <= 0) {
565                    return BCConstants.REQUEST_IMPORT_FILE_PROCESSING_ERROR_MESSAGE_GENERIC + " " + lineNumber + ".";
566                }
567                if (budgetConstructionRequestMove.getFinancialDocumentMonth7LineAmount().compareTo(new KualiInteger(999999999)) >= 0 || budgetConstructionRequestMove.getFinancialDocumentMonth7LineAmount().compareTo(new KualiInteger(-999999999)) <= 0) {
568                    return BCConstants.REQUEST_IMPORT_FILE_PROCESSING_ERROR_MESSAGE_GENERIC + " " + lineNumber + ".";
569                }
570                if (budgetConstructionRequestMove.getFinancialDocumentMonth8LineAmount().compareTo(new KualiInteger(999999999)) >= 0 || budgetConstructionRequestMove.getFinancialDocumentMonth8LineAmount().compareTo(new KualiInteger(-999999999)) <= 0) {
571                    return BCConstants.REQUEST_IMPORT_FILE_PROCESSING_ERROR_MESSAGE_GENERIC + " " + lineNumber + ".";
572                }
573                if (budgetConstructionRequestMove.getFinancialDocumentMonth9LineAmount().compareTo(new KualiInteger(999999999)) >= 0 || budgetConstructionRequestMove.getFinancialDocumentMonth9LineAmount().compareTo(new KualiInteger(-999999999)) <= 0) {
574                    return BCConstants.REQUEST_IMPORT_FILE_PROCESSING_ERROR_MESSAGE_GENERIC + " " + lineNumber + ".";
575                }
576                if (budgetConstructionRequestMove.getFinancialDocumentMonth10LineAmount().compareTo(new KualiInteger(999999999)) >= 0 || budgetConstructionRequestMove.getFinancialDocumentMonth10LineAmount().compareTo(new KualiInteger(-999999999)) <= 0) {
577                    return BCConstants.REQUEST_IMPORT_FILE_PROCESSING_ERROR_MESSAGE_GENERIC + " " + lineNumber + ".";
578                }
579                if (budgetConstructionRequestMove.getFinancialDocumentMonth11LineAmount().compareTo(new KualiInteger(999999999)) >= 0 || budgetConstructionRequestMove.getFinancialDocumentMonth11LineAmount().compareTo(new KualiInteger(-999999999)) <= 0) {
580                    return BCConstants.REQUEST_IMPORT_FILE_PROCESSING_ERROR_MESSAGE_GENERIC + " " + lineNumber + ".";
581                }
582                if (budgetConstructionRequestMove.getFinancialDocumentMonth12LineAmount().compareTo(new KualiInteger(999999999)) >= 0 || budgetConstructionRequestMove.getFinancialDocumentMonth12LineAmount().compareTo(new KualiInteger(-999999999)) <= 0) {
583                    return BCConstants.REQUEST_IMPORT_FILE_PROCESSING_ERROR_MESSAGE_GENERIC + " " + lineNumber + ".";
584                }
585            }
586    
587            return "";
588        }
589        
590        protected ObjectCode getObjectCode(BudgetConstructionRequestMove record, Integer budgetYear) {
591            Map searchCriteria = new HashMap();
592    
593            searchCriteria.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, budgetYear);
594            searchCriteria.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, record.getChartOfAccountsCode());
595            searchCriteria.put(KFSPropertyConstants.FINANCIAL_OBJECT_CODE, record.getFinancialObjectCode());
596    
597            List<ObjectCode> objectList = new ArrayList<ObjectCode>(businessObjectService.findMatching(ObjectCode.class, searchCriteria));
598    
599            if (objectList.size() == 1)
600                return objectList.get(0);
601    
602            return null;
603        }
604    
605        protected SubObjectCode getSubObjectCode(BudgetConstructionRequestMove record, Integer budgetYear) {
606            Map searchCriteria = new HashMap();
607    
608            searchCriteria.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, budgetYear);
609            searchCriteria.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, record.getChartOfAccountsCode());
610            searchCriteria.put(KFSPropertyConstants.FINANCIAL_OBJECT_CODE, record.getFinancialObjectCode());
611            searchCriteria.put(KFSPropertyConstants.ACCOUNT_NUMBER, record.getAccountNumber());
612            searchCriteria.put(KFSPropertyConstants.FINANCIAL_SUB_OBJECT_CODE, record.getFinancialSubObjectCode());
613    
614            List<SubObjectCode> objectList = new ArrayList<SubObjectCode> (this.businessObjectService.findMatching(SubObjectCode.class, searchCriteria));
615    
616            if (objectList.size() == 1)
617                return objectList.get(0);
618    
619            return null;
620        }
621    
622        protected List<BudgetConstructionFundingLock> findBudgetLocks(BudgetConstructionRequestMove record, Integer budgetYear) {
623            Map searchCriteria = new HashMap();
624    
625            searchCriteria.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, budgetYear);
626            searchCriteria.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, record.getChartOfAccountsCode());
627            searchCriteria.put(KFSPropertyConstants.ACCOUNT_NUMBER, record.getAccountNumber());
628            searchCriteria.put(KFSPropertyConstants.SUB_ACCOUNT_NUMBER, record.getSubAccountNumber());
629    
630            List<BudgetConstructionFundingLock> lockList = new ArrayList<BudgetConstructionFundingLock> (this.businessObjectService.findMatching(BudgetConstructionFundingLock.class, searchCriteria));
631    
632            return lockList;
633        }
634    
635        List<BudgetConstructionMonthly> getMonthlyRecords(BudgetConstructionRequestMove record, BudgetConstructionHeader header) {
636            Map searchCriteria = new HashMap();
637    
638            searchCriteria.put(KFSPropertyConstants.DOCUMENT_NUMBER, header.getDocumentNumber());
639            searchCriteria.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, header.getUniversityFiscalYear());
640            searchCriteria.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, record.getChartOfAccountsCode());
641            searchCriteria.put(KFSPropertyConstants.ACCOUNT_NUMBER, record.getAccountNumber());
642            searchCriteria.put(KFSPropertyConstants.SUB_ACCOUNT_NUMBER, record.getSubAccountNumber());
643            searchCriteria.put(KFSPropertyConstants.FINANCIAL_OBJECT_CODE, record.getFinancialObjectCode());
644            searchCriteria.put(KFSPropertyConstants.FINANCIAL_SUB_OBJECT_CODE, record.getFinancialSubObjectCode());
645            searchCriteria.put(KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE, record.getFinancialObjectTypeCode());
646            searchCriteria.put(KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE, KFSConstants.BALANCE_TYPE_BASE_BUDGET);
647    
648            return new ArrayList<BudgetConstructionMonthly> (this.businessObjectService.findMatching(BudgetConstructionMonthly.class, searchCriteria));
649        }
650    
651        /**
652         * Clears BudgetConstructionRequestMove
653         * 
654         * @param principalId
655         */
656        protected void deleteBudgetConstructionMoveRecords(String principalId) {
657            Map<String, String> fieldValues = new HashMap<String, String>();
658            fieldValues.put(KFSPropertyConstants.PERSON_UNIVERSAL_IDENTIFIER, principalId);
659            businessObjectService.deleteMatching(BudgetConstructionRequestMove.class, fieldValues);
660        }
661        
662        /**
663         * 
664         * @see org.kuali.kfs.module.bc.document.service.BudgetRequestImportService#setDictionaryValidationService(org.kuali.rice.kns.service.DictionaryValidationService)
665         */
666        @NonTransactional
667        public void setDictionaryValidationService(DictionaryValidationService dictionaryValidationService) {
668            this.dictionaryValidationService = dictionaryValidationService;
669            
670        }
671        
672        /**
673         * 
674         * @see org.kuali.kfs.module.bc.document.service.BudgetRequestImportService#setLockService(org.kuali.kfs.module.bc.document.service.LockService)
675         */
676        @NonTransactional
677        public void setLockService(LockService lockService) {
678           this.lockService = lockService;
679        }
680        
681        /**
682         * Sets BudgetDocumentService
683         * 
684         * @param budgetDocumentService
685         */
686        @NonTransactional
687        public void setBudgetDocumentService(BudgetDocumentService budgetDocumentService) {
688            this.budgetDocumentService = budgetDocumentService;
689        }
690        
691        @NonTransactional
692        public void setLaborModuleService(LaborModuleService laborModuleService) {
693            this.laborModuleService = laborModuleService;
694        }
695        
696        @NonTransactional
697        public LaborModuleService getLaborModuleService() {
698            return this.laborModuleService;
699        }
700        
701        @NonTransactional
702        public BudgetParameterService getBudgetParameterService() {
703            return budgetParameterService;
704        }
705        
706        @NonTransactional
707        public void setBudgetParameterService(BudgetParameterService budgetParameterService) {
708            this.budgetParameterService = budgetParameterService;
709        }
710        
711        @NonTransactional
712        public OptionsService getOptionsService() {
713            return optionsService;
714        }
715        
716        @NonTransactional
717        public void setOptionsService(OptionsService optionsService) {
718            this.optionsService = optionsService;
719        }
720    
721        @NonTransactional
722        public DocumentHelperService getDocumentHelperService() {
723            return documentHelperService;
724        }
725    
726        @NonTransactional
727        public void setDocumentHelperService(DocumentHelperService documentHelperService) {
728            this.documentHelperService = documentHelperService;
729        }
730    
731        @NonTransactional
732        protected DocumentService getDocumentService() {
733            return documentService;
734        }
735    
736        @NonTransactional
737        public void setDocumentService(DocumentService documentService) {
738            this.documentService = documentService;
739        }
740        
741    }
742