/** get the traveler profile associated with the given travel document */ protected TemProfile getTravelProfile(TravelDocument travelDocument) { Integer travelProfileId = travelDocument.getProfileId(); if (travelProfileId != null) { return this.getBusinessObjectService() .findBySinglePrimaryKey(TemProfile.class, travelProfileId); } return null; }
/** build mail message object from the given travel document */ @SuppressWarnings("null") protected MailMessage buildDocumentStatusChangeMailMessage( TravelDocument travelDocument, DocumentRouteStatusChange statusChangeDTO, NotificationPreference preference) { MailMessage mailMessage = new MailMessage(); String senderEmailAddress = this.getNotificationSender(); mailMessage.setFromAddress(senderEmailAddress); TravelerDetail traveler = travelDocument.getTraveler(); String travelerEmailAddress = null; if (!ObjectUtils.isNull(traveler) && !ObjectUtils.isNull(travelDocument.getProfileId())) { TemProfile profile = SpringContext.getBean(TemProfileService.class) .findTemProfileById(travelDocument.getProfileId()); travelerEmailAddress = profile.getEmailAddress(); } else { travelerEmailAddress = traveler.getEmailAddress(); } if (senderEmailAddress != null && travelerEmailAddress != null) { mailMessage.addToAddress(travelerEmailAddress); String notificationSubject = this.getNotificationSubject(preference); mailMessage.setSubject(notificationSubject); String notificationBody = this.buildNotificationBody(travelDocument, statusChangeDTO, preference); mailMessage.setMessage(notificationBody); return mailMessage; } return null; }
/** * @see * org.kuali.kfs.module.tem.service.TravelDocumentNotificationService#sendNotificationOnChange(org.kuali.kfs.module.tem.document.TravelDocument, * org.kuali.rice.kew.dto.DocumentRouteStatusChange) */ @Override public void sendNotificationOnChange( TravelDocument travelDocument, DocumentRouteStatusChange statusChangeDTO) { String documentTypeCode = travelDocument.getDocumentHeader().getWorkflowDocument().getDocumentTypeName(); NotificationPreference preference = null; if (this.isNotificationEnabled()) { TemProfile travelProfile = this.getTravelProfile(travelDocument); String newRouteStatus = statusChangeDTO.getNewRouteStatus(); if (travelProfile == null) { LOG.error("travelProfile is null."); return; } if (travelDocument instanceof TravelAuthorizationDocument) { if (!verifyDocumentTypeCodes( documentTypeCode, this.getEligibleTravelAuthorizationDocumentTypeCodes())) { return; } preference = getEmailNotificationPreference( preference, newRouteStatus, travelProfile.getNotifyTAFinal(), travelProfile.getNotifyTAStatusChange(), documentTypeCode); } else { // TR/ENT/RELO if (!verifyDocumentTypeCodes( documentTypeCode, this.getEligibleTravelExpenseDocumentTypeCodes())) { return; } preference = getEmailNotificationPreference( preference, newRouteStatus, travelProfile.getNotifyTERFinal(), travelProfile.getNotifyTERStatusChange(), documentTypeCode); } this.sendNotificationByPreference(travelDocument, statusChangeDTO, preference); } }
/** * @see * org.kuali.kfs.sys.document.validation.Validation#validate(org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent) */ @SuppressWarnings("rawtypes") @Override public boolean validate(AttributedDocumentEvent event) { final Person currentUser = GlobalVariables.getUserSession().getPerson(); TemSourceAccountingLine line = null; if (event instanceof UpdateAccountingLineEvent) { line = (TemSourceAccountingLine) ((UpdateAccountingLineEvent) event).getUpdatedAccountingLine(); } else { line = (TemSourceAccountingLine) ((AccountingLineEvent) event).getAccountingLine(); } List<String> holdErrors = new ArrayList<String>(); holdErrors.addAll(GlobalVariables.getMessageMap().getErrorPath()); GlobalVariables.getMessageMap().clearErrorPath(); TravelDocument travelDocument = (TravelDocument) event.getDocument(); final boolean canUpdate = isAtTravelNode(event.getDocument().getDocumentHeader().getWorkflowDocument()) || isAdvancePaymentMethodException( event.getDocument(), line); // Are we at the travel node? If so, there's a chance that accounting lines // changed; if they did, that // was a permission granted to the travel manager so we should allow it. Also, if we're at // PaymentMethod and the line is an advance accounting line, that's allowed to boolean valid = true; String errorPath = TemPropertyConstants.NEW_SOURCE_ACCTG_LINE; for (TemSourceAccountingLine sourceLine : (List<TemSourceAccountingLine>) travelDocument.getSourceAccountingLines()) { if (line.equals(sourceLine)) { errorPath = "document." + TemPropertyConstants.SOURCE_ACCOUNTING_LINE + "[" + travelDocument.getSourceAccountingLines().indexOf(line) + "]"; break; } } // Test added accounting lines for null values and if there is an access change. valid = getTravelDocumentService().validateSourceAccountingLines(travelDocument, false); if ((!travelDocument .getAppDocStatus() .equalsIgnoreCase(TemConstants.TRAVEL_DOC_APP_DOC_STATUS_INIT)) && (!travelDocument .getAppDocStatus() .equalsIgnoreCase(TemConstants.TravelAuthorizationStatusCodeKeys.IN_PROCESS)) && (!travelDocument .getAppDocStatus() .equalsIgnoreCase(TemConstants.TravelAuthorizationStatusCodeKeys.CHANGE_IN_PROCESS))) { if (!line.getAccount() .getAccountFiscalOfficerUser() .getPrincipalId() .equals(currentUser.getPrincipalId()) && !canUpdate) { GlobalVariables.getMessageMap() .putError( KFSPropertyConstants.ACCOUNT_NUMBER, TemKeyConstants.ERROR_TA_FISCAL_OFFICER_ACCOUNT, line.getAccountNumber()); return false; } } GlobalVariables.getMessageMap().addToErrorPath(errorPath); // skip accounting line validation for TA if (!(event.getDocument() instanceof TravelAuthorizationDocument)) { if (ObjectUtils.isNotNull(line.getObjectTypeCode())) { // check to make sure they're the same List<AccountingDistribution> list = getAccountingDistributionService().buildDistributionFrom(travelDocument); List<AccountingLineDistributionKey> distributionList = new ArrayList<AccountingLineDistributionKey>(); List<String> expectedObjectCodes = new ArrayList<String>(); for (AccountingDistribution dist : list) { distributionList.add( new AccountingLineDistributionKey(dist.getObjectCode(), dist.getCardType())); expectedObjectCodes.add(dist.getObjectCode()); } final String expectedObjectCodesString = StringUtils.join(expectedObjectCodes, ", "); if (!distributionList.contains( new AccountingLineDistributionKey(line.getFinancialObjectCode(), line.getCardType()))) { GlobalVariables.getMessageMap() .putError( TravelAuthorizationFields.FIN_OBJ_CD, TemKeyConstants.ERROR_TEM_ACCOUNTING_LINES_OBJECT_CODE_CARD_TYPE, line.getFinancialObjectCode(), line.getCardType(), expectedObjectCodesString); valid &= false; } } } if (line.getAmount().isLessEqual(KualiDecimal.ZERO) && !travelDocument.getBlanketTravel()) { GlobalVariables.getMessageMap() .putError( KFSPropertyConstants.AMOUNT, KFSKeyConstants.ERROR_CUSTOM, "Amount must be greater than zero."); valid &= false; } if (valid) { // Fly America validation TravelDocument document = (TravelDocument) event.getDocument(); List<TemExpense> allExpenses = new ArrayList<TemExpense>(); allExpenses.addAll(document.getImportedExpenses()); allExpenses.addAll(document.getActualExpenses()); if (allExpenses.size() > 0) { boolean hasAttachment = false; boolean showFlyAmerica = false; for (Note note : document.getNotes()) { if (note.getAttachment() != null) { hasAttachment = true; break; } } boolean isCGEnabled = getParameterService() .getParameterValueAsBoolean( KFSConstants.CoreModuleNamespaces.CHART, KFSConstants.RouteLevelNames.ACCOUNT, KFSConstants.ChartApcParms.ACCOUNT_FUND_GROUP_DENOTES_CG); if (isCGEnabled) { for (TemExpense expense : allExpenses) { if (expense.getExpenseTypeCode().equals(TemConstants.ExpenseTypes.AIRFARE)) { Map<String, Object> fieldValues = new HashMap<String, Object>(); fieldValues.put(KRADPropertyConstants.CODE, TemConstants.ExpenseTypes.AIRFARE); fieldValues.put(KRADPropertyConstants.NAME, expense.getTravelCompanyCodeName()); TravelCompanyCode travelCompany = getBusinessObjectService().findByPrimaryKey(TravelCompanyCode.class, fieldValues); if (travelCompany != null && travelCompany.isForeignCompany()) { String financialObjectCode = expense.getExpenseTypeObjectCode() != null ? expense.getExpenseTypeObjectCode().getFinancialObjectCode() : null; if (travelDocument instanceof TravelAuthorizationDocument && expense instanceof ActualExpense) { if (document.getTripType() != null) { financialObjectCode = document.getTripType().getEncumbranceObjCode(); } } if (financialObjectCode != null && financialObjectCode.equals(line.getFinancialObjectCode())) { String cg = getParameterService() .getParameterValueAsString( KFSConstants.CoreModuleNamespaces.CHART, KFSConstants.RouteLevelNames.ACCOUNT, KFSConstants.ChartApcParms.ACCOUNT_CG_DENOTING_VALUE); if (line.getAccount() == null) { line.refreshReferenceObject(KFSPropertyConstants.ACCOUNT); } if (line.getAccount().getSubFundGroup() == null) { line.refreshReferenceObject(KFSPropertyConstants.SUB_FUND_GROUP); } if (line.getAccount().getSubFundGroup().getFundGroupCode().equals(cg)) { showFlyAmerica = true; } } } } } } // Fly America error has been triggered, determine what accounting line to show it on. if (showFlyAmerica && !hasAttachment) { boolean newLine = true; for (TemSourceAccountingLine sourceLine : (List<TemSourceAccountingLine>) travelDocument.getSourceAccountingLines()) { if (line.equals(sourceLine)) { newLine = false; } } // if line is a new accounting line or a current one being saved/submitted in the // document. // figure out where the new accounting line will be added and set the error to that line # if (newLine) { GlobalVariables.getMessageMap().clearErrorPath(); int newIndex = document .getSourceAccountingLine(document.getSourceAccountingLines().size() - 1) .getSequenceNumber() + 1; errorPath = "document." + TemPropertyConstants.SOURCE_ACCOUNTING_LINE + "[" + newIndex + "]"; GlobalVariables.getMessageMap().addToErrorPath(errorPath); } GlobalVariables.getMessageMap() .putError( KFSPropertyConstants.ACCOUNT_NUMBER, TemKeyConstants.ERROR_ACCOUNTING_LINE_CG); } } } GlobalVariables.getMessageMap().clearErrorPath(); GlobalVariables.getMessageMap().getErrorPath().addAll(holdErrors); return valid; }
@Override public boolean validate(AttributedDocumentEvent event) { boolean rulePassed = true; TravelDocument travelDocument = (TravelDocument) event.getDocument(); GlobalVariables.getMessageMap().addToErrorPath(KRADPropertyConstants.DOCUMENT); // Actual Expenses int counter = 0; for (ActualExpense actualExpense : travelDocument.getActualExpenses()) { String property = TemPropertyConstants.ACTUAL_EXPENSES + "[" + counter + "]"; /* * Determine if the detail is an amount that doesn't go over the threshold */ KualiDecimal total = actualExpense.getTotalDetailExpenseAmount(); if (!total.isZero()) { if (total.isGreaterThan(actualExpense.getExpenseAmount())) { GlobalVariables.getMessageMap() .putError( property + "." + TemPropertyConstants.EXPENSE_AMOUNT, TemKeyConstants.ERROR_TEM_DETAIL_GREATER_THAN_EXPENSE); rulePassed = false; } else if (total.isLessThan(actualExpense.getExpenseAmount())) { GlobalVariables.getMessageMap() .putError( property + "." + TemPropertyConstants.EXPENSE_AMOUNT, TemKeyConstants.ERROR_TEM_DETAIL_LESS_THAN_EXPENSE); rulePassed = false; } } counter++; } // Imported Expenses counter = 0; for (ImportedExpense importedExpense : travelDocument.getImportedExpenses()) { String property = TemPropertyConstants.IMPORTED_EXPENSES + "[" + counter + "]"; // Determine if the detail is an amount that doesn't go over the threshold KualiDecimal total = KualiDecimal.ZERO; for (TemExpense detail : importedExpense.getExpenseDetails()) { total = total.add(detail.getExpenseAmount()); } if (!total.isZero()) { if (total.isGreaterThan(importedExpense.getExpenseAmount())) { GlobalVariables.getMessageMap() .putError( property + "." + TemPropertyConstants.EXPENSE_AMOUNT, TemKeyConstants.ERROR_TEM_DETAIL_GREATER_THAN_EXPENSE); rulePassed = false; } else if (total.isLessThan(importedExpense.getExpenseAmount())) { GlobalVariables.getMessageMap() .putError( property + "." + TemPropertyConstants.EXPENSE_AMOUNT, TemKeyConstants.ERROR_TEM_DETAIL_LESS_THAN_EXPENSE); rulePassed = false; } } counter++; } GlobalVariables.getMessageMap().clearErrorPath(); return rulePassed; }