001/*
002 * Copyright 2008 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 */
016package org.kuali.ole.sys.service.impl;
017
018import java.util.ArrayList;
019import java.util.HashSet;
020import java.util.List;
021import java.util.Map;
022import java.util.Set;
023
024import org.apache.commons.lang.StringUtils;
025import org.apache.struts.action.ActionForward;
026import org.apache.struts.action.ActionMapping;
027import org.kuali.ole.sys.OLEKeyConstants;
028import org.kuali.ole.sys.businessobject.ElectronicPaymentClaim;
029import org.kuali.ole.sys.service.ElectronicFundTransferActionHelper;
030import org.kuali.ole.sys.service.ElectronicPaymentClaimingDocumentGenerationStrategy;
031import org.kuali.ole.sys.service.ElectronicPaymentClaimingService;
032import org.kuali.ole.sys.web.struts.ElectronicFundTransferForm;
033import org.kuali.ole.sys.web.struts.ElectronicPaymentClaimClaimedHelper;
034import org.kuali.rice.kim.api.identity.Person;
035import org.kuali.rice.kns.service.DataDictionaryService;
036import org.kuali.rice.krad.exception.AuthorizationException;
037import org.kuali.rice.krad.service.BusinessObjectService;
038import org.kuali.rice.krad.service.DocumentService;
039import org.kuali.rice.krad.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 */
045public 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.ole.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().getNumberOfPropertiesWithErrors() > 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, OLEKeyConstants.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+"]", OLEKeyConstants.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, OLEKeyConstants.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