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.ar.document.validation.impl;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.apache.log4j.Logger;
020    import org.kuali.kfs.coa.businessobject.ObjectCode;
021    import org.kuali.kfs.coa.service.ObjectTypeService;
022    import org.kuali.kfs.module.ar.ArConstants;
023    import org.kuali.kfs.module.ar.ArKeyConstants;
024    import org.kuali.kfs.module.ar.ArPropertyConstants;
025    import org.kuali.kfs.module.ar.businessobject.OrganizationAccountingDefault;
026    import org.kuali.kfs.module.ar.document.CustomerInvoiceDocument;
027    import org.kuali.kfs.module.ar.document.CustomerInvoiceWriteoffDocument;
028    import org.kuali.kfs.sys.context.SpringContext;
029    import org.kuali.rice.kns.document.MaintenanceDocument;
030    import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
031    import org.kuali.rice.kns.service.ParameterService;
032    import org.kuali.rice.kns.util.ObjectUtils;
033    
034    public class OrganizationAccountingDefaultRule extends MaintenanceDocumentRuleBase {
035        protected static Logger LOG = org.apache.log4j.Logger.getLogger(OrganizationAccountingDefaultRule.class);
036    
037        protected ObjectTypeService objectTypeService;
038        protected OrganizationAccountingDefault newOrganizationAccountingDefault;
039        protected OrganizationAccountingDefault oldOrganizationAccountingDefault;
040    
041        public OrganizationAccountingDefaultRule() {
042    
043            // insert object type service
044            this.setObjectTypeService(SpringContext.getBean(ObjectTypeService.class));
045        }
046    
047        @Override
048        public void setupConvenienceObjects() {
049            newOrganizationAccountingDefault = (OrganizationAccountingDefault) super.getNewBo();
050            oldOrganizationAccountingDefault = (OrganizationAccountingDefault) super.getOldBo();
051        }
052    
053        @Override
054        protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) {
055    
056            boolean success = true;
057            success &= isWriteOffObjectValidExpense(newOrganizationAccountingDefault);
058            success &= isLateChargeObjectValidIncome(newOrganizationAccountingDefault);
059            success &= isDefaultInvoiceFinancialObjectValidIncome(newOrganizationAccountingDefault);
060            
061            // validate receivable FAU line if system parameter for receivable is set to 3
062            String receivableOffsetOption = SpringContext.getBean(ParameterService.class).getParameterValue(CustomerInvoiceDocument.class, ArConstants.GLPE_RECEIVABLE_OFFSET_GENERATION_METHOD);
063            if (ArConstants.GLPE_RECEIVABLE_OFFSET_GENERATION_METHOD_FAU.equals(receivableOffsetOption)) {
064                success &= doesPaymentAccountNumberExist(newOrganizationAccountingDefault);
065                success &= doesPaymentChartOfAccountsCodeExist(newOrganizationAccountingDefault);
066                success &= doesPaymentFinancialObjectCodeExist(newOrganizationAccountingDefault);
067            }
068            
069            // validate writeoff FAU line if system parameter for writeoff is set to 2
070            String writeoffOption = SpringContext.getBean(ParameterService.class).getParameterValue(CustomerInvoiceWriteoffDocument.class, ArConstants.GLPE_WRITEOFF_GENERATION_METHOD);
071            if (ArConstants.GLPE_WRITEOFF_GENERATION_METHOD_ORG_ACCT_DEFAULT.equals(writeoffOption)) {
072                success &= doesWriteoffAccountNumberExist(newOrganizationAccountingDefault);
073                success &= doesWriteoffChartOfAccountsCodeExist(newOrganizationAccountingDefault);
074                success &= doesWriteoffFinancialObjectCodeExist(newOrganizationAccountingDefault);
075            }        
076    
077            return success;
078        }
079        
080        
081    
082        /**
083         * This method returns true if payment account number is provided and is valid.
084         * 
085         * @param doc
086         * @return
087         */
088        protected boolean doesWriteoffAccountNumberExist(OrganizationAccountingDefault organizationAccountingDefault) {
089    
090            if (StringUtils.isEmpty(organizationAccountingDefault.getWriteoffAccountNumber())) {
091                putFieldError(ArPropertyConstants.OrganizationAccountingDefaultFields.WRITEOFF_ACCOUNT_NUMBER, ArKeyConstants.OrganizationAccountingDefaultErrors.ERROR_WRITEOFF_ACCOUNT_NUMBER_REQUIRED);
092                return false;
093            }
094    
095            return true;
096        }
097    
098        /**
099         * This method returns true if payment chart of accounts code is provided and is valid
100         * 
101         * @param doc
102         * @return
103         */
104        protected boolean doesWriteoffChartOfAccountsCodeExist(OrganizationAccountingDefault organizationAccountingDefault) {
105    
106            if (StringUtils.isEmpty(organizationAccountingDefault.getWriteoffChartOfAccountsCode())) {
107                putFieldError(ArPropertyConstants.OrganizationAccountingDefaultFields.WRITEOFF_CHART_OF_ACCOUNTS_CODE, ArKeyConstants.OrganizationAccountingDefaultErrors.ERROR_WRITEOFF_CHART_OF_ACCOUNTS_CODE_REQUIRED);
108                return false;
109            }
110    
111            return true;
112        }
113    
114        /**
115         * This method returns true if payment financial object code is provided and is valid
116         * 
117         * @param doc
118         * @return
119         */
120        protected boolean doesWriteoffFinancialObjectCodeExist(OrganizationAccountingDefault organizationAccountingDefault) {
121            if (StringUtils.isEmpty(organizationAccountingDefault.getWriteoffFinancialObjectCode())) {
122                putFieldError(ArPropertyConstants.OrganizationAccountingDefaultFields.WRITEOFF_FINANCIAL_OBJECT_CODE, ArKeyConstants.OrganizationAccountingDefaultErrors.ERROR_WRITEOFF_OBJECT_CODE_REQUIRED);
123                return false;
124            }
125    
126            return true;
127        }    
128    
129    
130        @Override
131        protected boolean processCustomSaveDocumentBusinessRules(MaintenanceDocument document) {
132            // always return true even if there are business rule failures.
133            processCustomRouteDocumentBusinessRules(document);
134            return true;
135    
136        }
137    
138        /**
139         * 
140         * This method checks to see if the Org specified in this document has an Org Options record for it
141         * 
142         * @return false if it does not have an OrgOptions record
143         */
144        protected boolean checkOrgOptionsExists() {
145            return true;
146        }
147    
148        /**
149         * 
150         * This method checks that the Writeoff Object Code is of type Expense
151         * <ul>
152         * <li>EX</li>
153         * <li>EE</li>
154         * <li>ES</li>
155         * </ul>
156         * 
157         * @return true if it is an expense object
158         */
159        protected boolean isWriteOffObjectValidExpense(OrganizationAccountingDefault organizationAccountingDefault) {
160    
161            boolean success = true;
162            Integer universityFiscalYear = organizationAccountingDefault.getUniversityFiscalYear();
163            ObjectCode writeObject = organizationAccountingDefault.getWriteoffFinancialObject();
164    
165            if (ObjectUtils.isNotNull(universityFiscalYear) && ObjectUtils.isNotNull(writeObject)) {
166    
167                success = objectTypeService.getBasicExpenseObjectTypes(universityFiscalYear).contains(writeObject.getFinancialObjectTypeCode());
168    
169                if (!success) {
170                    putFieldError(ArPropertyConstants.OrganizationAccountingDefaultFields.WRITEOFF_FINANCIAL_OBJECT_CODE, ArKeyConstants.OrganizationAccountingDefaultErrors.WRITE_OFF_OBJECT_CODE_INVALID, writeObject.getCode());
171                }
172            }
173    
174            return success;
175        }
176    
177        /**
178         * 
179         * This method checks that the Late Charge Object Code is of type Income Using the ParameterService to find this valid value?
180         * <ul>
181         * <li>IN</li>
182         * <li>IC</li>
183         * <li>CH</li>
184         * </ul>
185         * 
186         * @return true if it is an income object
187         */
188        protected boolean isLateChargeObjectValidIncome(OrganizationAccountingDefault organizationAccountingDefault) {
189            boolean success = true;
190            Integer universityFiscalYear = organizationAccountingDefault.getUniversityFiscalYear();
191            ObjectCode lateChargeObject = organizationAccountingDefault.getOrganizationLateChargeObject();
192    
193            if (ObjectUtils.isNotNull(universityFiscalYear) && ObjectUtils.isNotNull(lateChargeObject)) {
194                success = objectTypeService.getBasicIncomeObjectTypes(universityFiscalYear).contains(lateChargeObject.getFinancialObjectTypeCode());
195    
196                if (!success) {
197                    putFieldError(ArPropertyConstants.OrganizationAccountingDefaultFields.LATE_CHARGE_OBJECT_CODE, ArKeyConstants.OrganizationAccountingDefaultErrors.LATE_CHARGE_OBJECT_CODE_INVALID, lateChargeObject.getCode());
198                }
199            }
200    
201            return success;
202        }
203    
204        /**
205         * 
206         * This method checks to see if the invoice object code is of type Income
207         * <ul>
208         * <li>IN</li>
209         * <li>IC</li>
210         * <li>CH</li>
211         * </ul>
212         * 
213         * @return true if it is an income object
214         */
215        protected boolean isDefaultInvoiceFinancialObjectValidIncome(OrganizationAccountingDefault organizationAccountingDefault) {
216            boolean success = true;
217    
218            if (StringUtils.isNotEmpty(organizationAccountingDefault.getDefaultInvoiceFinancialObjectCode()) &&
219                    StringUtils.isEmpty(organizationAccountingDefault.getDefaultInvoiceChartOfAccountsCode())) {
220                
221                putFieldError(ArPropertyConstants.OrganizationAccountingDefaultFields.INVOICE_CHART_OF_ACCOUNTS_CODE, ArKeyConstants.OrganizationAccountingDefaultErrors.DEFAULT_CHART_OF_ACCOUNTS_REQUIRED_IF_DEFAULT_OBJECT_CODE_EXISTS );
222                success = false;
223                
224            } else {
225                Integer universityFiscalYear = organizationAccountingDefault.getUniversityFiscalYear();
226    
227    
228                ObjectCode defaultInvoiceFinancialObject = organizationAccountingDefault.getDefaultInvoiceFinancialObject();
229    
230                if (ObjectUtils.isNotNull(universityFiscalYear) && ObjectUtils.isNotNull(defaultInvoiceFinancialObject)) {
231                    success = objectTypeService.getBasicIncomeObjectTypes(universityFiscalYear).contains(defaultInvoiceFinancialObject.getFinancialObjectTypeCode());
232    
233                    if (!success) {
234                        putFieldError(ArPropertyConstants.OrganizationAccountingDefaultFields.INVOICE_CHART_OF_ACCOUNTS_CODE, ArKeyConstants.OrganizationAccountingDefaultErrors.DEFAULT_INVOICE_FINANCIAL_OBJECT_CODE_INVALID, defaultInvoiceFinancialObject.getCode());
235                    }
236                }
237            }
238    
239            return success;
240        }
241        
242        /**
243         * This method returns true if payment account number is provided and is valid.
244         * 
245         * @param doc
246         * @return
247         */
248        protected boolean doesPaymentAccountNumberExist(OrganizationAccountingDefault organizationAccountingDefault) {
249    
250            if (StringUtils.isEmpty(organizationAccountingDefault.getDefaultPaymentAccountNumber())) {
251                putFieldError(ArPropertyConstants.OrganizationAccountingDefaultFields.PAYMENT_ACCOUNT_NUMBER, ArKeyConstants.OrganizationAccountingDefaultErrors.ERROR_PAYMENT_ACCOUNT_NUMBER_REQUIRED);
252                return false;
253            }
254    
255            return true;
256        }
257    
258        /**
259         * This method returns true if payment chart of accounts code is provided and is valid
260         * 
261         * @param doc
262         * @return
263         */
264        protected boolean doesPaymentChartOfAccountsCodeExist(OrganizationAccountingDefault organizationAccountingDefault) {
265    
266            if (StringUtils.isEmpty(organizationAccountingDefault.getDefaultPaymentChartOfAccountsCode())) {
267                putFieldError(ArPropertyConstants.OrganizationAccountingDefaultFields.PAYMENT_CHART_OF_ACCOUNTS_CODE, ArKeyConstants.OrganizationAccountingDefaultErrors.ERROR_PAYMENT_CHART_OF_ACCOUNTS_CODE_REQUIRED);
268                return false;
269            }
270    
271            return true;
272        }
273    
274        /**
275         * This method returns true if payment financial object code is provided and is valid
276         * 
277         * @param doc
278         * @return
279         */
280        protected boolean doesPaymentFinancialObjectCodeExist(OrganizationAccountingDefault organizationAccountingDefault) {
281            if (StringUtils.isEmpty(organizationAccountingDefault.getDefaultPaymentFinancialObjectCode())) {
282                putFieldError(ArPropertyConstants.OrganizationAccountingDefaultFields.PAYMENT_FINANCIAL_OBJECT_CODE, ArKeyConstants.OrganizationAccountingDefaultErrors.ERROR_PAYMENT_OBJECT_CODE_REQUIRED);
283                return false;
284            }
285    
286            return true;
287        }    
288    
289        public ObjectTypeService getObjectTypeService() {
290            return objectTypeService;
291        }
292    
293        public void setObjectTypeService(ObjectTypeService objectTypeService) {
294            this.objectTypeService = objectTypeService;
295        }
296    }