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.module.purap.document;
017    
018    import java.util.LinkedHashMap;
019    import java.util.List;
020    
021    import org.apache.commons.lang.StringUtils;
022    import org.kuali.kfs.module.purap.PurapConstants;
023    import org.kuali.kfs.module.purap.PurapWorkflowConstants;
024    import org.kuali.kfs.module.purap.businessobject.LineItemReceivingItem;
025    import org.kuali.kfs.module.purap.businessobject.PurchaseOrderItem;
026    import org.kuali.kfs.module.purap.document.service.PurapService;
027    import org.kuali.kfs.module.purap.document.service.PurchaseOrderService;
028    import org.kuali.kfs.module.purap.document.service.ReceivingService;
029    import org.kuali.kfs.module.purap.document.validation.event.AttributedContinuePurapEvent;
030    import org.kuali.kfs.sys.context.SpringContext;
031    import org.kuali.rice.kew.dto.DocumentRouteLevelChangeDTO;
032    import org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO;
033    import org.kuali.rice.kns.bo.DocumentHeader;
034    import org.kuali.rice.kns.rule.event.KualiDocumentEvent;
035    import org.kuali.rice.kns.service.DataDictionaryService;
036    import org.kuali.rice.kns.util.KNSPropertyConstants;
037    import org.kuali.rice.kns.util.KualiDecimal;
038    import org.kuali.rice.kns.util.TypedArrayList;
039    
040    /**
041     * @author Kuali Nervous System Team (kualidev@oncourse.iu.edu)
042     */
043    public class LineItemReceivingDocument extends ReceivingDocumentBase {
044    
045        //Collections
046        protected List<LineItemReceivingItem> items;
047    
048        /**
049         * Default constructor.
050         */
051        public LineItemReceivingDocument() {
052            super();
053            items = new TypedArrayList(getItemClass());
054        }
055    
056        @Override
057        public void initiateDocument(){
058            super.initiateDocument();
059            this.setLineItemReceivingStatusCode(PurapConstants.LineItemReceivingStatuses.IN_PROCESS);
060        }
061        
062        public void populateReceivingLineFromPurchaseOrder(PurchaseOrderDocument po){
063            
064            //populate receiving line document from purchase order
065            this.setPurchaseOrderIdentifier( po.getPurapDocumentIdentifier() );
066            this.getDocumentHeader().setOrganizationDocumentNumber( po.getDocumentHeader().getOrganizationDocumentNumber() );
067            this.setAccountsPayablePurchasingDocumentLinkIdentifier( po.getAccountsPayablePurchasingDocumentLinkIdentifier() );
068            
069            //copy vendor
070            this.setVendorHeaderGeneratedIdentifier( po.getVendorHeaderGeneratedIdentifier() );
071            this.setVendorDetailAssignedIdentifier( po.getVendorDetailAssignedIdentifier() );        
072            this.setVendorName( po.getVendorName() );
073            this.setVendorNumber( po.getVendorNumber() );
074            this.setVendorAddressGeneratedIdentifier( po.getVendorAddressGeneratedIdentifier() );
075            this.setVendorLine1Address( po.getVendorLine1Address() );
076            this.setVendorLine2Address( po.getVendorLine2Address() );
077            this.setVendorCityName( po.getVendorCityName() );
078            this.setVendorStateCode( po.getVendorStateCode() );
079            this.setVendorPostalCode( po.getVendorPostalCode() );
080            this.setVendorCountryCode( po.getVendorCountryCode() );
081            
082            //copy alternate vendor
083            this.setAlternateVendorName( po.getAlternateVendorName() );
084            this.setAlternateVendorNumber( po.getAlternateVendorNumber() );
085            this.setAlternateVendorDetailAssignedIdentifier( po.getAlternateVendorDetailAssignedIdentifier() );
086            this.setAlternateVendorHeaderGeneratedIdentifier( po.getAlternateVendorHeaderGeneratedIdentifier() );
087            
088            //copy delivery
089            this.setDeliveryBuildingCode( po.getDeliveryBuildingCode() );
090            this.setDeliveryBuildingLine1Address( po.getDeliveryBuildingLine1Address() );
091            this.setDeliveryBuildingLine2Address( po.getDeliveryBuildingLine2Address() );
092            this.setDeliveryBuildingName( po.getDeliveryBuildingName() );        
093            this.setDeliveryBuildingRoomNumber( po.getDeliveryBuildingRoomNumber() );
094            this.setDeliveryCampusCode( po.getDeliveryCampusCode() );
095            this.setDeliveryCityName( po.getDeliveryCityName() );
096            this.setDeliveryCountryCode( po.getDeliveryCountryCode() );
097            this.setDeliveryInstructionText( po.getDeliveryInstructionText() );
098            this.setDeliveryPostalCode( po.getDeliveryPostalCode() );
099            this.setDeliveryRequiredDate( po.getDeliveryRequiredDate() );
100            this.setDeliveryRequiredDateReasonCode( po.getDeliveryRequiredDateReasonCode() );
101            this.setDeliveryStateCode( po.getDeliveryStateCode() );
102            this.setDeliveryToEmailAddress( po.getDeliveryToEmailAddress() );
103            this.setDeliveryToName( po.getDeliveryToName() );
104            this.setDeliveryToPhoneNumber( po.getDeliveryToPhoneNumber() );
105                    
106            //copy purchase order items
107            for (PurchaseOrderItem poi : (List<PurchaseOrderItem>) po.getItems()) {
108                //TODO: Refactor this check into a service call. route FYI during submit
109                if(poi.isItemActiveIndicator() && 
110                   poi.getItemType().isQuantityBasedGeneralLedgerIndicator() && 
111                   poi.getItemType().isLineItemIndicator() ){
112                    this.getItems().add(new LineItemReceivingItem(poi, this));
113                }
114            }
115            
116            populateDocumentDescription(po);
117        }
118            
119        /**
120         * Perform logic needed to clear the initial fields on a Receiving Line Document
121         */
122        public void clearInitFields(boolean fromPurchaseOrder) {
123            // Clearing document overview fields
124            this.getDocumentHeader().setDocumentDescription(null);
125            this.getDocumentHeader().setExplanation(null);
126            this.getDocumentHeader().setFinancialDocumentTotalAmount(null);
127            this.getDocumentHeader().setOrganizationDocumentNumber(null);
128    
129            // Clearing document Init fields
130            if(fromPurchaseOrder == false){
131                this.setPurchaseOrderIdentifier(null);
132            }        
133            this.setShipmentReceivedDate(null);
134            this.setShipmentPackingSlipNumber(null);
135            this.setShipmentBillOfLadingNumber(null);
136            this.setCarrierCode(null);        
137        }
138    
139        
140        @Override
141        public void prepareForSave(KualiDocumentEvent event) {
142    
143            // first populate, then call super
144            if (event instanceof AttributedContinuePurapEvent) {
145                SpringContext.getBean(ReceivingService.class).populateReceivingLineFromPurchaseOrder(this);
146            }
147            
148            super.prepareForSave(event);
149        }
150    
151        @Override
152        public void doRouteStatusChange(DocumentRouteStatusChangeDTO statusChangeEvent) {
153            super.doRouteStatusChange(statusChangeEvent);
154            // DOCUMENT CANCELED
155            // If the document is canceled then set the line item receiving 
156            // status code to CANC.
157            if (this.getDocumentHeader().getWorkflowDocument().stateIsCanceled()) {
158                setLineItemReceivingStatusCode(PurapConstants.LineItemReceivingStatuses.CANCELLED);
159            }
160        }
161        
162        @Override
163        public void doRouteLevelChange(DocumentRouteLevelChangeDTO change) {
164            //If the new node is Outstanding Transactions then we want to set the line item
165            //receiving status code to APOO.
166            if (StringUtils.equals(PurapConstants.LineItemReceivingDocumentStrings.AWAITING_PO_OPEN_STATUS, change.getNewNodeName())){
167                setLineItemReceivingStatusCode(PurapConstants.LineItemReceivingStatuses.AWAITING_PO_OPEN_STATUS);
168            } 
169            //If the new node is Join, this means we're done with the routing, so we'll set
170            //the line item receiving status code to CMPT.
171            else if (StringUtils.equals(PurapConstants.LineItemReceivingDocumentStrings.JOIN_NODE, change.getNewNodeName())) {
172                setLineItemReceivingStatusCode(PurapConstants.LineItemReceivingStatuses.COMPLETE);
173            }
174            SpringContext.getBean(PurapService.class).saveDocumentNoValidation(this);
175        }
176        
177        /**
178         * @see org.kuali.rice.kns.bo.BusinessObjectBase#toStringMapper()
179         */
180        protected LinkedHashMap toStringMapper() {
181            LinkedHashMap m = new LinkedHashMap();      
182            m.put("documentNumber", this.documentNumber);
183            return m;
184        }
185    
186        public Class getItemClass() {
187            return LineItemReceivingItem.class;
188        }
189    
190        public List getItems() {
191            return items;
192        }
193    
194        public void setItems(List items) {
195            this.items = items;
196        }
197    
198        public LineItemReceivingItem getItem(int pos) {
199            return (LineItemReceivingItem) items.get(pos);
200        }
201    
202        public void addItem(LineItemReceivingItem item) {
203            getItems().add(item);
204        }
205    
206        public void deleteItem(int lineNum) {
207            if (getItems().remove(lineNum) == null) {
208                // throw error here
209            }
210        }
211    
212        protected void populateDocumentDescription(PurchaseOrderDocument poDocument) {
213            String description = "PO: " + poDocument.getPurapDocumentIdentifier() + " Vendor: " + poDocument.getVendorName();
214            int noteTextMaxLength = SpringContext.getBean(DataDictionaryService.class).getAttributeMaxLength(DocumentHeader.class, KNSPropertyConstants.DOCUMENT_DESCRIPTION).intValue();
215            if (noteTextMaxLength < description.length()) {
216                description = description.substring(0, noteTextMaxLength);
217            }
218            getDocumentHeader().setDocumentDescription(description);
219        }
220    
221    
222        protected boolean isAwaitingPurchaseOrderOpen() {
223            return SpringContext.getBean(PurchaseOrderService.class).isPurchaseOrderOpenForProcessing(getPurchaseOrderDocument());
224        }
225    
226        /**
227         * Provides answers to the following splits:
228         * RelatesToOutstandingTransactions
229         * 
230         * @see org.kuali.kfs.sys.document.FinancialSystemTransactionalDocumentBase#answerSplitNodeQuestion(java.lang.String)
231         */
232        public boolean answerSplitNodeQuestion(String nodeName) throws UnsupportedOperationException {
233            if (nodeName.equals(PurapWorkflowConstants.RELATES_TO_OUTSTANDING_TRANSACTIONS)) return !isAwaitingPurchaseOrderOpen();
234            throw new UnsupportedOperationException("Cannot answer split question for this node you call \""+nodeName+"\"");
235        }
236        
237        public List buildListOfDeletionAwareLists() {
238            List managedLists = super.buildListOfDeletionAwareLists();
239            managedLists.add(this.getItems());
240            return managedLists;
241        }
242    
243        public KualiDecimal getTotalItemReceivedGivenLineNumber(Integer lineNumber) {
244            for (LineItemReceivingItem item : items) {
245                if (item.getItemLineNumber().equals(lineNumber)) {
246                    return item.getItemReceivedTotalQuantity();
247                }
248            }
249            return new KualiDecimal(0);
250        }
251    }