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.math.BigDecimal;
019: import java.util.Date;
020: import java.util.List;
021:
022: import org.apache.commons.lang.StringUtils;
023: import org.kuali.core.datadictionary.validation.fieldlevel.PhoneNumberValidationPattern;
024: import org.kuali.core.service.DataDictionaryService;
025: import org.kuali.core.service.DateTimeService;
026: import org.kuali.core.util.ErrorMap;
027: import org.kuali.core.util.GlobalVariables;
028: import org.kuali.core.util.KualiDecimal;
029: import org.kuali.core.util.ObjectUtils;
030: import org.kuali.kfs.KFSConstants;
031: import org.kuali.kfs.KFSKeyConstants;
032: import org.kuali.kfs.bo.AccountingLine;
033: import org.kuali.kfs.context.SpringContext;
034: import org.kuali.kfs.document.AccountingDocument;
035: import org.kuali.kfs.service.ParameterService;
036: import org.kuali.kfs.service.impl.ParameterConstants;
037: import org.kuali.module.purap.PurapConstants;
038: import org.kuali.module.purap.PurapKeyConstants;
039: import org.kuali.module.purap.PurapPropertyConstants;
040: import org.kuali.module.purap.PurapRuleConstants;
041: import org.kuali.module.purap.PurapConstants.ItemFields;
042: import org.kuali.module.purap.PurapConstants.ItemTypeCodes;
043: import org.kuali.module.purap.bo.PurApAccountingLine;
044: import org.kuali.module.purap.bo.PurApItem;
045: import org.kuali.module.purap.bo.PurchasingItemBase;
046: import org.kuali.module.purap.document.PurchasingAccountsPayableDocument;
047: import org.kuali.module.purap.document.PurchasingDocument;
048: import org.kuali.module.vendor.VendorPropertyConstants;
049: import org.kuali.module.vendor.bo.VendorDetail;
050: import org.kuali.module.vendor.bo.VendorHeader;
051: import org.kuali.module.vendor.service.VendorService;
052:
053: /**
054: * Business rule(s) applicable to Purchasing document.
055: */
056: public class PurchasingDocumentRuleBase extends
057: PurchasingAccountsPayableDocumentRuleBase {
058:
059: /**
060: * Overrides the method in PurchasingAccountsPayableDocumentRuleBase to add validations for Payment Info and Delivery tabs.
061: *
062: * @param purapDocument the purchasing document to be validated
063: * @return boolean false if there is any validation that fails.
064: * @see org.kuali.module.purap.rules.PurchasingAccountsPayableDocumentRuleBase#processValidation(org.kuali.module.purap.document.PurchasingAccountsPayableDocument)
065: */
066: @Override
067: public boolean processValidation(
068: PurchasingAccountsPayableDocument purapDocument) {
069: boolean valid = super .processValidation(purapDocument);
070: valid &= processPaymentInfoValidation((PurchasingDocument) purapDocument);
071: valid &= processDeliveryValidation((PurchasingDocument) purapDocument);
072:
073: return valid;
074: }
075:
076: /**
077: * Overrides the method in PurchasingAccountsPayableDocumentRuleBase to add the validations for the unit price, unit of measure,
078: * item quantity (for above the line items), the validateBelowTheLineItemNoUnitcost, validateTotalCost and
079: * validateContainsAtLeastOneItem.
080: *
081: * @param purDocument the purchasing document to be validated
082: * @return boolean false if there is any validation that fails.
083: * @see org.kuali.module.purap.rules.PurchasingAccountsPayableDocumentRuleBase#processItemValidation(org.kuali.module.purap.document.PurchasingAccountsPayableDocument)
084: */
085: @Override
086: public boolean processItemValidation(
087: PurchasingAccountsPayableDocument purapDocument) {
088: boolean valid = super .processItemValidation(purapDocument);
089: List<PurApItem> itemList = purapDocument.getItems();
090: int i = 0;
091: for (PurApItem item : itemList) {
092: // refresh item type for validation
093: item
094: .refreshReferenceObject(PurapPropertyConstants.ITEM_TYPE);
095:
096: GlobalVariables.getErrorMap().addToErrorPath(
097: "document.item[" + i + "]");
098: String identifierString = (item.getItemType()
099: .isItemTypeAboveTheLineIndicator() ? "Item "
100: + item.getItemLineNumber().toString() : item
101: .getItemType().getItemTypeDescription());
102: valid &= validateItemUnitPrice(item);
103: valid &= validateUnitOfMeasure(item, identifierString);
104: // This validation is applicable to the above the line items only.
105: if (item.getItemType().isItemTypeAboveTheLineIndicator()) {
106: valid &= validateItemQuantity(item, identifierString);
107: } else {
108: // If the item is below the line, no accounts can be entered on below the line items
109: // that have no unit cost
110: valid &= validateBelowTheLineItemNoUnitCost(item,
111: identifierString);
112: }
113: GlobalVariables.getErrorMap().removeFromErrorPath(
114: "document.item[" + i + "]");
115: i++;
116: }
117: valid &= validateTotalCost((PurchasingDocument) purapDocument);
118: valid &= validateContainsAtLeastOneItem((PurchasingDocument) purapDocument);
119:
120: return valid;
121: }
122:
123: /**
124: * Overrides the method in PurchasingAccountsPayableDocumentRuleBase to also invoke the validateAccountNotExpired for each of
125: * the accounts.
126: *
127: * @see org.kuali.module.purap.rules.PurchasingAccountsPayableDocumentRuleBase#processAccountValidation(org.kuali.kfs.document.AccountingDocument,
128: * java.util.List, java.lang.String)
129: */
130: @Override
131: public boolean processAccountValidation(
132: AccountingDocument accountingDocument,
133: List<PurApAccountingLine> purAccounts, String itemLineNumber) {
134: boolean valid = true;
135: for (PurApAccountingLine accountingLine : purAccounts) {
136: boolean notExpired = this
137: .validateAccountNotExpired(accountingLine);
138: if (!notExpired) {
139: GlobalVariables.getErrorMap().putError(
140: PurapConstants.ITEM_TAB_ERROR_PROPERTY,
141: PurapKeyConstants.ERROR_ITEM_ACCOUNT_EXPIRED,
142: itemLineNumber + " has ",
143: accountingLine.getAccount().getAccountNumber());
144: }
145: }
146: valid &= super .processAccountValidation(accountingDocument,
147: purAccounts, itemLineNumber);
148:
149: return valid;
150: }
151:
152: /**
153: * Validates that if the item unit price is null and the source accounting lines is not empty, add error message and return
154: * false.
155: *
156: * @param item the item to be validated
157: * @param identifierString the identifierString of the item to be validated
158: * @return boolean false if the item unit price is null and the source accounting lines is not empty.
159: */
160: private boolean validateBelowTheLineItemNoUnitCost(PurApItem item,
161: String identifierString) {
162: if (ObjectUtils.isNull(item.getItemUnitPrice())
163: && ObjectUtils.isNotNull(item
164: .getSourceAccountingLines())
165: && !item.getSourceAccountingLines().isEmpty()) {
166: GlobalVariables
167: .getErrorMap()
168: .putError(
169: PurapPropertyConstants.ITEM_UNIT_PRICE,
170: PurapKeyConstants.ERROR_ITEM_BELOW_THE_LINE_NO_UNIT_COST,
171: identifierString);
172:
173: return false;
174: }
175:
176: return true;
177: }
178:
179: /**
180: * Validates that the document contains at least one item.
181: *
182: * @param purDocument the purchasing document to be validated
183: * @return boolean false if the document does not contain at least one item.
184: */
185: private boolean validateContainsAtLeastOneItem(
186: PurchasingDocument purDocument) {
187: boolean valid = false;
188: for (PurApItem item : purDocument.getItems()) {
189: if (!((PurchasingItemBase) item).isEmpty()
190: && item.getItemType()
191: .isItemTypeAboveTheLineIndicator()) {
192:
193: return true;
194: }
195: }
196: String documentType = SpringContext.getBean(
197: DataDictionaryService.class).getDataDictionary()
198: .getDocumentEntry(
199: purDocument.getDocumentHeader()
200: .getWorkflowDocument()
201: .getDocumentType()).getLabel();
202:
203: if (!valid) {
204: GlobalVariables.getErrorMap()
205: .putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY,
206: PurapKeyConstants.ERROR_ITEM_REQUIRED,
207: documentType);
208: }
209:
210: return valid;
211: }
212:
213: /**
214: * Validates the unit price for all applicable item types. It also validates that the unit price and description fields were
215: * entered for all above the line items.
216: *
217: * @param purDocument the purchasing document to be validated
218: * @return boolean false if there is any validation that fails.
219: */
220: private boolean validateItemUnitPrice(PurApItem item) {
221: boolean valid = true;
222: if (item.getItemType().isItemTypeAboveTheLineIndicator()) {
223: if (ObjectUtils.isNull(item.getItemUnitPrice())) {
224: valid = false;
225: GlobalVariables.getErrorMap().putError(
226: PurapPropertyConstants.ITEM_UNIT_PRICE,
227: KFSKeyConstants.ERROR_REQUIRED,
228: ItemFields.UNIT_COST + " in "
229: + item.getItemIdentifierString());
230: }
231: if (StringUtils.isEmpty(item.getItemDescription())) {
232: valid = false;
233: GlobalVariables.getErrorMap().putError(
234: PurapPropertyConstants.ITEM_DESCRIPTION,
235: KFSKeyConstants.ERROR_REQUIRED,
236: ItemFields.DESCRIPTION + " in "
237: + item.getItemIdentifierString());
238: }
239: }
240: if (ObjectUtils.isNotNull(item.getItemUnitPrice())) {
241: if ((BigDecimal.ZERO.compareTo(item.getItemUnitPrice()) > 0)
242: && ((!item
243: .getItemTypeCode()
244: .equals(
245: ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE)) && (!item
246: .getItemTypeCode()
247: .equals(
248: ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE)))) {
249: // If the item type is not full order discount or trade in items, don't allow negative unit price.
250: GlobalVariables.getErrorMap().putError(
251: PurapPropertyConstants.ITEM_UNIT_PRICE,
252: PurapKeyConstants.ERROR_ITEM_AMOUNT_BELOW_ZERO,
253: ItemFields.UNIT_COST,
254: item.getItemIdentifierString());
255: valid = false;
256: } else if ((BigDecimal.ZERO.compareTo(item
257: .getItemUnitPrice()) < 0)
258: && ((item.getItemTypeCode()
259: .equals(ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE)) || (item
260: .getItemTypeCode()
261: .equals(ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE)))) {
262: // If the item type is full order discount or trade in items, its unit price must be negative.
263: GlobalVariables
264: .getErrorMap()
265: .putError(
266: PurapPropertyConstants.ITEM_UNIT_PRICE,
267: PurapKeyConstants.ERROR_ITEM_AMOUNT_NOT_BELOW_ZERO,
268: ItemFields.UNIT_COST,
269: item.getItemIdentifierString());
270: valid = false;
271: }
272: }
273:
274: return valid;
275: }
276:
277: /**
278: * Overrides the method in PurchasingAccountsPayableDocumentRuleBase to add invocation to validateItemUnitPrice.
279: *
280: * @param financialDocument the purchasing document to be validated
281: * @param item the item to be validated
282: * @return boolean false if there is any fail validation
283: * @see org.kuali.module.purap.rules.PurchasingAccountsPayableDocumentRuleBase#processAddItemBusinessRules(org.kuali.kfs.document.AccountingDocument,
284: * org.kuali.module.purap.bo.PurApItem)
285: */
286: public boolean processAddItemBusinessRules(
287: AccountingDocument financialDocument, PurApItem item) {
288: boolean valid = super .processAddItemBusinessRules(
289: financialDocument, item);
290: GlobalVariables.getErrorMap().addToErrorPath(
291: PurapPropertyConstants.NEW_PURCHASING_ITEM_LINE);
292: valid &= validateItemUnitPrice(item);
293: GlobalVariables.getErrorMap().removeFromErrorPath(
294: PurapPropertyConstants.NEW_PURCHASING_ITEM_LINE);
295:
296: return valid;
297: }
298:
299: /**
300: * Validates that the total cost must be greater or equal to zero
301: *
302: * @param purDocument the purchasing document to be validated
303: * @return boolean false if the total cost is less than zero.
304: */
305: private boolean validateTotalCost(PurchasingDocument purDocument) {
306: boolean valid = true;
307: if (purDocument.getTotalDollarAmount().isLessThan(
308: new KualiDecimal(BigDecimal.ZERO))) {
309: valid = false;
310: GlobalVariables.getErrorMap().putError(
311: PurapConstants.ITEM_TAB_ERROR_PROPERTY,
312: PurapKeyConstants.ERROR_ITEM_TOTAL_NEGATIVE);
313: }
314:
315: return valid;
316: }
317:
318: /**
319: * Validates that if the item type is quantity based, the unit of measure is required.
320: *
321: * @param item the item to be validated
322: * @return boolean false if the item type is quantity based and the unit of measure is empty.
323: */
324: private boolean validateUnitOfMeasure(PurApItem item,
325: String identifierString) {
326: boolean valid = true;
327: PurchasingItemBase purItem = (PurchasingItemBase) item;
328: // Validations for quantity based item type
329: if (purItem.getItemType()
330: .isQuantityBasedGeneralLedgerIndicator()) {
331: if (StringUtils.isEmpty(purItem.getItemUnitOfMeasureCode())) {
332: valid = false;
333: GlobalVariables
334: .getErrorMap()
335: .putError(
336: PurapPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE,
337: KFSKeyConstants.ERROR_REQUIRED,
338: ItemFields.UNIT_OF_MEASURE + " in "
339: + identifierString);
340: }
341: }
342:
343: return valid;
344: }
345:
346: /**
347: * Validates that if the item type is quantity based, the item quantity is required and if the item type is amount based, the
348: * quantity is not allowed.
349: *
350: * @param item the item to be validated
351: * @return boolean false if there's any validation that fails.
352: */
353: private boolean validateItemQuantity(PurApItem item,
354: String identifierString) {
355: boolean valid = true;
356: PurchasingItemBase purItem = (PurchasingItemBase) item;
357: if (purItem.getItemType()
358: .isQuantityBasedGeneralLedgerIndicator()
359: && (ObjectUtils.isNull(purItem.getItemQuantity()))) {
360: valid = false;
361: GlobalVariables.getErrorMap().putError(
362: PurapPropertyConstants.QUANTITY,
363: KFSKeyConstants.ERROR_REQUIRED,
364: ItemFields.QUANTITY + " in " + identifierString);
365: } else if (purItem.getItemType()
366: .isAmountBasedGeneralLedgerIndicator()
367: && ObjectUtils.isNotNull(purItem.getItemQuantity())) {
368: valid = false;
369: GlobalVariables.getErrorMap().putError(
370: PurapPropertyConstants.QUANTITY,
371: PurapKeyConstants.ERROR_ITEM_QUANTITY_NOT_ALLOWED,
372: ItemFields.QUANTITY + " in " + identifierString);
373: }
374:
375: return valid;
376: }
377:
378: /**
379: * Performs any validation for the Payment Info tab.
380: *
381: * @param purDocument the purchasing document to be validated
382: * @return boolean false if there's any validation that fails.
383: */
384: public boolean processPaymentInfoValidation(
385: PurchasingDocument purDocument) {
386: boolean valid = true;
387: GlobalVariables.getErrorMap().addToErrorPath(
388: PurapConstants.PAYMENT_INFO_ERRORS);
389: valid &= checkBeginDateBeforeEndDate(purDocument);
390: if (valid
391: && (ObjectUtils.isNotNull(purDocument
392: .getPurchaseOrderBeginDate()) || ObjectUtils
393: .isNotNull(purDocument
394: .getPurchaseOrderEndDate()))) {
395: if (ObjectUtils.isNotNull(purDocument
396: .getPurchaseOrderBeginDate())
397: && ObjectUtils.isNull(purDocument
398: .getPurchaseOrderEndDate())) {
399: GlobalVariables
400: .getErrorMap()
401: .putError(
402: PurapPropertyConstants.PURCHASE_ORDER_END_DATE,
403: PurapKeyConstants.ERROR_PURCHASE_ORDER_BEGIN_DATE_NO_END_DATE);
404: valid &= false;
405: } else {
406: if (ObjectUtils.isNull(purDocument
407: .getPurchaseOrderBeginDate())
408: && ObjectUtils.isNotNull(purDocument
409: .getPurchaseOrderEndDate())) {
410: GlobalVariables
411: .getErrorMap()
412: .putError(
413: PurapPropertyConstants.PURCHASE_ORDER_BEGIN_DATE,
414: PurapKeyConstants.ERROR_PURCHASE_ORDER_END_DATE_NO_BEGIN_DATE);
415: valid &= false;
416: }
417: }
418: }
419: if (valid
420: && ObjectUtils.isNotNull(purDocument
421: .getPurchaseOrderBeginDate())
422: && ObjectUtils.isNotNull(purDocument
423: .getPurchaseOrderEndDate())) {
424: if (ObjectUtils.isNull(purDocument
425: .getRecurringPaymentTypeCode())) {
426: GlobalVariables
427: .getErrorMap()
428: .putError(
429: PurapPropertyConstants.RECURRING_PAYMENT_TYPE_CODE,
430: PurapKeyConstants.ERROR_RECURRING_DATE_NO_TYPE);
431:
432: valid &= false;
433: }
434: } else if (valid
435: && ObjectUtils.isNotNull(purDocument
436: .getRecurringPaymentTypeCode())) {
437: GlobalVariables.getErrorMap().putError(
438: PurapPropertyConstants.PURCHASE_ORDER_BEGIN_DATE,
439: PurapKeyConstants.ERROR_RECURRING_TYPE_NO_DATE);
440: valid &= false;
441: }
442: GlobalVariables.getErrorMap().removeFromErrorPath(
443: PurapConstants.PAYMENT_INFO_ERRORS);
444:
445: return valid;
446: }
447:
448: /**
449: * Performs any validation for the Delivery tab.
450: *
451: * @param purDocument the purchasing document to be validated
452: * @return boolean true (for now it will always return true; this might change someday in the future)
453: */
454: public boolean processDeliveryValidation(
455: PurchasingDocument purDocument) {
456: boolean valid = true;
457: // currently, there is no validation to force at the PUR level for this tab
458:
459: return valid;
460: }
461:
462: /**
463: * Overrides the method in PurchasingAccountsPayableDocumentBase to do all of the vendor validations. The method in
464: * PurchasingAccountsPayableDocumentBase currently does not do any validation (it only returns true all the time).
465: *
466: * @param purapDocument the purchasing document to be validated
467: * @return boolean false if there's any validation that fails.
468: * @see org.kuali.module.purap.rules.PurchasingAccountsPayableDocumentRuleBase#processVendorValidation(org.kuali.module.purap.document.PurchasingAccountsPayableDocument)
469: */
470: @Override
471: public boolean processVendorValidation(
472: PurchasingAccountsPayableDocument purapDocument) {
473: boolean valid = super .processVendorValidation(purapDocument);
474: PurchasingDocument purDocument = (PurchasingDocument) purapDocument;
475: ErrorMap errorMap = GlobalVariables.getErrorMap();
476: if (!purDocument.getRequisitionSourceCode().equals(
477: PurapConstants.RequisitionSources.B2B)) {
478: if (StringUtils
479: .isNotBlank(purDocument.getVendorFaxNumber())) {
480: PhoneNumberValidationPattern phonePattern = new PhoneNumberValidationPattern();
481: if (!phonePattern.matches(purDocument
482: .getVendorFaxNumber())) {
483: valid &= false;
484: errorMap.putError(
485: VendorPropertyConstants.VENDOR_FAX_NUMBER,
486: PurapKeyConstants.ERROR_FAX_NUMBER_INVALID);
487: }
488: }
489: }
490:
491: VendorDetail vendorDetail = SpringContext.getBean(
492: VendorService.class).getVendorDetail(
493: purDocument.getVendorHeaderGeneratedIdentifier(),
494: purDocument.getVendorDetailAssignedIdentifier());
495: if (ObjectUtils.isNull(vendorDetail))
496: return valid;
497: VendorHeader vendorHeader = vendorDetail.getVendorHeader();
498:
499: // make sure that the vendor is not debarred
500: if (vendorDetail.isVendorDebarred()) {
501: valid &= false;
502: errorMap.putError(VendorPropertyConstants.VENDOR_NAME,
503: PurapKeyConstants.ERROR_DEBARRED_VENDOR);
504: }
505:
506: // make sure that the vendor is of allowed type
507: String allowedVendorType = SpringContext
508: .getBean(ParameterService.class)
509: .getParameterValue(
510: ParameterConstants.PURCHASING_DOCUMENT.class,
511: PurapRuleConstants.PURAP_VENDOR_TYPE_ALLOWED_ON_REQ_AND_PO);
512: if (ObjectUtils.isNotNull(vendorHeader)
513: && ObjectUtils.isNotNull(vendorHeader
514: .getVendorTypeCode())
515: && !vendorHeader.getVendorTypeCode().equals(
516: allowedVendorType)) {
517: valid &= false;
518: errorMap.putError(VendorPropertyConstants.VENDOR_NAME,
519: PurapKeyConstants.ERROR_INVALID_VENDOR_TYPE);
520: }
521:
522: // make sure that the vendor is active
523: if (!vendorDetail.isActiveIndicator()) {
524: valid &= false;
525: errorMap.putError(VendorPropertyConstants.VENDOR_NAME,
526: PurapKeyConstants.ERROR_INACTIVE_VENDOR);
527: }
528:
529: return valid;
530: }
531:
532: /**
533: * Implementation of the rule that if a document has a recurring payment begin date and end date, the begin date should come
534: * before the end date. In EPIC, we needed to play around with this order if the fiscal year is the next fiscal year, since we
535: * were dealing just with month and day, but we don't need to do that here; we're dealing with the whole Date object.
536: *
537: * @param purDocument the purchasing document to be validated
538: * @return boolean false if the begin date is not before the end date.
539: */
540: private boolean checkBeginDateBeforeEndDate(
541: PurchasingDocument purDocument) {
542: boolean valid = true;
543: DateTimeService dateTimeService = SpringContext
544: .getBean(DateTimeService.class);
545:
546: Date beginDate = purDocument.getPurchaseOrderBeginDate();
547: Date endDate = purDocument.getPurchaseOrderEndDate();
548: if (ObjectUtils.isNotNull(beginDate)
549: && ObjectUtils.isNotNull(endDate)) {
550: if (dateTimeService.dateDiff(beginDate, endDate, false) <= 0) {
551: valid &= false;
552: GlobalVariables
553: .getErrorMap()
554: .putError(
555: PurapPropertyConstants.PURCHASE_ORDER_END_DATE,
556: PurapKeyConstants.ERROR_PURCHASE_ORDER_BEGIN_DATE_AFTER_END);
557: }
558: }
559:
560: return valid;
561: }
562:
563: /**
564: * Overrides the method in PurapAccountingDocumentRuleBase to invoke the verifyAccountingLinePercent.
565: *
566: * @param accountingDocument the purchasing document to be validated
567: * @param originalAccountingLine the original accounting line
568: * @param updatedAccountingLine the updated accounting line
569: * @return boolean false if there's any validation that fails.
570: * @see org.kuali.module.purap.rules.PurapAccountingDocumentRuleBase#processCustomUpdateAccountingLineBusinessRules(org.kuali.kfs.document.AccountingDocument,
571: * org.kuali.kfs.bo.AccountingLine, org.kuali.kfs.bo.AccountingLine)
572: */
573: @Override
574: protected boolean processCustomUpdateAccountingLineBusinessRules(
575: AccountingDocument accountingDocument,
576: AccountingLine originalAccountingLine,
577: AccountingLine updatedAccountingLine) {
578: if (!super .processCustomUpdateAccountingLineBusinessRules(
579: accountingDocument, originalAccountingLine,
580: updatedAccountingLine)) {
581:
582: return false;
583: }
584:
585: return verifyAccountingLinePercent((PurApAccountingLine) updatedAccountingLine);
586: }
587:
588: /**
589: * Overrides the method in PurapAccountingDocumentRuleBase to also invoke the validateAccountNotExpired and
590: * verifyAccountingLinePercent.
591: *
592: * @param financialDocument the purchasing document to be validated
593: * @param accountingLine the accounting line to be validated before being added
594: * @return boolean false if there's any validation that fails.
595: * @see org.kuali.module.purap.rules.PurapAccountingDocumentRuleBase#processAddAccountingLineBusinessRules(org.kuali.kfs.document.AccountingDocument,
596: * org.kuali.kfs.bo.AccountingLine)
597: */
598: @Override
599: public boolean processAddAccountingLineBusinessRules(
600: AccountingDocument financialDocument,
601: AccountingLine accountingLine) {
602: boolean valid = validateAccountNotExpired(accountingLine);
603: if (!valid) {
604: GlobalVariables.getErrorMap().putError(
605: KFSConstants.ACCOUNT_NUMBER_PROPERTY_NAME,
606: PurapKeyConstants.ERROR_ITEM_ACCOUNT_EXPIRED,
607: KFSConstants.EMPTY_STRING,
608: accountingLine.getAccountNumber());
609: }
610: valid &= super .processAddAccountingLineBusinessRules(
611: financialDocument, accountingLine);
612: if (!valid) {
613:
614: return false;
615: }
616:
617: return verifyAccountingLinePercent((PurApAccountingLine) accountingLine);
618: }
619:
620: /**
621: * Validates that the account is not expired.
622: *
623: * @param accountingLine The account to be validated.
624: * @return boolean false if the account is expired.
625: */
626: private boolean validateAccountNotExpired(
627: AccountingLine accountingLine) {
628: accountingLine.refreshNonUpdateableReferences();
629: if (accountingLine.getAccount() != null
630: && accountingLine.getAccount().isExpired()) {
631:
632: return false;
633: }
634:
635: return true;
636: }
637:
638: /**
639: * Verifies that the accounting line percent is a whole number.
640: *
641: * @param purapAccountingLine the accounting line to be validated
642: * @return boolean false if the accounting line percent is not a whole number.
643: */
644: private boolean verifyAccountingLinePercent(
645: PurApAccountingLine purapAccountingLine) {
646: // make sure it's a whole number
647: if (purapAccountingLine.getAccountLinePercent()
648: .stripTrailingZeros().scale() > 0) {
649: GlobalVariables
650: .getErrorMap()
651: .putError(
652: PurapPropertyConstants.ACCOUNTS,
653: PurapKeyConstants.ERROR_PURCHASING_PERCENT_NOT_WHOLE,
654: purapAccountingLine.getAccountLinePercent()
655: .toPlainString());
656:
657: return false;
658: }
659:
660: return true;
661: }
662:
663: }
|