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