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.service.impl;
017    
018    import java.util.ArrayList;
019    import java.util.HashSet;
020    import java.util.List;
021    import java.util.Map;
022    import java.util.Set;
023    
024    import org.apache.commons.lang.StringUtils;
025    import org.apache.struts.action.ActionForward;
026    import org.apache.struts.action.ActionMapping;
027    import org.kuali.kfs.sys.KFSKeyConstants;
028    import org.kuali.kfs.sys.businessobject.ElectronicPaymentClaim;
029    import org.kuali.kfs.sys.service.ElectronicFundTransferActionHelper;
030    import org.kuali.kfs.sys.service.ElectronicPaymentClaimingDocumentGenerationStrategy;
031    import org.kuali.kfs.sys.service.ElectronicPaymentClaimingService;
032    import org.kuali.kfs.sys.web.struts.ElectronicFundTransferForm;
033    import org.kuali.kfs.sys.web.struts.ElectronicPaymentClaimClaimedHelper;
034    import org.kuali.rice.kim.bo.Person;
035    import org.kuali.rice.kns.exception.AuthorizationException;
036    import org.kuali.rice.kns.service.BusinessObjectService;
037    import org.kuali.rice.kns.service.DataDictionaryService;
038    import org.kuali.rice.kns.service.DocumentService;
039    import org.kuali.rice.kns.util.GlobalVariables;
040    
041    /**
042     * An Electronic Funds Transfer action which claims the electronic payment claims in a form and redirects
043     * to the claiming document.
044     */
045    public class ElectronicFundTransferClaimActionHelper implements ElectronicFundTransferActionHelper {
046        private ElectronicPaymentClaimingService electronicPaymentClaimingService;
047        private DataDictionaryService ddService;
048        private BusinessObjectService boService;
049        private DocumentService documentService;
050        
051        protected static final String ACTION_NAME = "claim";
052        protected static final String CHOSEN_DOCUMENT_PROPERTY = "chosenElectronicPaymentClaimingDocumentCode";
053        protected static final String CLAIM_PROPERTY = "claims";
054        protected static final String HAS_DOCUMENTATION_PROPERTY = "hasDocumentation";
055        protected static final String BASIC_FORWARD = "basic";
056        protected static final String PORTAL_FORWARD = "portal";
057    
058        /**
059         * Claims the ElectronicPaymentClaim records with a document and then redirects to that docment.
060         * @see org.kuali.kfs.sys.service.ElectronicFundTransferActionHelper#performAction(org.kuali.rice.kns.web.struts.form.KualiForm, org.apache.struts.action.ActionMapping)
061         */
062        public ActionForward performAction(ElectronicFundTransferForm form, ActionMapping mapping, Map paramMap, String basePath) {
063            // can the user claim electronic payments at all?
064            Person currentUser = GlobalVariables.getUserSession().getPerson();
065    
066            if (!form.hasAvailableClaimingDocumentStrategies()) {
067                throw new AuthorizationException(currentUser.getPrincipalName(), ElectronicFundTransferClaimActionHelper.ACTION_NAME, ddService.getDataDictionary().getBusinessObjectEntry(ElectronicPaymentClaim.class.getName()).getTitleAttribute());
068            }
069            
070            // did the user say they have documentation?  If not, give an error...
071            boolean continueClaiming = true;
072            continueClaiming = handleDocumentationForClaim(form.getHasDocumentation());
073            
074            // process admin's pre-claimed records
075            List<ElectronicPaymentClaim> claims = form.getClaims();
076            
077            boolean isAuthorized = form.isAllowElectronicFundsTransferAdministration();
078            if (isAuthorized) {
079                claims = handlePreClaimedRecords(claims, generatePreClaimedByCheckboxSet(form.getClaimedByCheckboxHelpers()), form.getAvailableClaimingDocumentStrategies());
080                if (GlobalVariables.getMessageMap().size() > 0) {
081                    // if there were any errors, we'll need to redirect to the page again
082                    return mapping.findForward(ElectronicFundTransferClaimActionHelper.BASIC_FORWARD);
083                }
084                else if (claims.size() == 0) {
085                    // no more claims to process...so don't make a document, just redirect to the portal
086                    return mapping.findForward(PORTAL_FORWARD);
087                }
088            }
089            
090            // put any remaining claims into a claiming doc
091            String chosenDoc = form.getChosenElectronicPaymentClaimingDocumentCode();
092            continueClaiming &= checkChosenDocumentType(chosenDoc);
093            // get the requested document claiming helper
094            if (continueClaiming) {
095                
096                ElectronicPaymentClaimingDocumentGenerationStrategy documentCreationHelper = getRequestedClaimingHelper(form.getChosenElectronicPaymentClaimingDocumentCode(), form.getAvailableClaimingDocumentStrategies(), currentUser);
097                // take the claims from the form, create a document, and redirect to the given URL...which is easy
098                String redirectURL = electronicPaymentClaimingService.createPaymentClaimingDocument(form.getClaims(), documentCreationHelper, currentUser);
099                return new ActionForward(redirectURL, true);
100            } else {
101                return mapping.findForward(ElectronicFundTransferClaimActionHelper.BASIC_FORWARD);
102            }
103        }
104        
105        /**
106         * Verifies that the chosenElectronicPaymentClaimingDocumentCode has been filled in.
107         * @param chosenDoc the value of chosenElectronicPaymentClaimingDocumentCode from the form
108         * @return true if the validation resulted in no errors, false if otherwise
109         */
110        protected boolean checkChosenDocumentType(String chosenDoc) {
111            boolean result = true;
112            if (StringUtils.isBlank(chosenDoc)) {
113                GlobalVariables.getMessageMap().putError(ElectronicFundTransferClaimActionHelper.CHOSEN_DOCUMENT_PROPERTY, KFSKeyConstants.ElectronicPaymentClaim.ERROR_EFT_NO_CHOSEN_CLAIMING_DOCTYPE, new String[]{});
114                result = false;
115            }
116            return result;
117        }
118    
119        /**
120         * Using user entered form values, determines which of the available ElectronicPaymentClaimingDocumentGenerationStrategy implementations to use. 
121         * @param chosenDoc the document type code for the doc that the user selected
122         * @param availableClaimingDocs a List of ElectronicPaymentClaimingDocumentGenerationStrategy implementations that can be used by the given user
123         * @param currentUser the currently logged in user
124         * @throws AuthorizationException thrown if the user entered an invalid or unusable ElectronicPaymentClaimingDocumentGenerationStrategy code
125         * @return an ElectronicPaymentClaimingDocumentGenerationStrategy helper to use to create the document
126         */
127        protected ElectronicPaymentClaimingDocumentGenerationStrategy getRequestedClaimingHelper(String chosenDoc, List<ElectronicPaymentClaimingDocumentGenerationStrategy> availableClaimingDocs, Person currentUser) {
128            ElectronicPaymentClaimingDocumentGenerationStrategy chosenDocHelper = null;
129            int count = 0;
130            while (count < availableClaimingDocs.size() && chosenDocHelper == null) {
131                ElectronicPaymentClaimingDocumentGenerationStrategy claimingDoc = availableClaimingDocs.get(count);
132                if (StringUtils.equals(claimingDoc.getClaimingDocumentWorkflowDocumentType(), chosenDoc)) {
133                    chosenDocHelper = claimingDoc;
134                }
135                count += 1;
136            }
137            if (chosenDocHelper == null || !chosenDocHelper.userMayUseToClaim(currentUser)) {
138                throw new AuthorizationException(currentUser.getPrincipalName(), ElectronicFundTransferClaimActionHelper.ACTION_NAME, ddService.getDataDictionary().getBusinessObjectEntry(ElectronicPaymentClaim.class.getName()).getObjectLabel());
139            }
140            return chosenDocHelper;
141        }
142        
143        /**
144         * Administrative users can fill in a field that says that a given electronic payment claim has already been claimed by another document.  This method
145         * traverses through the list of electronic payment claims, checks if it is pre-claimed, and saves it if it is pre-claimed
146         * @param claims the list of electronic payment claims 
147         * @return the list of electronic payment claims with all pre-claimed records removed
148         */
149        protected List<ElectronicPaymentClaim> handlePreClaimedRecords(List<ElectronicPaymentClaim> claims, Set<String> preClaimedByCheckbox, List<ElectronicPaymentClaimingDocumentGenerationStrategy> documentGenerationStrategies) {
150            List<ElectronicPaymentClaim> stillToClaim = new ArrayList<ElectronicPaymentClaim>();
151            int count = 0;
152            for (ElectronicPaymentClaim claim: claims) {
153                if (StringUtils.isBlank(claim.getReferenceFinancialDocumentNumber()) && !preClaimedByCheckbox.contains(claim.getElectronicPaymentClaimRepresentation())) {
154                    // not claimed by any mechanism, add to stillToClaim list
155                    stillToClaim.add(claim);
156                } else {
157                    boolean savePreClaimed = true;
158                    if (StringUtils.isNotBlank(claim.getReferenceFinancialDocumentNumber())) {
159                        // check that the document exists
160                        boolean isValidDocRef = false;
161                        int stratCount = 0;
162                        while (!isValidDocRef && stratCount < documentGenerationStrategies.size()) {
163                            isValidDocRef |= documentGenerationStrategies.get(stratCount).isDocumentReferenceValid(claim.getReferenceFinancialDocumentNumber());
164                            stratCount += 1;
165                        }
166                        if (!isValidDocRef) {
167                            GlobalVariables.getMessageMap().putError(ElectronicFundTransferClaimActionHelper.CLAIM_PROPERTY+"["+count+"]", KFSKeyConstants.ElectronicPaymentClaim.ERROR_PRE_CLAIMING_DOCUMENT_DOES_NOT_EXIST, new String[] { claim.getReferenceFinancialDocumentNumber() });
168                            savePreClaimed = false;
169                        }
170                    }
171                    if (savePreClaimed) {
172                        claim.setPaymentClaimStatusCode(ElectronicPaymentClaim.ClaimStatusCodes.CLAIMED);
173                        // save that record
174                        boService.save(claim);
175                    }
176                }
177                count += 1;
178            }
179            return stillToClaim;
180        }
181        
182        /**
183         * Uses the list of checked pre-claimed checkbox helpers to create a Set of representations of electronic payment claim records that were marked as "pre-claimed"
184         * @param checkboxHelpers the list of checked ElectronicPaymentClaimClaimedHelpers from the form
185         * @return a Set of electronic payment claim representations for records that have been reclaimed
186         */
187        protected Set<String> generatePreClaimedByCheckboxSet(List<ElectronicPaymentClaimClaimedHelper> checkboxHelpers) {
188            Set<String> claimedByCheckboxRepresentations = new HashSet<String>();
189            for (ElectronicPaymentClaimClaimedHelper helper: checkboxHelpers) {
190                claimedByCheckboxRepresentations.add(helper.getElectronicPaymentClaimRepresentation());
191            }
192            return claimedByCheckboxRepresentations;
193        }
194        
195        /**
196         * Checks that the user was able to answer the "has documentation?" question correctly
197         * @param hasDocumentation the user's response to the "has documentation" question
198         * @return true if the user was able to successfully answer this question, false otherwise
199         */
200        protected boolean handleDocumentationForClaim(String hasDocumentation) {
201            boolean success = true;
202            if (StringUtils.isBlank(hasDocumentation) || !hasDocumentation.equalsIgnoreCase("yep")) {
203                GlobalVariables.getMessageMap().putError(ElectronicFundTransferClaimActionHelper.HAS_DOCUMENTATION_PROPERTY, KFSKeyConstants.ElectronicPaymentClaim.ERROR_NO_DOCUMENTATION, new String[] {});
204                success = false;
205            }
206            
207            return success;
208        }
209    
210        /**
211         * Sets the ddService attribute value.
212         * @param ddService The ddService to set.
213         */
214        public void setDataDictonaryService(DataDictionaryService ddService) {
215            this.ddService = ddService;
216        }
217    
218        /**
219         * Sets the electronicPaymentClaimingService attribute value.
220         * @param electronicPaymentClaimingService The electronicPaymentClaimingService to set.
221         */
222        public void setElectronicPaymentClaimingService(ElectronicPaymentClaimingService electronicPaymentClaimingService) {
223            this.electronicPaymentClaimingService = electronicPaymentClaimingService;
224        }
225    
226        /**
227         * Sets the boService attribute value.
228         * @param boService The boService to set.
229         */
230        public void setBusinessObjectService(BusinessObjectService boService) {
231            this.boService = boService;
232        }
233    
234        /**
235         * Sets the documentService attribute value.
236         * @param documentService The documentService to set.
237         */
238        public void setDocumentService(DocumentService documentService) {
239            this.documentService = documentService;
240        }
241        
242    }
243