001: /*
002: * Copyright 2006-2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.kuali.module.purap.rules;
017:
018: import java.util.List;
019:
020: import org.apache.commons.lang.StringUtils;
021: import org.kuali.RicePropertyConstants;
022: import org.kuali.core.datadictionary.validation.fieldlevel.ZipcodeValidationPattern;
023: import org.kuali.core.document.AmountTotaling;
024: import org.kuali.core.util.ErrorMap;
025: import org.kuali.core.util.GeneralLedgerPendingEntrySequenceHelper;
026: import org.kuali.core.util.GlobalVariables;
027: import org.kuali.core.util.ObjectUtils;
028: import org.kuali.core.workflow.service.KualiWorkflowDocument;
029: import org.kuali.kfs.KFSConstants;
030: import org.kuali.kfs.bo.AccountingLine;
031: import org.kuali.kfs.bo.GeneralLedgerPendingEntry;
032: import org.kuali.kfs.context.SpringContext;
033: import org.kuali.kfs.document.AccountingDocument;
034: import org.kuali.module.purap.PurapConstants;
035: import org.kuali.module.purap.PurapKeyConstants;
036: import org.kuali.module.purap.PurapPropertyConstants;
037: import org.kuali.module.purap.PurapWorkflowConstants.RequisitionDocument.NodeDetailEnum;
038: import org.kuali.module.purap.document.PurchasingAccountsPayableDocument;
039: import org.kuali.module.purap.document.PurchasingDocument;
040: import org.kuali.module.purap.document.RequisitionDocument;
041: import org.kuali.module.purap.service.PurApWorkflowIntegrationService;
042:
043: /**
044: * Business rule(s) applicable to Requisition document.
045: */
046: public class RequisitionDocumentRule extends PurchasingDocumentRuleBase {
047:
048: /**
049: * Overrides the method in PurchasingDocumentRuleBase class in order to add validation for the Additional tab. Tabs included on
050: * Purchasing Documents are: Payment Info, Delivery, and Additional
051: *
052: * @param purapDocument the requisition document to be validated
053: * @return boolean false when an error is found in any validation
054: * @see org.kuali.module.purap.rules.PurchasingAccountsPayableDocumentRuleBase#processValidation(org.kuali.module.purap.document.PurchasingAccountsPayableDocument)
055: */
056: @Override
057: public boolean processValidation(
058: PurchasingAccountsPayableDocument purapDocument) {
059: boolean valid = super .processValidation(purapDocument);
060: valid &= processAdditionalValidation((PurchasingDocument) purapDocument);
061:
062: return valid;
063: }
064:
065: /**
066: * Overrides the method in PurchasingAccountsPayableDocumentRuleBase class to check to see if the Requisition is going to stop
067: * at content review route level. If so, then this method returns false, otherwise it will call the
068: * requiresAccountValidationOnAllEnteredItems of the superclass, which returns true.
069: *
070: * @param document the requisition document to be validated
071: * @return boolean false when the Requisition is going to stop at content review route level.
072: * @see org.kuali.module.purap.rules.PurchasingAccountsPayableDocumentRuleBase#requiresAccountValidationOnAllEnteredItems(org.kuali.module.purap.document.PurchasingAccountsPayableDocument)
073: */
074: @Override
075: public boolean requiresAccountValidationOnAllEnteredItems(
076: PurchasingAccountsPayableDocument document) {
077: if (SpringContext
078: .getBean(PurApWorkflowIntegrationService.class)
079: .willDocumentStopAtGivenFutureRouteNode(document,
080: NodeDetailEnum.CONTENT_REVIEW)) {
081:
082: return false;
083: }
084:
085: return super
086: .requiresAccountValidationOnAllEnteredItems(document);
087: }
088:
089: /**
090: * Performs any validation for the Additional tab.
091: *
092: * @param purDocument the requisition document to be validated
093: * @return boolean false when the validateTotalDollarAmountIsLessThanPurchaseOrderTotalLimit returns false.
094: */
095: public boolean processAdditionalValidation(
096: PurchasingDocument purDocument) {
097: boolean valid = true;
098: valid = validateTotalDollarAmountIsLessThanPurchaseOrderTotalLimit(purDocument);
099:
100: return valid;
101: }
102:
103: /**
104: * Performs validations for the fields in vendor tab. The business rules to be validated is: If this is a standard
105: * order requisition (not B2B), then if Country is United States and the postal code is required and if zip code is entered, it
106: * should be a valid US Zip code. (format)
107: *
108: * @param purapDocument The requisition document object whose vendor tab is to be validated
109: * @return boolean true if it passes vendor validation, otherwise it will return false.
110: */
111: @Override
112: public boolean processVendorValidation(
113: PurchasingAccountsPayableDocument purapDocument) {
114: ErrorMap errorMap = GlobalVariables.getErrorMap();
115: errorMap.clearErrorPath();
116: errorMap.addToErrorPath(RicePropertyConstants.DOCUMENT);
117: boolean valid = super .processVendorValidation(purapDocument);
118: RequisitionDocument reqDocument = (RequisitionDocument) purapDocument;
119: if (reqDocument.getRequisitionSourceCode().equals(
120: PurapConstants.RequisitionSources.STANDARD_ORDER)) {
121: if (!StringUtils
122: .isBlank(reqDocument.getVendorCountryCode())
123: && reqDocument.getVendorCountryCode().equals(
124: KFSConstants.COUNTRY_CODE_UNITED_STATES)
125: && !StringUtils.isBlank(reqDocument
126: .getVendorPostalCode())) {
127: ZipcodeValidationPattern zipPattern = new ZipcodeValidationPattern();
128: if (!zipPattern.matches(reqDocument
129: .getVendorPostalCode())) {
130: valid = false;
131: errorMap
132: .putError(
133: PurapPropertyConstants.VENDOR_POSTAL_CODE,
134: PurapKeyConstants.ERROR_POSTAL_CODE_INVALID);
135: }
136: }
137: }
138: errorMap.clearErrorPath();
139:
140: return valid;
141: }
142:
143: /**
144: * Validate that if the PurchaseOrderTotalLimit is not null then the TotalDollarAmount cannot be greater than the
145: * PurchaseOrderTotalLimit.
146: *
147: * @param purDocument the requisition document to be validated
148: * @return boolean true if the TotalDollarAmount is less than the PurchaseOrderTotalLimit and false otherwise.
149: */
150: public boolean validateTotalDollarAmountIsLessThanPurchaseOrderTotalLimit(
151: PurchasingDocument purDocument) {
152: boolean valid = true;
153: GlobalVariables.getErrorMap().clearErrorPath();
154: GlobalVariables.getErrorMap().addToErrorPath(
155: RicePropertyConstants.DOCUMENT);
156: if (ObjectUtils.isNotNull(purDocument
157: .getPurchaseOrderTotalLimit())
158: && ObjectUtils.isNotNull(((AmountTotaling) purDocument)
159: .getTotalDollarAmount())) {
160: if (((AmountTotaling) purDocument).getTotalDollarAmount()
161: .isGreaterThan(
162: purDocument.getPurchaseOrderTotalLimit())) {
163: valid &= false;
164: GlobalVariables
165: .getErrorMap()
166: .putError(
167: PurapPropertyConstants.PURCHASE_ORDER_TOTAL_LIMIT,
168: PurapKeyConstants.ERROR_PURCHASE_ORDER_EXCEEDING_TOTAL_LIMIT);
169: }
170: }
171: GlobalVariables.getErrorMap().clearErrorPath();
172:
173: return valid;
174: }
175:
176: /**
177: * Overrides the method in PurapAccountingDocumentRuleBase class in order to return true when the Requisition is going to stop
178: * at Content Review level.
179: *
180: * @param financialDocument the requisition document to be validated
181: * @param accountingLine the accounting line to be validated
182: * @param action the AccountingLineAction enum that indicates what is being done to an accounting line
183: * @return boolean true if the Requisition is going to stop at Content Review Level.
184: * @see org.kuali.kfs.rules.AccountingDocumentRuleBase#checkAccountingLineAccountAccessibility(org.kuali.kfs.document.AccountingDocument,
185: * org.kuali.kfs.bo.AccountingLine, org.kuali.kfs.rules.AccountingDocumentRuleBase.AccountingLineAction)
186: */
187: @Override
188: protected boolean checkAccountingLineAccountAccessibility(
189: AccountingDocument financialDocument,
190: AccountingLine accountingLine, AccountingLineAction action) {
191: KualiWorkflowDocument workflowDocument = financialDocument
192: .getDocumentHeader().getWorkflowDocument();
193: List currentRouteLevels = getCurrentRouteLevels(workflowDocument);
194:
195: if (((RequisitionDocument) financialDocument)
196: .isDocumentStoppedInRouteNode(NodeDetailEnum.CONTENT_REVIEW)) {
197: // DO NOTHING: do not check that user owns acct lines; at this level, approvers can edit all detail on REQ
198:
199: return true;
200: } else {
201:
202: return super .checkAccountingLineAccountAccessibility(
203: financialDocument, accountingLine, action);
204: }
205: }
206:
207: /**
208: * Overrides the method in GeneralLedgerPostingDocumentRuleBase class in order to do nothing and return true, because
209: * Requisition doesn't generate GL entries.
210: *
211: * @param universityFiscalYear
212: * @param explicitEntry
213: * @param sequenceHelper
214: * @param offsetEntry
215: * @return boolean true
216: * @see org.kuali.kfs.rules.GeneralLedgerPostingDocumentRuleBase#populateOffsetGeneralLedgerPendingEntry(java.lang.Integer,
217: * org.kuali.kfs.bo.GeneralLedgerPendingEntry, org.kuali.core.util.GeneralLedgerPendingEntrySequenceHelper,
218: * org.kuali.kfs.bo.GeneralLedgerPendingEntry)
219: */
220: @Override
221: protected boolean populateOffsetGeneralLedgerPendingEntry(
222: Integer universityFiscalYear,
223: GeneralLedgerPendingEntry explicitEntry,
224: GeneralLedgerPendingEntrySequenceHelper sequenceHelper,
225: GeneralLedgerPendingEntry offsetEntry) {
226: // Requisition doesn't generate GL entries
227:
228: return true;
229: }
230:
231: /**
232: * Overrides the method in PurchasingDocumentRuleBase to return false if the account is closed.
233: *
234: * @param financialDocument the requisition document to be validated
235: * @param accountingLine the accounting line to be validated
236: * @return boolean false if the account is closed, otherwise it will return the result of the
237: * processAccAccountingLineBusinessRules in PurchasingDocumentRuleBase.
238: * @see org.kuali.module.purap.rules.PurchasingDocumentRuleBase#processAddAccountingLineBusinessRules(org.kuali.kfs.document.AccountingDocument,
239: * org.kuali.kfs.bo.AccountingLine)
240: */
241: @Override
242: public boolean processAddAccountingLineBusinessRules(
243: AccountingDocument financialDocument,
244: AccountingLine accountingLine) {
245: // make sure it's active for usage
246: if (isAccountClosed(accountingLine)) {
247:
248: return false;
249: }
250:
251: return super .processAddAccountingLineBusinessRules(
252: financialDocument, accountingLine);
253: }
254:
255: /**
256: * Overrides the method in PurapAccountingDocumentRuleBase to return false if the account is closed.
257: *
258: * @param financialDocument the requisition document to be validated
259: * @param accountingLine the accounting line to be validated
260: * @return boolean false if the account is closed, otherwise it will return the result of the
261: * processReviewAccountingLineBusinessRules in PurapAccountingDocumentRuleBase.
262: * @see org.kuali.module.purap.rules.PurapAccountingDocumentRuleBase#processReviewAccountingLineBusinessRules(org.kuali.kfs.document.AccountingDocument,
263: * org.kuali.kfs.bo.AccountingLine)
264: */
265: @Override
266: public boolean processReviewAccountingLineBusinessRules(
267: AccountingDocument financialDocument,
268: AccountingLine accountingLine) {
269: // make sure it's active for usage
270: if (isAccountClosed(accountingLine)) {
271:
272: return false;
273: }
274:
275: return super .processReviewAccountingLineBusinessRules(
276: financialDocument, accountingLine);
277: }
278:
279: /**
280: * Overrides the method in PurapAccountingDocumentRuleBase to return false if the account is closed.
281: *
282: * @param financialDocument the requisition document to be validated
283: * @param updatedAccountingLine the accounting line that was updated
284: * @return boolean false if the account is closed, otherwise it will return the result of the
285: * processUpdateAccountingLineBusinessRules in PurapAccountingDocumentRuleBase.
286: * @see org.kuali.module.purap.rules.PurapAccountingDocumentRuleBase#processUpdateAccountingLineBusinessRules(org.kuali.kfs.document.AccountingDocument,
287: * org.kuali.kfs.bo.AccountingLine, org.kuali.kfs.bo.AccountingLine)
288: */
289: @Override
290: public boolean processUpdateAccountingLineBusinessRules(
291: AccountingDocument financialDocument,
292: AccountingLine accountingLine,
293: AccountingLine updatedAccountingLine) {
294: // make sure it's active for usage
295: if (isAccountClosed(accountingLine)) {
296:
297: return false;
298: }
299:
300: return super .processUpdateAccountingLineBusinessRules(
301: financialDocument, accountingLine,
302: updatedAccountingLine);
303: }
304:
305: /**
306: * Checks whether the account is closed.
307: *
308: * @param accountingLine the accounting line to be validated
309: * @return boolean true if the account's closed indicator is true and false otherwise.
310: */
311: private boolean isAccountClosed(AccountingLine accountingLine) {
312: accountingLine.refreshNonUpdateableReferences();
313: if (accountingLine.getAccount() != null
314: && accountingLine.getAccount()
315: .isAccountClosedIndicator()) {
316: GlobalVariables.getErrorMap().putError(
317: PurapPropertyConstants.ACCOUNTS,
318: PurapKeyConstants.ERROR_REQUISITION_ACCOUNT_CLOSED,
319: accountingLine.getChartOfAccountsCode(),
320: accountingLine.getAccountNumber());
321:
322: return true;
323: }
324:
325: return false;
326: }
327:
328: }
|