001/*
002 * Copyright 2006 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 */
016package org.kuali.ole.module.purap.document.service.impl;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.ole.integration.cab.CapitalAssetBuilderModuleService;
020import org.kuali.ole.integration.purap.CapitalAssetSystem;
021import org.kuali.ole.module.purap.PurapConstants;
022import org.kuali.ole.module.purap.PurapPropertyConstants;
023import org.kuali.ole.module.purap.PurapRuleConstants;
024import org.kuali.ole.module.purap.businessobject.*;
025import org.kuali.ole.module.purap.document.PurchaseOrderDocument;
026import org.kuali.ole.module.purap.document.PurchasingDocument;
027import org.kuali.ole.module.purap.document.RequisitionDocument;
028import org.kuali.ole.module.purap.document.dataaccess.RequisitionDao;
029import org.kuali.ole.module.purap.document.service.PurapService;
030import org.kuali.ole.module.purap.document.service.RequisitionService;
031import org.kuali.ole.select.businessobject.OlePurchaseOrderItem;
032import org.kuali.ole.select.businessobject.OleRequisitionItem;
033import org.kuali.ole.select.document.OleRequisitionDocument;
034import org.kuali.ole.sys.context.SpringContext;
035import org.kuali.ole.sys.service.PostalCodeValidationService;
036import org.kuali.ole.sys.service.UniversityDateService;
037import org.kuali.ole.vnd.businessobject.VendorCommodityCode;
038import org.kuali.ole.vnd.businessobject.VendorContract;
039import org.kuali.ole.vnd.businessobject.VendorDetail;
040import org.kuali.ole.vnd.document.service.VendorService;
041import org.kuali.rice.core.api.config.property.ConfigurationService;
042import org.kuali.rice.core.api.datetime.DateTimeService;
043import org.kuali.rice.core.api.util.type.KualiDecimal;
044import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator;
045import org.kuali.rice.coreservice.framework.parameter.ParameterService;
046import org.kuali.rice.kew.actiontaken.ActionTakenValue;
047import org.kuali.rice.kew.api.KewApiServiceLocator;
048import org.kuali.rice.kew.api.document.DocumentStatus;
049import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
050import org.kuali.rice.kew.api.document.search.DocumentSearchResult;
051import org.kuali.rice.kew.api.document.search.DocumentSearchResults;
052import org.kuali.rice.kew.api.exception.WorkflowException;
053import org.kuali.rice.kew.service.KEWServiceLocator;
054import org.kuali.rice.kim.api.identity.Person;
055import org.kuali.rice.kim.api.identity.PersonService;
056import org.kuali.rice.krad.bo.Note;
057import org.kuali.rice.krad.service.BusinessObjectService;
058import org.kuali.rice.krad.service.DocumentService;
059import org.kuali.rice.krad.service.KualiRuleService;
060import org.kuali.rice.krad.service.SequenceAccessorService;
061import org.kuali.rice.krad.util.ObjectUtils;
062import org.springframework.transaction.annotation.Transactional;
063
064import java.math.BigDecimal;
065import java.util.*;
066
067
068/**
069 * Implementation of RequisitionService
070 */
071@Transactional
072public class RequisitionServiceImpl implements RequisitionService {
073    private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RequisitionServiceImpl.class);
074
075    private BusinessObjectService businessObjectService;
076    private CapitalAssetBuilderModuleService capitalAssetBuilderModuleService;
077    private DateTimeService dateTimeService;
078    private DocumentService documentService;
079    private KualiRuleService ruleService;
080    private ConfigurationService kualiConfigurationService;
081    private ParameterService parameterService;
082    private PersonService personService;
083    private PostalCodeValidationService postalCodeValidationService;
084    private PurapService purapService;
085    private RequisitionDao requisitionDao;
086    private UniversityDateService universityDateService;
087    private VendorService vendorService;
088
089    @Override
090    public PurchasingCapitalAssetItem createCamsItem(PurchasingDocument purDoc, PurApItem purapItem) {
091        PurchasingCapitalAssetItem camsItem = new RequisitionCapitalAssetItem();
092        camsItem.setItemIdentifier(purapItem.getItemIdentifier());
093        // If the system type is INDIVIDUAL then for each of the capital asset items, we need a system attached to it.
094        if (purDoc.getCapitalAssetSystemTypeCode().equals(PurapConstants.CapitalAssetTabStrings.INDIVIDUAL_ASSETS)) {
095            CapitalAssetSystem resultSystem = new RequisitionCapitalAssetSystem();
096            camsItem.setPurchasingCapitalAssetSystem(resultSystem);
097        }
098        camsItem.setPurchasingDocument(purDoc);
099
100        return camsItem;
101    }
102
103    @Override
104    public CapitalAssetSystem createCapitalAssetSystem() {
105        CapitalAssetSystem resultSystem = new RequisitionCapitalAssetSystem();
106        return resultSystem;
107    }
108
109    /**
110     * @see org.kuali.ole.module.purap.document.service.RequisitionService#getRequisitionById(java.lang.Integer)
111     */
112    @Override
113    public RequisitionDocument getRequisitionById(Integer id) {
114        String documentNumber = requisitionDao.getDocumentNumberForRequisitionId(id);
115        if (ObjectUtils.isNotNull(documentNumber)) {
116            try {
117                RequisitionDocument doc = (RequisitionDocument) documentService.getByDocumentHeaderId(documentNumber);
118
119                return doc;
120            } catch (WorkflowException e) {
121                String errorMessage = "Error getting requisition document from document service";
122                LOG.error("getRequisitionById() " + errorMessage, e);
123                throw new RuntimeException(errorMessage, e);
124            }
125        }
126
127        return null;
128    }
129
130    private boolean isReqCreatedByPo(String routeHeaderId) {
131        List<ActionTakenValue> result = (List<ActionTakenValue>) KEWServiceLocator.getActionTakenService().getActionsTaken(routeHeaderId);
132        if (result != null && result.size() > 0) {
133            for (ActionTakenValue val : result) {
134                if (val.getAnnotation() != null &&
135                        val.getAnnotation().trim().equals("Automatic Approval From PO")) {
136                    return true;
137                }
138            }
139        }
140        return false;
141    }
142
143    /**
144     * @see org.kuali.ole.module.purap.document.service.RequisitionService#isAutomaticPurchaseOrderAllowed(org.kuali.ole.module.purap.document.RequisitionDocument)
145     */
146    @Override
147    public boolean isAutomaticPurchaseOrderAllowed(RequisitionDocument requisition) {
148        LOG.debug("isAutomaticPurchaseOrderAllowed() started");
149
150        /*
151         * The private checkAutomaticPurchaseOrderRules method contains rules to check if a requisition can become an APO (Automatic
152         * Purchase Order). The method returns a string containing the reason why this method should return false. Save the reason
153         * as a note on the requisition.
154         */
155        String note = checkAutomaticPurchaseOrderRules(requisition);
156        if (StringUtils.isNotEmpty(note)) {
157            note = PurapConstants.REQ_REASON_NOT_APO + note;
158            try {
159                Note apoNote = documentService.createNoteFromDocument(requisition, note);
160                requisition.addNote(apoNote);
161                documentService.saveDocumentNotes(requisition);
162            } catch (Exception e) {
163                throw new RuntimeException(PurapConstants.REQ_UNABLE_TO_CREATE_NOTE + " " + e);
164            }
165
166            if (LOG.isDebugEnabled()) {
167                LOG.debug("isAutomaticPurchaseOrderAllowed() return false; " + note);
168            }
169            return false;
170        }
171
172        LOG.debug("isAutomaticPurchaseOrderAllowed() You made it!  Your REQ can become an APO; return true.");
173        return true;
174    }
175
176    public Collection<String> getAPORules() {
177        return CoreFrameworkServiceLocator.getParameterService().getParameterValuesAsString(
178                PurchaseOrderDocument.class, "APORules");
179    }
180
181    /**
182     * Checks the rule for Automatic Purchase Order eligibility of the requisition and return a String containing the reason why the
183     * requisition was not eligible to become an APO if it was not eligible, or return an empty String if the requisition is
184     * eligible to become an APO
185     *
186     * @param requisition the requisition document to be checked for APO eligibility.
187     * @return String containing the reason why the requisition was not eligible to become an APO if it was not eligible, or an
188     *         empty String if the requisition is eligible to become an APO.
189     */
190    protected String checkAutomaticPurchaseOrderRules(RequisitionDocument requisition) {
191        Collection<String> APORules = getAPORules();
192        String requisitionSource = requisition.getRequisitionSourceCode();
193        KualiDecimal reqTotal = requisition.getTotalDollarAmount();
194        KualiDecimal apoLimit = purapService.getApoLimit(requisition.getVendorContractGeneratedIdentifier(), requisition.getChartOfAccountsCode(), requisition.getOrganizationCode());
195        requisition.setOrganizationAutomaticPurchaseOrderLimit(apoLimit);
196
197        if (LOG.isDebugEnabled()) {
198            LOG.debug("isAPO() reqId = " + requisition.getPurapDocumentIdentifier() + "; apoLimit = " + apoLimit + "; reqTotal = " + reqTotal);
199        }
200        if (apoLimit == null) {
201            return "APO limit is empty.";
202        } else {
203            if (APORules.contains(PurapConstants.APO_LIMIT)) {
204                if (reqTotal.compareTo(apoLimit) == 1) {
205                    return "Requisition total is greater than the APO limit.";
206                }
207            }
208        }
209       /* if (APORules.contains(PurapConstants.REQ_TOT)) {
210            if (reqTotal.compareTo(KualiDecimal.ZERO) <= 0) {
211                return "Requisition total is not greater than zero.";
212            }
213        }*/
214
215        if (this.isReqCreatedByPo(requisition.getDocumentNumber())) {
216            return "Requsiusion is created by PO";
217        }
218
219        LOG.debug("isAPO() vendor #" + requisition.getVendorHeaderGeneratedIdentifier() + "-" + requisition.getVendorDetailAssignedIdentifier());
220        if (APORules.contains(PurapConstants.VEN_NOT_SEL)) {
221            if (requisition.getVendorHeaderGeneratedIdentifier() == null || requisition.getVendorDetailAssignedIdentifier() == null) {
222                return "Vendor was not selected from the vendor database.";
223            }
224        } else {
225            VendorDetail vendorDetail = vendorService.getVendorDetail(requisition.getVendorHeaderGeneratedIdentifier(), requisition.getVendorDetailAssignedIdentifier());
226            if (APORules.contains(PurapConstants.ERR_RTV_VENDOR)) {
227                if (vendorDetail == null) {
228                    return "Error retrieving vendor from the database.";
229                }
230            }
231            if (StringUtils.isBlank(requisition.getVendorLine1Address()) ||
232                    StringUtils.isBlank(requisition.getVendorCityName()) ||
233                    StringUtils.isBlank(requisition.getVendorCountryCode())) {
234                return "Requisition does not have all of the vendor address fields that are required for Purchase Order.";
235            }
236            requisition.setVendorRestrictedIndicator(vendorDetail.getVendorRestrictedIndicator());
237            if (APORules.contains(PurapConstants.VENDOR_RESTRICTED)) {
238                if (requisition.getVendorRestrictedIndicator() != null && requisition.getVendorRestrictedIndicator()) {
239                    return "Selected vendor is marked as restricted.";
240                }
241                if (vendorDetail.isVendorDebarred()) {
242                    return "Selected vendor is marked as a debarred vendor";
243                }
244                requisition.setVendorDetail(vendorDetail);
245
246                if ((!PurapConstants.RequisitionSources.B2B.equals(requisitionSource)) && ObjectUtils.isNull(requisition.getVendorContractGeneratedIdentifier())) {
247                    Person initiator = getPersonService().getPerson(requisition.getDocumentHeader().getWorkflowDocument().getInitiatorPrincipalId());
248                    VendorContract b2bContract = vendorService.getVendorB2BContract(vendorDetail, initiator.getCampusCode());
249                    if (APORules.contains(PurapConstants.REQ_WITH_NO_CONTRACT)) {
250                        if (b2bContract != null) {
251                            return "Standard requisition with no contract selected but a B2B contract exists for the selected vendor.";
252                        }
253                    }
254                }
255            }
256
257            //if vendor address isn't complete, no APO
258            if (StringUtils.isBlank(requisition.getVendorLine1Address()) ||
259                    StringUtils.isBlank(requisition.getVendorCityName()) ||
260                    StringUtils.isBlank(requisition.getVendorCountryCode()) ||
261                    !postalCodeValidationService.validateAddress(requisition.getVendorCountryCode(), requisition.getVendorStateCode(), requisition.getVendorPostalCode(), "", "")) {
262                return "Requistion does not contain a complete vendor address";
263            }
264
265            // These are needed for commodity codes. They are put in here so that
266            // we don't have to loop through items too many times.
267            String purchaseOrderRequiresCommodityCode = parameterService.getParameterValueAsString(PurchaseOrderDocument.class, PurapRuleConstants.ITEMS_REQUIRE_COMMODITY_CODE_IND);
268            boolean commodityCodeRequired = purchaseOrderRequiresCommodityCode.equals("Y");
269
270            for (Iterator iter = requisition.getItems().iterator(); iter.hasNext(); ) {
271                RequisitionItem item = (RequisitionItem) iter.next();
272                if (APORules.contains(PurapConstants.ITM_RESTRICTED)) {
273                    if (item.isItemRestrictedIndicator()) {
274                        return "Requisition contains an item that is marked as restricted.";
275                    }
276                }
277
278                //We only need to check the commodity codes if this is an above the line item.
279                if (item.getItemType().isLineItemIndicator()) {
280                    String commodityCodesReason = "";
281                    List<VendorCommodityCode> vendorCommodityCodes = commodityCodeRequired ? requisition.getVendorDetail().getVendorCommodities() : null;
282                    commodityCodesReason = checkAPORulesPerItemForCommodityCodes(item, vendorCommodityCodes, commodityCodeRequired);
283                    if (StringUtils.isNotBlank(commodityCodesReason)) {
284                        return commodityCodesReason;
285                    }
286                }
287
288                if (PurapConstants.ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE.equals(item.getItemType().getItemTypeCode())
289                        || PurapConstants.ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE.equals(item.getItemType().getItemTypeCode())) {
290                    if (APORules.contains(PurapConstants.REQ_CON_TRADEIN)) {
291                        if ((item.getItemUnitPrice() != null) && ((BigDecimal.ZERO.compareTo(item.getItemUnitPrice())) != 0)) {
292                            // discount or trade-in item has unit price that is not empty or zero
293                            return "Requisition contains a " + item.getItemType().getItemTypeDescription() + " item, so it does not qualify as an APO.";
294                        }
295                    }
296                }
297                if (APORules.contains(PurapConstants.REQ_CON_ACC_LINE)) {
298                    if (!PurapConstants.RequisitionSources.B2B.equals(requisitionSource)) {
299                        for (PurApAccountingLine accountingLine : item.getSourceAccountingLines()) {
300                            if (capitalAssetBuilderModuleService.doesAccountingLineFailAutomaticPurchaseOrderRules(accountingLine)) {
301                                return "Requisition contains accounting line with capital object level";
302                            }
303                        }
304                    }
305                }
306            }
307
308        }// endfor items
309        if (APORules.contains(PurapConstants.RECUR_REQ_TYPE)) {
310            if (capitalAssetBuilderModuleService.doesDocumentFailAutomaticPurchaseOrderRules(requisition)) {
311                return "Requisition contains capital asset items.";
312            }
313        }
314        if (APORules.contains(PurapConstants.RECUR_PAY_TYPE)) {
315            if (StringUtils.isNotEmpty(requisition.getRecurringPaymentTypeCode())) {
316                return "Payment type is marked as recurring.";
317            }
318        }
319        if (APORules.contains(PurapConstants.PO_TOT_NOT_EXCEED)) {
320            if ((requisition.getPurchaseOrderTotalLimit() != null) && (KualiDecimal.ZERO.compareTo(requisition.getPurchaseOrderTotalLimit()) != 0)) {
321                LOG.debug("isAPO() po total limit is not null and not equal to zero; return false.");
322                return "The 'PO not to exceed' amount has been entered.";
323            }
324        }
325        if (APORules.contains(new String("ALT_VEN_NAM"))) {
326            if (StringUtils.isNotEmpty(requisition.getAlternate1VendorName()) || StringUtils.isNotEmpty(requisition.getAlternate2VendorName()) || StringUtils.isNotEmpty(requisition.getAlternate3VendorName()) || StringUtils.isNotEmpty(requisition.getAlternate4VendorName()) || StringUtils.isNotEmpty(requisition.getAlternate5VendorName())) {
327                LOG.debug("isAPO() alternate vendor name exists; return false.");
328                return "Requisition contains additional suggested vendor names.";
329            }
330        }
331        if (APORules.contains(PurapConstants.ALT_VEN_NAME_EXISTS)) {
332            if (requisition.isPostingYearNext() && !purapService.isTodayWithinApoAllowedRange()) {
333                return "Requisition is set to encumber next fiscal year and approval is not within APO allowed date range.";
334            }
335        }
336
337        return "";
338    }
339
340    /**
341     * Checks the APO rules for Commodity Codes.
342     * The rules are as follow:
343     * 1. If an institution does not require a commodity code on a requisition but
344     * does require a commodity code on a purchase order:
345     * a. If the requisition qualifies for an APO and the commodity code is blank
346     * on any line item then the system should use the default commodity code
347     * for the vendor.
348     * b. If there is not a default commodity code for the vendor then the
349     * requisition is not eligible to become an APO.
350     * 2. The commodity codes where the restricted indicator is Y should disallow
351     * the requisition from becoming an APO.
352     * 3. If the commodity code is Inactive when the requisition is finally approved
353     * do not allow the requisition to become an APO.
354     *
355     * @param purItem
356     * @param vendorCommodityCodes
357     * @param commodityCodeRequired
358     * @return
359     */
360    protected String checkAPORulesPerItemForCommodityCodes(RequisitionItem purItem, List<VendorCommodityCode> vendorCommodityCodes, boolean commodityCodeRequired) {
361        // If the commodity code is blank on any line item and a commodity code is required,
362        // then the system should use the default commodity code for the vendor
363        if (purItem.getCommodityCode() == null && commodityCodeRequired) {
364            for (VendorCommodityCode vcc : vendorCommodityCodes) {
365                if (vcc.isCommodityDefaultIndicator()) {
366                    purItem.setCommodityCode(vcc.getCommodityCode());
367                    purItem.setPurchasingCommodityCode(vcc.getPurchasingCommodityCode());
368                }
369            }
370        }
371        if (purItem.getCommodityCode() == null) {
372            // If there is not a default commodity code for the vendor then the requisition is not eligible to become an APO.
373            if (commodityCodeRequired) {
374                return "There are missing commodity code(s).";
375            }
376        } else if (!purItem.getCommodityCode().isActive()) {
377            return "Requisition contains inactive commodity codes.";
378        } else if (purItem.getCommodityCode().isRestrictedItemsIndicator()) {
379            return "Requisition contains an item with a restricted commodity code.";
380        }
381        return "";
382    }
383
384    /**
385     * @see org.kuali.ole.module.purap.document.service.RequisitionService#getRequisitionsAwaitingContractManagerAssignment()
386     */
387    @Override
388    public List<RequisitionDocument> getRequisitionsAwaitingContractManagerAssignment() {
389        List<RequisitionDocument> unassignedRequisitions = new ArrayList<RequisitionDocument>();
390        List<RequisitionDocument> requisitions = new ArrayList<RequisitionDocument>();
391
392        List<String> documentsNumbersAwaitingContractManagerAssignment = getDocumentsNumbersAwaitingContractManagerAssignment();
393
394        for (String documentNumber : documentsNumbersAwaitingContractManagerAssignment) {
395            Map fieldValues = new HashMap();
396            fieldValues.put(PurapPropertyConstants.DOCUMENT_NUMBER, documentNumber);
397
398            requisitions = (List<RequisitionDocument>) businessObjectService.findMatching(RequisitionDocument.class, fieldValues);
399
400            for (RequisitionDocument req : requisitions) {
401                unassignedRequisitions.add(req);
402            }
403        }
404
405        return unassignedRequisitions;
406    }
407
408    /**
409     * Gets a list of strings of document numbers from workflow documents where
410     * document status = 'P', 'F'  and document type = 'REQS'.  If appDocStatus status
411     * of 'Awaiting Contract Manager Assignment' then the document number is added to the list
412     * <p/>
413     * NOTE: simplify using DocSearch lookup with AppDocStatus
414     *
415     * @return list of documentNumbers to retrieve requisitions.
416     */
417    protected List<String> getDocumentsNumbersAwaitingContractManagerAssignment() {
418        List<String> requisitionDocumentNumbers = new ArrayList<String>();
419
420        DocumentSearchCriteria.Builder documentSearchCriteriaDTO = DocumentSearchCriteria.Builder.create();
421        //Search for status of P and F and "Awaiting Contract Manager Assignment" application document status
422        documentSearchCriteriaDTO.setDocumentStatuses(Arrays.asList(DocumentStatus.PROCESSED, DocumentStatus.FINAL));
423        documentSearchCriteriaDTO.setDocumentTypeName(PurapConstants.REQUISITION_DOCUMENT_TYPE);
424        documentSearchCriteriaDTO.setApplicationDocumentStatus(PurapConstants.RequisitionStatuses.APPDOC_AWAIT_CONTRACT_MANAGER_ASSGN);
425        documentSearchCriteriaDTO.setSaveName(null);
426
427        DocumentSearchResults results = KewApiServiceLocator.getWorkflowDocumentService().documentSearch(null, documentSearchCriteriaDTO.build());
428
429        String documentHeaderId = null;
430
431        for (DocumentSearchResult result : results.getSearchResults()) {
432            requisitionDocumentNumbers.add(result.getDocument().getDocumentId());
433        }
434
435        return requisitionDocumentNumbers;
436    }
437
438    /**
439     * @see org.kuali.ole.module.purap.document.service.RequisitionService#getCountOfRequisitionsAwaitingContractManagerAssignment()
440     */
441    @Override
442    public int getCountOfRequisitionsAwaitingContractManagerAssignment() {
443        List<RequisitionDocument> unassignedRequisitions = getRequisitionsAwaitingContractManagerAssignment();
444        if (ObjectUtils.isNotNull(unassignedRequisitions)) {
445            return unassignedRequisitions.size();
446        } else {
447            return 0;
448        }
449    }
450
451    /**
452     * Create Purchase Order and populate with data from Purchase Order and other default data
453     *
454     * @param reqDocument The requisition document from which we create the purchase order document.
455     * @return The purchase order document created by this method.
456     * @throws WorkflowException
457     */
458    @Override
459    public OleRequisitionDocument generateRequisitionFromPurchaseOrder(PurchaseOrderDocument purDocument) throws WorkflowException {
460
461        OleRequisitionDocument rdoc = null;
462        rdoc = (OleRequisitionDocument) documentService.getNewDocument("OLE_REQS");
463        rdoc = populateRequisitionFromPurchaseOrder(rdoc, purDocument);
464
465//        rdoc.setStatusCode(PurchaseOrderStatuses.IN_PROCESS);
466        if (ObjectUtils.isNotNull(purDocument.getVendorContract())) {
467            rdoc.setVendorPaymentTermsCode(purDocument.getVendorContract().getVendorPaymentTermsCode());
468            rdoc.setVendorShippingPaymentTermsCode(purDocument.getVendorContract().getVendorShippingPaymentTermsCode());
469            rdoc.setVendorShippingTitleCode(purDocument.getVendorContract().getVendorShippingTitleCode());
470        } else {
471            VendorDetail vendor = vendorService.getVendorDetail(purDocument.getVendorHeaderGeneratedIdentifier(), purDocument.getVendorDetailAssignedIdentifier());
472            if (ObjectUtils.isNotNull(vendor)) {
473                rdoc.setVendorPaymentTermsCode(vendor.getVendorPaymentTermsCode());
474                rdoc.setVendorShippingPaymentTermsCode(vendor.getVendorShippingPaymentTermsCode());
475                rdoc.setVendorShippingTitleCode(vendor.getVendorShippingTitleCode());
476            }
477        }
478
479        if (!PurapConstants.RequisitionSources.B2B.equals(purDocument.getRequisitionSourceCode())) {
480            purapService.addBelowLineItems(rdoc);
481        }
482        // rdoc.fixItemReferences();
483
484        return rdoc;
485    }
486
487
488    public OleRequisitionDocument populateRequisitionFromPurchaseOrder(OleRequisitionDocument requisitionDocument, PurchaseOrderDocument pdoc) {
489
490        requisitionDocument.getDocumentHeader().setOrganizationDocumentNumber(pdoc.getDocumentHeader().getOrganizationDocumentNumber());
491        requisitionDocument.getDocumentHeader().setDocumentDescription(pdoc.getDocumentHeader().getDocumentDescription());
492        requisitionDocument.getDocumentHeader().setExplanation(pdoc.getDocumentHeader().getExplanation());
493
494        requisitionDocument.setBillingName(pdoc.getBillingName());
495        requisitionDocument.setBillingLine1Address(pdoc.getBillingLine1Address());
496        requisitionDocument.setBillingLine2Address(pdoc.getBillingLine2Address());
497        requisitionDocument.setBillingCityName(pdoc.getBillingCityName());
498        requisitionDocument.setBillingStateCode(pdoc.getBillingStateCode());
499        requisitionDocument.setBillingPostalCode(pdoc.getBillingPostalCode());
500        requisitionDocument.setBillingCountryCode(pdoc.getBillingCountryCode());
501        requisitionDocument.setBillingPhoneNumber(pdoc.getBillingPhoneNumber());
502
503        requisitionDocument.setReceivingName(pdoc.getReceivingName());
504        requisitionDocument.setReceivingCityName(pdoc.getReceivingCityName());
505        requisitionDocument.setReceivingLine1Address(pdoc.getReceivingLine1Address());
506        requisitionDocument.setReceivingLine2Address(pdoc.getReceivingLine2Address());
507        requisitionDocument.setReceivingStateCode(pdoc.getReceivingStateCode());
508        requisitionDocument.setReceivingPostalCode(pdoc.getReceivingPostalCode());
509        requisitionDocument.setReceivingCountryCode(pdoc.getReceivingCountryCode());
510        requisitionDocument.setAddressToVendorIndicator(pdoc.getAddressToVendorIndicator());
511
512        requisitionDocument.setDeliveryBuildingCode(pdoc.getDeliveryBuildingCode());
513        requisitionDocument.setDeliveryBuildingRoomNumber(pdoc.getDeliveryBuildingRoomNumber());
514        requisitionDocument.setDeliveryBuildingName(pdoc.getDeliveryBuildingName());
515        requisitionDocument.setDeliveryCampusCode(pdoc.getDeliveryCampusCode());
516        requisitionDocument.setDeliveryCityName(pdoc.getDeliveryCityName());
517        requisitionDocument.setDeliveryCountryCode(pdoc.getDeliveryCountryCode());
518        requisitionDocument.setDeliveryInstructionText(pdoc.getDeliveryInstructionText());
519        requisitionDocument.setDeliveryBuildingLine1Address(pdoc.getDeliveryBuildingLine1Address());
520        requisitionDocument.setDeliveryBuildingLine2Address(pdoc.getDeliveryBuildingLine2Address());
521        requisitionDocument.setDeliveryPostalCode(pdoc.getDeliveryPostalCode());
522        requisitionDocument.setDeliveryRequiredDate(pdoc.getDeliveryRequiredDate());
523        requisitionDocument.setDeliveryRequiredDateReasonCode(pdoc.getDeliveryRequiredDateReasonCode());
524        requisitionDocument.setDeliveryStateCode(pdoc.getDeliveryStateCode());
525        requisitionDocument.setDeliveryToEmailAddress(pdoc.getDeliveryToEmailAddress());
526        requisitionDocument.setDeliveryToName(pdoc.getDeliveryToName());
527        requisitionDocument.setDeliveryToPhoneNumber(pdoc.getDeliveryToPhoneNumber());
528        requisitionDocument.setDeliveryBuildingOtherIndicator(pdoc.isDeliveryBuildingOtherIndicator());
529
530        requisitionDocument.setPurchaseOrderBeginDate(pdoc.getPurchaseOrderBeginDate());
531        requisitionDocument.setPurchaseOrderCostSourceCode(pdoc.getPurchaseOrderCostSourceCode());
532        requisitionDocument.setPostingYear(pdoc.getPostingYear());
533        requisitionDocument.setPurchaseOrderEndDate(pdoc.getPurchaseOrderEndDate());
534        requisitionDocument.setChartOfAccountsCode(pdoc.getChartOfAccountsCode());
535        requisitionDocument.setDocumentFundingSourceCode(pdoc.getDocumentFundingSourceCode());
536        requisitionDocument.setInstitutionContactEmailAddress(pdoc.getInstitutionContactEmailAddress());
537        requisitionDocument.setInstitutionContactName(pdoc.getInstitutionContactName());
538        requisitionDocument.setInstitutionContactPhoneNumber(pdoc.getInstitutionContactPhoneNumber());
539        requisitionDocument.setNonInstitutionFundAccountNumber(pdoc.getNonInstitutionFundAccountNumber());
540        requisitionDocument.setNonInstitutionFundChartOfAccountsCode(pdoc.getNonInstitutionFundChartOfAccountsCode());
541        requisitionDocument.setNonInstitutionFundOrgChartOfAccountsCode(pdoc.getNonInstitutionFundOrgChartOfAccountsCode());
542        requisitionDocument.setNonInstitutionFundOrganizationCode(pdoc.getNonInstitutionFundOrganizationCode());
543        requisitionDocument.setOrganizationCode(pdoc.getOrganizationCode());
544        requisitionDocument.setRecurringPaymentTypeCode(pdoc.getRecurringPaymentTypeCode());
545        requisitionDocument.setRequestorPersonEmailAddress(pdoc.getRequestorPersonEmailAddress());
546        requisitionDocument.setRequestorPersonName(pdoc.getRequestorPersonName());
547        requisitionDocument.setRequestorPersonPhoneNumber(pdoc.getRequestorPersonPhoneNumber());
548//        requisitionDocument.setPurapDocumentIdentifier(pdoc.getRequisitionIdentifier());
549        requisitionDocument.setPurchaseOrderTotalLimit(pdoc.getPurchaseOrderTotalLimit());
550        requisitionDocument.setPurchaseOrderTransmissionMethodCode(pdoc.getPurchaseOrderTransmissionMethodCode());
551        requisitionDocument.setUseTaxIndicator(pdoc.isUseTaxIndicator());
552        requisitionDocument.setPurchaseOrderTypeId(pdoc.getPurchaseOrderTypeId());
553        /*requisitionDocument.setLicensingRequirementIndicator(pdoc.isLicensingRequirementIndicator());*/
554        /*requisitionDocument.setLicensingRequirementCode(pdoc.getLicensingRequirementCode());*/
555        requisitionDocument.setVendorCityName(pdoc.getVendorCityName());
556        requisitionDocument.setVendorContractGeneratedIdentifier(pdoc.getVendorContractGeneratedIdentifier());
557        requisitionDocument.setVendorCountryCode(pdoc.getVendorCountryCode());
558        requisitionDocument.setVendorCustomerNumber(pdoc.getVendorCustomerNumber());
559        requisitionDocument.setVendorAttentionName(pdoc.getVendorAttentionName());
560        requisitionDocument.setVendorDetailAssignedIdentifier(pdoc.getVendorDetailAssignedIdentifier());
561        requisitionDocument.setVendorFaxNumber(pdoc.getVendorFaxNumber());
562        requisitionDocument.setVendorHeaderGeneratedIdentifier(pdoc.getVendorHeaderGeneratedIdentifier());
563        requisitionDocument.setVendorLine1Address(pdoc.getVendorLine1Address());
564        requisitionDocument.setVendorLine2Address(pdoc.getVendorLine2Address());
565        requisitionDocument.setVendorAddressInternationalProvinceName(pdoc.getVendorAddressInternationalProvinceName());
566        requisitionDocument.setVendorName(pdoc.getVendorName());
567        requisitionDocument.setVendorNoteText(pdoc.getVendorNoteText());
568        requisitionDocument.setVendorPhoneNumber(pdoc.getVendorPhoneNumber());
569        requisitionDocument.setVendorPostalCode(pdoc.getVendorPostalCode());
570        requisitionDocument.setVendorStateCode(pdoc.getVendorStateCode());
571        requisitionDocument.setVendorRestrictedIndicator(pdoc.getVendorRestrictedIndicator());
572
573        requisitionDocument.setExternalOrganizationB2bSupplierIdentifier(pdoc.getExternalOrganizationB2bSupplierIdentifier());
574        requisitionDocument.setRequisitionSourceCode(pdoc.getRequisitionSourceCode());
575        requisitionDocument.setAccountsPayablePurchasingDocumentLinkIdentifier(pdoc.getAccountsPayablePurchasingDocumentLinkIdentifier());
576        requisitionDocument.setReceivingDocumentRequiredIndicator(pdoc.isReceivingDocumentRequiredIndicator());
577        requisitionDocument.setPaymentRequestPositiveApprovalIndicator(pdoc.isPaymentRequestPositiveApprovalIndicator());
578        /*requisitionDocument.setLicensingRequirementIndicator(pdoc.isLicensingRequirementIndicator());*/
579        /*requisitionDocument.setLicensingRequirementCode(pdoc.getLicensingRequirementCode());*/
580
581//        requisitionDocument.setStatusCode(PurapConstants.PurchaseOrderStatuses.IN_PROCESS);
582
583        // Copy items from requisition (which will copy the item's accounts and capital assets)
584        List<OleRequisitionItem> items = new ArrayList();
585        for (OlePurchaseOrderItem reqItem : (List<OlePurchaseOrderItem>) pdoc.getItems()) {
586            PurchasingCapitalAssetItem reqCamsItem = null;
587            OleRequisitionItem ritem = getRequisitionItem(reqItem, requisitionDocument, reqCamsItem);
588
589            reqCamsItem = pdoc.
590                    getPurchasingCapitalAssetItemByItemIdentifier(reqItem.getItemIdentifier().intValue());
591            ritem = populateCapitalAssetItem(ritem, requisitionDocument, reqCamsItem);
592            items.add(ritem);
593        }
594        requisitionDocument.setItems(items);
595
596        // Copy capital asset information that is directly off the document.
597        requisitionDocument.setCapitalAssetSystemTypeCode(pdoc.getCapitalAssetSystemTypeCode());
598        requisitionDocument.setCapitalAssetSystemStateCode(pdoc.getCapitalAssetSystemStateCode());
599        requisitionDocument.setStatusCode(PurapConstants.RequisitionStatuses.APPDOC_CLOSED);
600
601
602        for (CapitalAssetSystem capitalAssetSystem : pdoc.getPurchasingCapitalAssetSystems()) {
603            RequisitionCapitalAssetSystem item = new RequisitionCapitalAssetSystem(capitalAssetSystem);
604            item.setPurapDocumentIdentifier(requisitionDocument.getPurapDocumentIdentifier());
605            requisitionDocument.getPurchasingCapitalAssetSystems().add(new RequisitionCapitalAssetSystem(capitalAssetSystem));
606        }
607
608//        requisitionDocument.fixItemReferences();
609        return requisitionDocument;
610    }
611
612    private OleRequisitionItem getRequisitionItem(OlePurchaseOrderItem pitem, RequisitionDocument requisitionDocument, PurchasingCapitalAssetItem reqCamsItem) {
613        OleRequisitionItem ritem = new OleRequisitionItem();
614        ritem.setRequisition(requisitionDocument);
615        SequenceAccessorService sas = SpringContext.getBean(SequenceAccessorService.class);
616        Integer itemIdentifier = sas.getNextAvailableSequenceNumber("REQS_ITM_ID", RequisitionDocument.class).intValue();
617        ritem.setItemIdentifier(itemIdentifier);
618        ritem.setItemLineNumber(pitem.getItemLineNumber());
619        ritem.setItemUnitOfMeasureCode(pitem.getItemUnitOfMeasureCode());
620        ritem.setItemQuantity(pitem.getItemQuantity());
621        ritem.setItemCatalogNumber(pitem.getItemCatalogNumber());
622        ritem.setItemDescription(pitem.getItemDescription());
623        ritem.setItemUnitPrice(pitem.getItemUnitPrice());
624        ritem.setItemAuxiliaryPartIdentifier(pitem.getItemAuxiliaryPartIdentifier());
625        ritem.setItemAssignedToTradeInIndicator(pitem.getItemAssignedToTradeInIndicator());
626        ritem.setItemTaxAmount(pitem.getItemTaxAmount());
627        ritem.setItemTitleId(pitem.getItemTitleId());
628
629        for (PurApItemUseTax useTaxItem : pitem.getUseTaxItems()) {
630            useTaxItem.setItemIdentifier(itemIdentifier);
631            ritem.getUseTaxItems().add(useTaxItem);
632        }
633
634        ritem.setExternalOrganizationB2bProductReferenceNumber(pitem.getExternalOrganizationB2bProductReferenceNumber());
635        ritem.setExternalOrganizationB2bProductTypeName(pitem.getExternalOrganizationB2bProductTypeName());
636        ritem.setItemTypeCode(pitem.getItemTypeCode());
637
638        if (pitem.getSourceAccountingLines() != null && pitem.getSourceAccountingLines().size() > 0 &&
639                !StringUtils.equals(PurapConstants.ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE, pitem.getItemType().getItemTypeCode())) {
640            List accounts = new ArrayList();
641            for (PurApAccountingLine account : pitem.getSourceAccountingLines()) {
642                PurApAccountingLineBase poAccount = (PurApAccountingLineBase) account;
643                RequisitionAccount acc = convertAccount(poAccount, ritem);
644                accounts.add(acc);
645            }
646            ritem.setSourceAccountingLines(accounts);
647        }
648        ritem.setPurchasingCommodityCode(pitem.getPurchasingCommodityCode());
649        ritem.setCommodityCode(pitem.getCommodityCode());
650
651        if (ObjectUtils.isNotNull(reqCamsItem)) {
652            RequisitionCapitalAssetItem item = new RequisitionCapitalAssetItem(reqCamsItem, ritem.getItemIdentifier());
653            requisitionDocument.getPurchasingCapitalAssetItems().add(item);
654        }
655        return ritem;
656    }
657
658    private OleRequisitionItem populateCapitalAssetItem(OleRequisitionItem ritem, RequisitionDocument requisitionDocument, PurchasingCapitalAssetItem reqCamsItem) {
659        if (ObjectUtils.isNotNull(reqCamsItem)) {
660            RequisitionCapitalAssetItem item = new RequisitionCapitalAssetItem(reqCamsItem, ritem.getItemIdentifier());
661            requisitionDocument.getPurchasingCapitalAssetItems().add(item);
662        }
663        return ritem;
664    }
665
666    private RequisitionAccount convertAccount(PurApAccountingLine account, RequisitionItem requisitionItem) {
667        RequisitionAccount result = new RequisitionAccount();
668        result.setAccountLinePercent(account.getAccountLinePercent());
669        result.setAccountNumber(account.getAccountNumber());
670        result.setChartOfAccountsCode(account.getChartOfAccountsCode());
671        result.setFinancialObjectCode(account.getFinancialObjectCode());
672        result.setFinancialSubObjectCode(account.getFinancialSubObjectCode());
673        result.setOrganizationReferenceId(account.getOrganizationReferenceId());
674        result.setProjectCode(account.getProjectCode());
675        result.setSubAccountNumber(account.getSubAccountNumber());
676        result.setRequisitionItem(requisitionItem);
677        return result;
678    }
679
680    private RequisitionCapitalAssetItem convert(PurchaseOrderCapitalAssetItem pitem) {
681        RequisitionCapitalAssetItem result = new RequisitionCapitalAssetItem();
682        result.setCapitalAssetItemIdentifier(pitem.getCapitalAssetItemIdentifier());
683        result.setCapitalAssetSystemIdentifier(pitem.getCapitalAssetSystemIdentifier());
684        result.setCapitalAssetTransactionTypeCode(pitem.getCapitalAssetTransactionTypeCode());
685        result.setItemIdentifier(pitem.getItemIdentifier());
686        result.setPurapDocumentIdentifier(pitem.getPurchasingDocument().getPurapDocumentIdentifier());
687        return result;
688    }
689
690
691    public void setBusinessObjectService(BusinessObjectService boService) {
692        this.businessObjectService = boService;
693    }
694
695    public void setDocumentService(DocumentService documentService) {
696        this.documentService = documentService;
697    }
698
699    public void setRequisitionDao(RequisitionDao requisitionDao) {
700        this.requisitionDao = requisitionDao;
701    }
702
703    public void setPurapService(PurapService purapService) {
704        this.purapService = purapService;
705    }
706
707    public KualiRuleService getRuleService() {
708        return ruleService;
709    }
710
711    public void setRuleService(KualiRuleService ruleService) {
712        this.ruleService = ruleService;
713    }
714
715    public void setParameterService(ParameterService parameterService) {
716        this.parameterService = parameterService;
717    }
718
719    public void setDateTimeService(DateTimeService dateTimeService) {
720        this.dateTimeService = dateTimeService;
721    }
722
723    public void setUniversityDateService(UniversityDateService universityDateService) {
724        this.universityDateService = universityDateService;
725    }
726
727    public void setVendorService(VendorService vendorService) {
728        this.vendorService = vendorService;
729    }
730
731    public void setConfigurationService(ConfigurationService kualiConfigurationService) {
732        this.kualiConfigurationService = kualiConfigurationService;
733    }
734
735    public void setCapitalAssetBuilderModuleService(CapitalAssetBuilderModuleService capitalAssetBuilderModuleService) {
736        this.capitalAssetBuilderModuleService = capitalAssetBuilderModuleService;
737    }
738
739    public void setPostalCodeValidationService(PostalCodeValidationService postalCodeValidationService) {
740        this.postalCodeValidationService = postalCodeValidationService;
741    }
742
743    /**
744     * @return Returns the personService.
745     */
746    protected PersonService getPersonService() {
747        if (personService == null) {
748            personService = SpringContext.getBean(PersonService.class);
749        }
750        return personService;
751    }
752
753}