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.vnd.document.service.impl; 017 018 import java.util.HashMap; 019 import java.util.List; 020 import java.util.Map; 021 022 import org.apache.commons.lang.StringUtils; 023 import org.apache.log4j.Logger; 024 import org.kuali.kfs.sys.context.SpringContext; 025 import org.kuali.kfs.vnd.VendorConstants; 026 import org.kuali.kfs.vnd.VendorPropertyConstants; 027 import org.kuali.kfs.vnd.businessobject.VendorAddress; 028 import org.kuali.kfs.vnd.businessobject.VendorContract; 029 import org.kuali.kfs.vnd.businessobject.VendorContractOrganization; 030 import org.kuali.kfs.vnd.businessobject.VendorDefaultAddress; 031 import org.kuali.kfs.vnd.businessobject.VendorDetail; 032 import org.kuali.kfs.vnd.businessobject.VendorHeader; 033 import org.kuali.kfs.vnd.businessobject.VendorRoutingComparable; 034 import org.kuali.kfs.vnd.dataaccess.VendorDao; 035 import org.kuali.kfs.vnd.document.service.VendorService; 036 import org.kuali.rice.kew.exception.WorkflowException; 037 import org.kuali.rice.kim.bo.Person; 038 import org.kuali.rice.kim.service.PersonService; 039 import org.kuali.rice.kns.document.MaintenanceDocument; 040 import org.kuali.rice.kns.service.BusinessObjectService; 041 import org.kuali.rice.kns.service.DocumentService; 042 import org.kuali.rice.kns.service.PersistenceService; 043 import org.kuali.rice.kns.util.KualiDecimal; 044 import org.kuali.rice.kns.util.ObjectUtils; 045 import org.springframework.transaction.annotation.Transactional; 046 047 @Transactional 048 public class VendorServiceImpl implements VendorService { 049 private static Logger LOG = Logger.getLogger(VendorServiceImpl.class); 050 051 private BusinessObjectService businessObjectService; 052 private DocumentService documentService; 053 private PersistenceService persistenceService; 054 private VendorDao vendorDao; 055 056 /** 057 * @see org.kuali.kfs.vnd.document.service.VendorService#saveVendorHeader(org.kuali.kfs.vnd.businessobject.VendorDetail) 058 */ 059 public void saveVendorHeader(VendorDetail vendorDetail) { 060 businessObjectService.save(vendorDetail.getVendorHeader()); 061 } 062 063 /** 064 * @see org.kuali.kfs.vnd.document.service.getByVendorNumber(String) 065 */ 066 public VendorDetail getByVendorNumber(String vendorNumber) { 067 return this.getVendorDetail(vendorNumber); 068 } 069 070 /** 071 * @see org.kuali.kfs.vnd.document.service.VendorService#getVendorDetail(String) 072 */ 073 public VendorDetail getVendorDetail(String vendorNumber) { 074 LOG.debug("Entering getVendorDetail for vendorNumber: " + vendorNumber); 075 if (StringUtils.isEmpty(vendorNumber)) 076 return null; 077 078 int dashInd = vendorNumber.indexOf('-'); 079 // make sure there's at least one char before and after '-' 080 if (dashInd > 0 && dashInd < vendorNumber.length() - 1) { 081 try { 082 Integer headerId = new Integer(vendorNumber.substring(0, dashInd)); 083 Integer detailId = new Integer(vendorNumber.substring(dashInd + 1)); 084 return getVendorDetail(headerId, detailId); 085 } 086 catch (NumberFormatException e) { 087 // in case of invalid number format 088 return null; 089 } 090 } 091 092 return null; 093 } 094 095 /** 096 * @see org.kuali.kfs.vnd.document.service.VendorService#getVendorDetail(java.lang.Integer, java.lang.Integer) 097 */ 098 public VendorDetail getVendorDetail(Integer headerId, Integer detailId) { 099 LOG.debug("Entering getVendorDetail for headerId:" + headerId + ", detailId:" + detailId); 100 Map keys = new HashMap(); 101 keys.put("vendorHeaderGeneratedIdentifier", headerId); 102 keys.put("vendorDetailAssignedIdentifier", detailId); 103 return (VendorDetail) businessObjectService.findByPrimaryKey(VendorDetail.class, keys); 104 } 105 106 /** 107 * @see org.kuali.kfs.vnd.document.service.VendorService#getApoLimitFromContract(Integer, String, String) 108 */ 109 public KualiDecimal getApoLimitFromContract(Integer contractId, String chart, String org) { 110 LOG.debug("Entering getApoLimitFromContract with contractId:" + contractId + ", chart:" + chart + ", org:" + org); 111 112 // check for the special case of a contractOrg for this contract in the contract-orgs table 113 if (ObjectUtils.isNotNull(contractId) && ObjectUtils.isNotNull(chart) && ObjectUtils.isNotNull(org)) { 114 VendorContractOrganization exampleContractOrg = new VendorContractOrganization(); 115 exampleContractOrg.setVendorContractGeneratedIdentifier(contractId); 116 exampleContractOrg.setChartOfAccountsCode(chart); 117 exampleContractOrg.setOrganizationCode(org); 118 Map orgKeys = persistenceService.getPrimaryKeyFieldValues(exampleContractOrg); 119 VendorContractOrganization contractOrg = (VendorContractOrganization) businessObjectService.findByPrimaryKey(VendorContractOrganization.class, orgKeys); 120 // if the contractOrg is found 121 if (ObjectUtils.isNotNull(contractOrg)) { 122 // if the contractOrg is excluded, return the special value of the APO limit from the table 123 if (!contractOrg.isVendorContractExcludeIndicator()) { 124 return contractOrg.getVendorContractPurchaseOrderLimitAmount(); 125 } 126 // otherwise return null, as if there's no contract 127 else return null; 128 } 129 } 130 131 // didn't search the contract-org table or not found in the table but contract exists, return the default APO limit in contract 132 if (ObjectUtils.isNotNull(contractId)) { 133 VendorContract exampleContract = new VendorContract(); 134 exampleContract.setVendorContractGeneratedIdentifier(contractId); 135 Map contractKeys = persistenceService.getPrimaryKeyFieldValues(exampleContract); 136 VendorContract contract = (VendorContract) businessObjectService.findByPrimaryKey(VendorContract.class, contractKeys); 137 if (ObjectUtils.isNotNull(contract)) { 138 return contract.getOrganizationAutomaticPurchaseOrderLimit(); 139 } 140 } 141 142 // otherwise no APO limit found from contract 143 return null; 144 } 145 146 /** 147 * @see org.kuali.kfs.vnd.document.service.VendorService#getParentVendor(java.lang.Integer) 148 */ 149 public VendorDetail getParentVendor(Integer vendorHeaderGeneratedIdentifier) { 150 LOG.debug("Entering getParentVendor for vendorHeaderGeneratedIdentifier:" + vendorHeaderGeneratedIdentifier); 151 Map criterion = new HashMap(); 152 criterion.put("vendorHeaderGeneratedIdentifier", vendorHeaderGeneratedIdentifier); 153 List<VendorDetail> vendors = (List<VendorDetail>) businessObjectService.findMatching(VendorDetail.class, criterion); 154 VendorDetail result = null; 155 if (ObjectUtils.isNull(vendors)) { 156 LOG.warn("Error: No vendors exist with vendor header " + vendorHeaderGeneratedIdentifier + "."); 157 } 158 else { 159 for (VendorDetail vendor : vendors) { 160 if (vendor.isVendorParentIndicator()) { 161 if (ObjectUtils.isNull(result)) { 162 result = vendor; 163 } 164 else { 165 LOG.error("Error: More than one parent vendor for vendor header " + vendorHeaderGeneratedIdentifier + "."); 166 throw new RuntimeException("Error: More than one parent vendor for vendor header " + vendorHeaderGeneratedIdentifier + "."); 167 } 168 } 169 } 170 if (ObjectUtils.isNull(result)) { 171 LOG.error("Error: No parent vendor for vendor header " + vendorHeaderGeneratedIdentifier + "."); 172 throw new RuntimeException("Error: No parent vendor for vendor header " + vendorHeaderGeneratedIdentifier + "."); 173 } 174 } 175 LOG.debug("Exiting getParentVendor normally."); 176 return result; 177 } 178 179 /** 180 * @see org.kuali.kfs.vnd.document.service.VendorService#getVendorByDunsNumber(String) 181 */ 182 public VendorDetail getVendorByDunsNumber(String vendorDunsNumber) { 183 LOG.debug("Entering getVendorByDunsNumber for vendorDunsNumber:" + vendorDunsNumber); 184 Map criteria = new HashMap(); 185 criteria.put(VendorPropertyConstants.VENDOR_DUNS_NUMBER, vendorDunsNumber); 186 List<VendorDetail> vds = (List) businessObjectService.findMatching(VendorDetail.class, criteria); 187 LOG.debug("Exiting getVendorByDunsNumber."); 188 if (vds.size() < 1) { 189 return null; 190 } 191 else { 192 return vds.get(0); 193 } 194 } 195 196 /** 197 * @see org.kuali.kfs.vnd.document.service.VendorService#getVendorDefaultAddress(Integer, Integer, String, String) 198 */ 199 public VendorAddress getVendorDefaultAddress(Integer vendorHeaderId, Integer vendorDetailId, String addressType, String campus) { 200 LOG.debug("Entering getVendorDefaultAddress for vendorHeaderId:" + vendorHeaderId + ", vendorDetailId:" + vendorDetailId + ", addressType:" + addressType + ", campus:" + campus); 201 Map criteria = new HashMap(); 202 criteria.put(VendorPropertyConstants.VENDOR_HEADER_GENERATED_ID, vendorHeaderId); 203 criteria.put(VendorPropertyConstants.VENDOR_DETAIL_ASSIGNED_ID, vendorDetailId); 204 criteria.put(VendorPropertyConstants.VENDOR_ADDRESS_TYPE_CODE, addressType); 205 List<VendorAddress> addresses = (List) businessObjectService.findMatching(VendorAddress.class, criteria); 206 LOG.debug("Exiting getVendorDefaultAddress."); 207 return getVendorDefaultAddress(addresses, addressType, campus); 208 } 209 210 /** 211 * @see org.kuali.kfs.vnd.document.service.VendorService#getVendorDefaultAddress(List, String, String) 212 */ 213 public VendorAddress getVendorDefaultAddress(List<VendorAddress> addresses, String addressType, String campus) { 214 LOG.debug("Entering getVendorDefaultAddress."); 215 VendorAddress allDefaultAddress = null; 216 for (VendorAddress address : addresses) { 217 // if address is of the right type, continue check 218 if (addressType.equals(address.getVendorAddressTypeCode())) { 219 // if campus was passed in and list of campuses on address exist, continue check 220 if (StringUtils.isNotEmpty(campus) && address.getVendorDefaultAddresses() != null) { 221 // looping through list of campus defaults to find a match for the passed in campus 222 for (VendorDefaultAddress defaultCampus : address.getVendorDefaultAddresses()) { 223 if (campus.equals(defaultCampus.getVendorCampusCode())) { 224 // found campus default; return it 225 LOG.debug("Exiting getVendorDefaultAddress with single campus default."); 226 return address; 227 } 228 }// endfor campuses 229 } 230 231 // if this address is set as the default for this address type; keep it for possible future use 232 if (address.isVendorDefaultAddressIndicator()) { 233 allDefaultAddress = address; 234 } 235 } 236 }// endfor addresses 237 238 // if we got this far, there is no campus default; so return the default set for all (could return null) 239 LOG.debug("Exiting getVendorDefaultAddress with default set for all."); 240 return allDefaultAddress; 241 } 242 243 /** 244 * @see org.kuali.kfs.vnd.document.service.VendorService#shouldVendorRouteForApproval(java.lang.String) 245 */ 246 public boolean shouldVendorRouteForApproval(String documentId) { 247 LOG.debug("Entering shouldVendorRouteForApproval."); 248 boolean shouldRoute = true; 249 MaintenanceDocument newDoc = null; 250 try { 251 newDoc = (MaintenanceDocument) documentService.getByDocumentHeaderId(documentId); 252 } 253 catch (WorkflowException we) { 254 throw new RuntimeException("A WorkflowException was thrown which prevented the loading of " + "the comparison document (" + documentId + ")", we); 255 } 256 257 if (ObjectUtils.isNotNull(newDoc)) { 258 259 VendorDetail oldVDtl = (VendorDetail) (newDoc.getOldMaintainableObject().getBusinessObject()); 260 VendorHeader oldVHdr = oldVDtl.getVendorHeader(); 261 VendorDetail newVDtl = (VendorDetail) (newDoc.getNewMaintainableObject().getBusinessObject()); 262 VendorHeader newVHdr = newVDtl.getVendorHeader(); 263 264 if ((ObjectUtils.isNotNull(oldVHdr)) && (ObjectUtils.isNotNull(oldVDtl)) && (ObjectUtils.isNotNull(newVHdr)) && (ObjectUtils.isNotNull(newVDtl))) { 265 shouldRoute = !(noRouteSignificantChangeOccurred(newVDtl, newVHdr, oldVDtl, oldVHdr)); 266 } 267 else { 268 shouldRoute = true; 269 } 270 } 271 LOG.debug("Exiting shouldVendorRouteForApproval."); 272 return shouldRoute; 273 } 274 275 /** 276 * @see org.kuali.kfs.vnd.document.service.VendorService#noRouteSignificantChangeOccurred(org.kuali.kfs.vnd.businessobject.VendorDetail, 277 * org.kuali.kfs.vnd.businessobject.VendorHeader, org.kuali.kfs.vnd.businessobject.VendorDetail, 278 * org.kuali.kfs.vnd.businessobject.VendorHeader) 279 */ 280 public boolean noRouteSignificantChangeOccurred(VendorDetail newVDtl, VendorHeader newVHdr, VendorDetail oldVDtl, VendorHeader oldVHdr) { 281 LOG.debug("Entering noRouteSignificantChangeOccurred."); 282 283 // The subcollections which are being compared here must implement VendorRoutingComparable. 284 boolean unchanged = ((oldVHdr.isEqualForRouting(newVHdr)) && (equalMemberLists(oldVHdr.getVendorSupplierDiversities(), newVHdr.getVendorSupplierDiversities())) && (oldVDtl.isEqualForRouting(newVDtl)) && (equalMemberLists(oldVDtl.getVendorAddresses(), newVDtl.getVendorAddresses())) && (equalMemberLists(oldVDtl.getVendorContracts(), newVDtl.getVendorContracts())) && (equalMemberLists(oldVDtl.getVendorShippingSpecialConditions(), newVDtl.getVendorShippingSpecialConditions()))); 285 286 LOG.debug("Exiting noRouteSignificantChangeOccurred."); 287 return unchanged; 288 } 289 290 /** 291 * @see org.kuali.kfs.vnd.document.service.VendorService#equalMemberLists(java.util.List, java.util.List) 292 */ 293 public boolean equalMemberLists(List<? extends VendorRoutingComparable> list_a, List<? extends VendorRoutingComparable> list_b) { 294 LOG.debug("Entering equalMemberLists."); 295 boolean result = true; 296 int listSize = list_a.size(); 297 if (listSize != list_b.size()) { 298 LOG.debug("Exiting equalMemberLists because list sizes are unequal."); 299 return false; 300 } 301 VendorRoutingComparable aMember = null; 302 for (int i = 0; i < listSize; i++) { 303 aMember = list_a.get(i); 304 if (!aMember.isEqualForRouting(list_b.get(i))) { 305 result = false; 306 break; 307 } 308 } 309 LOG.debug("Exiting equalMemberLists."); 310 return result; 311 } 312 313 /** 314 * @see org.kuali.kfs.vnd.document.service.VendorService#isVendorInstitutionEmployee(java.lang.Integer) 315 */ 316 public boolean isVendorInstitutionEmployee(Integer vendorHeaderGeneratedIdentifier) { 317 VendorDetail vendorToUse = getParentVendor(vendorHeaderGeneratedIdentifier); 318 if (ObjectUtils.isNull(vendorToUse)) { 319 String errorMsg = "Vendor with header generated id '" + vendorHeaderGeneratedIdentifier + "' cannot be found in the system"; 320 LOG.error(errorMsg); 321 throw new RuntimeException(errorMsg); 322 } 323 if (VendorConstants.TAX_TYPE_SSN.equals(vendorToUse.getVendorHeader().getVendorTaxTypeCode())) { 324 String ssnTaxId = vendorToUse.getVendorHeader().getVendorTaxNumber(); 325 if (StringUtils.isNotBlank(ssnTaxId)) { 326 List<Person> personList = SpringContext.getBean(PersonService.class).getPersonByExternalIdentifier(org.kuali.rice.kim.util.KimConstants.PersonExternalIdentifierTypes.TAX, ssnTaxId); 327 if (personList != null && !personList.isEmpty()) { 328 return ObjectUtils.isNotNull(personList.get(0)); 329 } else { 330 // user is not in the system... assume non-person 331 return false; 332 } 333 } 334 } 335 return false; 336 } 337 338 /** 339 * @see org.kuali.kfs.vnd.document.service.VendorService#isVendorNonResidentAlien(java.lang.Integer) 340 */ 341 public boolean isVendorForeign(Integer vendorHeaderGeneratedIdentifier) { 342 VendorDetail vendorToUse = getParentVendor(vendorHeaderGeneratedIdentifier); 343 if (ObjectUtils.isNull(vendorToUse)) { 344 String errorMsg = "Vendor with header generated id '" + vendorHeaderGeneratedIdentifier + "' cannot be found in the system"; 345 LOG.error(errorMsg); 346 throw new RuntimeException(errorMsg); 347 } 348 return vendorToUse.getVendorHeader().getVendorForeignIndicator(); 349 } 350 351 /** 352 * 353 * @see org.kuali.kfs.vnd.document.service.VendorService#isSubjectPaymentVendor(java.lang.Integer) 354 */ 355 public boolean isSubjectPaymentVendor(Integer vendorHeaderGeneratedIdentifier) { 356 VendorDetail vendorToUse = getParentVendor(vendorHeaderGeneratedIdentifier); 357 if (ObjectUtils.isNull(vendorToUse)) { 358 String errorMsg = "Vendor with header generated id '" + vendorHeaderGeneratedIdentifier + "' cannot be found in the system"; 359 LOG.error(errorMsg); 360 throw new RuntimeException(errorMsg); 361 } 362 return VendorConstants.VendorTypes.SUBJECT_PAYMENT.equals(vendorToUse.getVendorHeader().getVendorTypeCode()); 363 } 364 365 /** 366 * 367 * @see org.kuali.kfs.vnd.document.service.VendorService#isRevolvingFundCodeVendor(java.lang.Integer) 368 */ 369 public boolean isRevolvingFundCodeVendor(Integer vendorHeaderGeneratedIdentifier) { 370 VendorDetail vendorToUse = getParentVendor(vendorHeaderGeneratedIdentifier); 371 if (ObjectUtils.isNull(vendorToUse)) { 372 String errorMsg = "Vendor with header generated id '" + vendorHeaderGeneratedIdentifier + "' cannot be found in the system"; 373 LOG.error(errorMsg); 374 throw new RuntimeException(errorMsg); 375 } 376 return VendorConstants.VendorTypes.REVOLVING_FUND.equals(vendorToUse.getVendorHeader().getVendorTypeCode()); 377 } 378 379 /** 380 * @see org.kuali.kfs.vnd.document.service.VendorService#getVendorB2BContract(org.kuali.kfs.vnd.businessobject.VendorDetail, java.lang.String) 381 */ 382 public VendorContract getVendorB2BContract(VendorDetail vendorDetail, String campus) { 383 return vendorDao.getVendorB2BContract(vendorDetail, campus); 384 } 385 386 public void setBusinessObjectService(BusinessObjectService boService) { 387 this.businessObjectService = boService; 388 } 389 390 public void setDocumentService(DocumentService documentService) { 391 this.documentService = documentService; 392 } 393 394 public void setPersistenceService(PersistenceService persistenceService) { 395 this.persistenceService = persistenceService; 396 } 397 398 public void setVendorDao(VendorDao vendorDao) { 399 this.vendorDao = vendorDao; 400 } 401 } 402