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.businessobject.lookup;
017    
018    import java.util.ArrayList;
019    import java.util.Collection;
020    import java.util.HashMap;
021    import java.util.List;
022    import java.util.Map;
023    
024    import org.apache.commons.lang.StringUtils;
025    import org.kuali.kfs.fp.document.AdvanceDepositDocument;
026    import org.kuali.kfs.sys.KFSConstants;
027    import org.kuali.kfs.sys.businessobject.ElectronicPaymentClaim;
028    import org.kuali.kfs.sys.businessobject.SourceAccountingLine;
029    import org.kuali.kfs.sys.context.SpringContext;
030    import org.kuali.rice.kns.bo.BusinessObject;
031    import org.kuali.rice.kns.bo.PersistableBusinessObject;
032    import org.kuali.rice.kns.dao.LookupDao;
033    import org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl;
034    import org.kuali.rice.kns.lookup.CollectionIncomplete;
035    import org.kuali.rice.kns.lookup.HtmlData.AnchorHtmlData;
036    import org.kuali.rice.kns.service.KualiConfigurationService;
037    import org.kuali.rice.kns.web.struts.form.LookupForm;
038    import org.kuali.rice.kns.web.ui.Column;
039    import org.kuali.rice.kns.web.ui.ResultRow;
040    import org.springframework.transaction.annotation.Transactional;
041    
042    /**
043     * A helper class that gives us the ability to do special lookups on electronic payment claims.
044     */
045    @Transactional
046    public class ElectronicPaymentClaimLookupableHelperServiceImpl extends AbstractLookupableHelperServiceImpl {
047        private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ElectronicPaymentClaimLookupableHelperServiceImpl.class);
048        private LookupDao lookupDao;
049        
050        /**
051         * 
052         * @see org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl#getSearchResults(java.util.Map)
053         */
054        @Override
055        public List<PersistableBusinessObject> getSearchResults(Map<String, String> fieldValues) {
056            boolean unbounded = false;
057            String claimingStatus = fieldValues.remove("paymentClaimStatusCode");
058            if (claimingStatus != null && !claimingStatus.equals("A")) {
059                if (claimingStatus.equals(ElectronicPaymentClaim.ClaimStatusCodes.CLAIMED)) {
060                    fieldValues.put("paymentClaimStatusCode", ElectronicPaymentClaim.ClaimStatusCodes.CLAIMED);
061                } else {
062                    fieldValues.put("paymentClaimStatusCode", ElectronicPaymentClaim.ClaimStatusCodes.UNCLAIMED);
063                }
064            }
065            String organizationReferenceId = fieldValues.remove("generatingAccountingLine.organizationReferenceId");
066            List<PersistableBusinessObject> resultsList = (List)lookupDao.findCollectionBySearchHelper(ElectronicPaymentClaim.class, fieldValues, unbounded, false, null);
067            if (!StringUtils.isBlank(organizationReferenceId)) {
068                
069                List<PersistableBusinessObject> prunedResults = pruneResults(resultsList, organizationReferenceId);
070                resultsList = new CollectionIncomplete<PersistableBusinessObject>(prunedResults, ((CollectionIncomplete)resultsList).getActualSizeIfTruncated());
071                
072            } 
073            return resultsList;
074        }
075        
076        /**
077         * If organization reference id was present in lookup fields, only returns electronic payment claims which associate with the given organization reference id
078         * @param paymentsToPrune the Collection of electronic payment claims, still unfiltered by organization reference id 
079         * @param organizationReferenceId the organization reference id to use as a filter
080         * @return the filtered results
081         */
082        protected List<PersistableBusinessObject> pruneResults(List<PersistableBusinessObject> paymentsToPrune, String organizationReferenceId) {
083            final String matchingAdvanceDepositDocumentNumbers = getAdvanceDepositsWithOrganizationReferenceId(organizationReferenceId);
084            final List<GeneratingLineHolder> generatingLineHolders = getGeneratingLinesForDocuments(matchingAdvanceDepositDocumentNumbers, organizationReferenceId); 
085            
086            List<PersistableBusinessObject> prunedResults = new ArrayList<PersistableBusinessObject>();
087            for (PersistableBusinessObject epcAsPBO : paymentsToPrune) {
088                final ElectronicPaymentClaim epc = (ElectronicPaymentClaim)epcAsPBO;
089                
090                int count = 0;
091                boolean epcMatches = false;
092                while (count < generatingLineHolders.size() && !epcMatches) {
093                    final GeneratingLineHolder generatingLine = generatingLineHolders.get(count);
094                    if (generatingLine.isMommy(epc)) {
095                        prunedResults.add(epc);
096                        epcMatches = true;
097                    }
098                    
099                    count += 1;
100                }
101            }
102            
103            return prunedResults;
104        }
105        
106        /**
107         * Finds the document ids for all AD documents which have an accounting line with the given organizationReferenceId
108         * @param organizationReferenceId the organization reference id to find advance deposit documents for
109         * @return a lookup String that holds the document numbers of the matching advance deposit documents
110         */
111        protected String getAdvanceDepositsWithOrganizationReferenceId(String organizationReferenceId) {
112            StringBuilder documentNumbers = new StringBuilder();
113            
114            Map fields = new HashMap();
115            fields.put("sourceAccountingLines.organizationReferenceId", organizationReferenceId);
116            Collection ads = getLookupService().findCollectionBySearchUnbounded(AdvanceDepositDocument.class, fields);
117            for (Object adAsObject : ads) {
118                final AdvanceDepositDocument adDoc = (AdvanceDepositDocument)adAsObject;
119                documentNumbers.append("|");
120                documentNumbers.append(adDoc.getDocumentNumber());
121            }
122            
123            return documentNumbers.substring(1);
124        }
125        
126        /**
127         * Looks up all of the generating lines and stores essential information about them on documents given by the matchingAdvanceDepositDocumentNumbers parameter
128         * and matching the given organization reference id
129         * @param matchingAdvanceDepositDocumentNumbers the document numbers of matching advance deposit documents in lookup form 
130         * @param organizationReferenceId the organization reference id the accounting line must match
131         * @return a List of essential information about each of the matching accounting lines
132         */
133        protected List<GeneratingLineHolder> getGeneratingLinesForDocuments(String matchingAdvanceDepositDocumentNumbers, String organizationReferenceId) {
134            List<GeneratingLineHolder> holders = new ArrayList<GeneratingLineHolder>();
135            
136            Map fields = new HashMap();
137            fields.put("documentNumber", matchingAdvanceDepositDocumentNumbers);
138            fields.put("organizationReferenceId", organizationReferenceId);
139            
140            Collection als = getLookupService().findCollectionBySearchUnbounded(SourceAccountingLine.class, fields);
141            for (Object alAsObject : als) {
142                final SourceAccountingLine accountingLine = (SourceAccountingLine)alAsObject;
143                holders.add(new GeneratingLineHolder(accountingLine.getDocumentNumber(), accountingLine.getSequenceNumber()));
144            }
145            
146            return holders;
147        }
148    
149        /**
150         * @see org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl#validateSearchParameters(java.util.Map)
151         */
152        @Override
153        public void validateSearchParameters(Map fieldValues) {
154            // grab the backLocation and the docFormKey
155            this.setDocFormKey((String)fieldValues.get("docFormKey"));
156            this.setBackLocation((String)fieldValues.get("backLocation"));
157            super.validateSearchParameters(fieldValues);
158        }
159    
160        /**
161         * @see org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl#isResultReturnable(org.kuali.rice.kns.bo.BusinessObject)
162         */
163        @Override
164        public boolean isResultReturnable(BusinessObject claimAsBO) {
165            boolean result = super.isResultReturnable(claimAsBO);
166            ElectronicPaymentClaim claim = (ElectronicPaymentClaim)claimAsBO;
167            if (result && ((claim.getPaymentClaimStatusCode() != null && claim.getPaymentClaimStatusCode().equals(ElectronicPaymentClaim.ClaimStatusCodes.CLAIMED)) || (!StringUtils.isBlank(claim.getReferenceFinancialDocumentNumber())))) {
168                result = false;
169            }
170            return result;
171        }
172        
173        /**
174         * Using default results, add columnAnchor link for reference financial document number to open document
175         * 
176         * @param lookupForm
177         * @param kualiLookupable
178         * @param resultTable
179         * @param bounded
180         * @return
181         */
182        @Override
183        public Collection performLookup(LookupForm lookupForm, Collection resultTable, boolean bounded) {
184            Collection displayList = super.performLookup(lookupForm, resultTable, bounded);
185            for (ResultRow row : (Collection<ResultRow>)resultTable) {
186                for (Column col : row.getColumns()) {
187                    if (StringUtils.equals("referenceFinancialDocumentNumber", col.getPropertyName()) && StringUtils.isNotBlank(col.getPropertyValue())) {
188                        String propertyURL = SpringContext.getBean(KualiConfigurationService.class).getPropertyString(KFSConstants.WORKFLOW_URL_KEY) + "/DocHandler.do?docId=" + col.getPropertyValue() + "&command=displayDocSearchView";
189                        AnchorHtmlData htmlData = new AnchorHtmlData(propertyURL, "", col.getPropertyValue());
190                        htmlData.setTitle(col.getPropertyValue());
191                        col.setColumnAnchor(htmlData);
192                    }
193                }
194            }
195            return displayList;
196        }    
197    
198        /**
199         * Sets the lookupDao attribute value.
200         * @param lookupDao The lookupDao to set.
201         */
202        public void setLookupDao(LookupDao lookupDao) {
203            this.lookupDao = lookupDao;
204        }
205        
206        /**
207         * Holds information about an accounting line which created an electronic payment claim
208         */
209        class GeneratingLineHolder {
210            private String documentNumber;
211            private Integer lineNumber;
212            
213            /**
214             * Constructs a GeneratingLineHolder
215             * @param documentNumber the document the generating line is on
216             * @param lineNumber the line number of the generating line
217             */
218            public GeneratingLineHolder(String documentNumber, Integer lineNumber) {
219                this.documentNumber = documentNumber;
220                this.lineNumber = lineNumber;
221            }
222            
223            /**
224             * Determines if the given electronic payment claim was generated by the accounting line that this GeneratingLineHolder has information for
225             * @param epc the electronic payment claim to check
226             * @return true if this accounting line did generate the epc, false otherwise
227             */
228            public boolean isMommy(ElectronicPaymentClaim epc) {
229                return epc.getDocumentNumber().equals(documentNumber) && epc.getFinancialDocumentLineNumber().equals(lineNumber);
230            }
231        }
232    }