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.bo.BusinessObject;
023: import org.kuali.core.service.DataDictionaryService;
024: import org.kuali.core.util.GlobalVariables;
025: import org.kuali.core.util.KualiDecimal;
026: import org.kuali.core.util.ObjectUtils;
027: import org.kuali.kfs.KFSConstants;
028: import org.kuali.kfs.KFSKeyConstants;
029: import org.kuali.kfs.KFSPropertyConstants;
030: import org.kuali.kfs.bo.AccountingLine;
031: import org.kuali.kfs.bo.GeneralLedgerPendingEntry;
032: import org.kuali.kfs.bo.SourceAccountingLine;
033: import org.kuali.kfs.context.SpringContext;
034: import org.kuali.kfs.document.AccountingDocument;
035: import org.kuali.kfs.service.ParameterEvaluator;
036: import org.kuali.kfs.service.ParameterService;
037: import org.kuali.module.chart.bo.ObjectCode;
038: import org.kuali.module.purap.PurapConstants;
039: import org.kuali.module.purap.PurapKeyConstants;
040: import org.kuali.module.purap.PurapPropertyConstants;
041: import org.kuali.module.purap.PurapRuleConstants;
042: import org.kuali.module.purap.PurapConstants.PurapDocTypeCodes;
043: import org.kuali.module.purap.bo.CreditMemoAccount;
044: import org.kuali.module.purap.bo.CreditMemoItem;
045: import org.kuali.module.purap.bo.PurApAccountingLine;
046: import org.kuali.module.purap.bo.PurApItem;
047: import org.kuali.module.purap.bo.PurchaseOrderItem;
048: import org.kuali.module.purap.document.AccountsPayableDocument;
049: import org.kuali.module.purap.document.CreditMemoDocument;
050: import org.kuali.module.purap.document.PaymentRequestDocument;
051: import org.kuali.module.purap.document.PurchaseOrderDocument;
052: import org.kuali.module.purap.document.PurchasingAccountsPayableDocument;
053: import org.kuali.module.purap.service.CreditMemoService;
054: import org.kuali.module.purap.service.PaymentRequestService;
055: import org.kuali.module.purap.service.PurapGeneralLedgerService;
056: import org.kuali.module.purap.service.PurchaseOrderService;
057: import org.kuali.module.vendor.bo.VendorDetail;
058: import org.kuali.module.vendor.service.VendorService;
059: import org.kuali.module.vendor.util.VendorUtils;
060:
061: /**
062: * Business rules for the Credit Memo Document.
063: */
064: public class CreditMemoDocumentRule extends
065: AccountsPayableDocumentRuleBase {
066:
067: /**
068: * Validation that occurs on Route of the document.
069: *
070: * @param purapDocument - Credit Memo Document Instance
071: * @return boolean - true if validation was ok, false if there were errors
072: */
073: @Override
074: public boolean processValidation(
075: PurchasingAccountsPayableDocument purapDocument) {
076: boolean valid = super .processValidation(purapDocument);
077:
078: CreditMemoDocument cmDocument = (CreditMemoDocument) purapDocument;
079:
080: valid = processDocumentOverviewValidation(cmDocument);
081: valid &= processItemValidation(cmDocument);
082: valid &= validateTotalOverZero(cmDocument);
083:
084: return valid;
085: }
086:
087: /**
088: * Validates a new accounting line.
089: *
090: * @see org.kuali.module.purap.rules.PurchasingAccountsPayableDocumentRuleBase#processCustomAddAccountingLineBusinessRules(org.kuali.kfs.document.AccountingDocument,
091: * org.kuali.kfs.bo.AccountingLine)
092: */
093: @Override
094: protected boolean processCustomAddAccountingLineBusinessRules(
095: AccountingDocument financialDocument,
096: AccountingLine accountingLine) {
097: boolean valid = true;
098:
099: CreditMemoAccount cmAccount = (CreditMemoAccount) accountingLine;
100:
101: valid = verifyAccountingStringsBetween0And100Percent(cmAccount);
102: valid &= validateObjectCode(
103: (CreditMemoDocument) financialDocument, cmAccount);
104:
105: return valid;
106: }
107:
108: /**
109: * Validation that occurs when the continue action is selected from the initial screen.
110: *
111: * @param document - Credit Memo Document Instance
112: * @return boolean - true if validation was ok, false if there were errors
113: */
114: public boolean processContinueAccountsPayableBusinessRules(
115: AccountsPayableDocument document) {
116: boolean valid = true;
117:
118: CreditMemoDocument cmDocument = (CreditMemoDocument) document;
119: valid = validateInitTabRequiredFields(cmDocument);
120:
121: if (valid) {
122: valid = validateInitTabReferenceNumbers(cmDocument);
123: }
124:
125: if (valid && cmDocument.isSourceDocumentPurchaseOrder()) {
126: valid = checkPurchaseOrderForInvoicedItems(cmDocument);
127: }
128:
129: return valid;
130: }
131:
132: /**
133: * Validates extended price field and cm totals after a calculation has been performed.
134: *
135: * @see org.kuali.module.purap.rule.CalculateAccountsPayableRule#processCalculateAccountsPayableBusinessRules(org.kuali.module.purap.document.AccountsPayableDocument)
136: */
137: public boolean processCalculateAccountsPayableBusinessRules(
138: AccountsPayableDocument document) {
139: boolean valid = true;
140: CreditMemoDocument cmDocument = (CreditMemoDocument) document;
141:
142: // flag line just gives warnings
143: flagLineItemTotals(cmDocument.getItems());
144:
145: valid = validateTotalMatchesVendorAmount(cmDocument);
146: valid = valid && validateTotalOverZero(cmDocument);
147:
148: return valid;
149: }
150:
151: /**
152: * Validates item fields are valid for the calculation process.
153: *
154: * @see org.kuali.module.purap.rule.PreCalculateAccountsPayableRule#processPreCalculateAccountsPayableBusinessRules(org.kuali.module.purap.document.AccountsPayableDocument)
155: */
156: public boolean processPreCalculateAccountsPayableBusinessRules(
157: AccountsPayableDocument document) {
158: boolean valid = true;
159: CreditMemoDocument cmDocument = (CreditMemoDocument) document;
160:
161: return valid;
162: }
163:
164: /**
165: * Validates the necessary fields on the init tab were given and credit memo date is valid. (NOTE: formats for cm date and
166: * number already performed by pojo conversion)
167: *
168: * @param cmDocument - credit memo document which contains the fields that need checked
169: * @return boolean - true if validation was ok, false if there were errors
170: */
171: protected boolean validateInitTabRequiredFields(
172: CreditMemoDocument cmDocument) {
173: boolean valid = true;
174:
175: valid = validateRequiredField(cmDocument,
176: PurapPropertyConstants.CREDIT_MEMO_NUMBER);
177: valid = valid
178: && validateRequiredField(cmDocument,
179: PurapPropertyConstants.CREDIT_MEMO_AMOUNT);
180: boolean creditMemoDateExist = validateRequiredField(cmDocument,
181: PurapPropertyConstants.CREDIT_MEMO_DATE);
182:
183: if (creditMemoDateExist) {
184: if (SpringContext.getBean(PaymentRequestService.class)
185: .isInvoiceDateAfterToday(
186: cmDocument.getCreditMemoDate())) {
187: String label = SpringContext
188: .getBean(DataDictionaryService.class)
189: .getAttributeErrorLabel(
190: CreditMemoDocument.class,
191: PurapPropertyConstants.CREDIT_MEMO_DATE);
192: GlobalVariables.getErrorMap().putError(
193: PurapPropertyConstants.CREDIT_MEMO_DATE,
194: PurapKeyConstants.ERROR_INVALID_INVOICE_DATE,
195: label);
196: valid = false;
197: }
198: }
199:
200: return valid;
201:
202: }
203:
204: /**
205: * Validates only one of preq, po, or vendor number was given. Then validates the existence of that number.
206: *
207: * @param cmDocument - credit memo document which contains init reference numbers
208: * @return boolean - true if validation was ok, false if there were errors
209: */
210: protected boolean validateInitTabReferenceNumbers(
211: CreditMemoDocument cmDocument) {
212: boolean valid = true;
213: // GlobalVariables.getErrorMap().clearErrorPath();
214: // GlobalVariables.getErrorMap().addToErrorPath(RicePropertyConstants.DOCUMENT);
215:
216: if (!(ObjectUtils.isNotNull(cmDocument
217: .getPaymentRequestIdentifier())
218: ^ StringUtils.isNotEmpty(cmDocument.getVendorNumber()) ^ ObjectUtils
219: .isNotNull(cmDocument.getPurchaseOrderIdentifier()))
220: || (ObjectUtils.isNotNull(cmDocument
221: .getPaymentRequestIdentifier())
222: && StringUtils.isNotEmpty(cmDocument
223: .getVendorNumber()) && ObjectUtils
224: .isNotNull(cmDocument
225: .getPurchaseOrderIdentifier()))) {
226: GlobalVariables
227: .getErrorMap()
228: .putErrorWithoutFullErrorPath(
229: PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER,
230: PurapKeyConstants.ERROR_CREDIT_MEMO_REQUIRED_FIELDS);
231: valid = false;
232: } else {
233: // Make sure PREQ is valid if entered
234: Integer preqNumber = cmDocument
235: .getPaymentRequestIdentifier();
236: if (ObjectUtils.isNotNull(preqNumber)) {
237: PaymentRequestDocument preq = SpringContext.getBean(
238: PaymentRequestService.class)
239: .getPaymentRequestById(preqNumber);
240: if (ObjectUtils.isNull(preq)) {
241: GlobalVariables
242: .getErrorMap()
243: .putErrorWithoutFullErrorPath(
244: PurapPropertyConstants.PAYMENT_REQUEST_ID,
245: PurapKeyConstants.ERROR_CREDIT_MEMO_PAYMENT_REQEUEST_INVALID,
246: preqNumber.toString());
247: valid = false;
248: } else if ((PurapConstants.PaymentRequestStatuses.IN_PROCESS
249: .equals(preq.getStatusCode()))
250: || (PurapConstants.PaymentRequestStatuses.CANCELLED_STATUSES
251: .contains(preq.getStatusCode()))) {
252: GlobalVariables
253: .getErrorMap()
254: .putErrorWithoutFullErrorPath(
255: PurapPropertyConstants.PAYMENT_REQUEST_ID,
256: PurapKeyConstants.ERROR_CREDIT_MEMO_PAYMENT_REQEUEST_INVALID_SATATUS,
257: preqNumber.toString());
258: valid = false;
259: }
260: }
261:
262: // Make sure PO # is valid if entered
263: Integer purchaseOrderID = cmDocument
264: .getPurchaseOrderIdentifier();
265: if (ObjectUtils.isNotNull(purchaseOrderID)) {
266: PurchaseOrderDocument purchaseOrder = SpringContext
267: .getBean(PurchaseOrderService.class)
268: .getCurrentPurchaseOrder(purchaseOrderID);
269: if (ObjectUtils.isNull(purchaseOrder)) {
270: GlobalVariables
271: .getErrorMap()
272: .putError(
273: PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER,
274: PurapKeyConstants.ERROR_CREDIT_MEMO_PURCHASE_ORDER_INVALID,
275: purchaseOrderID.toString());
276: valid = false;
277: } else if (purchaseOrder.isPendingActionIndicator()) {
278: GlobalVariables
279: .getErrorMap()
280: .putError(
281: PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER,
282: PurapKeyConstants.ERROR_PURCHASE_PENDING_ACTION);
283: valid &= false;
284: } else if (!(StringUtils.equals(purchaseOrder
285: .getStatusCode(),
286: PurapConstants.PurchaseOrderStatuses.OPEN) || StringUtils
287: .equals(
288: purchaseOrder.getStatusCode(),
289: PurapConstants.PurchaseOrderStatuses.CLOSED))) {
290: GlobalVariables
291: .getErrorMap()
292: .putError(
293: PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER,
294: PurapKeyConstants.ERROR_CREDIT_MEMO_PURCAHSE_ORDER_INVALID_STATUS,
295: purchaseOrderID.toString());
296: valid = false;
297: }
298: }
299:
300: // Make sure vendorNumber is valid if entered
301: String vendorNumber = cmDocument.getVendorNumber();
302: if (StringUtils.isNotEmpty(vendorNumber)) {
303: VendorDetail vendor = SpringContext.getBean(
304: VendorService.class).getVendorDetail(
305: VendorUtils.getVendorHeaderId(vendorNumber),
306: VendorUtils.getVendorDetailId(vendorNumber));
307: if (ObjectUtils.isNull(vendor)) {
308: GlobalVariables
309: .getErrorMap()
310: .putErrorWithoutFullErrorPath(
311: PurapPropertyConstants.VENDOR_NUMBER,
312: PurapKeyConstants.ERROR_CREDIT_MEMO_VENDOR_NUMBER_INVALID,
313: vendorNumber);
314: valid = false;
315: }
316: }
317: }
318: // GlobalVariables.getErrorMap().clearErrorPath();
319: return valid;
320: }
321:
322: /**
323: * Validates item lines for the document. Checks numeric fields to verify they are positive and compares with source quantity
324: * and price.
325: *
326: * @param cmDocument - credit memo document which contains the po reference
327: * @return boolean - true if validation was ok, false if there were errors
328: */
329: @Override
330: public boolean processItemValidation(
331: PurchasingAccountsPayableDocument purapDocument) {
332: boolean valid = true;
333:
334: CreditMemoDocument cmDocument = (CreditMemoDocument) purapDocument;
335:
336: List itemList = cmDocument.getItems();
337: for (int i = 0; i < itemList.size(); i++) {
338: CreditMemoItem item = (CreditMemoItem) itemList.get(i);
339: item
340: .refreshReferenceObject(PurapPropertyConstants.ITEM_TYPE);
341: if (item.getItemType().isItemTypeAboveTheLineIndicator()) {
342: String errorKeyPrefix = KFSPropertyConstants.DOCUMENT
343: + "." + PurapPropertyConstants.ITEM + "["
344: + Integer.toString(i) + "].";
345:
346: valid &= validateItemQuantity(cmDocument, item,
347: errorKeyPrefix
348: + PurapPropertyConstants.QUANTITY);
349: valid &= validateItemUnitPrice(
350: cmDocument,
351: item,
352: errorKeyPrefix
353: + PurapPropertyConstants.ITEM_UNIT_PRICE);
354: valid &= validateItemExtendedPrice(cmDocument, item,
355: errorKeyPrefix
356: + PurapPropertyConstants.EXTENDED_PRICE);
357:
358: if (item.getExtendedPrice() != null
359: && item.getExtendedPrice().isNonZero()) {
360: valid &= processAccountValidation(purapDocument,
361: item.getSourceAccountingLines(),
362: errorKeyPrefix);
363: }
364: } else {
365: String documentTypeClassName = purapDocument.getClass()
366: .getName();
367: String[] documentTypeArray = StringUtils.split(
368: documentTypeClassName, ".");
369: String documentType = documentTypeArray[documentTypeArray.length - 1];
370: valid &= validateBelowTheLineValues(documentType, item);
371:
372: if (item.getExtendedPrice() != null
373: && item.getExtendedPrice().isNonZero()) {
374: valid &= processAccountValidation(purapDocument,
375: item.getSourceAccountingLines(), item
376: .getItemIdentifierString());
377: }
378: }
379: }
380:
381: return valid;
382: }
383:
384: /**
385: * Validates the credit memo quantity for an item line.
386: *
387: * @param cmDocument - credit memo document
388: * @param item - credit memo item
389: * @param errorKey - key to associate any generated errors with
390: * @return boolean - true if quantity is valid, false if invalid
391: */
392: public boolean validateItemQuantity(CreditMemoDocument cmDocument,
393: CreditMemoItem item, String errorKey) {
394: boolean valid = true;
395:
396: if (item.getItemQuantity() != null) {
397: if (item.getItemQuantity().isNegative()) {
398: String label = SpringContext.getBean(
399: DataDictionaryService.class)
400: .getAttributeErrorLabel(CreditMemoItem.class,
401: PurapPropertyConstants.QUANTITY);
402: GlobalVariables
403: .getErrorMap()
404: .putError(
405: errorKey,
406: PurapKeyConstants.ERROR_CREDIT_MEMO_ITEM_AMOUNT_NONPOSITIVE,
407: label);
408: valid = false;
409: }
410:
411: // check cm quantity is not greater than invoiced quantity
412: KualiDecimal invoicedQuantity = getSourceTotalInvoiceQuantity(
413: cmDocument, item);
414: if (item.getItemQuantity().isGreaterThan(invoicedQuantity)) {
415: GlobalVariables
416: .getErrorMap()
417: .putError(
418: errorKey,
419: PurapKeyConstants.ERROR_CREDIT_MEMO_ITEM_QUANTITY_TOOMUCH);
420: valid = false;
421: }
422: } else {
423: // check if quantity should be required
424: KualiDecimal invoicedQuantity = getSourceTotalInvoiceQuantity(
425: cmDocument, item);
426: if (item.getItemType()
427: .isQuantityBasedGeneralLedgerIndicator()
428: && (invoicedQuantity != null && invoicedQuantity
429: .isGreaterThan(KualiDecimal.ZERO))
430: && (item.getExtendedPrice() != null && item
431: .getExtendedPrice().isGreaterThan(
432: KualiDecimal.ZERO))) {
433: String label = SpringContext.getBean(
434: DataDictionaryService.class)
435: .getAttributeErrorLabel(CreditMemoItem.class,
436: PurapPropertyConstants.QUANTITY);
437: GlobalVariables.getErrorMap().putError(errorKey,
438: KFSKeyConstants.ERROR_REQUIRED, label);
439: valid = false;
440: }
441: }
442:
443: return valid;
444: }
445:
446: /**
447: * Validates the credit memo unit price for an item line.
448: *
449: * @param cmDocument - credit memo document
450: * @param item - credit memo item
451: * @param errorKey - key to associate any generated errors with
452: * @return boolean - true if quantity is valid, false if invalid
453: */
454: public boolean validateItemUnitPrice(CreditMemoDocument cmDocument,
455: CreditMemoItem item, String errorKey) {
456: boolean valid = true;
457:
458: if (item.getItemUnitPrice() != null) {
459: // verify unit price is not negative
460: if (item.getItemUnitPrice().signum() == -1) {
461: String label = SpringContext.getBean(
462: DataDictionaryService.class)
463: .getAttributeErrorLabel(CreditMemoItem.class,
464: PurapPropertyConstants.ITEM_UNIT_PRICE);
465: GlobalVariables
466: .getErrorMap()
467: .putError(
468: errorKey,
469: PurapKeyConstants.ERROR_CREDIT_MEMO_ITEM_AMOUNT_NONPOSITIVE,
470: label);
471: valid = false;
472: }
473: }
474:
475: return valid;
476: }
477:
478: /**
479: * Validates the credit memo extended price for an item line.
480: *
481: * @param cmDocument - credit memo document
482: * @param item - credit memo item
483: * @param errorKey - key to associate any generated errors with
484: * @return boolean - true if quantity is valid, false if invalid
485: */
486: public boolean validateItemExtendedPrice(
487: CreditMemoDocument cmDocument, CreditMemoItem item,
488: String errorKey) {
489: boolean valid = true;
490:
491: if (item.getExtendedPrice() != null) {
492: if (item.getExtendedPrice().isNegative()) {
493: String label = SpringContext.getBean(
494: DataDictionaryService.class)
495: .getAttributeErrorLabel(CreditMemoItem.class,
496: PurapPropertyConstants.EXTENDED_PRICE);
497: GlobalVariables
498: .getErrorMap()
499: .putError(
500: errorKey,
501: PurapKeyConstants.ERROR_CREDIT_MEMO_ITEM_AMOUNT_NONPOSITIVE,
502: label);
503: valid = false;
504: }
505: if (!cmDocument.isSourceVendor()) {
506: // check cm extended price is not greater than total invoiced amount
507: KualiDecimal invoicedAmount = null;
508: if (cmDocument.isSourceDocumentPurchaseOrder()) {
509: invoicedAmount = item.getPoExtendedPrice();
510: } else {
511: invoicedAmount = item.getPreqExtendedPrice();
512: }
513:
514: if (invoicedAmount == null) {
515: invoicedAmount = KualiDecimal.ZERO;
516: }
517:
518: if (item.getExtendedPrice().isGreaterThan(
519: invoicedAmount)) {
520: GlobalVariables
521: .getErrorMap()
522: .putError(
523: errorKey,
524: PurapKeyConstants.ERROR_CREDIT_MEMO_ITEM_EXTENDEDPRICE_TOOMUCH);
525: valid = false;
526: }
527: }
528:
529: }
530:
531: return valid;
532: }
533:
534: /**
535: * Returns the total invoiced quantity for the item line based on the type of credit memo.
536: *
537: * @param cmDocument - credit memo document
538: * @param item - credit memo item line to return total invoice quantity
539: * @return KualiDecimal - total invoiced quantity
540: */
541: private KualiDecimal getSourceTotalInvoiceQuantity(
542: CreditMemoDocument cmDocument, CreditMemoItem item) {
543: KualiDecimal invoicedQuantity = null;
544:
545: if (cmDocument.isSourceDocumentPurchaseOrder()) {
546: invoicedQuantity = item.getPoInvoicedTotalQuantity();
547: } else {
548: invoicedQuantity = item.getPreqInvoicedTotalQuantity();
549: }
550:
551: return invoicedQuantity;
552: }
553:
554: /**
555: * Verifies the purchase order for the credit memo has at least one invoiced item. If no invoiced items are found, a credit memo
556: * cannot be processed against the document.
557: *
558: * @param cmDocument - credit memo document which contains the po reference
559: * @return boolean - true if validation was ok, false if there were errors
560: */
561: protected boolean checkPurchaseOrderForInvoicedItems(
562: CreditMemoDocument cmDocument) {
563: boolean hasInvoicedItems = true;
564: GlobalVariables.getErrorMap().clearErrorPath();
565: GlobalVariables.getErrorMap().addToErrorPath(
566: RicePropertyConstants.DOCUMENT);
567:
568: PurchaseOrderDocument poDocument = SpringContext.getBean(
569: PurchaseOrderService.class).getCurrentPurchaseOrder(
570: cmDocument.getPurchaseOrderIdentifier());
571: List<PurchaseOrderItem> invoicedItems = SpringContext.getBean(
572: CreditMemoService.class).getPOInvoicedItems(poDocument);
573:
574: if (invoicedItems == null || invoicedItems.isEmpty()) {
575: GlobalVariables
576: .getErrorMap()
577: .putError(
578: PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER,
579: PurapKeyConstants.ERROR_CREDIT_MEMO_PURCAHSE_ORDER_NOITEMS);
580: hasInvoicedItems = false;
581: }
582:
583: GlobalVariables.getErrorMap().clearErrorPath();
584: return hasInvoicedItems;
585: }
586:
587: /**
588: * Helper method to perform required field checks add error messages if the validation fails. Adds an error required to
589: * GlobalVariables.errorMap using the given fieldName as the error key and retrieving the error label from the data dictionary
590: * for the error required message param.
591: *
592: * @param businessObject - Business object to check for value
593: * @param fieldName - Name of the property in the business object
594: */
595: private boolean validateRequiredField(
596: BusinessObject businessObject, String fieldName) {
597: boolean valid = true;
598:
599: Object fieldValue = ObjectUtils.getPropertyValue(
600: businessObject, fieldName);
601: if (fieldValue == null
602: || (fieldValue instanceof String && StringUtils
603: .isBlank(fieldName))) {
604: String label = SpringContext.getBean(
605: DataDictionaryService.class)
606: .getAttributeErrorLabel(businessObject.getClass(),
607: fieldName);
608: GlobalVariables.getErrorMap().putError(fieldName,
609: KFSKeyConstants.ERROR_REQUIRED, label);
610: valid = false;
611: }
612:
613: return valid;
614: }
615:
616: /**
617: * Validates the credit memo total matches the vendor credit memo amount. If the unmatched override is set to true, user has
618: * choosen to accept the difference and there should be no error added.
619: *
620: * @param cmDocument - credit memo document
621: * @return boolean - true if amounts match, false if they do not match
622: */
623: private boolean validateTotalMatchesVendorAmount(
624: CreditMemoDocument cmDocument) {
625: boolean valid = true;
626:
627: if (cmDocument.getGrandTotal().compareTo(
628: cmDocument.getCreditMemoAmount()) != 0
629: && !cmDocument.isUnmatchedOverride()) {
630: GlobalVariables
631: .getMessageList()
632: .add(
633: PurapKeyConstants.ERROR_CREDIT_MEMO_INVOICE_AMOUNT_NONMATCH);
634: valid = false;
635: }
636:
637: return valid;
638: }
639:
640: /**
641: * Validates the credit memo total is over zero.
642: *
643: * @param cmDocument - credit memo document
644: * @return boolean - true if amount is over zero, false if not
645: */
646: private boolean validateTotalOverZero(CreditMemoDocument cmDocument) {
647: boolean valid = true;
648:
649: if (!cmDocument.getGrandTotal().isPositive()) {
650: GlobalVariables.getErrorMap().putError(
651: KFSPropertyConstants.DOCUMENT + "."
652: + PurapPropertyConstants.ITEM,
653: PurapKeyConstants.ERROR_CREDIT_MEMO_TOTAL_ZERO);
654: valid = false;
655: }
656:
657: return valid;
658: }
659:
660: /**
661: * Compares the extended price of each item to the calculated price and if different adds a warning message.
662: *
663: * @param itemList - list of items to check
664: */
665: private void flagLineItemTotals(List<PurApItem> itemList) {
666: for (int i = 0; i < itemList.size(); i++) {
667: CreditMemoItem item = (CreditMemoItem) itemList.get(i);
668: if (item.getItemQuantity() != null
669: && item.calculateExtendedPrice().compareTo(
670: item.getExtendedPrice()) != 0) {
671: String errorKey = KFSPropertyConstants.DOCUMENT + "."
672: + PurapPropertyConstants.ITEM + "["
673: + Integer.toString(i) + "]."
674: + PurapPropertyConstants.EXTENDED_PRICE;
675: GlobalVariables
676: .getErrorMap()
677: .putError(
678: errorKey,
679: PurapKeyConstants.ERROR_PAYMENT_REQUEST_ITEM_TOTAL_NOT_EQUAL);
680: }
681: }
682: }
683:
684: /**
685: * Validates object code of accounting line against setup rule restrictions.
686: *
687: * @param cmDocument - credit memo document
688: * @param account - cm accounting line
689: * @return boolean - true if object code is valid, false if it fails a rule
690: */
691: public boolean validateObjectCode(CreditMemoDocument cmDocument,
692: PurApAccountingLine account) {
693: boolean valid = true;
694: ObjectCode objectCode = account.getObjectCode();
695:
696: ParameterEvaluator parameterEvaluator = SpringContext
697: .getBean(ParameterService.class)
698: .getParameterEvaluator(
699: CreditMemoDocument.class,
700: PurapRuleConstants.VALID_OBJECT_LEVELS_BY_OBJECT_TYPE_PARM_NM,
701: PurapRuleConstants.INVALID_OBJECT_LEVELS_BY_OBJECT_TYPE_PARM_NM,
702: objectCode.getFinancialObjectTypeCode(),
703: objectCode.getFinancialObjectLevelCode());
704: return parameterEvaluator.evaluateAndAddError(
705: SourceAccountingLine.class,
706: "objectCode.financialObjectLevelCode",
707: KFSPropertyConstants.FINANCIAL_OBJECT_CODE);
708: }
709:
710: /**
711: * Verifies the percentage given is not null and between 1 and 100.
712: *
713: * @param account - cm accounting line
714: * @return boolean - true if percentage is valid, false if not
715: */
716: private boolean verifyAccountingStringsBetween0And100Percent(
717: PurApAccountingLine account) {
718: boolean isValid = true;
719:
720: if (validateRequiredField(account,
721: PurapPropertyConstants.ACCOUNT_LINE_PERCENT)) {
722: double pct = account.getAccountLinePercent().doubleValue();
723: if (pct <= 0 || pct > 100) {
724: GlobalVariables
725: .getErrorMap()
726: .putError(
727: PurapPropertyConstants.ACCOUNT_LINE_PERCENT,
728: PurapKeyConstants.ERROR_CREDIT_MEMO_LINE_PERCENT);
729: isValid = false;
730: }
731: } else {
732: isValid = false;
733: }
734:
735: return isValid;
736: }
737:
738: /**
739: * Forces GL entries to be approved before document final approval.
740: *
741: * @see org.kuali.module.purap.rules.PurapAccountingDocumentRuleBase#customizeExplicitGeneralLedgerPendingEntry(org.kuali.kfs.document.AccountingDocument, org.kuali.kfs.bo.AccountingLine, org.kuali.kfs.bo.GeneralLedgerPendingEntry)
742: */
743: @Override
744: protected void customizeExplicitGeneralLedgerPendingEntry(
745: AccountingDocument accountingDocument,
746: AccountingLine accountingLine,
747: GeneralLedgerPendingEntry explicitEntry) {
748: super .customizeExplicitGeneralLedgerPendingEntry(
749: accountingDocument, accountingLine, explicitEntry);
750:
751: CreditMemoDocument cm = (CreditMemoDocument) accountingDocument;
752:
753: SpringContext.getBean(PurapGeneralLedgerService.class)
754: .customizeGeneralLedgerPendingEntry(cm, accountingLine,
755: explicitEntry, cm.getPurchaseOrderIdentifier(),
756: cm.getDebitCreditCodeForGLEntries(),
757: PurapDocTypeCodes.CREDIT_MEMO_DOCUMENT,
758: cm.isGenerateEncumbranceEntries());
759:
760: // CMs do not wait for document final approval to post GL entries; here we are forcing them to be APPROVED
761: explicitEntry
762: .setFinancialDocumentApprovedCode(KFSConstants.PENDING_ENTRY_APPROVED_STATUS_CODE.APPROVED);
763: }
764:
765: /**
766: * @see org.kuali.kfs.rules.AccountingDocumentRuleBase#checkAccountingLineAccountAccessibility(org.kuali.kfs.document.AccountingDocument,
767: * org.kuali.kfs.bo.AccountingLine, org.kuali.kfs.rules.AccountingDocumentRuleBase.AccountingLineAction)
768: */
769: @Override
770: protected boolean checkAccountingLineAccountAccessibility(
771: AccountingDocument financialDocument,
772: AccountingLine accountingLine, AccountingLineAction action) {
773: // always return true because CM does not have a FO type of level
774: return true;
775: }
776:
777: /**
778: * @see org.kuali.module.purap.rule.CancelAccountsPayableRule#processCancelAccountsPayableBusinessRules(org.kuali.module.purap.document.AccountsPayableDocument)
779: */
780: public boolean processCancelAccountsPayableBusinessRules(
781: AccountsPayableDocument document) {
782: CreditMemoDocument creditMemoDocument = (CreditMemoDocument) document;
783: return SpringContext.getBean(CreditMemoService.class)
784: .canCancelCreditMemo(
785: creditMemoDocument,
786: GlobalVariables.getUserSession()
787: .getUniversalUser());
788: }
789: }
|