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.fp.document.service.impl; 017 018 import java.util.HashMap; 019 import java.util.List; 020 import java.util.Map; 021 import java.util.Set; 022 023 import org.apache.commons.lang.StringUtils; 024 import org.kuali.kfs.fp.businessobject.DisbursementPayee; 025 import org.kuali.kfs.fp.businessobject.DisbursementVoucherPayeeDetail; 026 import org.kuali.kfs.fp.document.DisbursementVoucherConstants; 027 import org.kuali.kfs.fp.document.DisbursementVoucherDocument; 028 import org.kuali.kfs.fp.document.service.DisbursementVoucherPayeeService; 029 import org.kuali.kfs.sys.KFSPropertyConstants; 030 import org.kuali.kfs.sys.context.SpringContext; 031 import org.kuali.kfs.sys.document.authorization.FinancialSystemTransactionalDocumentAuthorizerBase; 032 import org.kuali.kfs.vnd.VendorConstants; 033 import org.kuali.kfs.vnd.businessobject.VendorDetail; 034 import org.kuali.kfs.vnd.businessobject.VendorType; 035 import org.kuali.kfs.vnd.document.service.VendorService; 036 import org.kuali.rice.kew.exception.WorkflowException; 037 import org.kuali.rice.kew.util.KEWConstants; 038 import org.kuali.rice.kim.bo.Person; 039 import org.kuali.rice.kim.service.PersonService; 040 import org.kuali.rice.kns.bo.AdHocRoutePerson; 041 import org.kuali.rice.kns.bo.Note; 042 import org.kuali.rice.kns.document.authorization.DocumentAuthorizer; 043 import org.kuali.rice.kns.service.BusinessObjectService; 044 import org.kuali.rice.kns.service.DataDictionaryService; 045 import org.kuali.rice.kns.service.DocumentService; 046 import org.kuali.rice.kns.service.ParameterService; 047 import org.kuali.rice.kns.util.ObjectUtils; 048 049 /** 050 * implementing the service methods defined in DisbursementVoucherPayeeService 051 * 052 * @see DisbursementVoucherPayeeService 053 */ 054 public class DisbursementVoucherPayeeServiceImpl implements DisbursementVoucherPayeeService { 055 private org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DisbursementVoucherPayeeServiceImpl.class); 056 057 private BusinessObjectService businessObjectService; 058 private DataDictionaryService dataDictionaryService; 059 private DocumentService documentService; 060 private ParameterService parameterService; 061 private VendorService vendorService; 062 063 /** 064 * @see org.kuali.kfs.fp.document.service.DisbursementVoucherPayeeService#getPayeeTypeDescription(java.lang.String) 065 */ 066 public String getPayeeTypeDescription(String payeeTypeCode) { 067 String payeeTypeDescription = StringUtils.EMPTY; 068 069 if (DisbursementVoucherConstants.DV_PAYEE_TYPE_EMPLOYEE.equals(payeeTypeCode)) { 070 payeeTypeDescription = parameterService.getParameterValue(DisbursementVoucherDocument.class, DisbursementVoucherConstants.NON_VENDOR_EMPLOYEE_PAYEE_TYPE_LABEL_PARM_NM); 071 } 072 else if (DisbursementVoucherConstants.DV_PAYEE_TYPE_VENDOR.equals(payeeTypeCode)) { 073 payeeTypeDescription = parameterService.getParameterValue(DisbursementVoucherDocument.class, DisbursementVoucherConstants.PO_AND_DV_PAYEE_TYPE_LABEL_PARM_NM); 074 } 075 else if (DisbursementVoucherConstants.DV_PAYEE_TYPE_REVOLVING_FUND_VENDOR.equals(payeeTypeCode)) { 076 payeeTypeDescription = this.getVendorTypeDescription(VendorConstants.VendorTypes.REVOLVING_FUND); 077 } 078 else if (DisbursementVoucherConstants.DV_PAYEE_TYPE_SUBJECT_PAYMENT_VENDOR.equals(payeeTypeCode)) { 079 payeeTypeDescription = this.getVendorTypeDescription(VendorConstants.VendorTypes.SUBJECT_PAYMENT); 080 } 081 082 return payeeTypeDescription; 083 } 084 085 /** 086 * @see org.kuali.kfs.fp.document.service.DisbursementVoucherPayeeService#isEmployee(org.kuali.kfs.fp.businessobject.DisbursementVoucherPayeeDetail) 087 */ 088 public boolean isEmployee(DisbursementVoucherPayeeDetail dvPayeeDetail) { 089 // If is vendor, then check vendor employee flag 090 if (this.isVendor(dvPayeeDetail)) { 091 VendorDetail vendor = vendorService.getByVendorNumber(dvPayeeDetail.getDisbVchrPayeeIdNumber()); 092 return vendor == null ? false : vendorService.isVendorInstitutionEmployee(vendor.getVendorHeaderGeneratedIdentifier()); 093 } 094 095 String payeeTypeCode = dvPayeeDetail.getDisbursementVoucherPayeeTypeCode(); 096 return DisbursementVoucherConstants.DV_PAYEE_TYPE_EMPLOYEE.equals(payeeTypeCode); 097 } 098 099 /** 100 * @see org.kuali.kfs.fp.document.service.DisbursementVoucherPayeeService#isEmployee(org.kuali.kfs.fp.businessobject.DisbursementPayee) 101 */ 102 public boolean isEmployee(DisbursementPayee payee) { 103 // If is vendor, then check vendor employee flag 104 if (this.isVendor(payee)) { 105 VendorDetail vendor = vendorService.getByVendorNumber(payee.getPayeeIdNumber()); 106 return vendor == null ? false : vendorService.isVendorInstitutionEmployee(vendor.getVendorHeaderGeneratedIdentifier()); 107 } 108 109 String payeeTypeCode = payee.getPayeeTypeCode(); 110 return DisbursementVoucherConstants.DV_PAYEE_TYPE_EMPLOYEE.equals(payeeTypeCode); 111 } 112 113 /** 114 * @see org.kuali.kfs.fp.document.service.DisbursementVoucherPayeeService#isVendor(org.kuali.kfs.fp.businessobject.DisbursementVoucherPayeeDetail) 115 */ 116 public boolean isVendor(DisbursementVoucherPayeeDetail dvPayeeDetail) { 117 String payeeTypeCode = dvPayeeDetail.getDisbursementVoucherPayeeTypeCode(); 118 return DisbursementVoucherConstants.VENDOR_PAYEE_TYPE_CODES.contains(payeeTypeCode); 119 } 120 121 /** 122 * @see org.kuali.kfs.fp.document.service.DisbursementVoucherPayeeService#isVendor(org.kuali.kfs.fp.businessobject.DisbursementPayee) 123 */ 124 public boolean isVendor(DisbursementPayee payee) { 125 String payeeTypeCode = payee.getPayeeTypeCode(); 126 return DisbursementVoucherConstants.VENDOR_PAYEE_TYPE_CODES.contains(payeeTypeCode); 127 } 128 129 /** 130 * @see org.kuali.kfs.fp.document.service.DisbursementVoucherPayeeService#isPayeeIndividualVendor(org.kuali.kfs.fp.businessobject.DisbursementVoucherPayeeDetail) 131 */ 132 public boolean isPayeeIndividualVendor(DisbursementVoucherPayeeDetail dvPayeeDetail) { 133 return this.isVendor(dvPayeeDetail) ? this.isPayeeIndividualVendor(dvPayeeDetail.getDisbVchrPayeeIdNumber()) : false; 134 } 135 136 /** 137 * @see org.kuali.kfs.fp.document.service.DisbursementVoucherPayeeService#isPayeeIndividualVendor(org.kuali.kfs.fp.businessobject.DisbursementPayee) 138 */ 139 public boolean isPayeeIndividualVendor(DisbursementPayee payee) { 140 return this.isVendor(payee) ? this.isPayeeIndividualVendor(payee.getPayeeIdNumber()) : false; 141 } 142 143 /** 144 * @see org.kuali.kfs.fp.document.service.DisbursementVoucherPayeeService#getVendorOwnershipTypeCode(org.kuali.kfs.fp.businessobject.DisbursementPayee) 145 */ 146 public String getVendorOwnershipTypeCode(DisbursementPayee payee) { 147 if(ObjectUtils.isNull(payee) || !this.isVendor(payee)) { 148 return null; 149 } 150 151 VendorDetail vendor = vendorService.getByVendorNumber(payee.getPayeeIdNumber()); 152 return vendor == null ? null : vendor.getVendorHeader().getVendorOwnershipCode(); 153 } 154 155 /** 156 * @see org.kuali.kfs.fp.document.service.DisbursementVoucherPayeeService#checkPayeeAddressForChanges(org.kuali.kfs.fp.document.DisbursementVoucherDocument) 157 */ 158 public void checkPayeeAddressForChanges(DisbursementVoucherDocument dvDoc) { 159 Map<String, String> pks = new HashMap<String, String>(); 160 pks.put("documentNumber", dvDoc.getDocumentNumber()); 161 162 DisbursementVoucherDocument savedDv = (DisbursementVoucherDocument) businessObjectService.findByPrimaryKey(DisbursementVoucherDocument.class, pks); 163 DisbursementVoucherPayeeDetail newPayeeDetail = dvDoc.getDvPayeeDetail(); 164 DisbursementVoucherPayeeDetail oldPayeeDetail = savedDv.getDvPayeeDetail(); 165 166 if (ObjectUtils.isNotNull(oldPayeeDetail) && ObjectUtils.isNotNull(newPayeeDetail)) { 167 if (!oldPayeeDetail.hasSameAddress(newPayeeDetail)) {// Addresses don't match, so let's start the recording of 168 // changes 169 170 // Put a note on the document to record the change to the address 171 try { 172 String noteText = buildPayeeChangedNoteText(newPayeeDetail, oldPayeeDetail); 173 174 int noteMaxSize = dataDictionaryService.getAttributeMaxLength("Note", "noteText"); 175 176 // Break up the note into multiple pieces if the note is too large to fit in the database field. 177 while (noteText.length() > noteMaxSize) { 178 int fromIndex = 0; 179 fromIndex = noteText.lastIndexOf(';', noteMaxSize); 180 181 String noteText1 = noteText.substring(0, fromIndex); 182 Note note1 = documentService.createNoteFromDocument(dvDoc, noteText1); 183 documentService.addNoteToDocument(dvDoc, note1); 184 noteText = noteText.substring(fromIndex); 185 } 186 187 Note note = documentService.createNoteFromDocument(dvDoc, noteText); 188 documentService.addNoteToDocument(dvDoc, note); 189 } 190 catch (Exception e) { 191 LOG.error("Exception while attempting to create or add note: " + e); 192 } 193 194 // Send out FYIs to all previous approvers so they're aware of the changes to the address 195 try { 196 Set<Person> priorApprovers = dvDoc.getDocumentHeader().getWorkflowDocument().getAllPriorApprovers(); 197 String initiatorUserId = dvDoc.getDocumentHeader().getWorkflowDocument().getRouteHeader().getInitiatorPrincipalId(); 198 Person finSysUser = SpringContext.getBean(PersonService.class).getPerson(initiatorUserId); 199 setupFYIs(dvDoc, priorApprovers, finSysUser.getPrincipalName()); 200 } 201 catch (WorkflowException we) { 202 LOG.error("Exception while attempting to retrieve all prior approvers from workflow: " + we); 203 } 204 catch (Exception unfe) { 205 LOG.error("Exception while attempting to retrieve all prior approvers for a disbursement voucher: " + unfe); 206 } 207 } 208 } 209 } 210 211 /** 212 * Creates text for a note which records changes to the payee 213 * @param newPayeeDetail the changed payee detail 214 * @param oldPayeeDetail the original payee detail 215 * @return the string for a note 216 */ 217 protected String buildPayeeChangedNoteText(DisbursementVoucherPayeeDetail newPayeeDetail, DisbursementVoucherPayeeDetail oldPayeeDetail) { 218 StringBuilder noteText = new StringBuilder(); 219 String valueLabel = ""; 220 try { 221 noteText.append("The following changes were made to the payee address: "); 222 223 valueLabel = dataDictionaryService.getAttributeLabel(DisbursementVoucherPayeeDetail.class, KFSPropertyConstants.DISB_VCHR_PAYEE_LINE1_ADDR); 224 noteText.append(buildAddressValueDifferenceText(valueLabel, oldPayeeDetail.getDisbVchrPayeeLine1Addr(), newPayeeDetail.getDisbVchrPayeeLine1Addr())); 225 226 valueLabel = dataDictionaryService.getAttributeLabel(DisbursementVoucherPayeeDetail.class, KFSPropertyConstants.DISB_VCHR_PAYEE_LINE2_ADDR); 227 noteText.append(buildAddressValueDifferenceText(valueLabel, oldPayeeDetail.getDisbVchrPayeeLine2Addr(), newPayeeDetail.getDisbVchrPayeeLine2Addr())); 228 229 valueLabel = dataDictionaryService.getAttributeLabel(DisbursementVoucherPayeeDetail.class, KFSPropertyConstants.DISB_VCHR_PAYEE_CITY_NAME); 230 noteText.append(buildAddressValueDifferenceText(valueLabel, oldPayeeDetail.getDisbVchrPayeeCityName(), newPayeeDetail.getDisbVchrPayeeCityName())); 231 232 valueLabel = dataDictionaryService.getAttributeLabel(DisbursementVoucherPayeeDetail.class, KFSPropertyConstants.DISB_VCHR_PAYEE_STATE_CODE); 233 noteText.append(buildAddressValueDifferenceText(valueLabel, oldPayeeDetail.getDisbVchrPayeeStateCode(), newPayeeDetail.getDisbVchrPayeeStateCode())); 234 235 valueLabel = dataDictionaryService.getAttributeLabel(DisbursementVoucherPayeeDetail.class, KFSPropertyConstants.DISB_VCHR_PAYEE_ZIP_CODE); 236 noteText.append(buildAddressValueDifferenceText(valueLabel, oldPayeeDetail.getDisbVchrPayeeZipCode(), newPayeeDetail.getDisbVchrPayeeZipCode())); 237 238 valueLabel = dataDictionaryService.getAttributeLabel(DisbursementVoucherPayeeDetail.class, KFSPropertyConstants.DISB_VCHR_PAYEE_COUNTRY_CODE); 239 noteText.append(buildAddressValueDifferenceText(valueLabel, oldPayeeDetail.getDisbVchrPayeeCountryCode(), newPayeeDetail.getDisbVchrPayeeCountryCode())); 240 } 241 catch (Exception ex) { 242 LOG.error("Error while attempting to build out note text for payee address change note: " + ex); 243 } 244 245 return noteText.toString(); 246 } 247 248 /** 249 * This method... 250 * 251 * @param valueName 252 * @param oldValue 253 * @param newValue 254 * @return 255 */ 256 protected String buildAddressValueDifferenceText(String valueName, String oldValue, String newValue) { 257 // Nothing to log if values are still the same 258 if (StringUtils.equals(oldValue, newValue)) { 259 return ""; 260 } 261 262 StringBuilder text = new StringBuilder(); 263 264 text.append(valueName).append(" was changed from "); 265 text.append(oldValue == null ? "(no value entered)" : oldValue).append(" to "); 266 text.append(newValue).append("; "); 267 268 return text.toString(); 269 } 270 271 /** 272 * Creates FYI requests to previous approvers 273 * 274 * @param dvDoc the document where the payee address has changed 275 * @param priorApprovers the previous approvers 276 * @param initiatorUserId the id of the initiator 277 */ 278 protected void setupFYIs(DisbursementVoucherDocument dvDoc, Set<Person> priorApprovers, String initiatorUserId) { 279 List<AdHocRoutePerson> adHocRoutePersons = dvDoc.getAdHocRoutePersons(); 280 final FinancialSystemTransactionalDocumentAuthorizerBase documentAuthorizer = getDocumentAuthorizer(dvDoc); 281 282 // Add FYI for each approver who has already approved the document 283 for (Person approver : priorApprovers) { 284 if (documentAuthorizer.canReceiveAdHoc(dvDoc, approver, KEWConstants.ACTION_REQUEST_FYI_REQ)) { 285 String approverPersonUserId = approver.getPrincipalName(); 286 adHocRoutePersons.add(buildFyiRecipient(approverPersonUserId)); 287 } 288 } 289 290 // Add FYI for initiator 291 adHocRoutePersons.add(buildFyiRecipient(initiatorUserId)); 292 } 293 294 /** 295 * Constructs a document authorizer for this class 296 * @return the document authorizer for this class 297 */ 298 protected FinancialSystemTransactionalDocumentAuthorizerBase getDocumentAuthorizer(DisbursementVoucherDocument dvDoc) { 299 final String docTypeName = dataDictionaryService.getDocumentTypeNameByClass(dvDoc.getClass()); 300 Class<? extends DocumentAuthorizer> documentAuthorizerClass = dataDictionaryService.getDataDictionary().getDocumentEntry(docTypeName).getDocumentAuthorizerClass(); 301 302 FinancialSystemTransactionalDocumentAuthorizerBase documentAuthorizer = null; 303 try { 304 documentAuthorizer = (FinancialSystemTransactionalDocumentAuthorizerBase)documentAuthorizerClass.newInstance(); 305 } 306 catch (InstantiationException ie) { 307 throw new RuntimeException("Could not construct document authorizer: "+documentAuthorizerClass.getName(), ie); 308 } 309 catch (IllegalAccessException iae) { 310 throw new RuntimeException("Could not construct document authorizer: "+documentAuthorizerClass.getName(), iae); 311 } 312 313 return documentAuthorizer; 314 } 315 316 /** 317 * This method... 318 * 319 * @param userId 320 * @return 321 */ 322 protected AdHocRoutePerson buildFyiRecipient(String userId) { 323 AdHocRoutePerson adHocRoutePerson = new AdHocRoutePerson(); 324 adHocRoutePerson.setActionRequested(KEWConstants.ACTION_REQUEST_FYI_REQ); 325 adHocRoutePerson.setId(userId); 326 return adHocRoutePerson; 327 } 328 329 // get the description of the vendor type with the given vendor type code 330 protected String getVendorTypeDescription(String vendorTypeCode) { 331 Map<String, String> primaryKeys = new HashMap<String, String>(); 332 primaryKeys.put(KFSPropertyConstants.VENDOR_TYPE_CODE, vendorTypeCode); 333 334 VendorType vendorType = (VendorType) businessObjectService.findByPrimaryKey(VendorType.class, primaryKeys); 335 return ObjectUtils.isNotNull(vendorType) ? vendorType.getVendorTypeDescription() : StringUtils.EMPTY; 336 } 337 338 // determine whether the given payee id number is associated with an individual vendor 339 protected boolean isPayeeIndividualVendor(String payeeIdNumber) { 340 List<String> individualOwnerShipTypeCodes = parameterService.getParameterValues(DisbursementVoucherDocument.class, DisbursementVoucherConstants.INDIVIDUAL_OWNERSHIP_TYPES_PARM_NM); 341 342 VendorDetail vendor = vendorService.getByVendorNumber(payeeIdNumber); 343 if (vendor != null && individualOwnerShipTypeCodes != null) { 344 return individualOwnerShipTypeCodes.contains(vendor.getVendorHeader().getVendorOwnershipCode()); 345 } 346 347 return false; 348 } 349 350 /** 351 * Sets the businessObjectService attribute value. 352 * 353 * @param businessObjectService The businessObjectService to set. 354 */ 355 public void setBusinessObjectService(BusinessObjectService businessObjectService) { 356 this.businessObjectService = businessObjectService; 357 } 358 359 /** 360 * Sets the documentService attribute value. 361 * 362 * @param documentService The documentService to set. 363 */ 364 public void setDocumentService(DocumentService documentService) { 365 this.documentService = documentService; 366 } 367 368 /** 369 * Sets the dataDictionaryService attribute value. 370 * 371 * @param dataDictionaryService The dataDictionaryService to set. 372 */ 373 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) { 374 this.dataDictionaryService = dataDictionaryService; 375 } 376 377 /** 378 * Sets the parameterService attribute value. 379 * 380 * @param parameterService The parameterService to set. 381 */ 382 public void setParameterService(ParameterService parameterService) { 383 this.parameterService = parameterService; 384 } 385 386 /** 387 * Sets the vendorService attribute value. 388 * @param vendorService The vendorService to set. 389 */ 390 public void setVendorService(VendorService vendorService) { 391 this.vendorService = vendorService; 392 } 393 }