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.sys.document.service.impl;
017    
018    import java.sql.Date;
019    import java.text.MessageFormat;
020    import java.util.List;
021    
022    import org.kuali.kfs.coa.businessobject.AccountingPeriod;
023    import org.kuali.kfs.coa.businessobject.BalanceType;
024    import org.kuali.kfs.coa.businessobject.ObjectCode;
025    import org.kuali.kfs.coa.service.ObjectCodeService;
026    import org.kuali.kfs.coa.service.ObjectTypeService;
027    import org.kuali.kfs.sys.KFSConstants;
028    import org.kuali.kfs.sys.KFSKeyConstants;
029    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail;
030    import org.kuali.kfs.sys.context.SpringContext;
031    import org.kuali.kfs.sys.document.service.AccountingDocumentRuleHelperService;
032    import org.kuali.rice.kns.datadictionary.AttributeDefinition;
033    import org.kuali.rice.kns.datadictionary.DataDictionaryEntry;
034    import org.kuali.rice.kns.service.DataDictionaryService;
035    import org.kuali.rice.kns.service.DateTimeService;
036    import org.kuali.rice.kns.service.KualiConfigurationService;
037    import org.kuali.rice.kns.util.GlobalVariables;
038    import org.kuali.rice.kns.util.ObjectUtils;
039    
040    /**
041     * The default implementation of the AccountingDocumentRuleHelperService
042     */
043    public class AccountingDocumentRuleHelperServiceImpl implements AccountingDocumentRuleHelperService {
044        private DataDictionaryService ddService;
045        private ObjectTypeService objectTypeService;
046    
047        /**
048         * @see org.kuali.kfs.sys.document.service.AccountingDocumentRuleHelperService#isExpense(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail)
049         */
050        public boolean isExpense(GeneralLedgerPendingEntrySourceDetail postable) {
051            // return SpringContext.getBean(KualiConfigurationService.class).succeedsRule(KFSConstants.FINANCIAL_NAMESPACE,
052            // KUALI_TRANSACTION_PROCESSING_GLOBAL_RULES_SECURITY_GROUPING, APPLICATION_PARAMETER.EXPENSE_OBJECT_TYPE_CODES,
053            // getObjectCodeTypeCodeWithoutSideEffects(accountingLine) );
054            List<String> expenseObjectTypes = objectTypeService.getCurrentYearBasicExpenseObjectTypes();
055            return expenseObjectTypes.contains(getObjectCodeTypeCodeWithoutSideEffects(postable));
056        }
057    
058        /**
059         * @see org.kuali.kfs.sys.document.service.AccountingDocumentRuleHelperService#isIncome(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail)
060         */
061        public boolean isIncome(GeneralLedgerPendingEntrySourceDetail postable) {
062            List<String> incomeObjectTypes = objectTypeService.getCurrentYearBasicIncomeObjectTypes();
063            return incomeObjectTypes.contains(getObjectCodeTypeCodeWithoutSideEffects(postable));
064        }
065    
066        /**
067         * Makes sure that the objectCode attribute is fully populated b/c we are using proxying in our persistence layer.
068         * 
069         * @param accountingLine
070         * @return the object type code of the object code of the given accounting line
071         */
072        public String getObjectCodeTypeCodeWithoutSideEffects(GeneralLedgerPendingEntrySourceDetail postable) {
073            Integer fiscalYear = postable.getPostingYear();
074            String chartOfAccountsCode = postable.getChartOfAccountsCode();
075            String financialObjectCode = postable.getFinancialObjectCode();
076    
077            ObjectCodeService objectCodeService = SpringContext.getBean(ObjectCodeService.class);
078            ObjectCode objectCode = objectCodeService.getByPrimaryIdWithCaching(fiscalYear, chartOfAccountsCode, financialObjectCode);
079    
080            return ObjectUtils.isNotNull(objectCode) ? objectCode.getFinancialObjectTypeCode() : null;
081        }
082    
083        /**
084         * @see org.kuali.kfs.sys.document.service.AccountingDocumentRuleHelperService#isValidBalanceType(org.kuali.kfs.coa.businessobject.BalanceTyp,
085         *      java.lang.String)
086         */
087        public boolean isValidBalanceType(BalanceType balanceType, String errorPropertyName) {
088            return isValidBalanceType(balanceType, BalanceType.class, errorPropertyName, errorPropertyName);
089        }
090    
091        /**
092         * Looks up a label from the data dictionary
093         * 
094         * @param entryClass the class of the attribute to lookup the label for
095         * @param attributeName the attribute to look up the label for
096         * @return the label
097         */
098        protected String getLabelFromDataDictionary(Class entryClass, String attributeName) {
099            DataDictionaryEntry entry = ddService.getDataDictionary().getDictionaryObjectEntry(entryClass.getName());
100            if (entry == null) {
101                throw new IllegalArgumentException("Cannot find DataDictionary entry for " + entryClass);
102            }
103            AttributeDefinition attributeDefinition = entry.getAttributeDefinition(attributeName);
104            if (attributeDefinition == null) {
105                throw new IllegalArgumentException("Cannot find " + entryClass + " attribute with name " + attributeName);
106            }
107            return attributeDefinition.getLabel();
108        }
109    
110        /**
111         * @see org.kuali.kfs.sys.document.service.AccountingDocumentRuleHelperService#isValidBalanceType(org.kuali.kfs.coa.businessobject.BalanceTyp,
112         *      java.lang.Class, java.lang.String, java.lang.String)
113         */
114        public boolean isValidBalanceType(BalanceType balanceType, Class entryClass, String attributeName, String errorPropertyName) {
115            String label = getLabelFromDataDictionary(entryClass, attributeName);
116            if (ObjectUtils.isNull(balanceType)) {
117                GlobalVariables.getMessageMap().putError(errorPropertyName, KFSKeyConstants.ERROR_EXISTENCE, label);
118                return false;
119            }
120            // make sure it's active for usage
121            if (!balanceType.isActive()) {
122                GlobalVariables.getMessageMap().putError(errorPropertyName, KFSKeyConstants.ERROR_INACTIVE, label);
123                return false;
124            }
125            return true;
126        }
127    
128        /**
129         * @see org.kuali.kfs.sys.document.service.AccountingDocumentRuleHelperService#isValidOpenAccountingPeriod(org.kuali.kfs.coa.businessobject.AccountingPeriod,
130         *      java.lang.Class, java.lang.String, java.lang.String)
131         */
132        public boolean isValidOpenAccountingPeriod(AccountingPeriod accountingPeriod, Class entryClass, String attribueName, String errorPropertyName) {
133            // retrieve from system to make sure it exists
134            String label = getLabelFromDataDictionary(entryClass, attribueName);
135            if (ObjectUtils.isNull(accountingPeriod)) {
136                GlobalVariables.getMessageMap().putError(errorPropertyName, KFSKeyConstants.ERROR_EXISTENCE, label);
137                return false;
138            }
139    
140            // make sure it's open for use
141            if (!accountingPeriod.isActive()) {
142                GlobalVariables.getMessageMap().putError(errorPropertyName, KFSKeyConstants.ERROR_DOCUMENT_ACCOUNTING_PERIOD_CLOSED);
143                return false;
144            }
145    
146            return true;
147        }
148    
149        /**
150         * @see org.kuali.kfs.sys.document.service.AccountingDocumentRuleHelperService#isValidReversalDate(java.sql.Date,
151         *      java.lang.String)
152         */
153        public boolean isValidReversalDate(Date reversalDate, String errorPropertyName) {
154            java.sql.Date today = SpringContext.getBean(DateTimeService.class).getCurrentSqlDateMidnight();
155            if (null != reversalDate && reversalDate.before(today)) {
156                GlobalVariables.getMessageMap().putError(errorPropertyName, KFSKeyConstants.ERROR_DOCUMENT_INCORRECT_REVERSAL_DATE);
157                return false;
158            }
159            else {
160                return true;
161            }
162        }
163    
164        /**
165         * Gets the named property from KualiConfigurationService (i.e., from ApplicationResources.properties) and formats it with the
166         * given arguments (if any).
167         * 
168         * @param propertyName
169         * @param arguments
170         * @return the formatted property (i.e., message), with any {@code {0}} replaced with the first argument, {@code {1}} with the
171         *         second argument, etc.
172         */
173        public String formatProperty(String propertyName, Object... arguments) {
174            return MessageFormat.format(SpringContext.getBean(KualiConfigurationService.class).getPropertyString(propertyName), arguments);
175        }
176    
177        /**
178         * Sets the dataDictionaryService attribute value.
179         * 
180         * @param ddService The ddService to set.
181         */
182        public void setDataDictionaryService(DataDictionaryService ddService) {
183            this.ddService = ddService;
184        }
185    
186        /**
187         * Sets the objectTypeService attribute value.
188         * 
189         * @param objectTypeService The objectTypeService to set.
190         */
191        public void setObjectTypeService(ObjectTypeService objectTypeService) {
192            this.objectTypeService = objectTypeService;
193        }
194    
195    }