/*
* 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.cam.document;
import java.sql.Timestamp;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.kuali.kfs.integration.cam.CapitalAssetManagementModuleService;
import org.kuali.kfs.module.cam.CamsConstants;
import org.kuali.kfs.module.cam.CamsKeyConstants;
import org.kuali.kfs.module.cam.CamsPropertyConstants;
import org.kuali.kfs.module.cam.businessobject.Asset;
import org.kuali.kfs.module.cam.businessobject.AssetFabrication;
import org.kuali.kfs.module.cam.businessobject.defaultvalue.NextAssetNumberFinder;
import org.kuali.kfs.module.cam.document.service.AssetLocationService;
import org.kuali.kfs.module.cam.document.service.AssetService;
import org.kuali.kfs.module.cam.document.service.EquipmentLoanOrReturnService;
import org.kuali.kfs.module.cam.document.service.PaymentSummaryService;
import org.kuali.kfs.module.cam.document.service.RetirementInfoService;
import org.kuali.kfs.module.cam.service.AssetLockService;
import org.kuali.kfs.module.cam.util.MaintainableWorkflowUtils;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.kfs.sys.document.FinancialSystemMaintainable;
import org.kuali.kfs.sys.service.BankService;
import org.kuali.rice.core.api.config.property.ConfigurationService;
import org.kuali.rice.core.api.datetime.DateTimeService;
import org.kuali.rice.coreservice.framework.parameter.ParameterService;
import org.kuali.rice.kew.api.WorkflowDocument;
import org.kuali.rice.kew.api.exception.WorkflowException;
import org.kuali.rice.kim.api.identity.IdentityService;
import org.kuali.rice.kns.document.MaintenanceDocument;
import org.kuali.rice.kns.maintenance.Maintainable;
import org.kuali.rice.kns.web.ui.Section;
import org.kuali.rice.krad.bo.DocumentHeader;
import org.kuali.rice.krad.bo.Note;
import org.kuali.rice.krad.maintenance.MaintenanceLock;
import org.kuali.rice.krad.service.DocumentService;
import org.kuali.rice.krad.service.NoteService;
import org.kuali.rice.krad.util.GlobalVariables;
import org.kuali.rice.krad.util.KRADConstants;
/**
* This class implements custom data preparation for displaying asset edit screen.
*/
public class AssetMaintainableImpl extends FinancialSystemMaintainable {
private static final Logger LOG = Logger.getLogger(AssetMaintainableImpl.class);
private Asset asset;
private Asset copyAsset;
private boolean fabricationOn;
protected static volatile IdentityService identityService;
protected static volatile DocumentService documentService;
private static final Map<String, String> FINANCIAL_DOC_NAME_MAP = new HashMap<String, String>();
static {
FINANCIAL_DOC_NAME_MAP.put(KFSConstants.FinancialDocumentTypeCodes.CASH_RECEIPT, KFSConstants.FinancialDocumentTypeNames.CASH_RECEIPT);
FINANCIAL_DOC_NAME_MAP.put(KFSConstants.FinancialDocumentTypeCodes.DISTRIBUTION_OF_INCOME_AND_EXPENSE, KFSConstants.FinancialDocumentTypeNames.DISTRIBUTION_OF_INCOME_AND_EXPENSE);
FINANCIAL_DOC_NAME_MAP.put(KFSConstants.FinancialDocumentTypeCodes.GENERAL_ERROR_CORRECTION, KFSConstants.FinancialDocumentTypeNames.GENERAL_ERROR_CORRECTION);
FINANCIAL_DOC_NAME_MAP.put(KFSConstants.FinancialDocumentTypeCodes.INTERNAL_BILLING, KFSConstants.FinancialDocumentTypeNames.INTERNAL_BILLING);
FINANCIAL_DOC_NAME_MAP.put(KFSConstants.FinancialDocumentTypeCodes.SERVICE_BILLING, KFSConstants.FinancialDocumentTypeNames.SERVICE_BILLING);
FINANCIAL_DOC_NAME_MAP.put(KFSConstants.FinancialDocumentTypeCodes.YEAR_END_DISTRIBUTION_OF_INCOME_AND_EXPENSE, KFSConstants.FinancialDocumentTypeNames.YEAR_END_DISTRIBUTION_OF_INCOME_AND_EXPENSE);
FINANCIAL_DOC_NAME_MAP.put(KFSConstants.FinancialDocumentTypeCodes.YEAR_END_GENERAL_ERROR_CORRECTION, KFSConstants.FinancialDocumentTypeNames.YEAR_END_GENERAL_ERROR_CORRECTION);
FINANCIAL_DOC_NAME_MAP.put(KFSConstants.FinancialDocumentTypeCodes.PROCUREMENT_CARD, KFSConstants.FinancialDocumentTypeNames.PROCUREMENT_CARD);
}
/**
* We are using a substitute mechanism for asset locking which can lock on assets when rule check passed. Return empty list from
* this method.
*
* @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#generateMaintenanceLocks()
*/
@Override
public List<MaintenanceLock> generateMaintenanceLocks() {
return new ArrayList<MaintenanceLock>();
}
/**
* @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#doRouteStatusChange(org.kuali.rice.krad.bo.DocumentHeader)
*/
@Override
public void doRouteStatusChange(DocumentHeader documentHeader) {
super.doRouteStatusChange(documentHeader);
WorkflowDocument workflowDoc = documentHeader.getWorkflowDocument();
// release lock for asset edit...
if ((this.getBusinessObject() instanceof Asset && !(this.getBusinessObject() instanceof AssetFabrication)) && (workflowDoc.isCanceled() || workflowDoc.isDisapproved() || workflowDoc.isProcessed() || workflowDoc.isFinal())) {
this.getCapitalAssetManagementModuleService().deleteAssetLocks(getDocumentNumber(), null);
}
}
protected CapitalAssetManagementModuleService getCapitalAssetManagementModuleService() {
return SpringContext.getBean(CapitalAssetManagementModuleService.class);
}
/**
* @see org.kuali.rice.kns.maintenance.Maintainable#processAfterEdit(org.kuali.rice.kns.document.MaintenanceDocument,
* java.util.Map)
* @param document Maintenance Document used for editing
* @param parameters Parameters available
*/
@Override
public void processAfterEdit(MaintenanceDocument document, Map parameters) {
initializeAttributes(document);
// Identifies the latest location information
getAssetLocationService().setOffCampusLocation(copyAsset);
getAssetLocationService().setOffCampusLocation(asset);
// Calculates payment summary and depreciation summary based on available payment records
PaymentSummaryService paymentSummaryService = SpringContext.getBean(PaymentSummaryService.class);
paymentSummaryService.calculateAndSetPaymentSummary(copyAsset);
paymentSummaryService.calculateAndSetPaymentSummary(asset);
// Identifies the merge history and separation history based on asset disposition records
getAssetService().setSeparateHistory(copyAsset);
getAssetService().setSeparateHistory(asset);
// Finds out the latest retirement info, is asset is currently retired.
RetirementInfoService retirementInfoService = SpringContext.getBean(RetirementInfoService.class);
retirementInfoService.setRetirementInfo(copyAsset);
retirementInfoService.setRetirementInfo(asset);
retirementInfoService.setMergeHistory(copyAsset);
retirementInfoService.setMergeHistory(asset);
// Finds out the latest equipment loan or return information if available
EquipmentLoanOrReturnService equipmentLoanOrReturnService = SpringContext.getBean(EquipmentLoanOrReturnService.class);
equipmentLoanOrReturnService.setEquipmentLoanInfo(copyAsset);
equipmentLoanOrReturnService.setEquipmentLoanInfo(asset);
super.processAfterEdit(document, parameters);
}
/**
* @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#refresh(java.lang.String, java.util.Map,
* org.kuali.rice.kns.document.MaintenanceDocument)
*
* KRAD Conversion: Performs customization of the core sections.
*
* Uses data dictionary for bo Asset to get the core section ids to set section titles.
*/
@Override
public List<Section> getCoreSections(MaintenanceDocument document, Maintainable oldMaintainable) {
List<Section> sections = super.getCoreSections(document, oldMaintainable);
Asset asset = (Asset) getBusinessObject();
if (asset.getAssetPayments().size() == 0) {
for (Section section : sections) {
if (CamsConstants.Asset.SECTION_ID_PAYMENT_INFORMATION.equals(section.getSectionId())) {
section.setSectionTitle(section.getSectionTitle() + CamsConstants.Asset.SECTION_TITLE_NO_PAYMENT + asset.getCapitalAssetNumber());
}
}
}
return sections;
}
/**
* This method gets old and new maintainable objects and creates convenience handles to them
*
* @param document Asset Edit Document
*/
private void initializeAttributes(MaintenanceDocument document) {
if (asset == null) {
asset = (Asset) document.getNewMaintainableObject().getBusinessObject();
asset.setTagged();
}
if (copyAsset == null) {
copyAsset = (Asset) document.getOldMaintainableObject().getBusinessObject();
}
setFabricationOn(document.getNewMaintainableObject().getBusinessObject() instanceof AssetFabrication);
}
/**
* KFSMI-5964: added refresh to Asset object after retrieve to prevent updated depreciation data from
* wiped on existing saved/enrouted maint. doc
*
* @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#processAfterRetrieve()
*/
@Override
public void processAfterRetrieve() {
//Asset only
if (this.getBusinessObject() instanceof Asset && MaintainableWorkflowUtils.isDocumentSavedOrEnroute(getDocumentNumber())) {
Asset asset = (Asset)getBusinessObject();
asset.refreshReferenceObject(CamsPropertyConstants.Asset.ASSET_PAYMENTS);
PaymentSummaryService paymentSummaryService = SpringContext.getBean(PaymentSummaryService.class);
paymentSummaryService.calculateAndSetPaymentSummary(asset);
}
}
/**
* @see org.kuali.kfs.sys.document.FinancialSystemMaintainable.processAfterPost
*/
@Override
public void processAfterPost(MaintenanceDocument document, Map<String, String[]> parameters) {
String[] customAction = parameters.get(KRADConstants.CUSTOM_ACTION);
if (customAction != null && customAction.length > 0 && StringUtils.equals(CamsPropertyConstants.Asset.LAST_INVENTORY_DATE_UPDATE_BUTTON,customAction[0])) {
WorkflowDocument workflowDoc = document.getDocumentHeader().getWorkflowDocument();
if(workflowDoc != null && workflowDoc.isInitiated()) {
asset.setLastInventoryDate(new Timestamp(SpringContext.getBean(DateTimeService.class).getCurrentSqlDate().getTime()));
String userPrincipalName= GlobalVariables.getUserSession().getPrincipalName();
final String noteTextPattern = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(CamsKeyConstants.Asset.LAST_INVENTORY_DATE_UPDATE_NOTE_TEXT);
Object[] arguments = { userPrincipalName, asset.getCapitalAssetNumber().toString() };
String noteText = MessageFormat.format(noteTextPattern, arguments);
Note lastInventoryDateUpdatedNote = getDocumentService().createNoteFromDocument(document, noteText);
lastInventoryDateUpdatedNote.setAuthorUniversalIdentifier(getIdentityService().getPrincipalByPrincipalName(KFSConstants.SYSTEM_USER).getPrincipalId());
document.addNote(lastInventoryDateUpdatedNote);
getDocumentService().saveDocumentNotes(document);
}
}
super.processAfterPost(document, parameters);
}
@Override
public void saveBusinessObject() {
Asset asset = ((Asset) businessObject);
if (asset.getCapitalAssetNumber() == null) {
asset.setCapitalAssetNumber(NextAssetNumberFinder.getLongValue());
}
asset.refreshReferenceObject(CamsPropertyConstants.Asset.ASSET_LOCATIONS);
// update and save asset location
if (getAssetLocationService().isOffCampusLocationExists(asset.getOffCampusLocation())) {
getAssetLocationService().updateOffCampusLocation(asset);
}
super.saveBusinessObject();
}
@Override
public void processAfterNew(MaintenanceDocument document, Map<String, String[]> parameters) {
super.processAfterNew(document, parameters);
initializeAttributes(document);
// document.getNewMaintainableObject().setGenerateDefaultValues(false);
if (asset.getCreateDate() == null) {
asset.setCreateDate(SpringContext.getBean(DateTimeService.class).getCurrentSqlDate());
asset.setAcquisitionTypeCode(CamsConstants.Asset.ACQUISITION_TYPE_CODE_C);
asset.setVendorName(CamsConstants.Asset.VENDOR_NAME_CONSTRUCTED);
asset.setInventoryStatusCode(CamsConstants.InventoryStatusCode.CAPITAL_ASSET_UNDER_CONSTRUCTION);
asset.setPrimaryDepreciationMethodCode(CamsConstants.Asset.DEPRECIATION_METHOD_STRAIGHT_LINE_CODE);
asset.setCapitalAssetTypeCode(SpringContext.getBean(ParameterService.class).getParameterValueAsString(Asset.class, CamsConstants.Parameters.DEFAULT_FABRICATION_ASSET_TYPE_CODE));
asset.setManufacturerName(SpringContext.getBean(ParameterService.class).getParameterValueAsString(Asset.class, CamsConstants.Parameters.DEFAULT_FABRICATION_ASSET_MANUFACTURER));
getAssetService().setFiscalPeriod(asset);
}
// setup offCampusLocation
getAssetLocationService().setOffCampusLocation(asset);
}
@Override
public void setGenerateDefaultValues(String docTypeName) {
}
public List<String> getFpLinks() {
Asset asset = (Asset) getBusinessObject();
List<Long> assetNumbers = new ArrayList<Long>();
assetNumbers.add(asset.getCapitalAssetNumber());
return SpringContext.getBean(AssetLockService.class).getAssetLockingDocuments(assetNumbers, CamsConstants.DocumentTypeName.ASSET_FP_INQUIRY, "");
}
public List<String> getPreqLinks() {
Asset asset = (Asset) getBusinessObject();
List<Long> assetNumbers = new ArrayList<Long>();
assetNumbers.add(asset.getCapitalAssetNumber());
return SpringContext.getBean(AssetLockService.class).getAssetLockingDocuments(assetNumbers, CamsConstants.DocumentTypeName.ASSET_PREQ_INQUIRY, "");
}
public List<String> getFpLinkedDocumentInfo() {
List<String> documentInfo = new ArrayList<String>();
Iterator<String> fpDocumentNumbers = getFpLinks().iterator();
while (fpDocumentNumbers.hasNext()) {
String aDocumentNumber = fpDocumentNumbers.next();
try {
String docTypeName = getDocumentService().getByDocumentHeaderId(aDocumentNumber).getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
documentInfo.add(FINANCIAL_DOC_NAME_MAP.get(docTypeName) + "-" + aDocumentNumber);
}
catch (WorkflowException e) {
throw new RuntimeException("Caught WorkflowException trying to get document type name", e);
}
}
return documentInfo;
}
public boolean isFabricationOn() {
return fabricationOn;
}
public void setFabricationOn(boolean fabricationOn) {
this.fabricationOn = fabricationOn;
}
private AssetService getAssetService() {
return SpringContext.getBean(AssetService.class);
}
private AssetLocationService getAssetLocationService() {
return SpringContext.getBean(AssetLocationService.class);
}
/**
* @return the default implementation of the DocumentService
*/
protected static DocumentService getDocumentService() {
if (documentService == null) {
documentService = SpringContext.getBean(DocumentService.class);
}
return documentService;
}
public IdentityService getIdentityService() {
if (identityService == null) {
identityService = SpringContext.getBean(IdentityService.class);
}
return identityService;
}
public void setIdentityService(IdentityService identityService) {
this.identityService = identityService;
}
}