0001: /*
0002: * Copyright 2007 The Kuali Foundation.
0003: *
0004: * Licensed under the Educational Community License, Version 1.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.opensource.org/licenses/ecl1.php
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016: package org.kuali.kfs.web.struts.action;
0017:
0018: import static org.kuali.kfs.KFSKeyConstants.ERROR_DOCUMENT_ACCOUNTING_LINE_SALES_TAX_INVALID_ACCOUNT;
0019: import static org.kuali.kfs.KFSKeyConstants.ERROR_DOCUMENT_ACCOUNTING_LINE_SALES_TAX_REQUIRED;
0020: import static org.kuali.kfs.KFSKeyConstants.ERROR_REQUIRED;
0021:
0022: import java.io.FileNotFoundException;
0023: import java.io.IOException;
0024: import java.util.Arrays;
0025: import java.util.HashMap;
0026: import java.util.HashSet;
0027: import java.util.Iterator;
0028: import java.util.List;
0029: import java.util.Map;
0030: import java.util.Properties;
0031: import java.util.Set;
0032:
0033: import javax.servlet.http.HttpServletRequest;
0034: import javax.servlet.http.HttpServletResponse;
0035:
0036: import org.apache.commons.lang.StringUtils;
0037: import org.apache.struts.action.ActionForm;
0038: import org.apache.struts.action.ActionForward;
0039: import org.apache.struts.action.ActionMapping;
0040: import org.apache.struts.upload.FormFile;
0041: import org.kuali.core.document.AmountTotaling;
0042: import org.kuali.core.service.BusinessObjectService;
0043: import org.kuali.core.service.DictionaryValidationService;
0044: import org.kuali.core.service.DocumentTypeService;
0045: import org.kuali.core.service.KualiRuleService;
0046: import org.kuali.core.service.PersistenceService;
0047: import org.kuali.core.util.GlobalVariables;
0048: import org.kuali.core.util.ObjectUtils;
0049: import org.kuali.core.util.Timer;
0050: import org.kuali.core.util.UrlFactory;
0051: import org.kuali.core.web.struts.action.KualiTransactionalDocumentActionBase;
0052: import org.kuali.core.web.struts.form.KualiDocumentFormBase;
0053: import org.kuali.core.workflow.service.WorkflowDocumentService;
0054: import org.kuali.kfs.KFSConstants;
0055: import org.kuali.kfs.KFSKeyConstants;
0056: import org.kuali.kfs.bo.AccountingLine;
0057: import org.kuali.kfs.bo.AccountingLineOverride;
0058: import org.kuali.kfs.bo.AccountingLineParser;
0059: import org.kuali.kfs.bo.SourceAccountingLine;
0060: import org.kuali.kfs.bo.TargetAccountingLine;
0061: import org.kuali.kfs.context.SpringContext;
0062: import org.kuali.kfs.document.AccountingDocument;
0063: import org.kuali.kfs.exceptions.AccountingLineParserException;
0064: import org.kuali.kfs.rule.event.AddAccountingLineEvent;
0065: import org.kuali.kfs.rule.event.DeleteAccountingLineEvent;
0066: import org.kuali.kfs.rule.event.UpdateAccountingLineEvent;
0067: import org.kuali.kfs.rules.AccountingDocumentRuleBaseConstants.APPLICATION_PARAMETER;
0068: import org.kuali.kfs.service.ParameterEvaluator;
0069: import org.kuali.kfs.service.ParameterService;
0070: import org.kuali.kfs.service.impl.ParameterConstants;
0071: import org.kuali.kfs.web.struts.form.KualiAccountingDocumentFormBase;
0072: import org.kuali.kfs.web.ui.AccountingLineDecorator;
0073: import org.kuali.module.financial.bo.SalesTax;
0074:
0075: import edu.iu.uis.eden.exception.WorkflowException;
0076:
0077: /**
0078: * This class handles UI actions for all shared methods of financial documents.
0079: */
0080: public class KualiAccountingDocumentActionBase extends
0081: KualiTransactionalDocumentActionBase {
0082: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
0083: .getLogger(KualiAccountingDocumentActionBase.class);
0084:
0085: /**
0086: * Adds check for accountingLine updates, generates and dispatches any events caused by such updates
0087: *
0088: * @see org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm,
0089: * javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
0090: */
0091: @Override
0092: public ActionForward execute(ActionMapping mapping,
0093: ActionForm form, HttpServletRequest request,
0094: HttpServletResponse response) throws Exception {
0095: Timer t0 = new Timer("KualiFinancialDocumentFormBase.execute");
0096: KualiAccountingDocumentFormBase transForm = (KualiAccountingDocumentFormBase) form;
0097:
0098: // handle changes to accountingLines
0099: if (transForm.hasDocumentId()) {
0100: AccountingDocument financialDocument = (AccountingDocument) transForm
0101: .getDocument();
0102:
0103: processAccountingLines(financialDocument, transForm,
0104: KFSConstants.SOURCE);
0105: processAccountingLines(financialDocument, transForm,
0106: KFSConstants.TARGET);
0107: }
0108:
0109: // This is after a potential handleUpdate(), to display automatically cleared overrides following a route or save.
0110: processAccountingLineOverrides(transForm);
0111:
0112: // this refershes if the accounting lines within the form are editable or not
0113: if (ObjectUtils.isNotNull(transForm.getDocument())
0114: && ObjectUtils.isNotNull(transForm.getDocument()
0115: .getDocumentHeader())
0116: && ObjectUtils.isNotNull(transForm.getDocument()
0117: .getDocumentNumber())
0118: && SpringContext.getBean(WorkflowDocumentService.class)
0119: .workflowDocumentExists(
0120: transForm.getDocument()
0121: .getDocumentNumber())) {
0122: transForm.refreshEditableAccounts();
0123: }
0124:
0125: // proceed as usual
0126: ActionForward result = super .execute(mapping, form, request,
0127: response);
0128: t0.log();
0129: return result;
0130: }
0131:
0132: /**
0133: * All document-creation gets routed through here
0134: *
0135: * @see org.kuali.core.web.struts.action.KualiDocumentActionBase#createDocument(org.kuali.core.web.struts.form.KualiDocumentFormBase)
0136: */
0137: @Override
0138: protected void createDocument(
0139: KualiDocumentFormBase kualiDocumentFormBase)
0140: throws WorkflowException {
0141: super .createDocument(kualiDocumentFormBase);
0142:
0143: KualiAccountingDocumentFormBase tform = (KualiAccountingDocumentFormBase) kualiDocumentFormBase;
0144:
0145: // reset baseline accountingLine lists
0146: tform.getBaselineSourceAccountingLines().clear();
0147: tform.getBaselineTargetAccountingLines().clear();
0148:
0149: // reset decorator lists
0150: tform.getSourceLineDecorators().clear();
0151: tform.getTargetLineDecorators().clear();
0152: }
0153:
0154: /**
0155: * All document-load operations get routed through here
0156: *
0157: * @see org.kuali.core.web.struts.action.KualiDocumentActionBase#loadDocument(org.kuali.core.web.struts.form.KualiDocumentFormBase)
0158: */
0159: @Override
0160: protected void loadDocument(
0161: KualiDocumentFormBase kualiDocumentFormBase)
0162: throws WorkflowException {
0163: super .loadDocument(kualiDocumentFormBase);
0164:
0165: KualiAccountingDocumentFormBase tform = (KualiAccountingDocumentFormBase) kualiDocumentFormBase;
0166:
0167: // populate baseline accountingLine lists
0168: List baselineSourceLines = tform
0169: .getBaselineSourceAccountingLines();
0170: baselineSourceLines.clear();
0171: baselineSourceLines.addAll(tform.getFinancialDocument()
0172: .getSourceAccountingLines());
0173: // sales tax handling
0174: handleSalesTaxRequiredAllLines(kualiDocumentFormBase,
0175: baselineSourceLines);
0176:
0177: List baselineTargetLines = tform
0178: .getBaselineTargetAccountingLines();
0179: baselineTargetLines.clear();
0180: baselineTargetLines.addAll(tform.getFinancialDocument()
0181: .getTargetAccountingLines());
0182: // sales tax handling
0183: handleSalesTaxRequiredAllLines(kualiDocumentFormBase,
0184: baselineTargetLines);
0185:
0186: // populate decorator lists
0187: tform.resetSourceLineDecorators(baselineSourceLines.size());
0188: tform.resetTargetLineDecorators(baselineTargetLines.size());
0189:
0190: // clear out the new accounting line holders
0191: tform.setNewSourceLine(null);
0192: tform.setNewTargetLine(null);
0193:
0194: processAccountingLineOverrides(tform);
0195: }
0196:
0197: /**
0198: * Needed to override this to keep from losing Sales Tax information
0199: *
0200: * @see org.kuali.core.web.struts.action.KualiAction#refresh(org.apache.struts.action.ActionMapping,
0201: * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
0202: */
0203: @Override
0204: public ActionForward refresh(ActionMapping mapping,
0205: ActionForm form, HttpServletRequest request,
0206: HttpServletResponse response) throws Exception {
0207: super .refresh(mapping, form, request, response);
0208: refreshSalesTaxInfo(form);
0209:
0210: return mapping.findForward(KFSConstants.MAPPING_BASIC);
0211: }
0212:
0213: /**
0214: * Needed to override this to keep from losing Sales Tax information
0215: *
0216: * @see org.kuali.core.web.struts.action.KualiAction#toggleTab(org.apache.struts.action.ActionMapping,
0217: * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
0218: */
0219: @Override
0220: public ActionForward toggleTab(ActionMapping mapping,
0221: ActionForm form, HttpServletRequest request,
0222: HttpServletResponse response) throws Exception {
0223: super .toggleTab(mapping, form, request, response);
0224: refreshSalesTaxInfo(form);
0225:
0226: return mapping.findForward(KFSConstants.MAPPING_BASIC);
0227: }
0228:
0229: // Set of actions for which updateEvents should be generated
0230: protected static final Set UPDATE_EVENT_ACTIONS;
0231: static {
0232: String[] updateEventActions = { KFSConstants.SAVE_METHOD,
0233: KFSConstants.ROUTE_METHOD, KFSConstants.APPROVE_METHOD,
0234: KFSConstants.BLANKET_APPROVE_METHOD };
0235: UPDATE_EVENT_ACTIONS = new HashSet();
0236: for (int i = 0; i < updateEventActions.length; ++i) {
0237: UPDATE_EVENT_ACTIONS.add(updateEventActions[i]);
0238: }
0239: }
0240:
0241: /**
0242: * @param transForm
0243: */
0244: protected void processAccountingLineOverrides(
0245: KualiAccountingDocumentFormBase transForm) {
0246: processAccountingLineOverrides(transForm.getNewSourceLine());
0247: processAccountingLineOverrides(transForm.getNewTargetLine());
0248: if (transForm.hasDocumentId()) {
0249: AccountingDocument financialDocument = (AccountingDocument) transForm
0250: .getDocument();
0251:
0252: processAccountingLineOverrides(financialDocument
0253: .getSourceAccountingLines());
0254: processAccountingLineOverrides(financialDocument
0255: .getTargetAccountingLines());
0256: }
0257: }
0258:
0259: /**
0260: * @param line
0261: */
0262: protected void processAccountingLineOverrides(AccountingLine line) {
0263: processAccountingLineOverrides(Arrays
0264: .asList(new AccountingLine[] { line }));
0265: }
0266:
0267: /**
0268: * @param accountingLines
0269: */
0270: protected void processAccountingLineOverrides(List accountingLines) {
0271: if (!accountingLines.isEmpty()) {
0272: SpringContext.getBean(PersistenceService.class)
0273: .retrieveReferenceObjects(accountingLines,
0274: AccountingLineOverride.REFRESH_FIELDS);
0275:
0276: for (Iterator i = accountingLines.iterator(); i.hasNext();) {
0277: AccountingLine line = (AccountingLine) i.next();
0278: AccountingLineOverride.processForOutput(line);
0279: }
0280: }
0281: }
0282:
0283: /**
0284: * @param transDoc
0285: * @param transForm
0286: * @param lineSet
0287: */
0288: private void processAccountingLines(AccountingDocument transDoc,
0289: KualiAccountingDocumentFormBase transForm, String lineSet) {
0290: // figure out which set of lines we're looking at
0291: List baseLines;
0292: List formLines;
0293: List<AccountingLineDecorator> decorators;
0294: String pathPrefix;
0295: boolean source;
0296: if (lineSet.equals(KFSConstants.SOURCE)) {
0297: baseLines = transForm.getBaselineSourceAccountingLines();
0298: formLines = transDoc.getSourceAccountingLines();
0299: decorators = transForm.getSourceLineDecorators(formLines
0300: .size());
0301: pathPrefix = KFSConstants.DOCUMENT_PROPERTY_NAME
0302: + "."
0303: + KFSConstants.EXISTING_SOURCE_ACCT_LINE_PROPERTY_NAME;
0304: source = true;
0305: } else {
0306: baseLines = transForm.getBaselineTargetAccountingLines();
0307: formLines = transDoc.getTargetAccountingLines();
0308: decorators = transForm.getTargetLineDecorators(formLines
0309: .size());
0310: pathPrefix = KFSConstants.DOCUMENT_PROPERTY_NAME
0311: + "."
0312: + KFSConstants.EXISTING_TARGET_ACCT_LINE_PROPERTY_NAME;
0313: source = false;
0314: }
0315:
0316: Map baseLineMap = new HashMap();
0317: for (Iterator i = baseLines.iterator(); i.hasNext();) {
0318: AccountingLine baseLine = (AccountingLine) i.next();
0319: baseLineMap.put(baseLine.getSequenceNumber(), baseLine);
0320: }
0321:
0322: // find and process corresponding form and baselines
0323: int index = 0;
0324: for (Iterator i = formLines.iterator(); i.hasNext(); index++) {
0325: AccountingLine formLine = (AccountingLine) i.next();
0326: AccountingLine baseLine = (AccountingLine) baseLineMap
0327: .get(formLine.getSequenceNumber());
0328: AccountingLineDecorator decorator = decorators.get(index);
0329:
0330: // always update decorator
0331: handleDecorator(formLine, baseLine, decorator);
0332:
0333: // update sales tax required attribute for view
0334: // handleSalesTaxRequired(transDoc, formLine, source, false, index);
0335: checkSalesTax(transDoc, formLine, source, false, index);
0336: if (baseLine != null) {
0337: handleSalesTaxRequired(transDoc, baseLine, source,
0338: false, index);
0339: // checkSalesTax(transDoc, baseLine, source, false, index);
0340: }
0341:
0342: // only generate update events for specific action methods
0343: String methodToCall = transForm.getMethodToCall();
0344: if (UPDATE_EVENT_ACTIONS.contains(methodToCall)) {
0345: handleUpdate(transDoc, pathPrefix + "[" + index + "]",
0346: formLine, baseLine);
0347: }
0348: }
0349: }
0350:
0351: /**
0352: * @param formLine
0353: * @param baseLine
0354: * @param decorator
0355: */
0356: private void handleDecorator(AccountingLine formLine,
0357: AccountingLine baseLine, AccountingLineDecorator decorator) {
0358: // if line is new, or line hasn't changed, make non-revertible;
0359: // otherwise, revertible
0360: if ((baseLine == null) || formLine.isLike(baseLine)) {
0361: decorator.setRevertible(false);
0362: } else {
0363: decorator.setRevertible(true);
0364: }
0365: }
0366:
0367: /**
0368: * @param transDoc
0369: * @param errorPathPrefix
0370: * @param formLine
0371: * @param baseLine
0372: */
0373: private void handleUpdate(AccountingDocument transDoc,
0374: String errorPathPrefix, AccountingLine formLine,
0375: AccountingLine baseLine) {
0376: if ((baseLine != null) && !formLine.isLike(baseLine)) {
0377: // reluctantly refresh BOs for clearOverridesThatBecameUnneeded()
0378: formLine.refreshNonUpdateableReferences();
0379: clearOverridesThatBecameUnneeded(formLine);
0380: // the rule itself is responsible for adding error messages to the global ErrorMap
0381: SpringContext.getBean(KualiRuleService.class).applyRules(
0382: new UpdateAccountingLineEvent(errorPathPrefix,
0383: transDoc, baseLine, formLine));
0384: }
0385: }
0386:
0387: /**
0388: * Automatically clears any overrides that have become unneeded. This is for accounting lines that were changed right before
0389: * final actions like route. Normally the unneeded overrides are cleared in accountingLineOverrideField.tag instead, but that
0390: * requires another form submit. This method shouldn't be called on lines that haven't changed, to avoid automatically changing
0391: * read-only lines. This cannot be done in the Rule because Rules cannot change the AccountingLines; they only get a deepCopy.
0392: *
0393: * @param formLine
0394: */
0395: protected void clearOverridesThatBecameUnneeded(
0396: AccountingLine formLine) {
0397: AccountingLineOverride currentlyNeeded = AccountingLineOverride
0398: .determineNeededOverrides(formLine);
0399: AccountingLineOverride currentOverride = AccountingLineOverride
0400: .valueOf(formLine.getOverrideCode());
0401: if (!currentOverride.isValidMask(currentlyNeeded)) {
0402: // todo: handle unsupported combinations of overrides (not a problem until we allow certain multiple overrides)
0403: }
0404: formLine.setOverrideCode(currentOverride.mask(currentlyNeeded)
0405: .getCode());
0406: }
0407:
0408: /**
0409: * This method will revert a TargetAccountingLine by overwriting its current values with the values in the corresponding
0410: * baseline accountingLine. This assumes that the user presses the revert button for a specific accounting line on the document
0411: * and that the document is represented by a FinancialDocumentFormBase.
0412: *
0413: * @param mapping
0414: * @param form
0415: * @param request
0416: * @param response
0417: * @return ActionForward
0418: * @throws Exception
0419: */
0420: public ActionForward revertTargetLine(ActionMapping mapping,
0421: ActionForm form, HttpServletRequest request,
0422: HttpServletResponse response) throws Exception {
0423: KualiAccountingDocumentFormBase financialDocumentForm = (KualiAccountingDocumentFormBase) form;
0424: AccountingDocument financialDocument = (AccountingDocument) financialDocumentForm
0425: .getDocument();
0426:
0427: int revertIndex = getSelectedLine(request);
0428:
0429: TargetAccountingLine originalLine = financialDocumentForm
0430: .getBaselineTargetAccountingLine(revertIndex);
0431: TargetAccountingLine brokenLine = financialDocument
0432: .getTargetAccountingLine(revertIndex);
0433:
0434: if (revertAccountingLine(financialDocumentForm, revertIndex,
0435: originalLine, brokenLine)) {
0436: financialDocumentForm.getTargetLineDecorator(revertIndex)
0437: .setRevertible(false);
0438: }
0439:
0440: // no business rules to check, no events to create
0441:
0442: return mapping.findForward(KFSConstants.MAPPING_BASIC);
0443: }
0444:
0445: /**
0446: * This method will revert a SourceAccountingLine by overwriting its current values with the values in the corresponding
0447: * baseline accountingLine. This assumes that the user presses the revert button for a specific accounting line on the document
0448: * and that the document is represented by a FinancialDocumentFormBase.
0449: *
0450: * @param mapping
0451: * @param form
0452: * @param request
0453: * @param response
0454: * @return ActionForward
0455: * @throws Exception
0456: */
0457: public ActionForward revertSourceLine(ActionMapping mapping,
0458: ActionForm form, HttpServletRequest request,
0459: HttpServletResponse response) throws Exception {
0460: KualiAccountingDocumentFormBase financialDocumentForm = (KualiAccountingDocumentFormBase) form;
0461: AccountingDocument financialDocument = (AccountingDocument) financialDocumentForm
0462: .getDocument();
0463:
0464: int revertIndex = getSelectedLine(request);
0465:
0466: SourceAccountingLine originalLine = financialDocumentForm
0467: .getBaselineSourceAccountingLine(revertIndex);
0468: SourceAccountingLine brokenLine = financialDocument
0469: .getSourceAccountingLine(revertIndex);
0470:
0471: if (revertAccountingLine(financialDocumentForm, revertIndex,
0472: originalLine, brokenLine)) {
0473: financialDocumentForm.getSourceLineDecorator(revertIndex)
0474: .setRevertible(false);
0475: }
0476:
0477: // no business rules to check, no events to create
0478:
0479: return mapping.findForward(KFSConstants.MAPPING_BASIC);
0480: }
0481:
0482: /**
0483: * Overwrites field values in the given brokenLine with those in the given originalLine, if the two accountingLines differ.
0484: *
0485: * @param transForm
0486: * @param revertIndex
0487: * @param originalLine
0488: * @param newerLine
0489: * @return true if and only if the brokenLine was actually changed
0490: */
0491: protected boolean revertAccountingLine(
0492: KualiAccountingDocumentFormBase transForm, int revertIndex,
0493: AccountingLine originalLine, AccountingLine newerLine) {
0494: boolean reverted = false;
0495:
0496: SpringContext.getBean(PersistenceService.class)
0497: .refreshAllNonUpdatingReferences(originalLine);
0498:
0499: // *always* revert (so that if someone manually changes the line to its original values, then hits revert, they won't get an
0500: // error message saying "couldn't revert")
0501: newerLine.copyFrom(originalLine);
0502: if (isSalesTaxRequired((AccountingDocument) transForm
0503: .getDocument(), newerLine)) {
0504: newerLine.setSalesTaxRequired(true);
0505: }
0506: reverted = true;
0507: GlobalVariables.getMessageList().add(
0508: KFSKeyConstants.MESSAGE_REVERT_SUCCESSFUL);
0509:
0510: return reverted;
0511: }
0512:
0513: /**
0514: * This method will remove a TargetAccountingLine from a FinancialDocument. This assumes that the user presses the delete button
0515: * for a specific accounting line on the document and that the document is represented by a FinancialDocumentFormBase.
0516: *
0517: * @param mapping
0518: * @param form
0519: * @param request
0520: * @param response
0521: * @return ActionForward
0522: * @throws Exception
0523: */
0524: public ActionForward deleteTargetLine(ActionMapping mapping,
0525: ActionForm form, HttpServletRequest request,
0526: HttpServletResponse response) throws Exception {
0527: KualiAccountingDocumentFormBase financialDocumentForm = (KualiAccountingDocumentFormBase) form;
0528:
0529: boolean rulePassed = false;
0530: int deleteIndex = getLineToDelete(request);
0531: String errorPath = KFSConstants.DOCUMENT_PROPERTY_NAME + "."
0532: + KFSConstants.EXISTING_TARGET_ACCT_LINE_PROPERTY_NAME
0533: + "[" + deleteIndex + "]";
0534:
0535: // check business rule, if there is a baseline copy
0536: // (accountingLines without baselines haven't been persisted yet, so they can safely be deleted)
0537: if (financialDocumentForm
0538: .hasBaselineTargetAccountingLine(deleteIndex)) {
0539: TargetAccountingLine baseline = financialDocumentForm
0540: .getBaselineTargetAccountingLine(deleteIndex);
0541: SpringContext.getBean(PersistenceService.class)
0542: .refreshAllNonUpdatingReferences(baseline);
0543:
0544: rulePassed = SpringContext
0545: .getBean(KualiRuleService.class)
0546: .applyRules(
0547: new DeleteAccountingLineEvent(
0548: errorPath,
0549: financialDocumentForm.getDocument(),
0550: baseline, false));
0551: } else {
0552: rulePassed = true;
0553: }
0554:
0555: // if the rule evaluation passed, let's delete it
0556: if (rulePassed) {
0557: deleteAccountingLine(false, financialDocumentForm,
0558: deleteIndex);
0559: } else {
0560: financialDocumentForm.getTargetLineDecorator(deleteIndex)
0561: .setRevertible(true);
0562:
0563: String[] errorParams = new String[] { "target",
0564: Integer.toString(deleteIndex + 1) };
0565: GlobalVariables
0566: .getErrorMap()
0567: .putError(
0568: errorPath,
0569: KFSKeyConstants.ERROR_ACCOUNTINGLINE_DELETERULE_INVALIDACCOUNT,
0570: errorParams);
0571: }
0572:
0573: return mapping.findForward(KFSConstants.MAPPING_BASIC);
0574: }
0575:
0576: /**
0577: * This method will remove a SourceAccountingLine from a FinancialDocument. This assumes that the user presses the delete button
0578: * for a specific accounting line on the document and that the document is represented by a FinancialDocumentFormBase.
0579: *
0580: * @param mapping
0581: * @param form
0582: * @param request
0583: * @param response
0584: * @return ActionForward
0585: * @throws Exception
0586: */
0587: public ActionForward deleteSourceLine(ActionMapping mapping,
0588: ActionForm form, HttpServletRequest request,
0589: HttpServletResponse response) throws Exception {
0590: KualiAccountingDocumentFormBase financialDocumentForm = (KualiAccountingDocumentFormBase) form;
0591:
0592: boolean rulePassed = false;
0593: int deleteIndex = getLineToDelete(request);
0594: String errorPath = KFSConstants.DOCUMENT_PROPERTY_NAME + "."
0595: + KFSConstants.EXISTING_SOURCE_ACCT_LINE_PROPERTY_NAME
0596: + "[" + deleteIndex + "]";
0597:
0598: // check business rule, if there is a baseline copy
0599: // (accountingLines without baselines haven't been persisted yet, so they can safely be deleted)
0600: if (financialDocumentForm
0601: .hasBaselineSourceAccountingLine(deleteIndex)) {
0602: SourceAccountingLine baseline = financialDocumentForm
0603: .getBaselineSourceAccountingLine(deleteIndex);
0604: SpringContext.getBean(PersistenceService.class)
0605: .refreshAllNonUpdatingReferences(baseline);
0606:
0607: rulePassed = SpringContext
0608: .getBean(KualiRuleService.class)
0609: .applyRules(
0610: new DeleteAccountingLineEvent(
0611: errorPath,
0612: financialDocumentForm.getDocument(),
0613: baseline, false));
0614: } else {
0615: rulePassed = true;
0616: }
0617:
0618: // if the rule evaluation passed, let's delete it
0619: if (rulePassed) {
0620: deleteAccountingLine(true, financialDocumentForm,
0621: deleteIndex);
0622: } else {
0623: financialDocumentForm.getSourceLineDecorator(deleteIndex)
0624: .setRevertible(true);
0625:
0626: String[] errorParams = new String[] { "source",
0627: Integer.toString(deleteIndex + 1) };
0628: GlobalVariables
0629: .getErrorMap()
0630: .putError(
0631: errorPath,
0632: KFSKeyConstants.ERROR_ACCOUNTINGLINE_DELETERULE_INVALIDACCOUNT,
0633: errorParams);
0634: }
0635:
0636: return mapping.findForward(KFSConstants.MAPPING_BASIC);
0637: }
0638:
0639: /**
0640: * Deletes the source or target accountingLine with the given index from the given form. Assumes that the rule- and form-
0641: * validation have already occurred.
0642: *
0643: * @param isSource
0644: * @param financialDocumentForm
0645: * @param deleteIndex
0646: */
0647: protected void deleteAccountingLine(boolean isSource,
0648: KualiAccountingDocumentFormBase financialDocumentForm,
0649: int deleteIndex) {
0650: if (isSource) {
0651: // remove from document
0652: financialDocumentForm.getFinancialDocument()
0653: .getSourceAccountingLines().remove(deleteIndex);
0654:
0655: // remove baseline duplicate and decorator
0656: if (deleteIndex < financialDocumentForm
0657: .getBaselineSourceAccountingLines().size()) {
0658: financialDocumentForm
0659: .getBaselineSourceAccountingLines().remove(
0660: deleteIndex);
0661: }
0662: financialDocumentForm.getSourceLineDecorators().remove(
0663: deleteIndex);
0664:
0665: // update the doc total
0666: AccountingDocument tdoc = (AccountingDocument) financialDocumentForm
0667: .getDocument();
0668: if (tdoc instanceof AmountTotaling)
0669: financialDocumentForm.getDocument().getDocumentHeader()
0670: .setFinancialDocumentTotalAmount(
0671: ((AmountTotaling) tdoc)
0672: .getTotalDollarAmount());
0673: } else {
0674: // remove from document
0675: financialDocumentForm.getFinancialDocument()
0676: .getTargetAccountingLines().remove(deleteIndex);
0677:
0678: // remove baseline duplicate and decorator
0679: if (deleteIndex < financialDocumentForm
0680: .getBaselineTargetAccountingLines().size()) {
0681: financialDocumentForm
0682: .getBaselineTargetAccountingLines().remove(
0683: deleteIndex);
0684: }
0685: financialDocumentForm.getTargetLineDecorators().remove(
0686: deleteIndex);
0687: }
0688: }
0689:
0690: /**
0691: * This action executes a call to upload CSV accounting line values as TargetAccountingLines for a given transactional document.
0692: * The "uploadAccountingLines()" method handles the multi-part request.
0693: *
0694: * @param mapping
0695: * @param form
0696: * @param request
0697: * @param response
0698: * @return ActionForward
0699: * @throws Exception
0700: */
0701: public ActionForward uploadTargetLines(ActionMapping mapping,
0702: ActionForm form, HttpServletRequest request,
0703: HttpServletResponse response) throws Exception {
0704:
0705: // call method that sourceform and destination list
0706: uploadAccountingLines(false, form);
0707:
0708: return mapping.findForward(KFSConstants.MAPPING_BASIC);
0709: }
0710:
0711: /**
0712: * This action executes a call to upload CSV accounting line values as SourceAccountingLines for a given transactional document.
0713: * The "uploadAccountingLines()" method handles the multi-part request.
0714: *
0715: * @param mapping
0716: * @param form
0717: * @param request
0718: * @param response
0719: * @return ActionForward
0720: * @throws FileNotFoundException
0721: * @throws IOException
0722: */
0723: public ActionForward uploadSourceLines(ActionMapping mapping,
0724: ActionForm form, HttpServletRequest request,
0725: HttpServletResponse response) throws FileNotFoundException,
0726: IOException {
0727: LOG.info("Uploading source accounting lines");
0728: // call method that sourceform and destination list
0729: uploadAccountingLines(true, form);
0730:
0731: return mapping.findForward(KFSConstants.MAPPING_BASIC);
0732: }
0733:
0734: /**
0735: * This method determines whether we are uploading source or target lines, and then calls uploadAccountingLines directly on the
0736: * document object. This method handles retrieving the actual upload file as an input stream into the document.
0737: *
0738: * @param isSource
0739: * @param form
0740: * @throws FileNotFoundException
0741: * @throws IOException
0742: */
0743: protected void uploadAccountingLines(boolean isSource,
0744: ActionForm form) throws FileNotFoundException, IOException {
0745: KualiAccountingDocumentFormBase tmpForm = (KualiAccountingDocumentFormBase) form;
0746:
0747: List importedLines = null;
0748:
0749: AccountingDocument financialDocument = tmpForm
0750: .getFinancialDocument();
0751: AccountingLineParser accountingLineParser = financialDocument
0752: .getAccountingLineParser();
0753:
0754: // import the lines
0755: String errorPathPrefix = null;
0756: try {
0757: if (isSource) {
0758: errorPathPrefix = KFSConstants.DOCUMENT_PROPERTY_NAME
0759: + "."
0760: + KFSConstants.SOURCE_ACCOUNTING_LINE_ERRORS;
0761: FormFile sourceFile = tmpForm.getSourceFile();
0762: checkUploadFile(sourceFile);
0763: importedLines = accountingLineParser
0764: .importSourceAccountingLines(sourceFile
0765: .getFileName(), sourceFile
0766: .getInputStream(), financialDocument);
0767: } else {
0768: errorPathPrefix = KFSConstants.DOCUMENT_PROPERTY_NAME
0769: + "."
0770: + KFSConstants.TARGET_ACCOUNTING_LINE_ERRORS;
0771: FormFile targetFile = tmpForm.getTargetFile();
0772: checkUploadFile(targetFile);
0773: importedLines = accountingLineParser
0774: .importTargetAccountingLines(targetFile
0775: .getFileName(), targetFile
0776: .getInputStream(), financialDocument);
0777: }
0778: } catch (AccountingLineParserException e) {
0779: GlobalVariables.getErrorMap().putError(errorPathPrefix,
0780: e.getErrorKey(), e.getErrorParameters());
0781: }
0782:
0783: // add line to list for those lines which were successfully imported
0784: if (importedLines != null) {
0785: for (Iterator i = importedLines.iterator(); i.hasNext();) {
0786: AccountingLine importedLine = (AccountingLine) i.next();
0787: insertAccountingLine(isSource, tmpForm, importedLine);
0788: }
0789: }
0790: }
0791:
0792: private void checkUploadFile(FormFile file) {
0793: if (file == null) {
0794: throw new AccountingLineParserException(
0795: "invalid (null) upload file",
0796: KFSKeyConstants.ERROR_UPLOADFILE_NULL);
0797: }
0798: }
0799:
0800: /**
0801: * This method will add a TargetAccountingLine to a FinancialDocument. This assumes that the user presses the add button for a
0802: * specific accounting line on the document and that the document is represented by a FinancialDocumentFormBase. It first
0803: * validates the line for data integrity and then checks appropriate business rules.
0804: *
0805: * @param mapping
0806: * @param form
0807: * @param request
0808: * @param response
0809: * @return ActionForward
0810: * @throws Exception
0811: */
0812: public ActionForward insertTargetLine(ActionMapping mapping,
0813: ActionForm form, HttpServletRequest request,
0814: HttpServletResponse response) throws Exception {
0815: KualiAccountingDocumentFormBase financialDocumentForm = (KualiAccountingDocumentFormBase) form;
0816:
0817: TargetAccountingLine line = financialDocumentForm
0818: .getNewTargetLine();
0819: boolean rulePassed = true;
0820: // before we check the regular rules we need to check the sales tax rules
0821: // TODO: Refactor rules so we no longer have to call this before a copy of the
0822: // accountingLine
0823: rulePassed &= checkSalesTax(
0824: (AccountingDocument) financialDocumentForm
0825: .getDocument(), line, false, true, 0);
0826:
0827: // check any business rules
0828: rulePassed &= SpringContext
0829: .getBean(KualiRuleService.class)
0830: .applyRules(
0831: new AddAccountingLineEvent(
0832: KFSConstants.NEW_TARGET_ACCT_LINE_PROPERTY_NAME,
0833: financialDocumentForm.getDocument(),
0834: line));
0835:
0836: // if the rule evaluation passed, let's add it
0837: if (rulePassed) {
0838: // add accountingLine
0839: SpringContext.getBean(PersistenceService.class)
0840: .refreshAllNonUpdatingReferences(line);
0841: insertAccountingLine(false, financialDocumentForm, line);
0842:
0843: // clear the used newTargetLine
0844: financialDocumentForm.setNewTargetLine(null);
0845: }
0846:
0847: return mapping.findForward(KFSConstants.MAPPING_BASIC);
0848: }
0849:
0850: /**
0851: * This action executes an insert of a SourceAccountingLine into a document only after validating the accounting line and
0852: * checking any appropriate business rules.
0853: *
0854: * @param mapping
0855: * @param form
0856: * @param request
0857: * @param response
0858: * @return ActionForward
0859: * @throws Exception
0860: */
0861: public ActionForward insertSourceLine(ActionMapping mapping,
0862: ActionForm form, HttpServletRequest request,
0863: HttpServletResponse response) throws Exception {
0864: KualiAccountingDocumentFormBase financialDocumentForm = (KualiAccountingDocumentFormBase) form;
0865:
0866: SourceAccountingLine line = financialDocumentForm
0867: .getNewSourceLine();
0868: boolean rulePassed = true;
0869: // before we check the regular rules we need to check the sales tax rules
0870: // TODO: Refactor rules so we no longer have to call this before a copy of the
0871: // accountingLine
0872: rulePassed &= checkSalesTax(
0873: (AccountingDocument) financialDocumentForm
0874: .getDocument(), line, true, true, 0);
0875: // check any business rules
0876: rulePassed &= SpringContext
0877: .getBean(KualiRuleService.class)
0878: .applyRules(
0879: new AddAccountingLineEvent(
0880: KFSConstants.NEW_SOURCE_ACCT_LINE_PROPERTY_NAME,
0881: financialDocumentForm.getDocument(),
0882: line));
0883:
0884: if (rulePassed) {
0885: // add accountingLine
0886: SpringContext.getBean(PersistenceService.class)
0887: .refreshAllNonUpdatingReferences(line);
0888: insertAccountingLine(true, financialDocumentForm, line);
0889:
0890: // clear the used newTargetLine
0891: financialDocumentForm.setNewSourceLine(null);
0892: }
0893:
0894: return mapping.findForward(KFSConstants.MAPPING_BASIC);
0895: }
0896:
0897: /**
0898: * Adds the given accountingLine to the appropriate form-related datastructures.
0899: *
0900: * @param isSource
0901: * @param financialDocumentForm
0902: * @param line
0903: */
0904: protected void insertAccountingLine(boolean isSource,
0905: KualiAccountingDocumentFormBase financialDocumentForm,
0906: AccountingLine line) {
0907: // create and init a decorator
0908: AccountingLineDecorator decorator = new AccountingLineDecorator();
0909: decorator.setRevertible(false);
0910:
0911: AccountingDocument tdoc = financialDocumentForm
0912: .getFinancialDocument();
0913: if (isSource) {
0914: // add it to the document
0915: tdoc.addSourceAccountingLine((SourceAccountingLine) line);
0916:
0917: // add it to the baseline, to prevent generation of spurious update events
0918: financialDocumentForm.getBaselineSourceAccountingLines()
0919: .add(line);
0920:
0921: // add the decorator
0922: financialDocumentForm.getSourceLineDecorators().add(
0923: decorator);
0924:
0925: // add PK fields to sales tax if needed
0926: if (line.isSalesTaxRequired()) {
0927: populateSalesTax(line);
0928: }
0929:
0930: // Update the doc total
0931: if (tdoc instanceof AmountTotaling)
0932: financialDocumentForm.getDocument().getDocumentHeader()
0933: .setFinancialDocumentTotalAmount(
0934: ((AmountTotaling) tdoc)
0935: .getTotalDollarAmount());
0936: } else {
0937: // add it to the document
0938: tdoc.addTargetAccountingLine((TargetAccountingLine) line);
0939:
0940: // add it to the baseline, to prevent generation of spurious update events
0941: financialDocumentForm.getBaselineTargetAccountingLines()
0942: .add(line);
0943:
0944: // add the decorator
0945: financialDocumentForm.getTargetLineDecorators().add(
0946: decorator);
0947:
0948: // add PK fields to sales tax if needed
0949: if (line.isSalesTaxRequired()) {
0950: populateSalesTax(line);
0951: }
0952: }
0953: }
0954:
0955: /**
0956: * Method that will take the current document, copy it, replace all references to doc header id with a new one, clear pending
0957: * entries, clear notes, and reset version numbers
0958: *
0959: * @param mapping
0960: * @param form
0961: * @param request
0962: * @param response
0963: * @return
0964: * @throws Exception
0965: */
0966: public ActionForward copy(ActionMapping mapping, ActionForm form,
0967: HttpServletRequest request, HttpServletResponse response)
0968: throws Exception {
0969: super .copy(mapping, form, request, response);
0970:
0971: KualiAccountingDocumentFormBase tmpForm = (KualiAccountingDocumentFormBase) form;
0972:
0973: // KULEDOCS-1440: need to reset base accounting lines since when doc number changes on copy base lines would still reference
0974: // old doc number causing revert button to show up
0975: tmpForm.setBaselineSourceAccountingLines(tmpForm
0976: .getFinancialDocument().getSourceAccountingLines());
0977: tmpForm.setBaselineTargetAccountingLines(tmpForm
0978: .getFinancialDocument().getTargetAccountingLines());
0979: tmpForm.getSourceLineDecorators().clear();
0980: tmpForm.getTargetLineDecorators().clear();
0981:
0982: return mapping.findForward(KFSConstants.MAPPING_BASIC);
0983: }
0984:
0985: /**
0986: * This action changes the value of the hide field in the user interface so that when the page is rendered, the UI knows to show
0987: * all of the labels for each of the accounting line values.
0988: *
0989: * @param mapping
0990: * @param form
0991: * @param request
0992: * @param response
0993: * @return ActionForward
0994: * @throws Exception
0995: */
0996: public ActionForward showDetails(ActionMapping mapping,
0997: ActionForm form, HttpServletRequest request,
0998: HttpServletResponse response) throws Exception {
0999: KualiAccountingDocumentFormBase tmpForm = (KualiAccountingDocumentFormBase) form;
1000: tmpForm.setHideDetails(false);
1001: return mapping.findForward(KFSConstants.MAPPING_BASIC);
1002: }
1003:
1004: /**
1005: * This method is triggered when the user toggles the show/hide button to "hide" thus making the UI render without any of the
1006: * accounting line labels/descriptions showing up underneath the values in the UI.
1007: *
1008: * @param mapping
1009: * @param form
1010: * @param request
1011: * @param response
1012: * @return ActionForward
1013: * @throws Exception
1014: */
1015: public ActionForward hideDetails(ActionMapping mapping,
1016: ActionForm form, HttpServletRequest request,
1017: HttpServletResponse response) throws Exception {
1018: KualiAccountingDocumentFormBase tmpForm = (KualiAccountingDocumentFormBase) form;
1019: tmpForm.setHideDetails(true);
1020: return mapping.findForward(KFSConstants.MAPPING_BASIC);
1021: }
1022:
1023: /**
1024: * Takes care of storing the action form in the User session and forwarding to the balance inquiry report menu action for a
1025: * source accounting line.
1026: *
1027: * @param mapping
1028: * @param form
1029: * @param request
1030: * @param response
1031: * @return ActionForward
1032: * @throws Exception
1033: */
1034: public ActionForward performBalanceInquiryForSourceLine(
1035: ActionMapping mapping, ActionForm form,
1036: HttpServletRequest request, HttpServletResponse response)
1037: throws Exception {
1038: SourceAccountingLine line = (SourceAccountingLine) getSourceAccountingLine(
1039: form, request);
1040: return performBalanceInquiryForAccountingLine(mapping, form,
1041: request, line);
1042: }
1043:
1044: /**
1045: * Takes care of storing the action form in the User session and forwarding to the balance inquiry report menu action for a
1046: * target accounting line.
1047: *
1048: * @param mapping
1049: * @param form
1050: * @param request
1051: * @param response
1052: * @return ActionForward
1053: * @throws Exception
1054: */
1055: public ActionForward performBalanceInquiryForTargetLine(
1056: ActionMapping mapping, ActionForm form,
1057: HttpServletRequest request, HttpServletResponse response)
1058: throws Exception {
1059: int lineIndex = getSelectedLine(request);
1060:
1061: TargetAccountingLine line = (TargetAccountingLine) ObjectUtils
1062: .deepCopy(((KualiAccountingDocumentFormBase) form)
1063: .getFinancialDocument()
1064: .getTargetAccountingLine(lineIndex));
1065:
1066: return performBalanceInquiryForAccountingLine(mapping, form,
1067: request, line);
1068: }
1069:
1070: /**
1071: * This method is a helper method that will return a source accounting line. The reason we're making it protected in here is so
1072: * that we can override this method in some of the modules. PurchasingActionBase is one of the subclasses that will be
1073: * overriding this, because in PurchasingActionBase, we'll need to get the source accounting line using both an item index and
1074: * an account index.
1075: *
1076: * @param form
1077: * @param request
1078: * @param isSource
1079: * @return
1080: */
1081: protected SourceAccountingLine getSourceAccountingLine(
1082: ActionForm form, HttpServletRequest request) {
1083: int lineIndex = getSelectedLine(request);
1084: SourceAccountingLine line = (SourceAccountingLine) ObjectUtils
1085: .deepCopy(((KualiAccountingDocumentFormBase) form)
1086: .getFinancialDocument()
1087: .getSourceAccountingLine(lineIndex));
1088: return line;
1089: }
1090:
1091: /**
1092: * This method handles preparing all of the accounting line data so that it can be pushed up to the balance inquiries for
1093: * populating the search criteria of each.
1094: *
1095: * @param mapping
1096: * @param form
1097: * @param request
1098: * @param line
1099: * @return ActionForward
1100: */
1101: protected ActionForward performBalanceInquiryForAccountingLine(
1102: ActionMapping mapping, ActionForm form,
1103: HttpServletRequest request, AccountingLine line) {
1104: // build out base path for return location
1105: String basePath = request.getScheme() + "://"
1106: + request.getServerName() + ":"
1107: + request.getServerPort() + request.getContextPath();
1108:
1109: // build out the actual form key that will be used to retrieve the form on refresh
1110: String callerDocFormKey = GlobalVariables.getUserSession()
1111: .addObject(form);
1112:
1113: // now add required parameters
1114: Properties parameters = new Properties();
1115: parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER,
1116: KFSConstants.START_METHOD);
1117: // need this next param b/c the lookup's return back will overwrite
1118: // the original doc form key
1119: parameters
1120: .put(
1121: KFSConstants.BALANCE_INQUIRY_REPORT_MENU_CALLER_DOC_FORM_KEY,
1122: callerDocFormKey);
1123: parameters.put(KFSConstants.DOC_FORM_KEY, callerDocFormKey);
1124: parameters.put(KFSConstants.BACK_LOCATION, basePath
1125: + mapping.getPath() + ".do");
1126:
1127: if (StringUtils.isNotBlank(line.getReferenceOriginCode())) {
1128: parameters.put("referenceOriginCode", line
1129: .getReferenceOriginCode());
1130: }
1131: if (StringUtils.isNotBlank(line.getReferenceNumber())) {
1132: parameters
1133: .put("referenceNumber", line.getReferenceNumber());
1134: }
1135: if (StringUtils.isNotBlank(line.getReferenceTypeCode())) {
1136: parameters.put("referenceTypeCode", line
1137: .getReferenceTypeCode());
1138: }
1139: if (StringUtils.isNotBlank(line.getDebitCreditCode())) {
1140: parameters
1141: .put("debitCreditCode", line.getDebitCreditCode());
1142: }
1143: if (StringUtils.isNotBlank(line.getChartOfAccountsCode())) {
1144: parameters.put("chartOfAccountsCode", line
1145: .getChartOfAccountsCode());
1146: }
1147: if (StringUtils.isNotBlank(line.getAccountNumber())) {
1148: parameters.put("accountNumber", line.getAccountNumber());
1149: }
1150: if (StringUtils.isNotBlank(line.getFinancialObjectCode())) {
1151: parameters.put("financialObjectCode", line
1152: .getFinancialObjectCode());
1153: }
1154: if (StringUtils.isNotBlank(line.getSubAccountNumber())) {
1155: parameters.put("subAccountNumber", line
1156: .getSubAccountNumber());
1157: }
1158: if (StringUtils.isNotBlank(line.getFinancialSubObjectCode())) {
1159: parameters.put("financialSubObjectCode", line
1160: .getFinancialSubObjectCode());
1161: }
1162: if (StringUtils.isNotBlank(line.getProjectCode())) {
1163: parameters.put("projectCode", line.getProjectCode());
1164: }
1165: if (StringUtils.isNotBlank(line.getObjectTypeCode())) {
1166: parameters.put("objectTypeCode", line.getObjectTypeCode());
1167: }
1168:
1169: String lookupUrl = UrlFactory.parameterizeUrl(basePath + "/"
1170: + KFSConstants.BALANCE_INQUIRY_REPORT_MENU_ACTION,
1171: parameters);
1172:
1173: return new ActionForward(lookupUrl, true);
1174: }
1175:
1176: @Override
1177: public ActionForward save(ActionMapping mapping, ActionForm form,
1178: HttpServletRequest request, HttpServletResponse response)
1179: throws Exception {
1180: ActionForward forward = super .save(mapping, form, request,
1181: response);
1182:
1183: // KULEDOCS-1443: For the revert button, set the new baseline accounting lines as the most recently saved lines
1184: KualiAccountingDocumentFormBase tmpForm = (KualiAccountingDocumentFormBase) form;
1185: tmpForm.setBaselineSourceAccountingLines(tmpForm
1186: .getFinancialDocument().getSourceAccountingLines());
1187: tmpForm.setBaselineTargetAccountingLines(tmpForm
1188: .getFinancialDocument().getTargetAccountingLines());
1189: // need to check on sales tax for all the accounting lines
1190: checkSalesTaxRequiredAllLines(tmpForm, tmpForm
1191: .getFinancialDocument().getSourceAccountingLines());
1192: checkSalesTaxRequiredAllLines(tmpForm, tmpForm
1193: .getFinancialDocument().getTargetAccountingLines());
1194: return forward;
1195: }
1196:
1197: @Override
1198: public ActionForward route(ActionMapping mapping, ActionForm form,
1199: HttpServletRequest request, HttpServletResponse response)
1200: throws Exception {
1201: ActionForward forward = super .route(mapping, form, request,
1202: response);
1203: KualiAccountingDocumentFormBase tmpForm = (KualiAccountingDocumentFormBase) form;
1204: checkSalesTaxRequiredAllLines(tmpForm, tmpForm
1205: .getFinancialDocument().getSourceAccountingLines());
1206: checkSalesTaxRequiredAllLines(tmpForm, tmpForm
1207: .getFinancialDocument().getTargetAccountingLines());
1208:
1209: return forward;
1210: }
1211:
1212: /**
1213: * Encapsulate the rule check so we can call it from multiple places
1214: *
1215: * @param document
1216: * @param line
1217: * @return true if sales is either not required or it contains sales tax
1218: */
1219: private boolean checkSalesTax(AccountingDocument document,
1220: AccountingLine line, boolean source, boolean newLine,
1221: int index) {
1222: boolean passed = true;
1223: if (isSalesTaxRequired(document, line)) {
1224: // then set the salesTaxRequired on the accountingLine
1225: line.setSalesTaxRequired(true);
1226: populateSalesTax(line);
1227: // check to see if the sales tax info has been put in
1228: passed &= isValidSalesTaxEntered(line, source, newLine,
1229: index);
1230: }
1231: return passed;
1232: }
1233:
1234: /**
1235: * This method checks to see if this doctype needs sales tax If it does then it checks to see if the account and object code
1236: * require sales tax If it does then it returns true. Note - this is hackish as we shouldn't have to call rules directly from
1237: * the action class But we need to in this instance because we are copying the lines before calling rules and need a way to
1238: * modify them before they go on
1239: *
1240: * @param accountingLine
1241: * @return true if sales tax check is needed, false otherwise
1242: */
1243: protected boolean isSalesTaxRequired(
1244: AccountingDocument financialDocument,
1245: AccountingLine accountingLine) {
1246: boolean required = false;
1247: DocumentTypeService docTypeService = SpringContext
1248: .getBean(DocumentTypeService.class);
1249: String docType = docTypeService
1250: .getDocumentTypeCodeByClass(financialDocument
1251: .getClass());
1252: // first we need to check just the doctype to see if it needs the sales tax check
1253: ParameterService parameterService = SpringContext
1254: .getBean(ParameterService.class);
1255: // apply the rule, see if it fails
1256: ParameterEvaluator docTypeSalesTaxCheckEvaluator = SpringContext
1257: .getBean(ParameterService.class)
1258: .getParameterEvaluator(
1259: ParameterConstants.FINANCIAL_PROCESSING_DOCUMENT.class,
1260: APPLICATION_PARAMETER.DOCTYPE_SALES_TAX_CHECK,
1261: docType);
1262: if (docTypeSalesTaxCheckEvaluator.evaluationSucceeds()) {
1263: required = true;
1264: }
1265:
1266: // second we need to check the account and object code combination to see if it needs sales tax
1267: if (required) {
1268: // get the object code and account
1269: String objCd = accountingLine.getFinancialObjectCode();
1270: String account = accountingLine.getAccountNumber();
1271: if (!StringUtils.isEmpty(objCd)
1272: && !StringUtils.isEmpty(account)) {
1273: String compare = account + ":" + objCd;
1274: ParameterEvaluator salesTaxApplicableAcctAndObjectEvaluator = SpringContext
1275: .getBean(ParameterService.class)
1276: .getParameterEvaluator(
1277: ParameterConstants.FINANCIAL_PROCESSING_DOCUMENT.class,
1278: APPLICATION_PARAMETER.SALES_TAX_APPLICABLE_ACCOUNTS_AND_OBJECT_CODES,
1279: compare);
1280: if (!salesTaxApplicableAcctAndObjectEvaluator
1281: .evaluationSucceeds()) {
1282: required = false;
1283: }
1284: } else {
1285: // the two fields are currently empty and we don't need to check yet
1286: required = false;
1287: }
1288: }
1289: return required;
1290: }
1291:
1292: /**
1293: * This method checks to see if the sales tax information was put into the accounting line
1294: *
1295: * @param accountingLine
1296: * @return true if entered correctly, false otherwise
1297: */
1298: private boolean isValidSalesTaxEntered(
1299: AccountingLine accountingLine, boolean source,
1300: boolean newLine, int index) {
1301: boolean valid = true;
1302: DictionaryValidationService dictionaryValidationService = SpringContext
1303: .getBean(DictionaryValidationService.class);
1304: BusinessObjectService boService = SpringContext
1305: .getBean(BusinessObjectService.class);
1306: String objCd = accountingLine.getFinancialObjectCode();
1307: String account = accountingLine.getAccountNumber();
1308: SalesTax salesTax = accountingLine.getSalesTax();
1309: String pathPrefix = "";
1310: if (source && !newLine) {
1311: pathPrefix = "document."
1312: + KFSConstants.EXISTING_SOURCE_ACCT_LINE_PROPERTY_NAME
1313: + "[" + index + "]";
1314: } else if (!source && !newLine) {
1315: pathPrefix = "document."
1316: + KFSConstants.EXISTING_TARGET_ACCT_LINE_PROPERTY_NAME
1317: + "[" + index + "]";
1318: } else if (source && newLine) {
1319: pathPrefix = KFSConstants.NEW_SOURCE_ACCT_LINE_PROPERTY_NAME;
1320: } else if (!source && newLine) {
1321: pathPrefix = KFSConstants.NEW_TARGET_ACCT_LINE_PROPERTY_NAME;
1322: }
1323: GlobalVariables.getErrorMap().addToErrorPath(pathPrefix);
1324: if (ObjectUtils.isNull(salesTax)) {
1325: valid &= false;
1326: GlobalVariables.getErrorMap().putError(
1327: "salesTax.chartOfAccountsCode",
1328: ERROR_DOCUMENT_ACCOUNTING_LINE_SALES_TAX_REQUIRED,
1329: account, objCd);
1330: } else {
1331:
1332: if (StringUtils.isBlank(salesTax.getChartOfAccountsCode())) {
1333: valid &= false;
1334: GlobalVariables.getErrorMap().putError(
1335: "salesTax.chartOfAccountsCode", ERROR_REQUIRED,
1336: "Chart of Accounts");
1337: }
1338: if (StringUtils.isBlank(salesTax.getAccountNumber())) {
1339: valid &= false;
1340: GlobalVariables.getErrorMap().putError(
1341: "salesTax.accountNumber", ERROR_REQUIRED,
1342: "Account Number");
1343: }
1344: if (salesTax.getFinancialDocumentGrossSalesAmount() == null) {
1345: valid &= false;
1346: GlobalVariables.getErrorMap().putError(
1347: "salesTax.financialDocumentGrossSalesAmount",
1348: ERROR_REQUIRED, "Gross Sales Amount");
1349: }
1350: if (salesTax.getFinancialDocumentTaxableSalesAmount() == null) {
1351: valid &= false;
1352: GlobalVariables.getErrorMap().putError(
1353: "salesTax.financialDocumentTaxableSalesAmount",
1354: ERROR_REQUIRED, "Taxable Sales Amount");
1355: }
1356: if (salesTax.getFinancialDocumentSaleDate() == null) {
1357: valid &= false;
1358: GlobalVariables.getErrorMap().putError(
1359: "salesTax.financialDocumentSaleDate",
1360: ERROR_REQUIRED, "Sale Date");
1361: }
1362: if (StringUtils.isNotBlank(salesTax
1363: .getChartOfAccountsCode())
1364: && StringUtils.isNotBlank(salesTax
1365: .getAccountNumber())) {
1366:
1367: if (boService.getReferenceIfExists(salesTax, "account") == null) {
1368: valid &= false;
1369: GlobalVariables
1370: .getErrorMap()
1371: .putError(
1372: "salesTax.accountNumber",
1373: ERROR_DOCUMENT_ACCOUNTING_LINE_SALES_TAX_INVALID_ACCOUNT,
1374: salesTax.getChartOfAccountsCode(),
1375: salesTax.getAccountNumber());
1376:
1377: }
1378: }
1379: if (!valid) {
1380: GlobalVariables
1381: .getErrorMap()
1382: .putError(
1383: "salesTax.chartOfAccountsCode",
1384: ERROR_DOCUMENT_ACCOUNTING_LINE_SALES_TAX_REQUIRED,
1385: account, objCd);
1386: }
1387: }
1388: GlobalVariables.getErrorMap().removeFromErrorPath(pathPrefix);
1389: return valid;
1390: }
1391:
1392: /**
1393: * This method removes the sales tax information from a line that no longer requires it
1394: *
1395: * @param accountingLine
1396: */
1397: private void removeSalesTax(AccountingLine accountingLine) {
1398: SalesTax salesTax = accountingLine.getSalesTax();
1399: if (ObjectUtils.isNotNull(salesTax)) {
1400: accountingLine.setSalesTax(null);
1401: }
1402: }
1403:
1404: /**
1405: * This method checks to see if the given accounting needs sales tax and if it does it sets the salesTaxRequired variable on the
1406: * line If it doesn't and it has it then it removes the sales tax information from the line This method is called from the
1407: * execute() on all accounting lines that have been edited or lines that have already been added to the document, not on new
1408: * lines
1409: *
1410: * @param transDoc
1411: * @param formLine
1412: * @param baseLine
1413: */
1414: private void handleSalesTaxRequired(AccountingDocument transDoc,
1415: AccountingLine formLine, boolean source, boolean newLine,
1416: int index) {
1417: boolean salesTaxRequired = isSalesTaxRequired(transDoc,
1418: formLine);
1419: if (salesTaxRequired) {
1420: formLine.setSalesTaxRequired(true);
1421: populateSalesTax(formLine);
1422: } else if (!salesTaxRequired
1423: && hasSalesTaxBeenEntered(formLine, source, newLine,
1424: index)) {
1425: // remove it if it has been added but is no longer required
1426: removeSalesTax(formLine);
1427: }
1428: }
1429:
1430: private boolean hasSalesTaxBeenEntered(
1431: AccountingLine accountingLine, boolean source,
1432: boolean newLine, int index) {
1433: boolean entered = true;
1434: String objCd = accountingLine.getFinancialObjectCode();
1435: String account = accountingLine.getAccountNumber();
1436: SalesTax salesTax = accountingLine.getSalesTax();
1437: if (ObjectUtils.isNull(salesTax)) {
1438: return false;
1439: }
1440: if (StringUtils.isBlank(salesTax.getChartOfAccountsCode())) {
1441: entered &= false;
1442: }
1443: if (StringUtils.isBlank(salesTax.getAccountNumber())) {
1444: entered &= false;
1445: }
1446: if (salesTax.getFinancialDocumentGrossSalesAmount() == null) {
1447: entered &= false;
1448: }
1449: if (salesTax.getFinancialDocumentTaxableSalesAmount() == null) {
1450: entered &= false;
1451: }
1452: if (salesTax.getFinancialDocumentSaleDate() == null) {
1453: entered &= false;
1454: }
1455: return entered;
1456: }
1457:
1458: /**
1459: * This method is called from the createDocument and processes through all the accouting lines and checks to see if they need
1460: * sales tax fields
1461: *
1462: * @param kualiDocumentFormBase
1463: * @param baselineSourceLines
1464: */
1465: private void handleSalesTaxRequiredAllLines(
1466: KualiDocumentFormBase kualiDocumentFormBase,
1467: List<AccountingLine> baselineAcctingLines) {
1468: AccountingDocument accoutingDocument = (AccountingDocument) kualiDocumentFormBase
1469: .getDocument();
1470: int index = 0;
1471: for (AccountingLine accountingLine : baselineAcctingLines) {
1472: boolean source = false;
1473: if (accountingLine.isSourceAccountingLine()) {
1474: source = true;
1475: }
1476: handleSalesTaxRequired(accoutingDocument, accountingLine,
1477: source, false, index);
1478: index++;
1479: }
1480:
1481: }
1482:
1483: private boolean checkSalesTaxRequiredAllLines(
1484: KualiDocumentFormBase kualiDocumentFormBase,
1485: List<AccountingLine> baselineAcctingLines) {
1486: AccountingDocument accoutingDocument = (AccountingDocument) kualiDocumentFormBase
1487: .getDocument();
1488: boolean passed = true;
1489: int index = 0;
1490: for (AccountingLine accountingLine : baselineAcctingLines) {
1491: boolean source = false;
1492: if (accountingLine.isSourceAccountingLine()) {
1493: source = true;
1494: }
1495: passed &= checkSalesTax(accoutingDocument, accountingLine,
1496: source, false, index);
1497: index++;
1498: }
1499: return passed;
1500: }
1501:
1502: /**
1503: * This method refreshes the sales tax fields on a refresh or tab toggle so that all the information that was there before is
1504: * still there after a state change
1505: *
1506: * @param form
1507: */
1508: private void refreshSalesTaxInfo(ActionForm form) {
1509: KualiAccountingDocumentFormBase accountingForm = (KualiAccountingDocumentFormBase) form;
1510: AccountingDocument document = (AccountingDocument) accountingForm
1511: .getDocument();
1512: List sourceLines = document.getSourceAccountingLines();
1513: List targetLines = document.getTargetAccountingLines();
1514: handleSalesTaxRequiredAllLines(accountingForm, sourceLines);
1515: handleSalesTaxRequiredAllLines(accountingForm, targetLines);
1516:
1517: AccountingLine newTargetLine = accountingForm
1518: .getNewTargetLine();
1519: AccountingLine newSourceLine = accountingForm
1520: .getNewSourceLine();
1521: if (newTargetLine != null) {
1522: handleSalesTaxRequired(document, newTargetLine, false,
1523: true, 0);
1524: }
1525: if (newSourceLine != null) {
1526: handleSalesTaxRequired(document, newSourceLine, true, true,
1527: 0);
1528: }
1529: }
1530:
1531: /**
1532: * This method populates the sales tax for a given accounting line with the appropriate primary key fields from the accounting
1533: * line since OJB won't do it automatically for us
1534: *
1535: * @param line
1536: */
1537: private void populateSalesTax(AccountingLine line) {
1538: SalesTax salesTax = line.getSalesTax();
1539:
1540: if (ObjectUtils.isNotNull(salesTax)) {
1541: salesTax.setDocumentNumber(line.getDocumentNumber());
1542: salesTax.setFinancialDocumentLineTypeCode(line
1543: .getFinancialDocumentLineTypeCode());
1544: salesTax.setFinancialDocumentLineNumber(line
1545: .getSequenceNumber());
1546: }
1547: }
1548:
1549: }
|