001: /*
002: * Copyright 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:
017: package org.kuali.module.purap.document;
018:
019: import java.sql.Date;
020: import java.sql.Timestamp;
021: import java.util.ArrayList;
022: import java.util.List;
023:
024: import org.apache.commons.lang.StringUtils;
025: import org.kuali.core.bo.user.UniversalUser;
026: import org.kuali.core.document.Document;
027: import org.kuali.core.rule.event.KualiDocumentEvent;
028: import org.kuali.core.service.DataDictionaryService;
029: import org.kuali.core.service.DateTimeService;
030: import org.kuali.core.service.NoteService;
031: import org.kuali.core.util.GlobalVariables;
032: import org.kuali.core.util.KualiDecimal;
033: import org.kuali.core.util.ObjectUtils;
034: import org.kuali.core.workflow.service.WorkflowDocumentService;
035: import org.kuali.kfs.context.SpringContext;
036: import org.kuali.kfs.service.ConciseXmlDocumentConversionService;
037: import org.kuali.kfs.service.ParameterService;
038: import org.kuali.module.purap.PurapConstants;
039: import org.kuali.module.purap.PurapParameterConstants;
040: import org.kuali.module.purap.PurapPropertyConstants;
041: import org.kuali.module.purap.PurapConstants.CREDIT_MEMO_TYPE_LABELS;
042: import org.kuali.module.purap.PurapConstants.CreditMemoStatuses;
043: import org.kuali.module.purap.PurapWorkflowConstants.NodeDetails;
044: import org.kuali.module.purap.PurapWorkflowConstants.CreditMemoDocument.NodeDetailEnum;
045: import org.kuali.module.purap.bo.CreditMemoItem;
046: import org.kuali.module.purap.rule.event.ContinueAccountsPayableEvent;
047: import org.kuali.module.purap.service.AccountsPayableDocumentSpecificService;
048: import org.kuali.module.purap.service.AccountsPayableService;
049: import org.kuali.module.purap.service.CreditMemoCreateService;
050: import org.kuali.module.purap.service.CreditMemoService;
051: import org.kuali.module.purap.service.PaymentRequestService;
052: import org.kuali.module.purap.service.PurapService;
053:
054: import edu.iu.uis.eden.exception.WorkflowException;
055:
056: /**
057: * Credit Memo Document Business Object. Contains the fields associated with the main document table.
058: */
059: public class CreditMemoDocument extends AccountsPayableDocumentBase {
060: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
061: .getLogger(CreditMemoDocument.class);
062:
063: private Integer paymentRequestIdentifier;
064: private String creditMemoNumber;
065: private Date creditMemoDate;
066: private KualiDecimal creditMemoAmount;
067: private Timestamp creditMemoPaidTimestamp;
068: private String itemMiscellaneousCreditDescription;
069: private Date purchaseOrderEndDate;
070:
071: private PaymentRequestDocument paymentRequestDocument;
072:
073: /**
074: * Default constructor.
075: */
076: public CreditMemoDocument() {
077: super ();
078: }
079:
080: /**
081: * @see org.kuali.core.document.DocumentBase#getDocumentRepresentationForSerialization()
082: */
083: @Override
084: protected Document getDocumentRepresentationForSerialization() {
085: return SpringContext.getBean(
086: ConciseXmlDocumentConversionService.class)
087: .getDocumentForSerialization(this );
088: }
089:
090: public boolean isSourceDocumentPaymentRequest() {
091: return getPaymentRequestIdentifier() != null;
092: }
093:
094: public boolean isSourceDocumentPurchaseOrder() {
095: return (!isSourceDocumentPaymentRequest())
096: && (getPurchaseOrderIdentifier() != null);
097: }
098:
099: public boolean isSourceVendor() {
100: return (!isSourceDocumentPaymentRequest())
101: && (!isSourceDocumentPurchaseOrder());
102: }
103:
104: /**
105: * Initializes the values for a new document.
106: */
107: public void initiateDocument() {
108: LOG.debug("initiateDocument() started");
109: setStatusCode(PurapConstants.CreditMemoStatuses.INITIATE);
110:
111: UniversalUser currentUser = (UniversalUser) GlobalVariables
112: .getUserSession().getUniversalUser();
113: setAccountsPayableProcessorIdentifier(currentUser
114: .getPersonUniversalIdentifier());
115: setProcessingCampusCode(currentUser.getCampusCode());
116: }
117:
118: /**
119: * Clear out the initially populated fields.
120: */
121: public void clearInitFields() {
122: LOG.debug("clearDocument() started");
123:
124: // Clearing document overview fields
125: getDocumentHeader().setFinancialDocumentDescription(null);
126: getDocumentHeader().setExplanation(null);
127: getDocumentHeader().setFinancialDocumentTotalAmount(null);
128: getDocumentHeader().setOrganizationDocumentNumber(null);
129:
130: // Clearing document Init fields
131: setPurchaseOrderIdentifier(null);
132: setCreditMemoNumber(null);
133: setCreditMemoDate(null);
134: setCreditMemoAmount(null);
135: setVendorNumber(null);
136: setPaymentRequestIdentifier(null);
137: }
138:
139: /**
140: * Returns the type of the Credit Memo that was selected on the init screen. It is based on them entering the Vendor, PO or PREQ #.
141: *
142: * @return Vendor, PO or PREQ
143: */
144: public String getCreditMemoType() {
145: String type = CREDIT_MEMO_TYPE_LABELS.TYPE_VENDOR;
146: if (isSourceDocumentPaymentRequest()) {
147: type = CREDIT_MEMO_TYPE_LABELS.TYPE_PREQ;
148: } else if (isSourceDocumentPurchaseOrder()) {
149: type = CREDIT_MEMO_TYPE_LABELS.TYPE_PO;
150: }
151: return type;
152: }
153:
154: /**
155: * @see org.kuali.core.bo.PersistableBusinessObjectBase#isBoNotesSupport()
156: */
157: @Override
158: public boolean isBoNotesSupport() {
159: return true;
160: }
161:
162: /**
163: * Determines if the purchase order has notes, using the note service.
164: *
165: * @return - true if po has notes, false if po does not have notes
166: */
167: public boolean getPurchaseOrderNotes() {
168: boolean hasNotes = false;
169:
170: ArrayList poNotes = SpringContext.getBean(NoteService.class)
171: .getByRemoteObjectId(
172: (this .getPurchaseOrderIdentifier()).toString());
173: if (poNotes.size() > 0) {
174: hasNotes = true;
175: }
176:
177: return hasNotes;
178: }
179:
180: /**
181: * Performs extended price calculation and sets on item if extended price is empty.
182: */
183: public void updateExtendedPriceOnItems() {
184: for (CreditMemoItem item : (List<CreditMemoItem>) getItems()) {
185: item
186: .refreshReferenceObject(PurapPropertyConstants.ITEM_TYPE);
187:
188: if ((ObjectUtils.isNull(item.getExtendedPrice()) || (KualiDecimal.ZERO
189: .compareTo(item.getExtendedPrice()) == 0))
190: && item.getItemType()
191: .isQuantityBasedGeneralLedgerIndicator()) {
192: KualiDecimal newExtendedPrice = item
193: .calculateExtendedPrice();
194: item.setExtendedPrice(newExtendedPrice);
195: }
196: }
197: }
198:
199: /**
200: * @see org.kuali.core.document.DocumentBase#handleRouteStatusChange()
201: */
202: @Override
203: public void handleRouteStatusChange() {
204: LOG.debug("handleRouteStatusChange() started");
205: super .handleRouteStatusChange();
206: try {
207: // DOCUMENT PROCESSED
208: if (this .getDocumentHeader().getWorkflowDocument()
209: .stateIsProcessed()) {
210: SpringContext.getBean(PurapService.class).updateStatus(
211: this ,
212: PurapConstants.CreditMemoStatuses.COMPLETE);
213: SpringContext.getBean(CreditMemoService.class)
214: .saveDocumentWithoutValidation(this );
215:
216: return;
217: }
218: // DOCUMENT DISAPPROVED
219: else if (this .getDocumentHeader().getWorkflowDocument()
220: .stateIsDisapproved()) {
221: String nodeName = SpringContext.getBean(
222: WorkflowDocumentService.class)
223: .getCurrentRouteLevelName(
224: getDocumentHeader()
225: .getWorkflowDocument());
226: NodeDetails currentNode = NodeDetailEnum
227: .getNodeDetailEnumByName(nodeName);
228: if (ObjectUtils.isNotNull(currentNode)) {
229: String newStatusCode = currentNode
230: .getDisapprovedStatusCode();
231: if ((StringUtils.isBlank(newStatusCode))
232: && ((StringUtils.isBlank(currentNode
233: .getDisapprovedStatusCode())) && ((CreditMemoStatuses.INITIATE
234: .equals(getStatusCode())) || (CreditMemoStatuses.IN_PROCESS
235: .equals(getStatusCode()))))) {
236: newStatusCode = CreditMemoStatuses.CANCELLED_IN_PROCESS;
237: }
238: if (StringUtils.isNotBlank(newStatusCode)) {
239: SpringContext.getBean(
240: AccountsPayableService.class)
241: .cancelAccountsPayableDocument(this ,
242: nodeName);
243: return;
244: }
245: }
246: logAndThrowRuntimeException("No status found to set for document being disapproved in node '"
247: + nodeName + "'");
248: }
249: // DOCUMENT CANCELED
250: else if (this .getDocumentHeader().getWorkflowDocument()
251: .stateIsCanceled()) {
252: String currentNodeName = SpringContext.getBean(
253: WorkflowDocumentService.class)
254: .getCurrentRouteLevelName(
255: getDocumentHeader()
256: .getWorkflowDocument());
257: SpringContext.getBean(AccountsPayableService.class)
258: .cancelAccountsPayableDocument(this ,
259: currentNodeName);
260: }
261: } catch (WorkflowException e) {
262: logAndThrowRuntimeException(
263: "Error saving routing data while saving document with id "
264: + getDocumentNumber(), e);
265: }
266: }
267:
268: /**
269: * Hook point for performing actions that occur after a route level change, in this case; Performs logic necessary after full
270: * entry has been completed when past Adhoc Review, or sets the AP approval date when past AP review.
271: *
272: * @see org.kuali.module.purap.document.AccountsPayableDocumentBase#preProcessNodeChange(java.lang.String, java.lang.String)
273: */
274: public boolean processNodeChange(String newNodeName,
275: String oldNodeName) {
276: if (NodeDetailEnum.ADHOC_REVIEW.getName().equals(oldNodeName)) {
277: SpringContext.getBean(PurapService.class)
278: .performLogicForFullEntryCompleted(this );
279: } else if (NodeDetailEnum.ACCOUNTS_PAYABLE_REVIEW.getName()
280: .equals(oldNodeName)) {
281: setAccountsPayableApprovalDate(SpringContext.getBean(
282: DateTimeService.class).getCurrentSqlDate());
283: }
284: return true;
285: }
286:
287: /**
288: * @see org.kuali.module.purap.document.AccountsPayableDocumentBase#getNodeDetailEnum(java.lang.String)
289: */
290: public NodeDetails getNodeDetailEnum(String nodeName) {
291: return NodeDetailEnum.getNodeDetailEnumByName(nodeName);
292: }
293:
294: /**
295: * @see org.kuali.module.purap.document.AccountsPayableDocumentBase#saveDocumentFromPostProcessing()
296: */
297: public void saveDocumentFromPostProcessing() {
298: SpringContext.getBean(CreditMemoService.class)
299: .saveDocumentWithoutValidation(this );
300: }
301:
302: /**
303: * @see org.kuali.module.purap.document.PurchasingAccountsPayableDocumentBase#getItemClass()
304: */
305: @Override
306: public Class<CreditMemoItem> getItemClass() {
307: return CreditMemoItem.class;
308: }
309:
310: /**
311: * @see org.kuali.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentIfPossible()
312: */
313: @Override
314: public PurchasingAccountsPayableDocument getPurApSourceDocumentIfPossible() {
315: PurchasingAccountsPayableDocument sourceDocument = null;
316: if (isSourceDocumentPaymentRequest()) {
317: sourceDocument = getPaymentRequestDocument();
318: } else if (isSourceDocumentPurchaseOrder()) {
319: sourceDocument = getPurchaseOrderDocument();
320: }
321: return sourceDocument;
322: }
323:
324: /**
325: * @see org.kuali.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentLabelIfPossible()
326: */
327: @Override
328: public String getPurApSourceDocumentLabelIfPossible() {
329: PurchasingAccountsPayableDocument document = getPurApSourceDocumentIfPossible();
330: if (ObjectUtils.isNotNull(document)) {
331: return SpringContext.getBean(DataDictionaryService.class)
332: .getDocumentLabelByClass(document.getClass());
333: }
334: return null;
335: }
336:
337: /**
338: * Calculates the total of the above the line items
339: *
340: * @return KualiDecimal - above the line item total
341: */
342: public KualiDecimal getLineItemTotal() {
343: KualiDecimal lineItemTotal = new KualiDecimal(0);
344:
345: for (CreditMemoItem item : (List<CreditMemoItem>) getItems()) {
346: item
347: .refreshReferenceObject(PurapPropertyConstants.ITEM_TYPE);
348: if (item.getItemType().isItemTypeAboveTheLineIndicator()
349: && item.getExtendedPrice() != null) {
350: lineItemTotal = lineItemTotal.add(item
351: .getExtendedPrice());
352: }
353: }
354:
355: return lineItemTotal;
356: }
357:
358: /**
359: * Calculates the credit memo total: Sum of above the line - restocking fees + misc amount
360: *
361: * @return KualiDecimal - credit memo document total
362: */
363: public KualiDecimal getGrandTotal() {
364: KualiDecimal grandTotal = new KualiDecimal(0);
365:
366: for (CreditMemoItem item : (List<CreditMemoItem>) getItems()) {
367: item
368: .refreshReferenceObject(PurapPropertyConstants.ITEM_TYPE);
369:
370: if (item.getExtendedPrice() != null) {
371: // make sure restocking fee is negative
372: if (StringUtils
373: .equals(
374: PurapConstants.ItemTypeCodes.ITEM_TYPE_RESTCK_FEE_CODE,
375: item.getItemTypeCode())) {
376: item.setExtendedPrice(item.getExtendedPrice().abs()
377: .negated());
378: }
379: grandTotal = grandTotal.add(item.getExtendedPrice());
380: }
381: }
382:
383: return grandTotal;
384: }
385:
386: public Integer getPaymentRequestIdentifier() {
387: return paymentRequestIdentifier;
388: }
389:
390: public void setPaymentRequestIdentifier(
391: Integer paymentRequestIdentifier) {
392: this .paymentRequestIdentifier = paymentRequestIdentifier;
393: }
394:
395: public String getCreditMemoNumber() {
396: return creditMemoNumber;
397: }
398:
399: public void setCreditMemoNumber(String creditMemoNumber) {
400: if (creditMemoNumber != null) {
401: creditMemoNumber = creditMemoNumber.toUpperCase();
402: }
403:
404: this .creditMemoNumber = creditMemoNumber;
405: }
406:
407: public Date getCreditMemoDate() {
408: return creditMemoDate;
409: }
410:
411: public void setCreditMemoDate(Date creditMemoDate) {
412: this .creditMemoDate = creditMemoDate;
413: }
414:
415: public KualiDecimal getCreditMemoAmount() {
416: return creditMemoAmount;
417: }
418:
419: public void setCreditMemoAmount(KualiDecimal creditMemoAmount) {
420: this .creditMemoAmount = creditMemoAmount;
421: }
422:
423: public String getItemMiscellaneousCreditDescription() {
424: return itemMiscellaneousCreditDescription;
425: }
426:
427: public void setItemMiscellaneousCreditDescription(
428: String itemMiscellaneousCreditDescription) {
429: this .itemMiscellaneousCreditDescription = itemMiscellaneousCreditDescription;
430: }
431:
432: public Timestamp getCreditMemoPaidTimestamp() {
433: return creditMemoPaidTimestamp;
434: }
435:
436: public void setCreditMemoPaidTimestamp(
437: Timestamp creditMemoPaidTimestamp) {
438: this .creditMemoPaidTimestamp = creditMemoPaidTimestamp;
439: }
440:
441: public PaymentRequestDocument getPaymentRequestDocument() {
442: if ((ObjectUtils.isNull(paymentRequestDocument))
443: && (ObjectUtils
444: .isNotNull(getPaymentRequestIdentifier()))) {
445: setPaymentRequestDocument(SpringContext.getBean(
446: PaymentRequestService.class).getPaymentRequestById(
447: getPaymentRequestIdentifier()));
448: }
449: return this .paymentRequestDocument;
450: }
451:
452: public void setPaymentRequestDocument(
453: PaymentRequestDocument paymentRequestDocument) {
454: if (ObjectUtils.isNull(paymentRequestDocument)) {
455: // KULPURAP-1185 - do not blank out input, instead throw an error
456: // setPaymentRequestIdentifier(null);
457: this .paymentRequestDocument = null;
458: } else {
459: setPaymentRequestIdentifier(paymentRequestDocument
460: .getPurapDocumentIdentifier());
461: this .paymentRequestDocument = paymentRequestDocument;
462: }
463: }
464:
465: /**
466: * AS A REPLACEMENT USE getPaymentRequestDocument()
467: *
468: * @deprecated
469: */
470: public PaymentRequestDocument getPaymentRequest() {
471: return getPaymentRequestDocument();
472: }
473:
474: /**
475: * AS A REPLACEMENT USE setPaymentRequestDocument(PaymentRequestDocument)
476: *
477: * @deprecated
478: */
479: public void setPaymentRequest(PaymentRequestDocument paymentRequest) {
480: setPaymentRequestDocument(paymentRequest);
481: }
482:
483: /**
484: * AS A REPLACEMENT USE getPurchaseOrderDocument()
485: *
486: * @deprecated
487: */
488: public PurchaseOrderDocument getPurchaseOrder() {
489: return getPurchaseOrderDocument();
490: }
491:
492: /**
493: * AS A REPLACEMENT USE setPurchaseOrderDocument(PurchaseOrderDocument)
494: *
495: * @deprecated
496: */
497: public void setPurchaseOrder(PurchaseOrderDocument purchaseOrder) {
498: setPurchaseOrderDocument(purchaseOrder);
499: }
500:
501: public Date getPurchaseOrderEndDate() {
502: return purchaseOrderEndDate;
503: }
504:
505: public void setPurchaseOrderEndDate(Date purchaseOrderEndDate) {
506: this .purchaseOrderEndDate = purchaseOrderEndDate;
507: }
508:
509: /**
510: * USED FOR ROUTING ONLY
511: *
512: * @deprecated
513: */
514: public String getStatusDescription() {
515: return "";
516: }
517:
518: /**
519: * USED FOR ROUTING ONLY
520: *
521: * @deprecated
522: */
523: public void setStatusDescription(String statusDescription) {
524: }
525:
526: /**
527: * @see org.kuali.module.purap.document.AccountsPayableDocumentBase#getPoDocumentTypeForAccountsPayableDocumentApprove()
528: */
529: public String getPoDocumentTypeForAccountsPayableDocumentCancel() {
530: return PurapConstants.PurchaseOrderDocTypes.PURCHASE_ORDER_CLOSE_DOCUMENT;
531: }
532:
533: /**
534: * @see org.kuali.module.purap.document.AccountsPayableDocumentBase#getInitialAmount()
535: */
536: public KualiDecimal getInitialAmount() {
537: return this .getCreditMemoAmount();
538: }
539:
540: /**
541: * Credit Memo document is first populated on Continue AP Event, and then prepareForSave continues.
542: *
543: * @see org.kuali.core.document.Document#prepareForSave(org.kuali.core.rule.event.KualiDocumentEvent)
544: */
545: @Override
546: public void prepareForSave(KualiDocumentEvent event) {
547:
548: // first populate, then call super
549: if (event instanceof ContinueAccountsPayableEvent) {
550: SpringContext.getBean(CreditMemoCreateService.class)
551: .populateDocumentAfterInit(this );
552: }
553:
554: super .prepareForSave(event);
555: }
556:
557: /**
558: * @see org.kuali.module.purap.document.AccountsPayableDocumentBase#isAttachmentRequired()
559: */
560: @Override
561: protected boolean isAttachmentRequired() {
562: return StringUtils.equalsIgnoreCase("Y", SpringContext.getBean(
563: ParameterService.class).getParameterValue(
564: CreditMemoDocument.class,
565: PurapParameterConstants.PURAP_CM_REQUIRE_ATTACHMENT));
566: }
567:
568: /**
569: * @see org.kuali.module.purap.document.AccountsPayableDocument#getDocumentSpecificService()
570: */
571: @Override
572: public AccountsPayableDocumentSpecificService getDocumentSpecificService() {
573: return SpringContext.getBean(CreditMemoService.class);
574: }
575:
576: }
|