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