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.financial.service.impl;
017:
018: import static org.kuali.kfs.KFSConstants.GL_CREDIT_CODE;
019: import static org.kuali.module.financial.rules.ProcurementCardDocumentRuleConstants.AUTO_APPROVE_DOCUMENTS_IND;
020: import static org.kuali.module.financial.rules.ProcurementCardDocumentRuleConstants.AUTO_APPROVE_NUMBER_OF_DAYS;
021: import static org.kuali.module.financial.rules.ProcurementCardDocumentRuleConstants.DEFAULT_TRANS_ACCOUNT_PARM_NM;
022: import static org.kuali.module.financial.rules.ProcurementCardDocumentRuleConstants.DEFAULT_TRANS_CHART_CODE_PARM_NM;
023: import static org.kuali.module.financial.rules.ProcurementCardDocumentRuleConstants.DEFAULT_TRANS_OBJECT_CODE_PARM_NM;
024: import static org.kuali.module.financial.rules.ProcurementCardDocumentRuleConstants.ERROR_TRANS_ACCOUNT_PARM_NM;
025: import static org.kuali.module.financial.rules.ProcurementCardDocumentRuleConstants.ERROR_TRANS_CHART_CODE_PARM_NM;
026: import static org.kuali.module.financial.rules.ProcurementCardDocumentRuleConstants.SINGLE_TRANSACTION_IND_PARM_NM;
027:
028: import java.sql.Timestamp;
029: import java.util.ArrayList;
030: import java.util.HashMap;
031: import java.util.Iterator;
032: import java.util.List;
033: import java.util.Map;
034:
035: import org.apache.commons.lang.StringUtils;
036: import org.kuali.core.bo.DocumentHeader;
037: import org.kuali.core.service.BusinessObjectService;
038: import org.kuali.core.service.DataDictionaryService;
039: import org.kuali.core.service.DateTimeService;
040: import org.kuali.core.service.DocumentService;
041: import org.kuali.core.util.DateUtils;
042: import org.kuali.core.util.ErrorMap;
043: import org.kuali.core.util.GlobalVariables;
044: import org.kuali.core.util.KualiDecimal;
045: import org.kuali.core.workflow.service.WorkflowDocumentService;
046: import org.kuali.kfs.KFSConstants;
047: import org.kuali.kfs.KFSPropertyConstants;
048: import org.kuali.kfs.rule.event.DocumentSystemSaveEvent;
049: import org.kuali.kfs.rules.AccountingLineRuleUtil;
050: import org.kuali.kfs.service.ParameterService;
051: import org.kuali.module.financial.batch.pcard.ProcurementCardAutoApproveDocumentsStep;
052: import org.kuali.module.financial.batch.pcard.ProcurementCardCreateDocumentsStep;
053: import org.kuali.module.financial.batch.pcard.ProcurementCardLoadStep;
054: import org.kuali.module.financial.bo.ProcurementCardHolder;
055: import org.kuali.module.financial.bo.ProcurementCardSourceAccountingLine;
056: import org.kuali.module.financial.bo.ProcurementCardTargetAccountingLine;
057: import org.kuali.module.financial.bo.ProcurementCardTransaction;
058: import org.kuali.module.financial.bo.ProcurementCardTransactionDetail;
059: import org.kuali.module.financial.bo.ProcurementCardVendor;
060: import org.kuali.module.financial.document.ProcurementCardDocument;
061: import org.kuali.module.financial.service.ProcurementCardCreateDocumentService;
062:
063: import edu.iu.uis.eden.exception.WorkflowException;
064:
065: /**
066: * This is the default implementation of the ProcurementCardCreateDocumentService interface.
067: *
068: * @see org.kuali.module.financial.service.ProcurementCardCreateDocumentService
069: */
070: public class ProcurementCardCreateDocumentServiceImpl implements
071: ProcurementCardCreateDocumentService {
072: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
073: .getLogger(ProcurementCardCreateDocumentServiceImpl.class);
074:
075: private ParameterService parameterService;
076: private BusinessObjectService businessObjectService;
077: private DocumentService documentService;
078: private DataDictionaryService dataDictionaryService;
079: private DateTimeService dateTimeService;
080: private WorkflowDocumentService workflowDocumentService;
081:
082: /**
083: * This method retrieves a collection of credit card transactions and traverses through this list, creating
084: * ProcurementCardDocuments for each card.
085: *
086: * @return True if the procurement card documents were created successfully. If any problem occur while creating the
087: * documents, a runtime exception will be thrown.
088: *
089: * @see org.kuali.module.financial.service.ProcurementCardCreateDocumentService#createProcurementCardDocuments()
090: */
091: public boolean createProcurementCardDocuments() {
092: List documents = new ArrayList();
093: List cardTransactions = retrieveTransactions();
094:
095: // iterate through card transaction list and create documents
096: for (Iterator iter = cardTransactions.iterator(); iter
097: .hasNext();) {
098: documents.add(createProcurementCardDocument((List) iter
099: .next()));
100: }
101:
102: // now store all the documents
103: for (Iterator iter = documents.iterator(); iter.hasNext();) {
104: ProcurementCardDocument pcardDocument = (ProcurementCardDocument) iter
105: .next();
106: try {
107: documentService.saveDocument(pcardDocument,
108: DocumentSystemSaveEvent.class);
109: // documentService.saveDocumentWithoutRunningValidation(pcardDocument);
110: } catch (Exception e) {
111: LOG.error("Error persisting document # "
112: + pcardDocument.getDocumentHeader()
113: .getDocumentNumber() + " "
114: + e.getMessage(), e);
115: throw new RuntimeException(
116: "Error persisting document # "
117: + pcardDocument.getDocumentHeader()
118: .getDocumentNumber() + " "
119: + e.getMessage());
120: }
121: }
122:
123: return true;
124: }
125:
126: /**
127: * This method retrieves all the procurement card documents with a status of 'I' and routes them to the next step in the
128: * routing path.
129: *
130: * @return True if the routing was performed successfully. A runtime exception will be thrown if any errors occur while routing.
131: *
132: * @see org.kuali.module.financial.service.ProcurementCardCreateDocumentService#routeProcurementCardDocuments(java.util.List)
133: */
134: public boolean routeProcurementCardDocuments() {
135: List documentList = new ArrayList();
136: try {
137: documentList = (List) documentService
138: .findByDocumentHeaderStatusCode(
139: ProcurementCardDocument.class,
140: KFSConstants.DocumentStatusCodes.INITIATED);
141: } catch (WorkflowException e1) {
142: LOG.error("Error retrieving pcdo documents for routing: "
143: + e1.getMessage());
144: throw new RuntimeException(e1.getMessage());
145: }
146: for (Iterator iter = documentList.iterator(); iter.hasNext();) {
147: ProcurementCardDocument pcardDocument = (ProcurementCardDocument) iter
148: .next();
149: try {
150: LOG.info("Routing PCDO document # "
151: + pcardDocument.getDocumentHeader()
152: .getDocumentNumber() + ".");
153: documentService.prepareWorkflowDocument(pcardDocument);
154:
155: // calling workflow service to bypass business rule checks
156: workflowDocumentService.route(pcardDocument
157: .getDocumentHeader().getWorkflowDocument(), "",
158: null);
159: } catch (WorkflowException e) {
160: LOG.error("Error routing document # "
161: + pcardDocument.getDocumentHeader()
162: .getDocumentNumber() + " "
163: + e.getMessage());
164: throw new RuntimeException(e.getMessage());
165: }
166: }
167:
168: return true;
169: }
170:
171: /**
172: * This method determines if procurement card documents can be auto approved. A document can be auto approved if
173: * the grace period for allowing auto approval of a procurement card document has passed. The grace period is defined
174: * by a parameter in the parameters table. The create date of the document is then compared against the current date and
175: * if the difference is larger than the grace period defined, then the document is auto approved.
176: *
177: * @return This method always returns true.
178: *
179: * @see org.kuali.module.financial.service.ProcurementCardCreateDocumentService#autoApproveProcurementCardDocuments()
180: */
181: public boolean autoApproveProcurementCardDocuments() {
182: // check if auto approve is turned on
183: boolean autoApproveOn = parameterService.getIndicatorParameter(
184: ProcurementCardAutoApproveDocumentsStep.class,
185: AUTO_APPROVE_DOCUMENTS_IND);
186:
187: if (!autoApproveOn) { // This doesn't make sense - ????
188: return true;
189: }
190:
191: List documentList = new ArrayList();
192:
193: try {
194: documentList = (List) documentService
195: .findByDocumentHeaderStatusCode(
196: ProcurementCardDocument.class,
197: KFSConstants.DocumentStatusCodes.ENROUTE);
198: } catch (WorkflowException e1) {
199: throw new RuntimeException(e1.getMessage());
200: }
201:
202: // get number of days and type for auto approve
203: int autoApproveNumberDays = Integer.parseInt(parameterService
204: .getParameterValue(
205: ProcurementCardAutoApproveDocumentsStep.class,
206: AUTO_APPROVE_NUMBER_OF_DAYS));
207:
208: Timestamp currentDate = dateTimeService.getCurrentTimestamp();
209: for (Iterator iter = documentList.iterator(); iter.hasNext();) {
210: ProcurementCardDocument pcardDocument = (ProcurementCardDocument) iter
211: .next();
212: Timestamp docCreateDate = pcardDocument.getDocumentHeader()
213: .getWorkflowDocument().getCreateDate();
214:
215: // if number of days in route is passed the allowed number, call doc service for super user approve
216: if (DateUtils.getDifferenceInDays(docCreateDate,
217: currentDate) > autoApproveNumberDays) {
218: // update document description to reflect the auto approval
219: pcardDocument
220: .getDocumentHeader()
221: .setFinancialDocumentDescription(
222: "Auto Approved On "
223: + dateTimeService
224: .toDateTimeString(currentDate)
225: + ".");
226:
227: try {
228: LOG.info("Auto approving document # "
229: + pcardDocument.getDocumentHeader()
230: .getDocumentNumber());
231: documentService.super UserApproveDocument(
232: pcardDocument, "");
233: } catch (WorkflowException e) {
234: LOG.error("Error auto approving document # "
235: + pcardDocument.getDocumentHeader()
236: .getDocumentNumber() + " "
237: + e.getMessage());
238: throw new RuntimeException(e.getMessage());
239: }
240: }
241: }
242:
243: return true;
244: }
245:
246: /**
247: * This method retrieves a list of transactions from a temporary table, and groups them into document lists, based on
248: * single transaction indicator or a grouping by card.
249: *
250: * @return List containing transactions for document.
251: */
252: private List retrieveTransactions() {
253: List groupedTransactions = new ArrayList();
254:
255: // retrieve records from transaction table order by card number
256: List transactions = (List) businessObjectService
257: .findMatchingOrderBy(
258: ProcurementCardTransaction.class,
259: new HashMap(),
260: KFSPropertyConstants.TRANSACTION_CREDIT_CARD_NUMBER,
261: true);
262:
263: // check apc for single transaction documents or multiple by card
264: boolean singleTransaction = parameterService
265: .getIndicatorParameter(
266: ProcurementCardCreateDocumentsStep.class,
267: SINGLE_TRANSACTION_IND_PARM_NM);
268:
269: List documentTransactions = new ArrayList();
270: if (singleTransaction) {
271: for (Iterator iter = transactions.iterator(); iter
272: .hasNext();) {
273: documentTransactions.add(iter.next());
274: groupedTransactions.add(documentTransactions);
275: documentTransactions = new ArrayList();
276: }
277: } else {
278: Map cardTransactionsMap = new HashMap();
279: for (Iterator iter = transactions.iterator(); iter
280: .hasNext();) {
281: ProcurementCardTransaction transaction = (ProcurementCardTransaction) iter
282: .next();
283: if (!cardTransactionsMap.containsKey(transaction
284: .getTransactionCreditCardNumber())) {
285: cardTransactionsMap.put(transaction
286: .getTransactionCreditCardNumber(),
287: new ArrayList());
288: }
289: ((List) cardTransactionsMap.get(transaction
290: .getTransactionCreditCardNumber()))
291: .add(transaction);
292: }
293:
294: for (Iterator iter = cardTransactionsMap.values()
295: .iterator(); iter.hasNext();) {
296: groupedTransactions.add(iter.next());
297:
298: }
299: }
300:
301: return groupedTransactions;
302: }
303:
304: /**
305: * Creates a ProcurementCardDocument from the List of transactions given.
306: *
307: * @param transactions List of ProcurementCardTransaction objects to be used for creating the document.
308: * @return A ProcurementCardDocument populated with the transactions provided.
309: */
310: private ProcurementCardDocument createProcurementCardDocument(
311: List transactions) {
312: ProcurementCardDocument pcardDocument = null;
313:
314: try {
315: // get new document from doc service
316: pcardDocument = (ProcurementCardDocument) documentService
317: .getNewDocument(ProcurementCardDocument.class);
318:
319: // set the card holder record on the document from the first transaction
320: createCardHolderRecord(pcardDocument,
321: (ProcurementCardTransaction) transactions.get(0));
322:
323: // for each transaction, create transaction detail object and then acct lines for the detail
324: int transactionLineNumber = 1;
325: KualiDecimal documentTotalAmount = new KualiDecimal(0);
326: String errorText = "";
327: for (Iterator iter = transactions.iterator(); iter
328: .hasNext();) {
329: ProcurementCardTransaction transaction = (ProcurementCardTransaction) iter
330: .next();
331:
332: // create transaction detail record with accounting lines
333: errorText += createTransactionDetailRecord(
334: pcardDocument, transaction,
335: transactionLineNumber);
336:
337: // update document total
338: documentTotalAmount = documentTotalAmount
339: .add(transaction
340: .getFinancialDocumentTotalAmount());
341:
342: transactionLineNumber++;
343: }
344:
345: pcardDocument.getDocumentHeader()
346: .setFinancialDocumentTotalAmount(
347: documentTotalAmount);
348: pcardDocument
349: .getDocumentHeader()
350: .setFinancialDocumentDescription("SYSTEM Generated");
351:
352: // Remove duplicate messages from errorText
353: String messages[] = StringUtils.split(errorText, ".");
354: for (int i = 0; i < messages.length; i++) {
355: int countMatches = StringUtils.countMatches(errorText,
356: messages[i]) - 1;
357: errorText = StringUtils.replace(errorText, messages[i]
358: + ".", "", countMatches);
359: }
360: // In case errorText is still too long, truncate it and indicate so.
361: Integer documentExplanationMaxLength = dataDictionaryService
362: .getAttributeMaxLength(DocumentHeader.class
363: .getName(),
364: KFSPropertyConstants.EXPLANATION);
365: if (documentExplanationMaxLength != null
366: && errorText.length() > documentExplanationMaxLength
367: .intValue()) {
368: String truncatedMessage = " ... TRUNCATED.";
369: errorText = errorText.substring(0,
370: documentExplanationMaxLength
371: - truncatedMessage.length())
372: + truncatedMessage;
373: }
374: pcardDocument.getDocumentHeader().setExplanation(errorText);
375: } catch (WorkflowException e) {
376: LOG.error("Error creating pcdo documents: "
377: + e.getMessage());
378: throw new RuntimeException(
379: "Error creating pcdo documents: " + e.getMessage());
380: }
381:
382: return pcardDocument;
383: }
384:
385: /**
386: * Creates card holder record and sets that record to the document given.
387: *
388: * @param pcardDocument Procurement card document to place the record in.
389: * @param transaction The transaction to set the card holder record fields from.
390: */
391: private void createCardHolderRecord(
392: ProcurementCardDocument pcardDocument,
393: ProcurementCardTransaction transaction) {
394: ProcurementCardHolder cardHolder = new ProcurementCardHolder();
395:
396: cardHolder.setDocumentNumber(pcardDocument.getDocumentNumber());
397: cardHolder.setAccountNumber(transaction.getAccountNumber());
398: cardHolder.setCardCycleAmountLimit(transaction
399: .getCardCycleAmountLimit());
400: cardHolder.setCardCycleVolumeLimit(transaction
401: .getCardCycleVolumeLimit());
402: cardHolder.setCardHolderAlternateName(transaction
403: .getCardHolderAlternateName());
404: cardHolder.setCardHolderCityName(transaction
405: .getCardHolderCityName());
406: cardHolder.setCardHolderLine1Address(transaction
407: .getCardHolderLine1Address());
408: cardHolder.setCardHolderLine2Address(transaction
409: .getCardHolderLine2Address());
410: cardHolder.setCardHolderName(transaction.getCardHolderName());
411: cardHolder.setCardHolderStateCode(transaction
412: .getCardHolderStateCode());
413: cardHolder.setCardHolderWorkPhoneNumber(transaction
414: .getCardHolderWorkPhoneNumber());
415: cardHolder.setCardHolderZipCode(transaction
416: .getCardHolderZipCode());
417: cardHolder.setCardLimit(transaction.getCardLimit());
418: cardHolder.setCardNoteText(transaction.getCardNoteText());
419: cardHolder.setCardStatusCode(transaction.getCardStatusCode());
420: cardHolder.setChartOfAccountsCode(transaction
421: .getChartOfAccountsCode());
422: cardHolder.setSubAccountNumber(transaction
423: .getSubAccountNumber());
424: cardHolder.setTransactionCreditCardNumber(transaction
425: .getTransactionCreditCardNumber());
426:
427: pcardDocument.setProcurementCardHolder(cardHolder);
428: }
429:
430: /**
431: * Creates a transaction detail record and adds that record to the document provided.
432: *
433: * @param pcardDocument Document to place record in.
434: * @param transaction Transaction to set fields from.
435: * @param transactionLineNumber Line number of the new transaction detail record within the procurement card document.
436: * @return The error text that was generated from the creation of the detail records. If the text is empty, no errors were encountered.
437: */
438: private String createTransactionDetailRecord(
439: ProcurementCardDocument pcardDocument,
440: ProcurementCardTransaction transaction,
441: Integer transactionLineNumber) {
442: ProcurementCardTransactionDetail transactionDetail = new ProcurementCardTransactionDetail();
443:
444: // set the document transaction detail fields from the loaded transaction record
445: transactionDetail.setDocumentNumber(pcardDocument
446: .getDocumentNumber());
447: transactionDetail
448: .setFinancialDocumentTransactionLineNumber(transactionLineNumber);
449: transactionDetail.setTransactionDate(transaction
450: .getTransactionDate());
451: transactionDetail.setTransactionReferenceNumber(transaction
452: .getTransactionReferenceNumber());
453: transactionDetail.setTransactionBillingCurrencyCode(transaction
454: .getTransactionBillingCurrencyCode());
455: transactionDetail
456: .setTransactionCurrencyExchangeRate(transaction
457: .getTransactionCurrencyExchangeRate());
458: transactionDetail.setTransactionDate(transaction
459: .getTransactionDate());
460: transactionDetail
461: .setTransactionOriginalCurrencyAmount(transaction
462: .getTransactionOriginalCurrencyAmount());
463: transactionDetail
464: .setTransactionOriginalCurrencyCode(transaction
465: .getTransactionOriginalCurrencyCode());
466: transactionDetail.setTransactionPointOfSaleCode(transaction
467: .getTransactionPointOfSaleCode());
468: transactionDetail.setTransactionPostingDate(transaction
469: .getTransactionPostingDate());
470: transactionDetail
471: .setTransactionPurchaseIdentifierDescription(transaction
472: .getTransactionPurchaseIdentifierDescription());
473: transactionDetail
474: .setTransactionPurchaseIdentifierIndicator(transaction
475: .getTransactionPurchaseIdentifierIndicator());
476: transactionDetail.setTransactionSalesTaxAmount(transaction
477: .getTransactionSalesTaxAmount());
478: transactionDetail.setTransactionSettlementAmount(transaction
479: .getTransactionSettlementAmount());
480: transactionDetail.setTransactionTaxExemptIndicator(transaction
481: .getTransactionTaxExemptIndicator());
482: transactionDetail
483: .setTransactionTravelAuthorizationCode(transaction
484: .getTransactionTravelAuthorizationCode());
485: transactionDetail.setTransactionUnitContactName(transaction
486: .getTransactionUnitContactName());
487:
488: if (GL_CREDIT_CODE.equals(transaction
489: .getTransactionDebitCreditCode())) {
490: transactionDetail.setTransactionTotalAmount(transaction
491: .getFinancialDocumentTotalAmount().negated());
492: } else {
493: transactionDetail.setTransactionTotalAmount(transaction
494: .getFinancialDocumentTotalAmount());
495: }
496:
497: // create transaction vendor record
498: createTransactionVendorRecord(pcardDocument, transaction,
499: transactionDetail);
500:
501: // add transaction detail to document
502: pcardDocument.getTransactionEntries().add(transactionDetail);
503:
504: // now create the initial source and target lines for this transaction
505: return createAndValidateAccountingLines(pcardDocument,
506: transaction, transactionDetail);
507: }
508:
509: /**
510: * Creates a transaction vendor detail record and adds it to the transaction detail.
511: *
512: * @param pcardDocument The procurement card document to retrieve values from.
513: * @param transaction Transaction to set fields from.
514: * @param transactionDetail The transaction detail to set the vendor record on.
515: */
516: private void createTransactionVendorRecord(
517: ProcurementCardDocument pcardDocument,
518: ProcurementCardTransaction transaction,
519: ProcurementCardTransactionDetail transactionDetail) {
520: ProcurementCardVendor transactionVendor = new ProcurementCardVendor();
521:
522: transactionVendor.setDocumentNumber(pcardDocument
523: .getDocumentNumber());
524: transactionVendor
525: .setFinancialDocumentTransactionLineNumber(transactionDetail
526: .getFinancialDocumentTransactionLineNumber());
527: transactionVendor
528: .setTransactionMerchantCategoryCode(transaction
529: .getTransactionMerchantCategoryCode());
530: transactionVendor.setVendorCityName(transaction
531: .getVendorCityName());
532: transactionVendor.setVendorLine1Address(transaction
533: .getVendorLine1Address());
534: transactionVendor.setVendorLine2Address(transaction
535: .getVendorLine2Address());
536: transactionVendor.setVendorName(transaction.getVendorName());
537: transactionVendor.setVendorOrderNumber(transaction
538: .getVendorOrderNumber());
539: transactionVendor.setVendorStateCode(transaction
540: .getVendorStateCode());
541: transactionVendor.setVendorZipCode(transaction
542: .getVendorZipCode());
543: transactionVendor.setVisaVendorIdentifier(transaction
544: .getVisaVendorIdentifier());
545:
546: transactionDetail.setProcurementCardVendor(transactionVendor);
547: }
548:
549: /**
550: * From the transaction accounting attributes, creates source and target accounting lines. Attributes are validated first, and
551: * replaced with default and error values if needed. There will be 1 source and 1 target line generated.
552: *
553: * @param pcardDocument The procurement card document to add the new accounting lines to.
554: * @param transaction The transaction to process into account lines.
555: * @param docTransactionDetail The transaction detail to create source and target accounting lines from.
556: * @return String containing any error messages.
557: */
558: private String createAndValidateAccountingLines(
559: ProcurementCardDocument pcardDocument,
560: ProcurementCardTransaction transaction,
561: ProcurementCardTransactionDetail docTransactionDetail) {
562: // build source lines
563: ProcurementCardSourceAccountingLine sourceLine = createSourceAccountingLine(
564: transaction, docTransactionDetail);
565:
566: // add line to transaction through document since document contains the next sequence number fields
567: pcardDocument.addSourceAccountingLine(sourceLine);
568:
569: // build target lines
570: ProcurementCardTargetAccountingLine targetLine = createTargetAccountingLine(
571: transaction, docTransactionDetail);
572:
573: // add line to transaction through document since document contains the next sequence number fields
574: pcardDocument.addTargetAccountingLine(targetLine);
575:
576: return validateTargetAccountingLine(targetLine);
577: }
578:
579: /**
580: * Creates the to record for the transaction. The chart of account attributes from the transaction are used to create
581: * the accounting line.
582: *
583: * @param transaction The transaction to pull information from to create the accounting line.
584: * @param docTransactionDetail The transaction detail to pull information from to populate the accounting line.
585: * @return The target accounting line fully populated with values from the parameters passed in.
586: */
587: private ProcurementCardTargetAccountingLine createTargetAccountingLine(
588: ProcurementCardTransaction transaction,
589: ProcurementCardTransactionDetail docTransactionDetail) {
590: ProcurementCardTargetAccountingLine targetLine = new ProcurementCardTargetAccountingLine();
591:
592: targetLine.setDocumentNumber(docTransactionDetail
593: .getDocumentNumber());
594: targetLine
595: .setFinancialDocumentTransactionLineNumber(docTransactionDetail
596: .getFinancialDocumentTransactionLineNumber());
597: targetLine.setChartOfAccountsCode(transaction
598: .getChartOfAccountsCode());
599: targetLine.setAccountNumber(transaction.getAccountNumber());
600: targetLine.setFinancialObjectCode(transaction
601: .getFinancialObjectCode());
602: targetLine.setSubAccountNumber(transaction
603: .getSubAccountNumber());
604: targetLine.setFinancialSubObjectCode(transaction
605: .getFinancialSubObjectCode());
606: targetLine.setProjectCode(transaction.getProjectCode());
607:
608: if (GL_CREDIT_CODE.equals(transaction
609: .getTransactionDebitCreditCode())) {
610: targetLine.setAmount(transaction
611: .getFinancialDocumentTotalAmount().negated());
612: } else {
613: targetLine.setAmount(transaction
614: .getFinancialDocumentTotalAmount());
615: }
616:
617: return targetLine;
618: }
619:
620: /**
621: * Creates the from record for the transaction. The clearing chart, account, and object code is used for creating the line.
622: *
623: * @param transaction The transaction to pull information from to create the accounting line.
624: * @param docTransactionDetail The transaction detail to pull information from to populate the accounting line.
625: * @return The source accounting line fully populated with values from the parameters passed in.
626: */
627: private ProcurementCardSourceAccountingLine createSourceAccountingLine(
628: ProcurementCardTransaction transaction,
629: ProcurementCardTransactionDetail docTransactionDetail) {
630: ProcurementCardSourceAccountingLine sourceLine = new ProcurementCardSourceAccountingLine();
631:
632: sourceLine.setDocumentNumber(docTransactionDetail
633: .getDocumentNumber());
634: sourceLine
635: .setFinancialDocumentTransactionLineNumber(docTransactionDetail
636: .getFinancialDocumentTransactionLineNumber());
637: sourceLine.setChartOfAccountsCode(getDefaultChartCode());
638: sourceLine.setAccountNumber(getDefaultAccountNumber());
639: sourceLine.setFinancialObjectCode(getDefaultObjectCode());
640:
641: if (GL_CREDIT_CODE.equals(transaction
642: .getTransactionDebitCreditCode())) {
643: sourceLine.setAmount(transaction
644: .getFinancialDocumentTotalAmount().negated());
645: } else {
646: sourceLine.setAmount(transaction
647: .getFinancialDocumentTotalAmount());
648: }
649:
650: return sourceLine;
651: }
652:
653: /**
654: * Validates the chart of account attributes for existence and active indicator. Will substitute for defined
655: * default parameters or set fields to empty that if they have errors.
656: *
657: * @param targetLine The target accounting line to be validated.
658: * @return String with error messages discovered during validation. An empty string indicates no validation errors were found.
659: */
660: private String validateTargetAccountingLine(
661: ProcurementCardTargetAccountingLine targetLine) {
662: String errorText = "";
663:
664: targetLine.refresh();
665:
666: if (!AccountingLineRuleUtil.isValidObjectCode(targetLine
667: .getObjectCode(), dataDictionaryService
668: .getDataDictionary())) {
669: String tempErrorText = "Chart "
670: + targetLine.getChartOfAccountsCode()
671: + " Object Code "
672: + targetLine.getFinancialObjectCode()
673: + " is invalid; using default Object Code.";
674: LOG.info(tempErrorText);
675: errorText += " " + tempErrorText;
676:
677: targetLine.setFinancialObjectCode(getDefaultObjectCode());
678: }
679:
680: if (StringUtils.isNotBlank(targetLine.getSubAccountNumber())
681: && !AccountingLineRuleUtil.isValidSubAccount(targetLine
682: .getSubAccount(), dataDictionaryService
683: .getDataDictionary())) {
684: String tempErrorText = "Chart "
685: + targetLine.getChartOfAccountsCode() + " Account "
686: + targetLine.getAccountNumber() + " Sub Account "
687: + targetLine.getSubAccountNumber()
688: + " is invalid; Setting Sub Account to blank.";
689: LOG.info(tempErrorText);
690: errorText += " " + tempErrorText;
691:
692: targetLine.setSubAccountNumber("");
693: }
694:
695: // refresh again since further checks depend on the above attributes (which could have changed)
696: targetLine.refresh();
697:
698: if (StringUtils.isNotBlank(targetLine
699: .getFinancialSubObjectCode())
700: && !AccountingLineRuleUtil.isValidSubObjectCode(
701: targetLine.getSubObjectCode(),
702: dataDictionaryService.getDataDictionary())) {
703: String tempErrorText = "Chart "
704: + targetLine.getChartOfAccountsCode() + " Account "
705: + targetLine.getAccountNumber() + " Object Code "
706: + targetLine.getFinancialObjectCode()
707: + " Sub Object Code "
708: + targetLine.getFinancialSubObjectCode()
709: + " is invalid; setting Sub Object to blank.";
710: LOG.info(tempErrorText);
711: errorText += " " + tempErrorText;
712:
713: targetLine.setFinancialSubObjectCode("");
714: }
715:
716: if (StringUtils.isNotBlank(targetLine.getProjectCode())
717: && !AccountingLineRuleUtil.isValidProjectCode(
718: targetLine.getProject(), dataDictionaryService
719: .getDataDictionary())) {
720: LOG.info("Project Code " + targetLine.getProjectCode()
721: + " is invalid; setting to blank.");
722: errorText += " Project Code " + targetLine.getProjectCode()
723: + " is invalid; setting to blank.";
724:
725: targetLine.setProjectCode("");
726: }
727:
728: if (!AccountingLineRuleUtil.isValidAccount(targetLine
729: .getAccount(), dataDictionaryService
730: .getDataDictionary())
731: || targetLine.getAccount().isExpired()) {
732: String tempErrorText = "Chart "
733: + targetLine.getChartOfAccountsCode() + " Account "
734: + targetLine.getAccountNumber()
735: + " is invalid; using error account.";
736: LOG.info(tempErrorText);
737: errorText += " " + tempErrorText;
738:
739: targetLine.setChartOfAccountsCode(getErrorChartCode());
740: targetLine.setAccountNumber(getErrorAccountNumber());
741: }
742:
743: targetLine.refresh();
744:
745: // clear out GlobalVariable error map, since we have taken care of the errors
746: GlobalVariables.setErrorMap(new ErrorMap());
747:
748: return errorText;
749: }
750:
751: /**
752: * Retrieves the error chart code from the parameter table.
753: * @return The error chart code defined in the parameter table.
754: */
755: private String getErrorChartCode() {
756: return parameterService.getParameterValue(
757: ProcurementCardCreateDocumentsStep.class,
758: ERROR_TRANS_CHART_CODE_PARM_NM);
759: }
760:
761: /**
762: * Retrieves the error account number from the parameter table.
763: * @return The error account number defined in the parameter table.
764: */
765: private String getErrorAccountNumber() {
766: return parameterService.getParameterValue(
767: ProcurementCardCreateDocumentsStep.class,
768: ERROR_TRANS_ACCOUNT_PARM_NM);
769: }
770:
771: /**
772: * Retrieves the default chard code from the parameter table.
773: * @return The default chart code defined in the parameter table.
774: */
775: private String getDefaultChartCode() {
776: return parameterService.getParameterValue(
777: ProcurementCardLoadStep.class,
778: DEFAULT_TRANS_CHART_CODE_PARM_NM);
779: }
780:
781: /**
782: * Retrieves the default account number from the parameter table.
783: * @return The default account number defined in the parameter table.
784: */
785: private String getDefaultAccountNumber() {
786: return parameterService.getParameterValue(
787: ProcurementCardLoadStep.class,
788: DEFAULT_TRANS_ACCOUNT_PARM_NM);
789: }
790:
791: /**
792: * Retrieves the default object code from the parameter table.
793: * @return The default object code defined in the parameter table.
794: */
795: private String getDefaultObjectCode() {
796: return parameterService.getParameterValue(
797: ProcurementCardLoadStep.class,
798: DEFAULT_TRANS_OBJECT_CODE_PARM_NM);
799: }
800:
801: /**
802: * Calls businessObjectService to remove all the procurement card transaction rows from the transaction load table.
803: */
804: private void cleanTransactionsTable() {
805: businessObjectService.deleteMatching(
806: ProcurementCardTransaction.class, new HashMap());
807: }
808:
809: /**
810: * Loads all the parsed XML transactions into the temp transaction table.
811: *
812: * @param transactions List of ProcurementCardTransactions to load.
813: */
814: private void loadTransactions(List transactions) {
815: businessObjectService.save(transactions);
816: }
817:
818: /**
819: * Sets the parameterService attribute.
820: * @param parameterService
821: */
822: public void setParameterService(ParameterService parameterService) {
823: this .parameterService = parameterService;
824: }
825:
826: /**
827: * Gets the businessObjectService attribute.
828: * @return Returns the businessObjectService.
829: */
830: public BusinessObjectService getBusinessObjectService() {
831: return businessObjectService;
832: }
833:
834: /**
835: * Sets the businessObjectService attribute.
836: * @param businessObjectService The businessObjectService to set.
837: */
838: public void setBusinessObjectService(
839: BusinessObjectService businessObjectService) {
840: this .businessObjectService = businessObjectService;
841: }
842:
843: /**
844: * Gets the documentService attribute.
845: * @return Returns the documentService.
846: */
847: public DocumentService getDocumentService() {
848: return documentService;
849: }
850:
851: /**
852: * Sets the documentService attribute.
853: * @param documentService The documentService to set.
854: */
855: public void setDocumentService(DocumentService documentService) {
856: this .documentService = documentService;
857: }
858:
859: /**
860: * Gets the dataDictionaryService attribute.
861: * @return Returns the dataDictionaryService.
862: */
863: public DataDictionaryService getDataDictionaryService() {
864: return dataDictionaryService;
865: }
866:
867: /**
868: * Sets the dataDictionaryService attribute.
869: * @param dataDictionaryService dataDictionaryService to set.
870: */
871: public void setDataDictionaryService(
872: DataDictionaryService dataDictionaryService) {
873: this .dataDictionaryService = dataDictionaryService;
874: }
875:
876: /**
877: * Gets the dateTimeService attribute.
878: * @return Returns the dateTimeService.
879: */
880: public DateTimeService getDateTimeService() {
881: return dateTimeService;
882: }
883:
884: /**
885: * Sets the dateTimeService attribute.
886: * @param dateTimeService The dateTimeService to set.
887: */
888: public void setDateTimeService(DateTimeService dateTimeService) {
889: this .dateTimeService = dateTimeService;
890: }
891:
892: /**
893: * Gets the workflowDocumentService attribute.
894: * @return Returns the workflowDocumentService.
895: */
896: public WorkflowDocumentService getWorkflowDocumentService() {
897: return workflowDocumentService;
898: }
899:
900: /**
901: * Sets the workflowDocumentService attribute value.
902: * @param workflowDocumentService The workflowDocumentService to set.
903: */
904: public void setWorkflowDocumentService(
905: WorkflowDocumentService workflowDocumentService) {
906: this.workflowDocumentService = workflowDocumentService;
907: }
908:
909: }
|