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.fp.document;
017    
018    import static org.kuali.kfs.sys.KFSConstants.EMPTY_STRING;
019    
020    import org.apache.commons.lang.StringUtils;
021    import org.kuali.kfs.fp.businessobject.NonCheckDisbursementDocumentAccountingLineParser;
022    import org.kuali.kfs.sys.KFSConstants;
023    import org.kuali.kfs.sys.KFSKeyConstants;
024    import org.kuali.kfs.sys.KFSPropertyConstants;
025    import org.kuali.kfs.sys.businessobject.AccountingLine;
026    import org.kuali.kfs.sys.businessobject.AccountingLineParser;
027    import org.kuali.kfs.sys.businessobject.Bank;
028    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry;
029    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper;
030    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail;
031    import org.kuali.kfs.sys.context.SpringContext;
032    import org.kuali.kfs.sys.document.AccountingDocumentBase;
033    import org.kuali.kfs.sys.document.AmountTotaling;
034    import org.kuali.kfs.sys.document.Correctable;
035    import org.kuali.kfs.sys.document.service.AccountingDocumentRuleHelperService;
036    import org.kuali.kfs.sys.document.service.DebitDeterminerService;
037    import org.kuali.kfs.sys.document.validation.impl.AccountingDocumentRuleBaseConstants.GENERAL_LEDGER_PENDING_ENTRY_CODE;
038    import org.kuali.kfs.sys.service.BankService;
039    import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService;
040    import org.kuali.rice.kns.document.Copyable;
041    import org.kuali.rice.kns.util.KNSConstants;
042    import org.kuali.rice.kns.util.KualiDecimal;
043    
044    /**
045     * This is the business object that represents the NonCheckDisbursementDocument in Kuali. The "Non-Check Disbursement" document is
046     * used to record charges or credits directly assessed to university bank accounts. It is used primarily by the Tax and Treasury
047     * Accounting office to record wire transfers, foreign drafts, etc.
048     */
049    public class NonCheckDisbursementDocument extends AccountingDocumentBase implements Copyable, Correctable, AmountTotaling {
050        protected String financialDocumentBankCode;
051    
052        protected Bank bank;
053    
054        /**
055         * Constructs a NonCheckDisbursementDocument instance.
056         */
057        public NonCheckDisbursementDocument() {
058            bank = new Bank();
059        }
060    
061        /**
062         * Sets the bank code for a new document to the setup default for the Non Check Disbursement document.
063         */
064        public void setDefautBankCode() {
065            Bank defaultBank = SpringContext.getBean(BankService.class).getDefaultBankByDocType(this.getClass());
066            if (defaultBank != null) {
067                this.financialDocumentBankCode = defaultBank.getBankCode();
068                this.bank = defaultBank;
069            }
070        }
071    
072        /**
073         * Gets the financialDocumentBankCode attribute.
074         * 
075         * @return Returns the financialDocumentBankCode.
076         */
077        public String getFinancialDocumentBankCode() {
078            return financialDocumentBankCode;
079        }
080    
081        /**
082         * Sets the financialDocumentBankCode attribute value.
083         * 
084         * @param financialDocumentBankCode The financialDocumentBankCode to set.
085         */
086        public void setFinancialDocumentBankCode(String financialDocumentBankCode) {
087            this.financialDocumentBankCode = financialDocumentBankCode;
088        }
089    
090        /**
091         * Gets the bank attribute.
092         * 
093         * @return Returns the bank.
094         */
095        public Bank getBank() {
096            return bank;
097        }
098    
099        /**
100         * Sets the bank attribute value.
101         * 
102         * @param bank The bank to set.
103         */
104        public void setBank(Bank bank) {
105            this.bank = bank;
106        }
107    
108        /**
109         * Overrides the base implementation to return "From".
110         * 
111         * @see org.kuali.kfs.sys.document.AccountingDocument#getSourceAccountingLinesSectionTitle()
112         */
113        @Override
114        public String getSourceAccountingLinesSectionTitle() {
115            return EMPTY_STRING;
116        }
117    
118        /**
119         * This method determines if a given accounting line is a debit accounting line. This is done by calling
120         * IsDebitUtiles.isDebitConsideringNothingPositiveOnly(). An IllegalStateException will be thrown if the accounting line passed
121         * in is not an expense, is an error correction with a positive dollar amount or is not an error correction and has a negative
122         * amount.
123         * 
124         * @param transactionalDocument The document the accounting line being checked is located in.
125         * @param accountingLine The accounting line being analyzed.
126         * @return True if the accounting line given is a debit accounting line, false otherwise.
127         * @throws IllegalStateException Thrown if accounting line attributes are invalid.
128         * @see IsDebitUtils#isDebitConsideringNothingPositiveOnly(FinancialDocumentRuleBase, FinancialDocument, AccountingLine)
129         * @see org.kuali.rice.kns.rule.AccountingLineRule#isDebit(org.kuali.rice.kns.document.FinancialDocument,
130         *      org.kuali.rice.kns.bo.AccountingLine)
131         */
132        public boolean isDebit(GeneralLedgerPendingEntrySourceDetail postable) throws IllegalStateException {
133            DebitDeterminerService isDebitUtils = SpringContext.getBean(DebitDeterminerService.class);
134            return isDebitUtils.isDebitConsideringNothingPositiveOnly(this, (AccountingLine) postable);
135        }
136    
137        /**
138         * This method sets attributes on the explicitly general ledger pending entry specific to NonCheckDisbursement documents. This
139         * includes setting the transaction ledger entry description and blanking out the reference financial document number, the
140         * reference financial system origin code and the reference financial document type code. These values must be nullified because
141         * they don't belong in general ledger pending entries and if they aren't null, the general error corrections won't post
142         * properly.
143         * 
144         * @param financialDocument The document which contains the general ledger pending entry being modified.
145         * @param accountingLine The accounting line the explicit entry was generated from.
146         * @param explicitEntry The explicit entry being updated.
147         * @see FinancialDocumentRuleBase#customizeExplicitGeneralLedgerPendingEntry(FinancialDocument, AccountingLine,
148         *      GeneralLedgerPendingEntry)
149         */
150        @Override
151        public void customizeExplicitGeneralLedgerPendingEntry(GeneralLedgerPendingEntrySourceDetail postable, GeneralLedgerPendingEntry explicitEntry) {
152            explicitEntry.setTransactionLedgerEntryDescription(buildTransactionLedgerEntryDescriptionUsingRefOriginAndRefDocNumber(postable));
153    
154            // Clearing fields that are already handled by the parent algorithm - we don't actually want
155            // these to copy over from the accounting lines b/c they don't belong in the GLPEs
156            // if they aren't nulled, then GECs fail to post
157            explicitEntry.setReferenceFinancialDocumentNumber(null);
158            explicitEntry.setReferenceFinancialSystemOriginationCode(null);
159            explicitEntry.setReferenceFinancialDocumentTypeCode(null);
160        }
161    
162        /**
163         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#generateDocumentGeneralLedgerPendingEntries(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper)
164         */
165        @Override
166        public boolean generateDocumentGeneralLedgerPendingEntries(GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
167            boolean success = true;
168    
169            if (!SpringContext.getBean(BankService.class).isBankSpecificationEnabled()) {
170                return success;
171            }
172            
173            this.refreshReferenceObject(KFSPropertyConstants.BANK);
174    
175            GeneralLedgerPendingEntryService glpeService = SpringContext.getBean(GeneralLedgerPendingEntryService.class);
176    
177            final KualiDecimal bankOffsetAmount = glpeService.getOffsetToCashAmount(this).negated();
178            GeneralLedgerPendingEntry bankOffsetEntry = new GeneralLedgerPendingEntry();
179            success &= glpeService.populateBankOffsetGeneralLedgerPendingEntry(getBank(), bankOffsetAmount, this, getPostingYear(), sequenceHelper, bankOffsetEntry, KNSConstants.DOCUMENT_PROPERTY_NAME + "." + KFSPropertyConstants.FINANCIAL_DOCUMENT_BANK_CODE);
180    
181            if (success) {
182                AccountingDocumentRuleHelperService accountingDocumentRuleUtil = SpringContext.getBean(AccountingDocumentRuleHelperService.class);
183                bankOffsetEntry.setTransactionLedgerEntryDescription(accountingDocumentRuleUtil.formatProperty(KFSKeyConstants.Bank.DESCRIPTION_GLPE_BANK_OFFSET));
184                getGeneralLedgerPendingEntries().add(bankOffsetEntry);
185                sequenceHelper.increment();
186    
187                GeneralLedgerPendingEntry offsetEntry = new GeneralLedgerPendingEntry(bankOffsetEntry);
188                success &= glpeService.populateOffsetGeneralLedgerPendingEntry(getPostingYear(), bankOffsetEntry, sequenceHelper, offsetEntry);
189                getGeneralLedgerPendingEntries().add(offsetEntry);
190                sequenceHelper.increment();
191            }
192    
193            return success;
194        }
195    
196        /**
197         * Builds an appropriately formatted string to be used for the <code>transactionLedgerEntryDescription</code>. It is built
198         * using information from the <code>{@link AccountingLine}</code>. Format is "01-12345: blah blah blah".
199         * 
200         * @param financialDocument The document the description will be pulled from, if the accounting line description is blank.
201         * @param line The accounting line that will be used for populating the transaction ledger entry description.
202         * @return The description to be applied to the transaction ledger entry.
203         */
204        protected String buildTransactionLedgerEntryDescriptionUsingRefOriginAndRefDocNumber(GeneralLedgerPendingEntrySourceDetail postable) {
205            String description = "";
206            if (StringUtils.isBlank(postable.getReferenceNumber())) {
207                throw new IllegalStateException("Reference Document Number is required and should be validated before this point.");
208            }
209    
210            description = KFSConstants.ORIGIN_CODE_KUALI + "-" + postable.getReferenceNumber();
211    
212            if (StringUtils.isNotBlank(postable.getFinancialDocumentLineDescription())) {
213                description += ": " + postable.getFinancialDocumentLineDescription();
214            }
215            else {
216                description += ": " + getDocumentHeader().getDocumentDescription();
217            }
218    
219            if (description.length() > GENERAL_LEDGER_PENDING_ENTRY_CODE.GLPE_DESCRIPTION_MAX_LENGTH) {
220                description = description.substring(0, GENERAL_LEDGER_PENDING_ENTRY_CODE.GLPE_DESCRIPTION_MAX_LENGTH - 3) + "...";
221            }
222    
223            return description;
224        }
225    }