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