/* * 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.cab.document.web.struts; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.kuali.kfs.module.cab.CabConstants; import org.kuali.kfs.module.cab.CabKeyConstants; import org.kuali.kfs.module.cab.CabPropertyConstants; import org.kuali.kfs.module.cab.businessobject.PurchasingAccountsPayableDocument; import org.kuali.kfs.module.cab.businessobject.PurchasingAccountsPayableItemAsset; import org.kuali.kfs.module.cab.businessobject.PurchasingAccountsPayableLineAssetAccount; import org.kuali.kfs.module.cab.document.service.PurApInfoService; import org.kuali.kfs.module.cab.document.service.PurApLineDocumentService; import org.kuali.kfs.module.cab.document.service.PurApLineService; import org.kuali.kfs.module.cab.document.web.PurApLineSession; import org.kuali.kfs.module.cam.CamsConstants; import org.kuali.kfs.module.cam.CamsKeyConstants; import org.kuali.kfs.module.cam.businessobject.AssetGlobal; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.rice.core.api.config.property.ConfigurationService; import org.kuali.rice.core.api.util.RiceKeyConstants; import org.kuali.rice.core.api.util.type.KualiDecimal; import org.kuali.rice.coreservice.framework.parameter.ParameterService; import org.kuali.rice.kew.api.exception.WorkflowException; import org.kuali.rice.kns.question.ConfirmationQuestion; import org.kuali.rice.kns.util.KNSGlobalVariables; import org.kuali.rice.krad.service.BusinessObjectService; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.KRADConstants; import org.kuali.rice.krad.util.KRADUtils; import org.kuali.rice.krad.util.ObjectUtils; public class PurApLineAction extends CabActionBase { private static final Logger LOG = Logger.getLogger(PurApLineAction.class); PurApLineService purApLineService = SpringContext.getBean(PurApLineService.class); PurApInfoService purApInfoService = SpringContext.getBean(PurApInfoService.class); PurApLineDocumentService purApLineDocumentService = SpringContext.getBean(PurApLineDocumentService.class); /** * Handle start action. * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { PurApLineForm purApLineForm = (PurApLineForm) form; if (purApLineForm.getPurchaseOrderIdentifier() == null) { GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, CabKeyConstants.ERROR_PO_ID_EMPTY); } else { // set Contact Email Address and Phone Number from PurAp Purchase Order document purApInfoService.setPurchaseOrderFromPurAp(purApLineForm); // save PurAp document list into form buildPurApDocList(purApLineForm); if (!purApLineForm.getPurApDocs().isEmpty()) { // set item pre-populated fields purApLineService.buildPurApItemAssetList(purApLineForm.getPurApDocs()); // create session object for current processing createPurApLineSession(purApLineForm.getPurchaseOrderIdentifier()); } } return mapping.findForward(KFSConstants.MAPPING_BASIC); } protected void createPurApLineSession(Integer purchaseOrderIdentifier) { GlobalVariables.getUserSession().addObject(CabConstants.CAB_PURAP_SESSION.concat(purchaseOrderIdentifier.toString()), new PurApLineSession()); } protected void clearPurApLineSession(Integer purchaseOrderIdentifier) { if (purchaseOrderIdentifier != null) { GlobalVariables.getUserSession().removeObject(CabConstants.CAB_PURAP_SESSION.concat(purchaseOrderIdentifier.toString())); } } public ActionForward reload(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { PurApLineForm purApLineForm = (PurApLineForm) form; if (purApLineForm.getPurchaseOrderIdentifier() == null) { GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, CabKeyConstants.ERROR_PO_ID_EMPTY); } purApLineForm.getPurApDocs().clear(); // clear the session and reload the page clearPurApLineSession(purApLineForm.getPurchaseOrderIdentifier()); return start(mapping, form, request, response); } /** * Build PurchasingAccountsPayableDocument list in which all documents have the same PO_ID. * * @param purApLineForm */ protected void buildPurApDocList(PurApLineForm purApLineForm) { Map<String, Object> cols = new HashMap<String, Object>(); cols.put(CabPropertyConstants.PurchasingAccountsPayableDocument.PURCHASE_ORDER_IDENTIFIER, purApLineForm.getPurchaseOrderIdentifier()); Collection<PurchasingAccountsPayableDocument> purApDocs = SpringContext.getBean(BusinessObjectService.class).findMatchingOrderBy(PurchasingAccountsPayableDocument.class, cols, CabPropertyConstants.PurchasingAccountsPayableDocument.DOCUMENT_NUMBER, true); if (purApDocs == null || purApDocs.isEmpty()) { GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, CabKeyConstants.ERROR_PO_ID_INVALID, purApLineForm.getPurchaseOrderIdentifier().toString()); } else { boolean existActiveDoc = false; for (PurchasingAccountsPayableDocument purApDoc : purApDocs) { if (ObjectUtils.isNotNull(purApDoc) && purApDoc.isActive()) { // If there exists active document, set the existActiveDoc indicator. existActiveDoc = true; break; } } purApLineForm.getPurApDocs().clear(); purApLineForm.getPurApDocs().addAll(purApDocs); setupObjectRelationship(purApLineForm.getPurApDocs()); // If no active item exists or no exist document, display a message. if (!existActiveDoc) { KNSGlobalVariables.getMessageList().add(CabKeyConstants.MESSAGE_NO_ACTIVE_PURAP_DOC); } } } /** * Setup relationship from account to item and item to doc. In this way, we keep all working objects in the same view as form. * * @param purApDocs */ protected void setupObjectRelationship(List<PurchasingAccountsPayableDocument> purApDocs) { for (PurchasingAccountsPayableDocument purApDoc : purApDocs) { for (PurchasingAccountsPayableItemAsset item : purApDoc.getPurchasingAccountsPayableItemAssets()) { item.setPurchasingAccountsPayableDocument(purApDoc); for (PurchasingAccountsPayableLineAssetAccount account : item.getPurchasingAccountsPayableLineAssetAccounts()) { account.setPurchasingAccountsPayableItemAsset(item); } } } } /** * Cancels the action and returns to portal main page * * @param mapping {@link ActionMapping} * @param form {@link ActionForm} * @param request {@link HttpServletRequest} * @param response {@link HttpServletResponse} * @return {@link ActionForward} * @throws Exception */ public ActionForward cancel(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { return mapping.findForward(KRADConstants.MAPPING_PORTAL); } /** * save the information in the current form into underlying data store */ public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { PurApLineForm purApLineForm = (PurApLineForm) form; // get the current processing object from session PurApLineSession purApLineSession = retrievePurApLineSession(purApLineForm); // persistent changes to CAB tables purApLineService.processSaveBusinessObjects(purApLineForm.getPurApDocs(), purApLineSession); KNSGlobalVariables.getMessageList().add(CabKeyConstants.MESSAGE_CAB_CHANGES_SAVED_SUCCESS); return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Handling for screen close. Default action is return to caller. */ public ActionForward close(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { PurApLineForm purApLineForm = (PurApLineForm) form; // Create question page for save before close. Object question = request.getParameter(KRADConstants.QUESTION_INST_ATTRIBUTE_NAME); ConfigurationService kualiConfiguration = SpringContext.getBean(ConfigurationService.class); // logic for close question if (question == null) { // ask question if not already asked return this.performQuestionWithoutInput(mapping, form, request, response, KRADConstants.DOCUMENT_SAVE_BEFORE_CLOSE_QUESTION, kualiConfiguration.getPropertyValueAsString(RiceKeyConstants.QUESTION_SAVE_BEFORE_CLOSE), KRADConstants.CONFIRMATION_QUESTION, KRADConstants.MAPPING_CLOSE, ""); } else { Object buttonClicked = request.getParameter(KRADConstants.QUESTION_CLICKED_BUTTON); PurApLineSession purApLineSession = retrievePurApLineSession(purApLineForm); if ((KRADConstants.DOCUMENT_SAVE_BEFORE_CLOSE_QUESTION.equals(question)) && ConfirmationQuestion.YES.equals(buttonClicked)) { purApLineService.processSaveBusinessObjects(purApLineForm.getPurApDocs(), purApLineSession); } // remove current processing object from session removePurApLineSession(purApLineForm.getPurchaseOrderIdentifier()); } return mapping.findForward(KRADConstants.MAPPING_PORTAL); } /** * Remove PurApLineSession object from user session. * * @param purApLineForm */ private void removePurApLineSession(Integer purchaseOrderIdentifier) { GlobalVariables.getUserSession().removeObject(CabConstants.CAB_PURAP_SESSION.concat(purchaseOrderIdentifier.toString())); } /** * This method handles split action. Create one item with split quantity * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward split(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { PurApLineForm purApLineForm = (PurApLineForm) form; // Get the line item for applying split action. PurchasingAccountsPayableItemAsset selectedLineItem = getSelectedLineItem((PurApLineForm) form); if (selectedLineItem == null) { return mapping.findForward(KFSConstants.MAPPING_BASIC); } String errorPath = CabPropertyConstants.PurApLineForm.PURAP_DOCS + KFSConstants.SQUARE_BRACKET_LEFT + purApLineForm.getActionPurApDocIndex() + KFSConstants.SQUARE_BRACKET_RIGHT + "." + CabPropertyConstants.PurchasingAccountsPayableDocument.PURCHASEING_ACCOUNTS_PAYABLE_ITEM_ASSETS + KFSConstants.SQUARE_BRACKET_LEFT + purApLineForm.getActionItemAssetIndex() + KFSConstants.SQUARE_BRACKET_RIGHT; GlobalVariables.getMessageMap().addToErrorPath(errorPath); // check user input split quantity. checkSplitQty(selectedLineItem, errorPath); GlobalVariables.getMessageMap().removeFromErrorPath(errorPath); // apply split when error free if (GlobalVariables.getMessageMap().hasNoErrors() && selectedLineItem != null) { PurApLineSession purApLineSession = retrievePurApLineSession(purApLineForm); // create a new item with split quantity from selected item purApLineService.processSplit(selectedLineItem, purApLineSession.getActionsTakenHistory()); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Get PurApLineSession object from user session. * * @param purApLineForm * @return */ private PurApLineSession retrievePurApLineSession(PurApLineForm purApForm) { PurApLineSession purApLineSession = (PurApLineSession) GlobalVariables.getUserSession().retrieveObject(CabConstants.CAB_PURAP_SESSION.concat(purApForm.getPurchaseOrderIdentifier().toString())); if (purApLineSession == null) { purApLineSession = new PurApLineSession(); GlobalVariables.getUserSession().addObject(CabConstants.CAB_PURAP_SESSION.concat(purApForm.getPurchaseOrderIdentifier().toString()), purApLineSession); } return purApLineSession; } /** * Check user input splitQty. It must be required and can't be zero or greater than current quantity. * * @param itemAsset * @param errorPath */ protected void checkSplitQty(PurchasingAccountsPayableItemAsset itemAsset, String errorPath) { if (itemAsset.getSplitQty() == null) itemAsset.setSplitQty(KualiDecimal.ZERO); if (itemAsset.getAccountsPayableItemQuantity() == null) itemAsset.setAccountsPayableItemQuantity(KualiDecimal.ZERO); KualiDecimal splitQty = itemAsset.getSplitQty(); KualiDecimal oldQty = itemAsset.getAccountsPayableItemQuantity(); KualiDecimal maxAllowQty = oldQty.subtract(new KualiDecimal(0.1)); if (splitQty == null) { GlobalVariables.getMessageMap().putError(CabPropertyConstants.PurchasingAccountsPayableItemAsset.SPLIT_QTY, CabKeyConstants.ERROR_SPLIT_QTY_REQUIRED); } else if (splitQty.isLessEqual(KualiDecimal.ZERO) || splitQty.isGreaterEqual(oldQty)) { GlobalVariables.getMessageMap().putError(CabPropertyConstants.PurchasingAccountsPayableItemAsset.SPLIT_QTY, CabKeyConstants.ERROR_SPLIT_QTY_INVALID, maxAllowQty.toString()); } return; } /** * Merge Action includes merge all functionality. * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward merge(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { PurApLineForm purApForm = (PurApLineForm) form; boolean isMergeAll = purApLineService.isMergeAllAction(purApForm.getPurApDocs()); List<PurchasingAccountsPayableItemAsset> mergeLines = purApLineService.getSelectedMergeLines(isMergeAll, purApForm.getPurApDocs()); Object question = request.getParameter(KRADConstants.QUESTION_INST_ATTRIBUTE_NAME); // logic for trade-in allowance question if (question != null) { Object buttonClicked = request.getParameter(KRADConstants.QUESTION_CLICKED_BUTTON); if (CabConstants.TRADE_IN_INDICATOR_QUESTION.equals(question) && ConfirmationQuestion.YES.equals(buttonClicked)) { if (purApLineService.mergeLinesHasDifferentObjectSubTypes(mergeLines)) { // check if objectSubTypes are different and bring the obj sub types warning message String warningMessage = generateObjectSubTypeQuestion(); return this.performQuestionWithoutInput(mapping, form, request, response, CabConstants.PAYMENT_DIFFERENT_OBJECT_SUB_TYPE_CONFIRMATION_QUESTION, warningMessage, KRADConstants.CONFIRMATION_QUESTION, CabConstants.Actions.MERGE, ""); } else { performMerge(purApForm, mergeLines, isMergeAll); } } else if (CabConstants.PAYMENT_DIFFERENT_OBJECT_SUB_TYPE_CONFIRMATION_QUESTION.equals(question) && ConfirmationQuestion.YES.equals(buttonClicked)) { performMerge(purApForm, mergeLines, isMergeAll); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } boolean tradeInAllowanceInAllLines = purApLineService.isTradeInAllowanceExist(purApForm.getPurApDocs()); boolean tradeInIndicatorInSelectedLines = purApLineService.isTradeInIndExistInSelectedLines(mergeLines); // validating... validateMergeAction(purApForm, mergeLines, isMergeAll, tradeInAllowanceInAllLines, tradeInIndicatorInSelectedLines); if (GlobalVariables.getMessageMap().hasNoErrors()) { // Display a warning message without blocking the action if TI indicator exists but TI allowance not exist. if (tradeInIndicatorInSelectedLines && !tradeInAllowanceInAllLines) { return this.performQuestionWithoutInput(mapping, form, request, response, CabConstants.TRADE_IN_INDICATOR_QUESTION, SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(CabKeyConstants.QUESTION_TRADE_IN_INDICATOR_EXISTING), KRADConstants.CONFIRMATION_QUESTION, CabConstants.Actions.MERGE, ""); } else if (purApLineService.mergeLinesHasDifferentObjectSubTypes(mergeLines)) { // check if objectSubTypes are different and bring the obj sub types warning message String warningMessage = generateObjectSubTypeQuestion(); return this.performQuestionWithoutInput(mapping, form, request, response, CabConstants.PAYMENT_DIFFERENT_OBJECT_SUB_TYPE_CONFIRMATION_QUESTION, warningMessage, KRADConstants.CONFIRMATION_QUESTION, CabConstants.Actions.MERGE, ""); } else { performMerge(purApForm, mergeLines, isMergeAll); } } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Generate the question string for different object sub type codes. * * @return */ protected String generateObjectSubTypeQuestion() { String parameterDetail = "(module:" + KRADUtils.getNamespaceAndComponentSimpleName(AssetGlobal.class) + ")"; ConfigurationService kualiConfiguration = this.getConfigurationService(); String continueQuestion = kualiConfiguration.getPropertyValueAsString(CamsKeyConstants.CONTINUE_QUESTION); String warningMessage = kualiConfiguration.getPropertyValueAsString(CabKeyConstants.QUESTION_DIFFERENT_OBJECT_SUB_TYPES) + " " + CamsConstants.Parameters.OBJECT_SUB_TYPE_GROUPS + " " + parameterDetail + ". " + continueQuestion; return warningMessage; } /** * Merge with service help. * * @param purApForm * @param mergeLines */ protected void performMerge(PurApLineForm purApForm, List<PurchasingAccountsPayableItemAsset> mergeLines, boolean isMergeAll) { PurApLineSession purApLineSession = retrievePurApLineSession(purApForm); // handle merging lines including merge all situation. retrieveUserInputForMerge(mergeLines.get(0), purApForm); purApLineService.processMerge(mergeLines, purApLineSession.getActionsTakenHistory(), isMergeAll); // add all other mergeLines except the first one into processedItem list. mergeLines.remove(0); purApLineSession.getProcessedItems().addAll(mergeLines); clearForMerge(purApForm); } /** * Retrieve user input merge quantity and merge description. * * @param firstItem * @param purApForm */ protected void retrieveUserInputForMerge(PurchasingAccountsPayableItemAsset firstItem, PurApLineForm purApForm) { if (ObjectUtils.isNotNull(firstItem)) { // Set new value for quantity and description. firstItem.setAccountsPayableItemQuantity(purApForm.getMergeQty()); firstItem.setAccountsPayableLineItemDescription(purApForm.getMergeDesc()); } } /** * Clear user input after merge. * * @param purApForm */ protected void clearForMerge(PurApLineForm purApForm) { // reset user input values. purApLineService.resetSelectedValue(purApForm.getPurApDocs()); purApForm.setMergeQty(null); purApForm.setMergeDesc(null); purApForm.setSelectAll(false); } /** * Check if the merge action is valid or not. * * @param purApForm * @param mergeLines */ protected void validateMergeAction(PurApLineForm purApForm, List<PurchasingAccountsPayableItemAsset> mergeLines, boolean isMergeAll, boolean tradeInAllowanceInAllLines, boolean tradeInIndicatorInSelectedLines) { // check if the user entered merge quantity and merge description checkMergeRequiredFields(purApForm); // Check if the selected merge lines violate the business constraints. if (isMergeAll) { checkMergeAllValid(tradeInAllowanceInAllLines, tradeInIndicatorInSelectedLines); } else { checkMergeLinesValid(mergeLines, tradeInAllowanceInAllLines, tradeInIndicatorInSelectedLines); } // Check the associated pre-tagging data entries. checkPreTagValidForMerge(mergeLines, purApForm.getPurchaseOrderIdentifier()); } /** * If to be merged items have: (1) No Pretag data: No problem; (2) 1 Pretag data entry: Associate this one with the new item * created after merge;(3) 1+ Pretag data entries: Display error, user has to manually fix data * * @param mergeLines */ protected void checkPreTagValidForMerge(List<PurchasingAccountsPayableItemAsset> mergeLines, Integer purchaseOrderIdentifier) { Map validNumberMap = getItemLineNumberMap(mergeLines); if (!validNumberMap.isEmpty() && validNumberMap.size() > 1 && purApLineService.isMultipleTagExisting(purchaseOrderIdentifier, validNumberMap.keySet())) { GlobalVariables.getMessageMap().putError(CabPropertyConstants.PurApLineForm.PURAP_DOCS, CabKeyConstants.ERROR_MERGE_WITH_PRETAGGING); } } /** * Build a Hashmap for itemLineNumber since itemLines could exist duplicate itemLineNumber * * @param itemLines * @return */ protected Map getItemLineNumberMap(List<PurchasingAccountsPayableItemAsset> itemLines) { Map validNumberMap = new HashMap<Integer, Integer>(); for (PurchasingAccountsPayableItemAsset item : itemLines) { if (item.getItemLineNumber() != null) { validNumberMap.put(item.getItemLineNumber(), item.getItemLineNumber()); } } return validNumberMap; } /** * For merge all, check if exists Trade-in allowance pending for allocate. * * @param mergeLines * @param purApForm */ protected void checkMergeAllValid(boolean tradeInAllowanceInAllLines, boolean tradeInIndicatorInSelectedLines) { if (tradeInAllowanceInAllLines && tradeInIndicatorInSelectedLines) { GlobalVariables.getMessageMap().putError(CabPropertyConstants.PurApLineForm.PURAP_DOCS, CabKeyConstants.ERROR_TRADE_IN_PENDING); } } /** * Check if merge lines selected are allowed to continue this action. Constraints include: merge lines must more than 1; no * additional charges pending for allocate. * * @param mergeLines * @param purApForm */ protected void checkMergeLinesValid(List<PurchasingAccountsPayableItemAsset> mergeLines, boolean tradeInAllowanceInAllLines, boolean tradeInIndicatorInSelectedLines) { if (mergeLines.size() <= 1) { GlobalVariables.getMessageMap().putError(CabPropertyConstants.PurApLineForm.PURAP_DOCS, CabKeyConstants.ERROR_MERGE_LINE_SELECTED); } else { // if merge for different document lines and that document has additional charge allocation pending, additional charges // should be allocated first. if (purApLineService.isAdditionalChargePending(mergeLines)) { GlobalVariables.getMessageMap().putError(CabPropertyConstants.PurApLineForm.PURAP_DOCS, CabKeyConstants.ERROR_ADDL_CHARGE_PENDING); } // if merge lines has indicator exists and trade-in allowance is pending for allocation, we will block this action. if (tradeInIndicatorInSelectedLines && tradeInAllowanceInAllLines) { GlobalVariables.getMessageMap().putError(CabPropertyConstants.PurApLineForm.PURAP_DOCS, CabKeyConstants.ERROR_TRADE_IN_PENDING); } } } /** * Check the required fields entered for merge. */ protected void checkMergeRequiredFields(PurApLineForm purApForm) { if (purApForm.getMergeQty() == null) { GlobalVariables.getMessageMap().putError(CabPropertyConstants.PurApLineForm.MERGE_QTY, CabKeyConstants.ERROR_MERGE_QTY_EMPTY); } if (StringUtils.isBlank(purApForm.getMergeDesc())) { GlobalVariables.getMessageMap().putError(CabPropertyConstants.PurApLineForm.MERGE_DESC, CabKeyConstants.ERROR_MERGE_DESCRIPTION_EMPTY); } } /** * Update the item quantity value from a decimal(less than 1) to 1. * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward percentPayment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { PurApLineForm purApform = (PurApLineForm) form; PurchasingAccountsPayableItemAsset itemAsset = getSelectedLineItem(purApform); if (itemAsset != null) { PurApLineSession purApLineSession = retrievePurApLineSession(purApform); purApLineService.processPercentPayment(itemAsset, purApLineSession.getActionsTakenHistory()); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Allocate line items including allocate additional charges functionality. * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward allocate(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { PurApLineForm purApForm = (PurApLineForm) form; PurchasingAccountsPayableItemAsset allocateSourceLine = getSelectedLineItem(purApForm); if (allocateSourceLine == null) { return mapping.findForward(KFSConstants.MAPPING_BASIC); } List<PurchasingAccountsPayableItemAsset> allocateTargetLines = purApLineService.getAllocateTargetLines(allocateSourceLine, purApForm.getPurApDocs()); Object question = request.getParameter(KRADConstants.QUESTION_INST_ATTRIBUTE_NAME); // logic for trade-in allowance question if (question != null) { Object buttonClicked = request.getParameter(KRADConstants.QUESTION_CLICKED_BUTTON); if ((CabConstants.TRADE_IN_INDICATOR_QUESTION.equals(question)) && ConfirmationQuestion.YES.equals(buttonClicked)) { if (purApLineService.allocateLinesHasDifferentObjectSubTypes(allocateTargetLines, allocateSourceLine)) { // check if objectSubTypes are different and bring the obj sub types warning message String warningMessage = generateObjectSubTypeQuestion(); return this.performQuestionWithoutInput(mapping, form, request, response, CabConstants.PAYMENT_DIFFERENT_OBJECT_SUB_TYPE_CONFIRMATION_QUESTION, warningMessage, KRADConstants.CONFIRMATION_QUESTION, CabConstants.Actions.ALLOCATE, ""); } else { performAllocate(purApForm, allocateSourceLine, allocateTargetLines); } } else if (CabConstants.PAYMENT_DIFFERENT_OBJECT_SUB_TYPE_CONFIRMATION_QUESTION.equals(question) && ConfirmationQuestion.YES.equals(buttonClicked)) { performAllocate(purApForm, allocateSourceLine, allocateTargetLines); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } boolean targetLineHasTradeIn = purApLineService.isTradeInIndExistInSelectedLines(allocateTargetLines); boolean hasTradeInAllowance = purApLineService.isTradeInAllowanceExist(purApForm.getPurApDocs()); // Check if this allocate is valid. validateAllocateAction(allocateSourceLine, allocateTargetLines, targetLineHasTradeIn, hasTradeInAllowance, purApForm.getPurApDocs()); if (GlobalVariables.getMessageMap().hasNoErrors()) { // TI indicator exists in either source or target lines, but TI allowance not found, bring up a warning message // to confirm this action. if (!allocateSourceLine.isAdditionalChargeNonTradeInIndicator() && !allocateSourceLine.isTradeInAllowance() && (allocateSourceLine.isItemAssignedToTradeInIndicator() || targetLineHasTradeIn) && hasTradeInAllowance) { return this.performQuestionWithoutInput(mapping, form, request, response, CabConstants.TRADE_IN_INDICATOR_QUESTION, SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(CabKeyConstants.QUESTION_TRADE_IN_INDICATOR_EXISTING), KRADConstants.CONFIRMATION_QUESTION, CabConstants.Actions.ALLOCATE, ""); } else if (purApLineService.allocateLinesHasDifferentObjectSubTypes(allocateTargetLines, allocateSourceLine)) { // check if objectSubTypes are different and bring the obj sub types warning message String warningMessage = generateObjectSubTypeQuestion(); return this.performQuestionWithoutInput(mapping, form, request, response, CabConstants.PAYMENT_DIFFERENT_OBJECT_SUB_TYPE_CONFIRMATION_QUESTION, warningMessage, KRADConstants.CONFIRMATION_QUESTION, CabConstants.Actions.ALLOCATE, ""); } else { performAllocate(purApForm, allocateSourceLine, allocateTargetLines); } } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Allocate with service help. * * @param purApForm * @param allocateSourceLine * @param allocateTargetLines */ protected void performAllocate(PurApLineForm purApForm, PurchasingAccountsPayableItemAsset allocateSourceLine, List<PurchasingAccountsPayableItemAsset> allocateTargetLines) { PurApLineSession purApLineSession = retrievePurApLineSession(purApForm); if (!purApLineService.processAllocate(allocateSourceLine, allocateTargetLines, purApLineSession.getActionsTakenHistory(), purApForm.getPurApDocs(), false)) { GlobalVariables.getMessageMap().putError(CabPropertyConstants.PurApLineForm.PURAP_DOCS, CabKeyConstants.ERROR_ALLOCATE_NO_TARGET_ACCOUNT); } else { purApLineSession.getProcessedItems().add(allocateSourceLine); // clear select check box purApLineService.resetSelectedValue(purApForm.getPurApDocs()); purApForm.setSelectAll(false); } } /** * Check if the line items are allowed to allocate. * * @param selectedLine * @param allocateTargetLines * @param purApForm */ protected void validateAllocateAction(PurchasingAccountsPayableItemAsset allocateSourceLine, List<PurchasingAccountsPayableItemAsset> allocateTargetLines, boolean targetLineHasTradeIn, boolean hasTradeInAllowance, List<PurchasingAccountsPayableDocument> purApDocs) { // if no target selected... if (allocateTargetLines.isEmpty()) { GlobalVariables.getMessageMap().putError(CabPropertyConstants.PurApLineForm.PURAP_DOCS, CabKeyConstants.ERROR_ALLOCATE_NO_LINE_SELECTED); } // For allocate trade-in allowance, additional charges(non trade-in) must be allocated before allocate trade-in. if (allocateSourceLine.isTradeInAllowance() && purApLineService.isAdditionalChargeExistInAllLines(purApDocs)) { GlobalVariables.getMessageMap().putError(CabPropertyConstants.PurApLineForm.PURAP_DOCS, CabKeyConstants.ERROR_ADDL_CHARGE_PENDING); } // For line item, we need to check... if (!allocateSourceLine.isAdditionalChargeNonTradeInIndicator() && !allocateSourceLine.isTradeInAllowance()) { allocateTargetLines.add(allocateSourceLine); // Pending additional charges(non trade-in) can't associate with either source line or target lines. if (purApLineService.isAdditionalChargePending(allocateTargetLines)) { GlobalVariables.getMessageMap().putError(CabPropertyConstants.PurApLineForm.PURAP_DOCS, CabKeyConstants.ERROR_ADDL_CHARGE_PENDING); } // For line item, check if trade-in allowance allocation pending. if (targetLineHasTradeIn && hasTradeInAllowance) { GlobalVariables.getMessageMap().putError(CabPropertyConstants.PurApLineForm.PURAP_DOCS, CabKeyConstants.ERROR_TRADE_IN_PENDING); } allocateTargetLines.remove(allocateSourceLine); } } /** * Get the user selected line item and set the link reference to document * * @param purApLineForm * @return */ private PurchasingAccountsPayableItemAsset getSelectedLineItem(PurApLineForm purApLineForm) { PurchasingAccountsPayableDocument purApDoc = purApLineForm.getPurApDocs().get(purApLineForm.getActionPurApDocIndex()); PurchasingAccountsPayableItemAsset selectedItem = purApDoc.getPurchasingAccountsPayableItemAssets().get(purApLineForm.getActionItemAssetIndex()); if (!selectedItem.isActive()) { selectedItem = null; } return selectedItem; } /** * Get the user selected document. * * @param purApLineForm * @return */ private PurchasingAccountsPayableDocument getSelectedPurApDoc(PurApLineForm purApLineForm) { return purApLineForm.getPurApDocs().get(purApLineForm.getActionPurApDocIndex()); } /** * Handle apply payment action. * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward applyPayment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { PurApLineForm purApForm = (PurApLineForm) form; PurchasingAccountsPayableItemAsset selectedLine = getSelectedLineItem(purApForm); if (selectedLine == null) { return mapping.findForward(KFSConstants.MAPPING_BASIC); } Object question = request.getParameter(KRADConstants.QUESTION_INST_ATTRIBUTE_NAME); if (question != null) { Object buttonClicked = request.getParameter(KRADConstants.QUESTION_CLICKED_BUTTON); if ((CabConstants.TRADE_IN_INDICATOR_QUESTION.equals(question)) && ConfirmationQuestion.YES.equals(buttonClicked)) { // create CAMS asset payment global document. return createApplyPaymentDocument(mapping, purApForm, selectedLine); } else { return mapping.findForward(KFSConstants.MAPPING_BASIC); } } if (selectedLine.isItemAssignedToTradeInIndicator()) { // TI indicator exists, bring up a warning message to confirm this action. return this.performQuestionWithoutInput(mapping, form, request, response, CabConstants.TRADE_IN_INDICATOR_QUESTION, SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(CabKeyConstants.QUESTION_TRADE_IN_INDICATOR_EXISTING), KRADConstants.CONFIRMATION_QUESTION, CabConstants.Actions.APPLY_PAYMENT, ""); } // create CAMS asset payment global document. return createApplyPaymentDocument(mapping, purApForm, selectedLine); } /** * Create CAMS asset payment document. * * @param mapping * @param purApForm * @param selectedLine * @param purApLineSession * @return * @throws WorkflowException */ private ActionForward createApplyPaymentDocument(ActionMapping mapping, PurApLineForm purApForm, PurchasingAccountsPayableItemAsset selectedLine) throws WorkflowException { PurApLineSession purApLineSession = retrievePurApLineSession(purApForm); String documentNumber; // create CAMS asset payment global document. if ((documentNumber = purApLineDocumentService.processApplyPayment(selectedLine, purApForm.getPurApDocs(), purApLineSession, purApForm.getRequisitionIdentifier())) != null) { purApForm.setDocumentNumber(documentNumber); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Handle create asset action. * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward createAsset(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { PurApLineForm purApForm = (PurApLineForm) form; PurchasingAccountsPayableItemAsset selectedLine = getSelectedLineItem(purApForm); if (selectedLine == null) { return mapping.findForward(KFSConstants.MAPPING_BASIC); } Object question = request.getParameter(KRADConstants.QUESTION_INST_ATTRIBUTE_NAME); if (question != null) { Object buttonClicked = request.getParameter(KRADConstants.QUESTION_CLICKED_BUTTON); if ((CabConstants.TRADE_IN_INDICATOR_QUESTION.equals(question)) && ConfirmationQuestion.YES.equals(buttonClicked)) { // If PurAp user set capitalAssetNumbers for apply Asset Payment document, bring up a warning message for // confirmation. if (isSettingAssetsInPurAp(selectedLine)) { return this.performQuestionWithoutInput(mapping, form, request, response, CabConstants.SKIP_ASSET_NUMBERS_TO_ASSET_GLOBAL_QUESTION, SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(CabKeyConstants.QUESTION_SKIP_ASSET_NUMBERS_TO_ASSET_GLOBAL), KRADConstants.CONFIRMATION_QUESTION, CabConstants.Actions.CREATE_ASSET, ""); } else { return createAssetGlobalDocument(mapping, purApForm, selectedLine); } } else if (CabConstants.SKIP_ASSET_NUMBERS_TO_ASSET_GLOBAL_QUESTION.equals(question) && ConfirmationQuestion.YES.equals(buttonClicked)) { return createAssetGlobalDocument(mapping, purApForm, selectedLine); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } // validate selected line item validateCreateAssetAction(selectedLine); if (GlobalVariables.getMessageMap().hasNoErrors()) { // TI indicator exists, bring up a warning message to confirm this action. if (selectedLine.isItemAssignedToTradeInIndicator()) { return this.performQuestionWithoutInput(mapping, form, request, response, CabConstants.TRADE_IN_INDICATOR_QUESTION, SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(CabKeyConstants.QUESTION_TRADE_IN_INDICATOR_EXISTING), KRADConstants.CONFIRMATION_QUESTION, CabConstants.Actions.CREATE_ASSET, ""); } // If PurAp user set capitalAssetNumbers for apply Asset Payment document, bring up a warning message to confirm using // Asset Global document. else if (isSettingAssetsInPurAp(selectedLine)) { return this.performQuestionWithoutInput(mapping, form, request, response, CabConstants.SKIP_ASSET_NUMBERS_TO_ASSET_GLOBAL_QUESTION, SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(CabKeyConstants.QUESTION_SKIP_ASSET_NUMBERS_TO_ASSET_GLOBAL), KRADConstants.CONFIRMATION_QUESTION, CabConstants.Actions.CREATE_ASSET, ""); } else { return createAssetGlobalDocument(mapping, purApForm, selectedLine); } } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * check if PurAp set CAMS Assets information * * @param selectedLine * @return */ private boolean isSettingAssetsInPurAp(PurchasingAccountsPayableItemAsset selectedLine) { return selectedLine.getPurApItemAssets() != null && !selectedLine.getPurApItemAssets().isEmpty(); } /** * Create asset global document * * @param mapping * @param purApForm * @param selectedLine * @param purApLineSession * @return * @throws WorkflowException */ private ActionForward createAssetGlobalDocument(ActionMapping mapping, PurApLineForm purApForm, PurchasingAccountsPayableItemAsset selectedLine) throws WorkflowException { PurApLineSession purApLineSession = retrievePurApLineSession(purApForm); String documentNumber = null; // create CAMS asset global document. if ((documentNumber = purApLineDocumentService.processCreateAsset(selectedLine, purApForm.getPurApDocs(), purApLineSession, purApForm.getRequisitionIdentifier())) != null) { // forward link to asset global purApForm.setDocumentNumber(documentNumber); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Validate selected line item for asset global creation. * * @param selectedLine */ protected void validateCreateAssetAction(PurchasingAccountsPayableItemAsset selectedLine) { KualiDecimal integerOne = new KualiDecimal(1); KualiDecimal quantity = selectedLine.getAccountsPayableItemQuantity(); // check if item quantity is a fractional value greater than 1. if (quantity.isGreaterThan(integerOne) && quantity.mod(integerOne).isNonZero()) { GlobalVariables.getMessageMap().putError(CabPropertyConstants.PurApLineForm.PURAP_DOCS, CabKeyConstants.ERROR_FRACTIONAL_QUANTITY); } // if quantity is between (0,1) , set it to 1. else if (quantity.isGreaterThan(KualiDecimal.ZERO) && quantity.isLessThan(integerOne)) { selectedLine.setAccountsPayableItemQuantity(integerOne); } } protected ParameterService getParameterService() { return (ParameterService) SpringContext.getBean(ParameterService.class); } protected ConfigurationService getConfigurationService() { return SpringContext.getBean(ConfigurationService.class); } }