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;
017    
018    import java.sql.Date;
019    import java.util.ArrayList;
020    import java.util.List;
021    
022    import org.apache.commons.lang.StringUtils;
023    import org.kuali.kfs.coa.businessobject.Account;
024    import org.kuali.kfs.coa.businessobject.Chart;
025    import org.kuali.kfs.coa.businessobject.ObjectCode;
026    import org.kuali.kfs.coa.businessobject.ProjectCode;
027    import org.kuali.kfs.coa.businessobject.SubAccount;
028    import org.kuali.kfs.coa.businessobject.SubObjectCode;
029    import org.kuali.kfs.module.ar.ArConstants;
030    import org.kuali.kfs.module.ar.businessobject.AccountsReceivableDocumentHeader;
031    import org.kuali.kfs.module.ar.businessobject.CustomerInvoiceDetail;
032    import org.kuali.kfs.module.ar.businessobject.ReceivableCustomerInvoiceDetail;
033    import org.kuali.kfs.module.ar.businessobject.SalesTaxCustomerInvoiceDetail;
034    import org.kuali.kfs.module.ar.businessobject.WriteoffCustomerInvoiceDetail;
035    import org.kuali.kfs.module.ar.businessobject.WriteoffTaxCustomerInvoiceDetail;
036    import org.kuali.kfs.module.ar.document.service.AccountsReceivableTaxService;
037    import org.kuali.kfs.module.ar.document.service.CustomerInvoiceGLPEService;
038    import org.kuali.kfs.module.ar.document.service.CustomerInvoiceWriteoffDocumentService;
039    import org.kuali.kfs.sys.KFSConstants;
040    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper;
041    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail;
042    import org.kuali.kfs.sys.businessobject.TaxDetail;
043    import org.kuali.kfs.sys.context.SpringContext;
044    import org.kuali.kfs.sys.document.AmountTotaling;
045    import org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource;
046    import org.kuali.kfs.sys.document.GeneralLedgerPostingDocumentBase;
047    import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService;
048    import org.kuali.kfs.sys.service.TaxService;
049    import org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO;
050    import org.kuali.rice.kns.bo.Note;
051    import org.kuali.rice.kns.exception.ValidationException;
052    import org.kuali.rice.kns.rule.event.KualiDocumentEvent;
053    import org.kuali.rice.kns.service.ParameterService;
054    import org.kuali.rice.kns.util.KualiDecimal;
055    import org.kuali.rice.kns.util.ObjectUtils;
056    import org.kuali.rice.kns.util.TypedArrayList;
057    
058    public class CustomerInvoiceWriteoffDocument extends GeneralLedgerPostingDocumentBase implements GeneralLedgerPendingEntrySource, AmountTotaling {
059    
060        protected static final String REQUIRES_APPROVAL_NODE = "RequiresApproval";
061        protected String chartOfAccountsCode;
062        protected String accountNumber;
063        protected String subAccountNumber;
064        protected String financialObjectCode;
065        protected String financialSubObjectCode;
066        protected String projectCode;
067        protected String organizationReferenceIdentifier;
068        protected String financialDocumentReferenceInvoiceNumber;
069        protected String statusCode;
070    
071        protected String customerNote;
072    
073        protected Account account;
074        protected Chart chartOfAccounts;
075        protected SubAccount subAccount;
076        protected ObjectCode financialObject;
077        protected SubObjectCode financialSubObject;
078        protected ProjectCode project;
079        protected CustomerInvoiceDocument customerInvoiceDocument;
080        protected AccountsReceivableDocumentHeader accountsReceivableDocumentHeader;
081        protected KualiDecimal invoiceWriteoffAmount;
082    
083        public AccountsReceivableDocumentHeader getAccountsReceivableDocumentHeader() {
084            return accountsReceivableDocumentHeader;
085        }
086    
087        public void setAccountsReceivableDocumentHeader(AccountsReceivableDocumentHeader accountsReceivableDocumentHeader) {
088            this.accountsReceivableDocumentHeader = accountsReceivableDocumentHeader;
089        }
090    
091        public String getChartOfAccountsCode() {
092            return chartOfAccountsCode;
093        }
094    
095        public void setChartOfAccountsCode(String chartOfAccountsCode) {
096            this.chartOfAccountsCode = chartOfAccountsCode;
097        }
098    
099        public String getAccountNumber() {
100            return accountNumber;
101        }
102    
103        public void setAccountNumber(String accountNumber) {
104            this.accountNumber = accountNumber;
105        }
106    
107        public String getSubAccountNumber() {
108            return subAccountNumber;
109        }
110    
111        public void setSubAccountNumber(String subAccountNumber) {
112            this.subAccountNumber = subAccountNumber;
113        }
114    
115        public String getFinancialObjectCode() {
116            return financialObjectCode;
117        }
118    
119        public void setFinancialObjectCode(String financialObjectCode) {
120            this.financialObjectCode = financialObjectCode;
121        }
122    
123        public String getFinancialSubObjectCode() {
124            return financialSubObjectCode;
125        }
126    
127        public void setFinancialSubObjectCode(String financialSubObjectCode) {
128            this.financialSubObjectCode = financialSubObjectCode;
129        }
130    
131        public String getProjectCode() {
132            return projectCode;
133        }
134    
135        public void setProjectCode(String projectCode) {
136            this.projectCode = projectCode;
137        }
138    
139        public String getOrganizationReferenceIdentifier() {
140            return organizationReferenceIdentifier;
141        }
142    
143        public void setOrganizationReferenceIdentifier(String organizationReferenceIdentifier) {
144            this.organizationReferenceIdentifier = organizationReferenceIdentifier;
145        }
146    
147        public String getFinancialDocumentReferenceInvoiceNumber() {
148            return financialDocumentReferenceInvoiceNumber;
149        }
150    
151        public void setFinancialDocumentReferenceInvoiceNumber(String financialDocumentReferenceInvoiceNumber) {
152            this.financialDocumentReferenceInvoiceNumber = financialDocumentReferenceInvoiceNumber;
153        }
154    
155        public Account getAccount() {
156            return account;
157        }
158    
159        public void setAccount(Account account) {
160            this.account = account;
161        }
162    
163        public Chart getChartOfAccounts() {
164            return chartOfAccounts;
165        }
166    
167        public void setChartOfAccounts(Chart chartOfAccounts) {
168            this.chartOfAccounts = chartOfAccounts;
169        }
170    
171        public SubAccount getSubAccount() {
172            return subAccount;
173        }
174    
175        public void setSubAccount(SubAccount subAccount) {
176            this.subAccount = subAccount;
177        }
178    
179        public ObjectCode getFinancialObject() {
180            return financialObject;
181        }
182    
183        public void setFinancialObject(ObjectCode financialObject) {
184            this.financialObject = financialObject;
185        }
186    
187        public SubObjectCode getFinancialSubObject() {
188            return financialSubObject;
189        }
190    
191        public void setFinancialSubObject(SubObjectCode financialSubObject) {
192            this.financialSubObject = financialSubObject;
193        }
194    
195        public ProjectCode getProject() {
196            return project;
197        }
198    
199        public void setProject(ProjectCode project) {
200            this.project = project;
201        }
202    
203        public CustomerInvoiceDocument getCustomerInvoiceDocument() {
204            if (ObjectUtils.isNull(customerInvoiceDocument) && StringUtils.isNotEmpty(financialDocumentReferenceInvoiceNumber)) {
205                refreshReferenceObject("customerInvoiceDocument");
206            }
207    
208            return customerInvoiceDocument;
209        }
210    
211        public void setCustomerInvoiceDocument(CustomerInvoiceDocument customerInvoiceDocument) {
212            this.customerInvoiceDocument = customerInvoiceDocument;
213        }
214    
215        /**
216         * This method returns all the applicable invoice details for writeoff. This method also sets the writeoff document number on
217         * each of the invoice details for making retrieval of the actual writeoff amount easier.
218         * 
219         * @return
220         */
221        public List<CustomerInvoiceDetail> getCustomerInvoiceDetailsForWriteoff() {
222            List<CustomerInvoiceDetail> customerInvoiceDetailsForWriteoff = new TypedArrayList(CustomerInvoiceDetail.class);
223            for (CustomerInvoiceDetail customerInvoiceDetail : getCustomerInvoiceDocument().getCustomerInvoiceDetailsWithoutDiscounts()) {
224                customerInvoiceDetail.setCustomerInvoiceWriteoffDocumentNumber(this.documentNumber);
225                customerInvoiceDetailsForWriteoff.add(customerInvoiceDetail);
226            }
227    
228            return customerInvoiceDetailsForWriteoff;
229        }
230    
231        /**
232         * This method returns the total amount to be written off
233         * 
234         * @return
235         */
236        public KualiDecimal getInvoiceWriteoffAmount() {
237            // only pull the invoice open amount as the invoice writeoff amount while the doc 
238            // is in play.  once its been approved, rely on the amount stored in the db.
239            if (!KFSConstants.DocumentStatusCodes.APPROVED.equals(getDocumentHeader().getFinancialDocumentStatusCode())) {
240                invoiceWriteoffAmount = customerInvoiceDocument.getOpenAmount();
241            }
242            return invoiceWriteoffAmount;
243        }
244    
245        public void setInvoiceWriteoffAmount(KualiDecimal invoiceWriteoffAmount) {
246            this.invoiceWriteoffAmount = invoiceWriteoffAmount;
247        }
248    
249        public String getStatusCode() {
250            return statusCode;
251        }
252    
253        public void setStatusCode(String statusCode) {
254            this.statusCode = statusCode;
255        }
256    
257        /**
258         * Initializes the values for a new document.
259         */
260        public void initiateDocument() {
261            setStatusCode(ArConstants.CustomerInvoiceWriteoffStatuses.INITIATE);
262        }
263    
264        /**
265         * Clear out the initially populated fields.
266         */
267        public void clearInitFields() {
268            setFinancialDocumentReferenceInvoiceNumber(null);
269        }
270    
271        @Override
272        public List<Long> getWorkflowEngineDocumentIdsToLock() {
273            if (StringUtils.isNotBlank(getFinancialDocumentReferenceInvoiceNumber())) {
274                List<Long> documentIds = new ArrayList<Long>();
275                documentIds.add(new Long(getFinancialDocumentReferenceInvoiceNumber()));
276                return documentIds;
277            }
278            return null;
279            
280        }
281    
282        /**
283         * When document is processed do the following: 1) Apply amounts to writeoff invoice 2) Mark off invoice indiciator
284         * 
285         * @see org.kuali.kfs.sys.document.GeneralLedgerPostingDocumentBase#doRouteStatusChange()
286         */
287        @Override
288        public void doRouteStatusChange(DocumentRouteStatusChangeDTO statusChangeEvent) {
289            super.doRouteStatusChange(statusChangeEvent);
290            if (getDocumentHeader().getWorkflowDocument().stateIsProcessed()) {
291                CustomerInvoiceWriteoffDocumentService writeoffService = SpringContext.getBean(CustomerInvoiceWriteoffDocumentService.class);
292                writeoffService.completeWriteoffProcess(this);
293            }
294        }
295    
296        /**
297         * do all the calculations before the document gets saved gets called for 'Submit', 'Save', and 'Blanket Approved'
298         * 
299         * @see org.kuali.rice.kns.document.Document#prepareForSave(org.kuali.rice.kns.rule.event.KualiDocumentEvent)
300         */
301        public void prepareForSave(KualiDocumentEvent event) {
302            // generate GLPEs
303            if (!SpringContext.getBean(GeneralLedgerPendingEntryService.class).generateGeneralLedgerPendingEntries(this)) {
304                logErrors();
305                throw new ValidationException("general ledger GLPE generation failed");
306            }
307            super.prepareForSave(event);
308        }
309    
310        public boolean generateDocumentGeneralLedgerPendingEntries(GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
311            return true;
312        }
313    
314        protected KualiDecimal getCustomerInvoiceDetailOpenPretaxAmount(CustomerInvoiceDetail customerInvoiceDetail) {
315            String postalCode = SpringContext.getBean(AccountsReceivableTaxService.class).getPostalCodeForTaxation(getCustomerInvoiceDocument());
316            Date dateOfTransaction = getCustomerInvoiceDocument().getBillingDate();
317            KualiDecimal pretaxAmount = SpringContext.getBean(TaxService.class).getPretaxAmount(dateOfTransaction, postalCode, customerInvoiceDetail.getAmountOpen());
318    
319            return pretaxAmount;
320        }
321    
322        /**
323         * This method creates the following GLPE's for the customer invoice writeoff 1. C Receivable object code with remaining amount
324         * 2. D Writeoff object code (or Writeoff FAU) with remaining amount 3. C Receivable object code for tax on state tax account 4.
325         * D Sales Tax object code for tax on the state tax account 5. C Receivable object code for tax on district tax account 6. D
326         * District tax object code for $1.00 on the district tax account
327         * 
328         * @see org.kuali.kfs.service.impl.GenericGeneralLedgerPendingEntryGenerationProcessImpl#processGenerateGeneralLedgerPendingEntries(org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource,
329         *      org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail,
330         *      org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper)
331         */
332    
333        public boolean generateGeneralLedgerPendingEntries(GeneralLedgerPendingEntrySourceDetail glpeSourceDetail, GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
334            CustomerInvoiceDetail customerInvoiceDetail = (CustomerInvoiceDetail) glpeSourceDetail;
335    
336            // if invoice item open amount <= 0 -> do not generate GLPEs for this glpeSourceDetail
337            if (!customerInvoiceDetail.getAmountOpen().isPositive())
338                return true;
339    
340            KualiDecimal amount;
341    
342            String receivableOffsetOption = SpringContext.getBean(ParameterService.class).getParameterValue(CustomerInvoiceDocument.class, ArConstants.GLPE_RECEIVABLE_OFFSET_GENERATION_METHOD);
343            boolean hasReceivableClaimOnCashOffset = ArConstants.GLPE_RECEIVABLE_OFFSET_GENERATION_METHOD_FAU.equals(receivableOffsetOption);
344    
345            String writeoffOffsetOption = SpringContext.getBean(ParameterService.class).getParameterValue(CustomerInvoiceWriteoffDocument.class, ArConstants.GLPE_WRITEOFF_GENERATION_METHOD);
346            boolean hasWriteoffClaimOnCashOffset = ArConstants.GLPE_WRITEOFF_GENERATION_METHOD_ORG_ACCT_DEFAULT.equals(writeoffOffsetOption);
347    
348            String writeoffTaxGenerationOption = SpringContext.getBean(ParameterService.class).getParameterValue(CustomerInvoiceWriteoffDocument.class, ArConstants.ALLOW_SALES_TAX_LIABILITY_ADJUSTMENT_IND);
349            boolean hasWriteoffTaxClaimOnCashOffset = ArConstants.ALLOW_SALES_TAX_LIABILITY_ADJUSTMENT_IND_NO.equals( writeoffTaxGenerationOption );
350    
351            boolean hasClaimOnCashOffset = hasReceivableClaimOnCashOffset || hasWriteoffClaimOnCashOffset;
352    
353            // if sales tax is enabled generate tax GLPEs
354            if (SpringContext.getBean(AccountsReceivableTaxService.class).isCustomerInvoiceDetailTaxable(getCustomerInvoiceDocument(), customerInvoiceDetail)) {
355                amount = getCustomerInvoiceDetailOpenPretaxAmount(customerInvoiceDetail);
356                addReceivableGLPEs(sequenceHelper, glpeSourceDetail, hasClaimOnCashOffset, amount);
357                sequenceHelper.increment();
358                addWriteoffGLPEs(sequenceHelper, glpeSourceDetail, hasClaimOnCashOffset, amount);
359                addSalesTaxGLPEs( sequenceHelper, glpeSourceDetail, hasWriteoffTaxClaimOnCashOffset, amount);
360            }
361            else {
362                amount = customerInvoiceDetail.getAmountOpen();
363                addReceivableGLPEs(sequenceHelper, glpeSourceDetail, hasClaimOnCashOffset, amount);
364                sequenceHelper.increment();
365                addWriteoffGLPEs(sequenceHelper, glpeSourceDetail, hasClaimOnCashOffset, amount);
366            }
367            return true;
368        }
369    
370        /**
371         * This method creates the receivable GLPEs for customer invoice details using the remaining amount
372         * 
373         * @param poster
374         * @param sequenceHelper
375         * @param postable
376         * @param explicitEntry
377         */
378        protected void addReceivableGLPEs(GeneralLedgerPendingEntrySequenceHelper sequenceHelper, GeneralLedgerPendingEntrySourceDetail glpeSourceDetail, boolean hasClaimOnCashOffset, KualiDecimal amount) {
379    
380            CustomerInvoiceDetail customerInvoiceDetail = (CustomerInvoiceDetail) glpeSourceDetail;
381            ReceivableCustomerInvoiceDetail receivableCustomerInvoiceDetail = new ReceivableCustomerInvoiceDetail(customerInvoiceDetail, getCustomerInvoiceDocument());
382            boolean isDebit = false;
383    
384            CustomerInvoiceGLPEService service = SpringContext.getBean(CustomerInvoiceGLPEService.class);
385            service.createAndAddGenericInvoiceRelatedGLPEs(this, receivableCustomerInvoiceDetail, sequenceHelper, isDebit, hasClaimOnCashOffset, amount);
386        }
387    
388        /**
389         * This method adds writeoff GLPE's for the customer invoice details using the remaining amount.
390         * 
391         * @param poster
392         * @param sequenceHelper
393         * @param postable
394         * @param explicitEntry
395         */
396        protected void addWriteoffGLPEs(GeneralLedgerPendingEntrySequenceHelper sequenceHelper, GeneralLedgerPendingEntrySourceDetail glpeSourceDetail, boolean hasClaimOnCashOffset, KualiDecimal amount) {
397    
398            CustomerInvoiceDetail customerInvoiceDetail = (CustomerInvoiceDetail) glpeSourceDetail;
399            WriteoffCustomerInvoiceDetail writeoffCustomerInvoiceDetail = new WriteoffCustomerInvoiceDetail(customerInvoiceDetail, this);
400            boolean isDebit = true;
401    
402            CustomerInvoiceGLPEService service = SpringContext.getBean(CustomerInvoiceGLPEService.class);
403            service.createAndAddGenericInvoiceRelatedGLPEs(this, writeoffCustomerInvoiceDetail, sequenceHelper, isDebit, hasClaimOnCashOffset, amount);
404        }
405    
406        protected void addSalesTaxGLPEs(GeneralLedgerPendingEntrySequenceHelper sequenceHelper, GeneralLedgerPendingEntrySourceDetail glpeSourceDetail, boolean hasWriteoffTaxClaimOnCashOffset, KualiDecimal amount){
407            CustomerInvoiceDetail customerInvoiceDetail = (CustomerInvoiceDetail) glpeSourceDetail;
408            WriteoffCustomerInvoiceDetail writeoffCustomerInvoiceDetail = new WriteoffCustomerInvoiceDetail(customerInvoiceDetail, this);
409    
410            boolean isDebit = true;
411    
412            String postalCode = SpringContext.getBean(AccountsReceivableTaxService.class).getPostalCodeForTaxation(getCustomerInvoiceDocument());
413            Date dateOfTransaction = getCustomerInvoiceDocument().getBillingDate();
414    
415            List<TaxDetail> salesTaxDetails = SpringContext.getBean(TaxService.class).getSalesTaxDetails(dateOfTransaction, postalCode, amount);
416    
417            CustomerInvoiceGLPEService service = SpringContext.getBean(CustomerInvoiceGLPEService.class);
418            SalesTaxCustomerInvoiceDetail salesTaxCustomerInvoiceDetail;
419            ReceivableCustomerInvoiceDetail receivableCustomerInvoiceDetail;
420            WriteoffTaxCustomerInvoiceDetail writeoffTaxCustomerInvoiceDetail;
421            for (TaxDetail salesTaxDetail : salesTaxDetails) {
422    
423                salesTaxCustomerInvoiceDetail = new SalesTaxCustomerInvoiceDetail(salesTaxDetail, customerInvoiceDetail);
424                receivableCustomerInvoiceDetail = new ReceivableCustomerInvoiceDetail(salesTaxCustomerInvoiceDetail, getCustomerInvoiceDocument());
425                writeoffTaxCustomerInvoiceDetail = new WriteoffTaxCustomerInvoiceDetail(salesTaxCustomerInvoiceDetail, this);
426    
427                sequenceHelper.increment();
428                service.createAndAddGenericInvoiceRelatedGLPEs(this, receivableCustomerInvoiceDetail, sequenceHelper, !isDebit, hasWriteoffTaxClaimOnCashOffset, salesTaxDetail.getTaxAmount());
429    
430                sequenceHelper.increment();
431                service.createAndAddGenericInvoiceRelatedGLPEs(this, writeoffTaxCustomerInvoiceDetail, sequenceHelper, isDebit, hasWriteoffTaxClaimOnCashOffset, salesTaxDetail.getTaxAmount());
432            }
433        }
434    
435        public KualiDecimal getGeneralLedgerPendingEntryAmountForDetail(GeneralLedgerPendingEntrySourceDetail glpeSourceDetail) {
436            // TODO Auto-generated method stub
437            return null;
438        }
439    
440        public List<GeneralLedgerPendingEntrySourceDetail> getGeneralLedgerPendingEntrySourceDetails() {
441            List<GeneralLedgerPendingEntrySourceDetail> generalLedgerPendingEntrySourceDetails = new ArrayList<GeneralLedgerPendingEntrySourceDetail>();
442            generalLedgerPendingEntrySourceDetails.addAll(getCustomerInvoiceDocument().getCustomerInvoiceDetailsWithoutDiscounts());
443            return generalLedgerPendingEntrySourceDetails;
444    
445        }
446    
447        public boolean isDebit(GeneralLedgerPendingEntrySourceDetail postable) {
448            // TODO Auto-generated method stub
449            return false;
450        }
451    
452        public KualiDecimal getTotalDollarAmount() {
453            return getInvoiceWriteoffAmount();
454        }
455    
456        /**
457         * Gets the customerNote attribute.
458         * 
459         * @return Returns the customerNote.
460         */
461        public String getCustomerNote() {
462            /*
463             * ArrayList boNotes = (ArrayList) this.getCustomerInvoiceDocument().getCustomer().getBoNotes(); if (boNotes.size() > 0)
464             * customerNote = boNotes.toString(); else customerNote = "";
465             */
466            return customerNote;
467        }
468    
469        /**
470         * Sets the customerNote attribute value.
471         * 
472         * @param customerNote The customerNote to set.
473         */
474        public void setCustomerNote(String customerNote) {
475            this.customerNote = customerNote;
476        }
477    
478        public void populateCustomerNote() {
479            customerNote = "";
480            ArrayList boNotes = (ArrayList) this.getCustomerInvoiceDocument().getCustomer().getBoNotes();
481            if (boNotes.size() > 0) {
482                for (int i = 0; i < boNotes.size(); i++)
483                    customerNote += ((Note) boNotes.get(i)).getNoteText() + " ";
484                customerNote.trim();
485            }
486        }
487    
488        /**
489         * Answers true when invoice write off amount is greater than default approved amount ($50???)
490         * 
491         * @see org.kuali.kfs.sys.document.FinancialSystemTransactionalDocumentBase#answerSplitNodeQuestion(java.lang.String)
492         */
493        @Override
494        public boolean answerSplitNodeQuestion(String nodeName) throws UnsupportedOperationException {
495            if (REQUIRES_APPROVAL_NODE.equals(nodeName)) {
496                
497                //  grab the approval threshold from the param service
498                ParameterService paramService = SpringContext.getBean(ParameterService.class); 
499                KualiDecimal approvalThreshold = new KualiDecimal(paramService.getParameterValue(CustomerInvoiceWriteoffDocument.class, ArConstants.WRITEOFF_APPROVAL_THRESHOLD));
500                
501                return (approvalThreshold.isLessThan(getInvoiceWriteoffAmount()));
502            }
503            throw new UnsupportedOperationException("answerSplitNode('" + nodeName + "') called but no handler for this nodeName present.");
504        }
505    
506    
507    }