/*
* The Kuali Financial System, a comprehensive financial management system for higher education.
*
* Copyright 2005-2014 The Kuali Foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kuali.kfs.module.purap.document;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.kuali.kfs.module.purap.PurapConstants;
import org.kuali.kfs.module.purap.PurapWorkflowConstants;
import org.kuali.kfs.module.purap.businessobject.LineItemReceivingItem;
import org.kuali.kfs.module.purap.businessobject.PurchaseOrderItem;
import org.kuali.kfs.module.purap.document.service.PurapService;
import org.kuali.kfs.module.purap.document.service.PurchaseOrderService;
import org.kuali.kfs.module.purap.document.service.ReceivingService;
import org.kuali.kfs.module.purap.document.validation.event.AttributedContinuePurapEvent;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.rice.core.api.util.type.KualiDecimal;
import org.kuali.rice.kew.framework.postprocessor.DocumentRouteLevelChange;
import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
import org.kuali.rice.kns.service.DataDictionaryService;
import org.kuali.rice.krad.bo.DocumentHeader;
import org.kuali.rice.krad.rules.rule.event.KualiDocumentEvent;
import org.kuali.rice.krad.util.KRADPropertyConstants;
/**
* @author Kuali Nervous System Team (kualidev@oncourse.iu.edu)
*/
public class LineItemReceivingDocument extends ReceivingDocumentBase {
//Collections
protected List<LineItemReceivingItem> items;
/**
* Default constructor.
*/
public LineItemReceivingDocument() {
super();
items = new ArrayList();
}
public void initiateDocument(){
super.initiateDocument();
this.setAppDocStatus(PurapConstants.LineItemReceivingStatuses.APPDOC_IN_PROCESS);
}
public void populateReceivingLineFromPurchaseOrder(PurchaseOrderDocument po){
//populate receiving line document from purchase order
this.setPurchaseOrderIdentifier( po.getPurapDocumentIdentifier() );
this.getDocumentHeader().setOrganizationDocumentNumber( po.getDocumentHeader().getOrganizationDocumentNumber() );
this.setAccountsPayablePurchasingDocumentLinkIdentifier( po.getAccountsPayablePurchasingDocumentLinkIdentifier() );
//copy vendor
this.setVendorHeaderGeneratedIdentifier( po.getVendorHeaderGeneratedIdentifier() );
this.setVendorDetailAssignedIdentifier( po.getVendorDetailAssignedIdentifier() );
this.setVendorName( po.getVendorName() );
this.setVendorNumber( po.getVendorNumber() );
this.setVendorAddressGeneratedIdentifier( po.getVendorAddressGeneratedIdentifier() );
this.setVendorLine1Address( po.getVendorLine1Address() );
this.setVendorLine2Address( po.getVendorLine2Address() );
this.setVendorCityName( po.getVendorCityName() );
this.setVendorStateCode( po.getVendorStateCode() );
this.setVendorPostalCode( po.getVendorPostalCode() );
this.setVendorCountryCode( po.getVendorCountryCode() );
//copy alternate vendor
this.setAlternateVendorName( po.getAlternateVendorName() );
this.setAlternateVendorNumber( po.getAlternateVendorNumber() );
this.setAlternateVendorDetailAssignedIdentifier( po.getAlternateVendorDetailAssignedIdentifier() );
this.setAlternateVendorHeaderGeneratedIdentifier( po.getAlternateVendorHeaderGeneratedIdentifier() );
//copy delivery
this.setDeliveryBuildingCode( po.getDeliveryBuildingCode() );
this.setDeliveryBuildingLine1Address( po.getDeliveryBuildingLine1Address() );
this.setDeliveryBuildingLine2Address( po.getDeliveryBuildingLine2Address() );
this.setDeliveryBuildingName( po.getDeliveryBuildingName() );
this.setDeliveryBuildingRoomNumber( po.getDeliveryBuildingRoomNumber() );
this.setDeliveryCampusCode( po.getDeliveryCampusCode() );
this.setDeliveryCityName( po.getDeliveryCityName() );
this.setDeliveryCountryCode( po.getDeliveryCountryCode() );
this.setDeliveryInstructionText( po.getDeliveryInstructionText() );
this.setDeliveryPostalCode( po.getDeliveryPostalCode() );
this.setDeliveryRequiredDate( po.getDeliveryRequiredDate() );
this.setDeliveryRequiredDateReasonCode( po.getDeliveryRequiredDateReasonCode() );
this.setDeliveryStateCode( po.getDeliveryStateCode() );
this.setDeliveryToEmailAddress( po.getDeliveryToEmailAddress() );
this.setDeliveryToName( po.getDeliveryToName() );
this.setDeliveryToPhoneNumber( po.getDeliveryToPhoneNumber() );
//copy purchase order items
for (PurchaseOrderItem poi : (List<PurchaseOrderItem>) po.getItems()) {
//TODO: Refactor this check into a service call. route FYI during submit
if(poi.isItemActiveIndicator() &&
poi.getItemType().isQuantityBasedGeneralLedgerIndicator() &&
poi.getItemType().isLineItemIndicator() ){
this.getItems().add(new LineItemReceivingItem(poi, this));
}
}
populateDocumentDescription(po);
}
/**
* Perform logic needed to clear the initial fields on a Receiving Line Document
*/
public void clearInitFields(boolean fromPurchaseOrder) {
// Clearing document overview fields
this.getDocumentHeader().setDocumentDescription(null);
this.getDocumentHeader().setExplanation(null);
this.getFinancialSystemDocumentHeader().setFinancialDocumentTotalAmount(null);
this.getDocumentHeader().setOrganizationDocumentNumber(null);
// Clearing document Init fields
if(fromPurchaseOrder == false){
this.setPurchaseOrderIdentifier(null);
}
this.setShipmentReceivedDate(null);
this.setShipmentPackingSlipNumber(null);
this.setShipmentBillOfLadingNumber(null);
this.setCarrierCode(null);
}
@Override
public void prepareForSave(KualiDocumentEvent event) {
// first populate, then call super
if (event instanceof AttributedContinuePurapEvent) {
SpringContext.getBean(ReceivingService.class).populateReceivingLineFromPurchaseOrder(this);
}
super.prepareForSave(event);
}
@Override
public void doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) {
super.doRouteStatusChange(statusChangeEvent);
// DOCUMENT CANCELED
// If the document is canceled then set the line item receiving
// status code to CANC.
if (this.getFinancialSystemDocumentHeader().getWorkflowDocument().isCanceled()) {
setAppDocStatus(PurapConstants.LineItemReceivingStatuses.APPDOC_CANCELLED);
SpringContext.getBean(PurapService.class).saveDocumentNoValidation(this);
}
}
@Override
public void doRouteLevelChange(DocumentRouteLevelChange change) {
//If the new node is Outstanding Transactions then we want to set the line item
//receiving status code to APOO.
if (StringUtils.equals(PurapConstants.LineItemReceivingDocumentStrings.AWAITING_PO_OPEN_STATUS, change.getNewNodeName())){
setAppDocStatus(PurapConstants.LineItemReceivingStatuses.APPDOC_AWAITING_PO_OPEN_STATUS);
SpringContext.getBean(PurapService.class).saveDocumentNoValidation(this);
}
//If the new node is Join, this means we're done with the routing, so we'll set
//the line item receiving status code to CMPT.
else if (StringUtils.equals(PurapConstants.LineItemReceivingDocumentStrings.JOIN_NODE, change.getNewNodeName())) {
setAppDocStatus(PurapConstants.LineItemReceivingStatuses.APPDOC_COMPLETE);
SpringContext.getBean(PurapService.class).saveDocumentNoValidation(this);
}
SpringContext.getBean(PurapService.class).saveDocumentNoValidation(this);
}
/**
* @see org.kuali.rice.krad.bo.BusinessObjectBase#toStringMapper()
*/
protected LinkedHashMap toStringMapper_RICE20_REFACTORME() {
LinkedHashMap m = new LinkedHashMap();
m.put("documentNumber", this.documentNumber);
return m;
}
public Class getItemClass() {
return LineItemReceivingItem.class;
}
public List getItems() {
return items;
}
public void setItems(List items) {
this.items = items;
}
public LineItemReceivingItem getItem(int pos) {
return (LineItemReceivingItem) items.get(pos);
}
public void addItem(LineItemReceivingItem item) {
getItems().add(item);
}
public void deleteItem(int lineNum) {
if (getItems().remove(lineNum) == null) {
// throw error here
}
}
protected void populateDocumentDescription(PurchaseOrderDocument poDocument) {
String description = "PO: " + poDocument.getPurapDocumentIdentifier() + " Vendor: " + poDocument.getVendorName();
int noteTextMaxLength = SpringContext.getBean(DataDictionaryService.class).getAttributeMaxLength(DocumentHeader.class, KRADPropertyConstants.DOCUMENT_DESCRIPTION).intValue();
if (noteTextMaxLength < description.length()) {
description = description.substring(0, noteTextMaxLength);
}
getDocumentHeader().setDocumentDescription(description);
}
protected boolean isRelatesToOutstandingTransactionsRequired() {
return SpringContext.getBean(ReceivingService.class).hasNewUnorderedItem(this) && !SpringContext.getBean(PurchaseOrderService.class).isPurchaseOrderOpenForProcessing(getPurchaseOrderDocument());
}
/**
* Provides answers to the following splits:
* RelatesToOutstandingTransactions
*
* @see org.kuali.kfs.sys.document.FinancialSystemTransactionalDocumentBase#answerSplitNodeQuestion(java.lang.String)
*/
public boolean answerSplitNodeQuestion(String nodeName) throws UnsupportedOperationException {
if (nodeName.equals(PurapWorkflowConstants.RELATES_TO_OUTSTANDING_TRANSACTIONS)) return isRelatesToOutstandingTransactionsRequired();
throw new UnsupportedOperationException("Cannot answer split question for this node you call \""+nodeName+"\"");
}
public List buildListOfDeletionAwareLists() {
List managedLists = super.buildListOfDeletionAwareLists();
managedLists.add(this.getItems());
return managedLists;
}
public KualiDecimal getTotalItemReceivedGivenLineNumber(Integer lineNumber) {
for (LineItemReceivingItem item : items) {
if (item.getItemLineNumber().equals(lineNumber)) {
return item.getItemReceivedTotalQuantity();
}
}
return new KualiDecimal(0);
}
}