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.Collection;
020    import java.util.Date;
021    import java.util.HashMap;
022    import java.util.List;
023    import java.util.Map;
024    
025    import org.kuali.kfs.fp.document.AdvanceDepositDocument;
026    import org.kuali.kfs.integration.ar.AccountsReceivableModuleService;
027    import org.kuali.kfs.sys.KFSConstants;
028    import org.kuali.kfs.sys.businessobject.AccountingLine;
029    import org.kuali.kfs.sys.businessobject.ElectronicPaymentClaim;
030    import org.kuali.kfs.sys.context.SpringContext;
031    import org.kuali.kfs.sys.identity.KfsKimAttributes;
032    import org.kuali.kfs.sys.service.ElectronicPaymentClaimingDocumentGenerationStrategy;
033    import org.kuali.kfs.sys.service.ElectronicPaymentClaimingService;
034    import org.kuali.rice.kim.bo.Person;
035    import org.kuali.rice.kim.bo.types.dto.AttributeSet;
036    import org.kuali.rice.kim.service.IdentityManagementService;
037    import org.kuali.rice.kns.document.Document;
038    import org.kuali.rice.kns.service.BusinessObjectService;
039    import org.kuali.rice.kns.service.DateTimeService;
040    import org.kuali.rice.kns.service.DocumentService;
041    import org.kuali.rice.kns.service.ParameterService;
042    import org.kuali.rice.kns.util.ObjectUtils;
043    
044    public class ElectronicPaymentClaimingServiceImpl implements ElectronicPaymentClaimingService {
045        private org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ElectronicPaymentClaimingServiceImpl.class);
046        private DocumentService documentService;
047        private BusinessObjectService businessObjectService;
048        private ParameterService parameterService;
049        private DateTimeService dateTimeService;
050    
051        protected static final String ELECTRONIC_FUNDS_CLAIMANT_GROUP_PARAMETER = "ELECTRONIC_FUNDS_CLAIMANT_GROUP";
052        protected final static String ELECTRONIC_PAYMENT_ADMINISTRATOR_GROUP_PARAM_NAME = "ELECTRONIC_FUNDS_ADMINISTRATOR_GROUP";
053        protected static final String ELECTRONIC_FUNDS_CLAIM_SUMMARIES_PER_NOTE_PARAMETER = "ELECTRONIC_FUNDS_CLAIM_SUMMARIES_PER_NOTE";
054        protected static final String CLAIMING_NOTE_PRELUDE = "Claiming CR Items: ";
055        protected static final String DI_CLAIMING_DOC_HELPER_BEAN_NAME = "distributionOfIncomeAndExpenseElectronicPaymentClaimingDocumentHelper";
056        protected static final String YEDI_CLAIMING_DOC_HELPER_BEAN_NAME = "yearEndDistributionOfIncomeAndExpenseElectronicPaymentClaimingDocumentHelper";
057        protected static final String CLAIMING_DOC_HELPER_BEAN_NAME = "expenseElectronicPaymentClaimingDocumentHelper";
058        protected static final String ELECTRONIC_PAYMENT_CLAIM_ACCOUNTS_PARAMETER = "ELECTRONIC_FUNDS_ACCOUNTS";
059    
060        /**
061         * @see org.kuali.kfs.sys.service.ElectronicPaymentClaimingService#constructNotesForClaims(java.util.List)
062         */
063        public List<String> constructNoteTextsForClaims(List<ElectronicPaymentClaim> claims) {
064            int summariesPerNote;
065            List<String> noteTexts = new ArrayList<String>();
066            try {
067                summariesPerNote = Integer.parseInt(parameterService.getParameterValue(ElectronicPaymentClaim.class, ELECTRONIC_FUNDS_CLAIM_SUMMARIES_PER_NOTE_PARAMETER));
068                int i = 0;
069                while (i < claims.size()) {
070                    String noteText = constructNoteText(claims, i, summariesPerNote);
071                    noteTexts.add(noteText);
072                    i += summariesPerNote;
073                }
074            }
075            catch (NumberFormatException nfe) {
076                throw new RuntimeException("The KFS-SYS / ElectronicPaymentClaim / " + ELECTRONIC_FUNDS_CLAIM_SUMMARIES_PER_NOTE_PARAMETER + " should have a value that can be parsed into an integer.", nfe);
077            }
078            return noteTexts;
079        }
080    
081        /**
082         * This creates a note for the given point in the list of summaries.
083         * 
084         * @param claims a List of ElectronicPaymentClaim records that are being claimed
085         * @param startPoint the point in the list the note is starting at
086         * @param maxSummariesPerNote the number of ElectronicPaymentClaim summaries we can have on a note
087         * @return a newly constructed note, that needs to have a user added
088         */
089        protected String constructNoteText(List<ElectronicPaymentClaim> claims, int startPoint, int maxSummariesPerNote) {
090            StringBuilder sb = new StringBuilder();
091            sb.append(CLAIMING_NOTE_PRELUDE);
092            for (int i = startPoint; i < (startPoint + maxSummariesPerNote) && i < claims.size(); i++) {
093                ElectronicPaymentClaim claim = claims.get(i);
094                sb.append(createSummaryLineForClaim(claim));
095            }
096            // substring out the final " ; "
097            String noteText = sb.substring(0, sb.length() - 3);
098            return noteText;
099        }
100    
101        /**
102         * Creates a summary line for a note from a claim
103         * 
104         * @param claim the electronic payment claim to summarize
105         * @return a String with the summary of the claim.
106         */
107        protected String createSummaryLineForClaim(ElectronicPaymentClaim claim) {
108            StringBuilder summary = new StringBuilder();
109            summary.append(claim.getDocumentNumber());
110            summary.append('-');
111            summary.append(claim.getFinancialDocumentLineNumber().toString());
112            summary.append(' ');
113            final Date advanceDepositDate = claim.getGeneratingAdvanceDepositDetail().getFinancialDocumentAdvanceDepositDate();
114            if (!ObjectUtils.isNull(advanceDepositDate)) {
115                summary.append(dateTimeService.toDateString(advanceDepositDate));
116                summary.append(' ');
117            }
118            summary.append('$');
119            summary.append(claim.getGeneratingAccountingLine().getAmount());
120            summary.append(' ');
121            summary.append(';');
122            summary.append(' ');
123            return summary.toString();
124        }
125    
126        /**
127         * @see org.kuali.kfs.sys.service.ElectronicPaymentClaimingService#createPaymentClaimingDocument(java.util.List,
128         *      org.kuali.kfs.sys.service.ElectronicPaymentClaimingDocumentGenerationStrategy)
129         */
130        public String createPaymentClaimingDocument(List<ElectronicPaymentClaim> claims, ElectronicPaymentClaimingDocumentGenerationStrategy documentCreationHelper, Person user) {
131            return documentCreationHelper.createDocumentFromElectronicPayments(claims, user);
132        }
133    
134        /**
135         * @see org.kuali.kfs.sys.service.ElectronicPaymentClaimingService#getClaimingDocumentChoices(org.kuali.rice.kim.bo.Person)
136         */
137        public List<ElectronicPaymentClaimingDocumentGenerationStrategy> getClaimingDocumentChoices(Person user) {
138            List<ElectronicPaymentClaimingDocumentGenerationStrategy> documentChoices = new ArrayList<ElectronicPaymentClaimingDocumentGenerationStrategy>();
139            Map<String, ElectronicPaymentClaimingDocumentGenerationStrategy> claimingDocHelpers = SpringContext.getBeansOfType(ElectronicPaymentClaimingDocumentGenerationStrategy.class);
140            ElectronicPaymentClaimingDocumentGenerationStrategy claimingDocHelper;
141            
142            // try the helper for no document case
143            claimingDocHelper = claimingDocHelpers.get(CLAIMING_DOC_HELPER_BEAN_NAME);
144            if (claimingDocHelper.userMayUseToClaim(user)) {
145                documentChoices.add(claimingDocHelper);
146            }        
147    
148            // try the DI
149            claimingDocHelper = claimingDocHelpers.get(DI_CLAIMING_DOC_HELPER_BEAN_NAME);
150            if (claimingDocHelper.userMayUseToClaim(user)) {
151                documentChoices.add(claimingDocHelper);
152            }
153            
154            // try the YEDI
155            claimingDocHelper = claimingDocHelpers.get(YEDI_CLAIMING_DOC_HELPER_BEAN_NAME);
156            if (claimingDocHelper.userMayUseToClaim(user)) {
157                documentChoices.add(claimingDocHelper);
158            }
159    
160            // try the AR Cash Control
161            claimingDocHelper = SpringContext.getBean(AccountsReceivableModuleService.class).getAccountsReceivablePaymentClaimingStrategy();
162            if (claimingDocHelper.userMayUseToClaim(user)) {
163                documentChoices.add(claimingDocHelper);
164            }
165    
166            return documentChoices;
167        }
168    
169        /**
170         * Sets the referenceFinancialDocumentNumber on each of the payments passed in with the given document number and then saves
171         * them.
172         * 
173         * @param payments a list of payments to claim
174         * @param docmentNumber the document number of the claiming document
175         */
176        public void claimElectronicPayments(List<ElectronicPaymentClaim> payments, String documentNumber) {
177            for (ElectronicPaymentClaim payment : payments) {
178                payment.setReferenceFinancialDocumentNumber(documentNumber);
179                payment.setPaymentClaimStatusCode(ElectronicPaymentClaim.ClaimStatusCodes.CLAIMED);
180                businessObjectService.save(payment);
181            }
182        }
183    
184        /**
185         * @see org.kuali.kfs.sys.service.ElectronicPaymentClaimingService#declaimElectronicPaymentClaimsForDocument(org.kuali.rice.kns.document.Document)
186         */
187        public void declaimElectronicPaymentClaimsForDocument(Document document) {
188            Map<String, String> searchKeys = new HashMap<String, String>();
189            searchKeys.put("referenceFinancialDocumentNumber", document.getDocumentNumber());
190            Collection<ElectronicPaymentClaim> claimsAsObjects = businessObjectService.findMatching(ElectronicPaymentClaim.class, searchKeys);
191            for (Object claimAsObject : claimsAsObjects) {
192                ElectronicPaymentClaim claim = (ElectronicPaymentClaim) claimAsObject;
193                claim.setReferenceFinancialDocumentNumber(null);
194                claim.setPaymentClaimStatusCode(ElectronicPaymentClaim.ClaimStatusCodes.UNCLAIMED);
195                businessObjectService.save(claim);
196            }
197        }
198    
199        /**
200         * @see org.kuali.kfs.sys.service.ElectronicPaymentClaimingService#isAuthorizedForClaimingElectronicPayment(org.kuali.rice.kim.bo.Person,
201         *      java.lang.String, java.lang.String)
202         */
203        public boolean isAuthorizedForClaimingElectronicPayment(Person user, String workflowDocumentTypeName) {
204            String principalId = user.getPrincipalId();
205            String namespaceCode = KFSConstants.ParameterNamespaces.KFS;
206            String permissionTemplateName = KFSConstants.PermissionTemplate.CLAIM_ELECTRONIC_PAYMENT.name;
207    
208            AttributeSet permissionDetails = new AttributeSet();
209            permissionDetails.put(KfsKimAttributes.DOCUMENT_TYPE_NAME, workflowDocumentTypeName);      
210    
211            IdentityManagementService identityManagementService = SpringContext.getBean(IdentityManagementService.class);
212            boolean isAuthorized = identityManagementService.hasPermissionByTemplateName(principalId, namespaceCode, permissionTemplateName, permissionDetails);
213            
214            return isAuthorized;
215        }
216    
217        /**
218         * @see org.kuali.kfs.sys.service.ElectronicPaymentClaimingService#generateElectronicPaymentClaimRecords(org.kuali.kfs.fp.document.AdvanceDepositDocument)
219         */
220        public List<ElectronicPaymentClaim> generateElectronicPaymentClaimRecords(AdvanceDepositDocument doc) {
221            List<ElectronicPaymentClaim> claimRecords = new ArrayList<ElectronicPaymentClaim>();
222            for (Object accountingLineAsObj : doc.getSourceAccountingLines()) {
223                final AccountingLine accountingLine = (AccountingLine) accountingLineAsObj;
224                if (this.representsElectronicFundAccount(accountingLine)) {
225                    ElectronicPaymentClaim electronicPayment = createElectronicPayment(doc, accountingLine);
226                    businessObjectService.save(electronicPayment);
227                    claimRecords.add(electronicPayment);
228                }
229            }
230            return claimRecords;
231        }
232        
233        /**
234         * Determines if the given accounting line represents an electronic payment
235         * @param accountingLine the accounting line to check
236         * @return true if the accounting line does represent an electronic payment, false otherwise
237         */
238        public boolean representsElectronicFundAccount(AccountingLine accountingLine) {
239            return parameterService.getParameterEvaluator(AdvanceDepositDocument.class, ELECTRONIC_PAYMENT_CLAIM_ACCOUNTS_PARAMETER, accountingLine.getChartOfAccountsCode(), accountingLine.getAccountNumber()).evaluationSucceeds();
240        }
241    
242        /**
243         * Creates an electronic payment claim record to match the given accounting line on the document
244         * 
245         * @param accountingLine an accounting line that an electronic payment claim record should be created for
246         * @return the created ElectronicPaymentClaim business object
247         */
248        protected ElectronicPaymentClaim createElectronicPayment(AdvanceDepositDocument document, AccountingLine accountingLine) {
249            ElectronicPaymentClaim electronicPayment = new ElectronicPaymentClaim();
250            electronicPayment.setDocumentNumber(document.getDocumentNumber());
251            electronicPayment.setFinancialDocumentLineNumber(accountingLine.getSequenceNumber());
252            electronicPayment.setFinancialDocumentPostingPeriodCode(document.getPostingPeriodCode());
253            electronicPayment.setFinancialDocumentPostingYear(document.getPostingYear());
254            electronicPayment.setPaymentClaimStatusCode(ElectronicPaymentClaim.ClaimStatusCodes.UNCLAIMED);
255            return electronicPayment;
256        }
257    
258        /**
259         * Sets the businessObjectService attribute value.
260         * 
261         * @param businessObjectService The businessObjectService to set.
262         */
263        public void setBusinessObjectService(BusinessObjectService businessObjectService) {
264            this.businessObjectService = businessObjectService;
265        }
266    
267        /**
268         * Sets the documentService attribute value.
269         * 
270         * @param documentService The documentService to set.
271         */
272        public void setDocumentService(DocumentService documentService) {
273            this.documentService = documentService;
274        }
275    
276        /**
277         * Sets the parameterService attribute value.
278         * 
279         * @param parameterService The parameterService to set.
280         */
281        public void setParameterService(ParameterService parameterService) {
282            this.parameterService = parameterService;
283        }
284    
285        /**
286         * Sets the dateTimeService attribute value.
287         * 
288         * @param dateTimeService The dateTimeService to set.
289         */
290        public void setDateTimeService(DateTimeService dateTimeService) {
291            this.dateTimeService = dateTimeService;
292        }
293    }