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.kra.routingform.rules;
017:
018: import java.util.ArrayList;
019: import java.util.Calendar;
020: import java.util.Date;
021: import java.util.HashMap;
022: import java.util.List;
023: import java.util.Map;
024:
025: import org.apache.commons.lang.StringUtils;
026: import org.kuali.core.authorization.AuthorizationConstants;
027: import org.kuali.core.document.Document;
028: import org.kuali.core.service.BusinessObjectService;
029: import org.kuali.core.service.DataDictionaryService;
030: import org.kuali.core.service.DateTimeService;
031: import org.kuali.core.service.DictionaryValidationService;
032: import org.kuali.core.service.DocumentService;
033: import org.kuali.core.util.ErrorMap;
034: import org.kuali.core.util.GlobalVariables;
035: import org.kuali.core.util.ObjectUtils;
036: import org.kuali.kfs.KFSKeyConstants;
037: import org.kuali.kfs.context.SpringContext;
038: import org.kuali.kfs.service.ParameterService;
039: import org.kuali.kfs.service.impl.ParameterConstants;
040: import org.kuali.module.kra.KraConstants;
041: import org.kuali.module.kra.KraKeyConstants;
042: import org.kuali.module.kra.budget.document.BudgetDocument;
043: import org.kuali.module.kra.budget.document.BudgetDocumentAuthorizer;
044: import org.kuali.module.kra.budget.rules.ResearchDocumentRuleBase;
045: import org.kuali.module.kra.document.ResearchDocument;
046: import org.kuali.module.kra.routingform.bo.RoutingFormAgency;
047: import org.kuali.module.kra.routingform.bo.RoutingFormInstitutionCostShare;
048: import org.kuali.module.kra.routingform.bo.RoutingFormOrganization;
049: import org.kuali.module.kra.routingform.bo.RoutingFormPersonnel;
050: import org.kuali.module.kra.routingform.bo.RoutingFormResearchRisk;
051: import org.kuali.module.kra.routingform.bo.RoutingFormResearchRiskStudy;
052: import org.kuali.module.kra.routingform.bo.RoutingFormSubcontractor;
053: import org.kuali.module.kra.routingform.document.RoutingFormDocument;
054:
055: import edu.iu.uis.eden.exception.WorkflowException;
056:
057: /**
058: * This class...
059: */
060: public class RoutingFormDocumentRule extends ResearchDocumentRuleBase {
061:
062: private DataDictionaryService dataDictionaryService;
063:
064: public RoutingFormDocumentRule() {
065: super ();
066: dataDictionaryService = SpringContext
067: .getBean(DataDictionaryService.class);
068: }
069:
070: /**
071: * Checks business rules related to saving a ResearchDocument.
072: *
073: * @param ResearchDocument researchDocument
074: * @return boolean True if the researchDocument is valid, false otherwise.
075: */
076: @Override
077: public boolean processCustomSaveDocumentBusinessRules(
078: ResearchDocument researchDocument) {
079: if (!(researchDocument instanceof RoutingFormDocument)) {
080: return false;
081: }
082:
083: boolean valid = true;
084:
085: RoutingFormDocument routingFormDocument = (RoutingFormDocument) researchDocument;
086:
087: // changing this to '0' so it doesn't validate reference objects within a list (Subcontractors was causing a problem).
088: SpringContext.getBean(DictionaryValidationService.class)
089: .validateDocumentRecursively(routingFormDocument, 0);
090:
091: valid &= processRoutingFormAgency(routingFormDocument);
092:
093: valid &= processInstitutionCostShare(routingFormDocument);
094:
095: valid &= processRoutingFormOrganizations(routingFormDocument);
096:
097: valid &= processRoutingFormSubcontractors(routingFormDocument);
098:
099: valid &= processRoutingFormResearchRisks(routingFormDocument);
100:
101: valid &= processRoutingFormPersonnel(routingFormDocument);
102:
103: valid &= GlobalVariables.getErrorMap().isEmpty();
104:
105: return valid;
106: }
107:
108: /**
109: * Runs audit mode business rule checks on a ResearchDocument.
110: *
111: * @param Document document
112: * @return boolean True if the researchDocument is valid, false otherwise.
113: */
114: public boolean processRunAuditBusinessRules(Document document) {
115: return RoutingFormAuditRule
116: .processRunAuditBusinessRules(document);
117: }
118:
119: /**
120: * This method validates that the Agency and Federal Pass Through Agency are, if entered, valid. No Agency will be handled via Audit Error.
121: * @param routingFormDocument
122: * @return
123: */
124: private boolean processRoutingFormAgency(
125: RoutingFormDocument routingFormDocument) {
126: boolean valid = true;
127:
128: routingFormDocument.getRoutingFormAgency()
129: .refreshReferenceObject("agency");
130: if (!StringUtils.isBlank(routingFormDocument
131: .getRoutingFormAgency().getAgencyNumber())
132: && routingFormDocument.getRoutingFormAgency()
133: .getAgency() == null) {
134: valid = false;
135: GlobalVariables.getErrorMap().putError(
136: "routingFormAgency.agencyNumber",
137: KraKeyConstants.ERROR_INVALID_VALUE,
138: new String[] { dataDictionaryService
139: .getAttributeLabel(RoutingFormAgency.class,
140: "agencyNumber") });
141: }
142:
143: routingFormDocument
144: .refreshReferenceObject("federalPassThroughAgency");
145: if (!StringUtils.isBlank(routingFormDocument
146: .getAgencyFederalPassThroughNumber())
147: && routingFormDocument.getFederalPassThroughAgency() == null) {
148: valid = false;
149: GlobalVariables
150: .getErrorMap()
151: .putError(
152: "agencyFederalPassThroughNumber",
153: KraKeyConstants.ERROR_INVALID_VALUE,
154: new String[] { dataDictionaryService
155: .getAttributeLabel(
156: RoutingFormDocument.class,
157: "agencyFederalPassThroughNumber") });
158: }
159:
160: return valid;
161: }
162:
163: /**
164: * This method validates Institution Cost Share Orgs. It checks the following:
165: * <ul>
166: * <li>The Org must exist</li>
167: * <li>If an Account Number is specified, the Account must exist</li>
168: * <li>Orgs without Accounts can appear in the list only once</li>
169: * <li>Accounts, when specified, can appear in the list only once </li>
170: * <li>Positive, non-zero amounts are required for all lines </li>
171: * </ul>
172: *
173: * @param routingFormDocument The routingFormDocument that is being validated
174: * @return valid Does the validation pass
175: */
176: private boolean processInstitutionCostShare(
177: RoutingFormDocument routingFormDocument) {
178: boolean valid = true;
179:
180: List accounts = new ArrayList();
181: List orgNoAccounts = new ArrayList();
182:
183: ErrorMap errorMap = GlobalVariables.getErrorMap();
184:
185: int i = 0;
186:
187: for (RoutingFormInstitutionCostShare costShare : routingFormDocument
188: .getRoutingFormInstitutionCostShares()) {
189: errorMap.addToErrorPath("routingFormInstitutionCostShare["
190: + i + "]");
191: costShare.refresh();
192:
193: if (costShare.getRoutingFormCostShareAmount() == null
194: || !costShare.getRoutingFormCostShareAmount()
195: .isPositive()) {
196: // Amount is zero or less
197: valid = false;
198: errorMap
199: .putError(
200: "routingFormCostShareAmount",
201: KraKeyConstants.ERROR_INVALID_AMOUNT_POSITIVE_ONLY);
202: }
203:
204: if (costShare.getOrganization() != null) {
205: if (costShare.getAccountNumber() == null) {
206: if (!orgNoAccounts.contains(costShare
207: .getOrganization())) {
208: orgNoAccounts.add(costShare.getOrganization());
209: } else {
210: // org already in list
211: valid = false;
212: errorMap
213: .putError(
214: "organizationCode",
215: KraKeyConstants.ERROR_ORG_ALREADY_EXISTS_ON_RF,
216: costShare
217: .getChartOfAccountsCode(),
218: costShare.getOrganizationCode());
219:
220: }
221: } else {
222: // account number is not null
223: if (costShare.getAccount() == null) {
224: // account number is specified account doesn't exist
225: valid = false;
226: errorMap
227: .putError(
228: "accountNumber",
229: KFSKeyConstants.ERROR_ACCOUNT_NOT_FOUND,
230: costShare
231: .getChartOfAccountsCode(),
232: costShare.getOrganizationCode(),
233: costShare.getAccountNumber());
234: } else if (!accounts.contains(costShare
235: .getAccount())) {
236: accounts.add(costShare.getAccount());
237: } else {
238: // account already in list
239: valid = false;
240: errorMap
241: .putError(
242: "accountNumber",
243: KraKeyConstants.ERROR_ACCOUNT_ALREADY_EXISTS_ON_RF,
244: costShare
245: .getChartOfAccountsCode(),
246: costShare.getOrganizationCode(),
247: costShare.getAccountNumber());
248: }
249: }
250: } else {
251: // organization doesn't exist
252: valid = false;
253: errorMap.putError("organizationCode",
254: KraKeyConstants.ERROR_ORG_NOT_FOUND, costShare
255: .getChartOfAccountsCode(), costShare
256: .getOrganizationCode());
257: }
258: errorMap
259: .removeFromErrorPath("routingFormInstitutionCostShare["
260: + i++ + "]");
261: }
262: return valid;
263: }
264:
265: /**
266: * This method validates 'Other Organizations'. It checks the following:
267: * <ul>
268: * <li>The Org must exist</li>
269: * <li>The Org must appear in the list only once</li>
270: * </ul>
271: *
272: * @param routingFormDocument The routingFormDocument that is being validated
273: * @return valid Does the validation pass
274: */
275: private boolean processRoutingFormOrganizations(
276: RoutingFormDocument routingFormDocument) {
277: boolean valid = true;
278:
279: List organizations = new ArrayList();
280:
281: ErrorMap errorMap = GlobalVariables.getErrorMap();
282:
283: int i = 0;
284:
285: for (RoutingFormOrganization organization : routingFormDocument
286: .getRoutingFormOrganizations()) {
287: organization.refresh();
288:
289: errorMap.addToErrorPath("routingFormOrganization[" + i
290: + "]");
291:
292: if (organization.getOrganization() == null) {
293: // organization does not exist
294: valid = false;
295: errorMap.putError("organizationCode",
296: KraKeyConstants.ERROR_ORG_NOT_FOUND,
297: organization.getChartOfAccountsCode(),
298: organization.getOrganizationCode());
299: } else {
300: if (!organizations.contains(organization
301: .getOrganization())) {
302: organizations.add(organization.getOrganization());
303: } else {
304: // organization already exists on RF
305: valid = false;
306: errorMap
307: .putError(
308: "organizationCode",
309: KraKeyConstants.ERROR_ORG_ALREADY_EXISTS_ON_RF,
310: organization
311: .getChartOfAccountsCode(),
312: organization.getOrganizationCode());
313: }
314: }
315: errorMap.removeFromErrorPath("routingFormOrganization["
316: + i++ + "]");
317: }
318:
319: return valid;
320: }
321:
322: /**
323: * This method validates 'Subcontractors'. It checks the following:
324: * <ul>
325: * <li>The Subcontractor must exist</li>
326: * <li>The Subcontractor must appear in the list only once</li>
327: * </ul>
328: *
329: * @param routingFormDocument The routingFormDocument that is being validated
330: * @return valid Does the validation pass
331: */
332: private boolean processRoutingFormSubcontractors(
333: RoutingFormDocument routingFormDocument) {
334: boolean valid = true;
335:
336: List subcontractors = new ArrayList();
337:
338: ErrorMap errorMap = GlobalVariables.getErrorMap();
339:
340: int i = 0;
341:
342: for (RoutingFormSubcontractor subcontractor : routingFormDocument
343: .getRoutingFormSubcontractors()) {
344: subcontractor.refresh();
345:
346: errorMap.addToErrorPath("routingFormSubcontractor[" + i
347: + "]");
348:
349: if (subcontractor.getRoutingFormSubcontractorAmount() == null
350: || subcontractor
351: .getRoutingFormSubcontractorAmount()
352: .isNegative()) {
353: // Amount is negative
354: valid = false;
355: errorMap
356: .putError(
357: "routingFormSubcontractorAmount",
358: KraKeyConstants.ERROR_INVALID_AMOUNT_NOT_NEGATIVE);
359: }
360:
361: if (subcontractor.getRoutingFormSubcontractorNumber() != null) {
362:
363: if (subcontractor.getSubcontractor() == null) {
364: // subcontractor doesn't exist
365: valid = false;
366: errorMap
367: .putError(
368: "routingFormSubcontractorAmount",
369: KraKeyConstants.ERROR_SUBCONTRACTOR_NOT_FOUND);
370: } else {
371: if (!subcontractors.contains(subcontractor
372: .getSubcontractor())) {
373: subcontractors.add(subcontractor
374: .getSubcontractor());
375: } else {
376: // subcontractor already exists on RF
377: valid = false;
378: errorMap
379: .putError(
380: "routingFormSubcontractorAmount",
381: KraKeyConstants.ERROR_SUBCONTRACTOR_ALREADY_EXISTS_ON_RF);
382: }
383: }
384: } else {
385: valid = false;
386: errorMap
387: .putError(
388: "routingFormSubcontractorAmount",
389: KraKeyConstants.ERROR_SUBCONTRACTOR_NOT_SELECTED);
390: }
391:
392: errorMap.removeFromErrorPath("routingFormSubcontractor["
393: + i++ + "]");
394: }
395: return valid;
396: }
397:
398: /**
399: * This method validates Personnel. It checks the following:
400: * <ul>
401: * <li>Required person name or TBNed selected.</li>
402: * </ul>
403: *
404: * @param routingFormDocument The routingFormDocument that is being validated
405: * @return valid Does the validation pass
406: */
407: private boolean processRoutingFormPersonnel(
408: RoutingFormDocument routingFormDocument) {
409: boolean valid = true;
410: ErrorMap errorMap = GlobalVariables.getErrorMap();
411:
412: // Functionally personnel doesn't need an index i, but it's left here for consistency of validating lists.
413: int i = 0;
414:
415: for (RoutingFormPersonnel person : routingFormDocument
416: .getRoutingFormPersonnel()) {
417: errorMap.addToErrorPath("routingFormPersonnel[" + i + "]");
418:
419: if (person.getPersonUniversalIdentifier() == null
420: && !person.isPersonToBeNamedIndicator()) {
421: valid = false;
422: errorMap.putError("personUniversalIdentifier",
423: KraKeyConstants.ERROR_PERSON_NOT_NAMED);
424: }
425:
426: if (person.getChartOfAccountsCode() == null
427: || person.getOrganizationCode() == null) {
428: valid = false;
429: errorMap.putError("personUniversalIdentifier",
430: KraKeyConstants.ERROR_MISSING,
431: "Routing Form Personnel Chart and/or Org");
432: }
433:
434: errorMap.removeFromErrorPath("routingFormPersonnel[" + i
435: + "]");
436: i++;
437: }
438:
439: return valid;
440: }
441:
442: /**
443: * This method validates 'Research Risks'. It checks the following:
444: * <ul>
445: * <li>If Study is approved, approval date is required.</li>
446: * <li>If study is not approved, approval date and expiration date must be empty.</li>
447: * <li>If review status is 'exempt', exception number is required.</li>
448: * <li>If review status in not 'exempt', exception number should be blank.</li>
449: * <li>Expiration date must not be earlier than approval date.</li>
450: * <li>If the Human Subjects approval date is more than one year prior to the routing form creation date, the user must enter a
451: * more current date, or set the status to Pending.</li>
452: * <li>If the Animal approval date is more than three years prior to the routing form creation date, the user must enter a more
453: * current date, or set the status to Pending.</li>
454: * </ul>
455: *
456: * @param routingFormDocument The routingFormDocument that is being validated
457: * @return valid Does the validation pass
458: */
459: private boolean processRoutingFormResearchRisks(
460: RoutingFormDocument routingFormDocument) {
461:
462: boolean valid = true;
463: ErrorMap errorMap = GlobalVariables.getErrorMap();
464:
465: String humanSubjectsActiveCode = SpringContext
466: .getBean(ParameterService.class)
467: .getParameterValue(
468: ParameterConstants.RESEARCH_ADMINISTRATION_DOCUMENT.class,
469: KraConstants.RESEARCH_RISKS_HUMAN_SUBJECTS_ACTIVE_CODE);
470:
471: String animalsActiveCode = SpringContext
472: .getBean(ParameterService.class)
473: .getParameterValue(
474: ParameterConstants.RESEARCH_ADMINISTRATION_DOCUMENT.class,
475: KraConstants.RESEARCH_RISKS_ANIMALS_ACTIVE_CODE);
476:
477: // Setup dates.
478: Date createDate = routingFormDocument
479: .getRoutingFormCreateDate();
480: Calendar createCalendar = SpringContext.getBean(
481: DateTimeService.class).getCalendar(createDate);
482: createCalendar.add(Calendar.YEAR, -1);
483: Date humanSubjectsEarliestApprovalDate = createCalendar
484: .getTime();
485: createCalendar.add(Calendar.YEAR, -2);
486: Date animalsEarliestApprovalDate = createCalendar.getTime();
487:
488: int i = 0;
489: for (RoutingFormResearchRisk researchRisk : routingFormDocument
490: .getRoutingFormResearchRisks()) {
491: errorMap.addToErrorPath("routingFormResearchRisk[" + i
492: + "]");
493: int j = 0;
494: for (RoutingFormResearchRiskStudy study : researchRisk
495: .getResearchRiskStudies()) {
496: errorMap.addToErrorPath("researchRiskStudy[" + j + "]");
497:
498: // If study is approved, approval date is required.
499: if (KraConstants.RESEARCH_RISK_STUDY_STATUS_APPROVED
500: .equals(study
501: .getResearchRiskStudyApprovalStatusCode())
502: && ObjectUtils.isNull(study
503: .getResearchRiskStudyApprovalDate())) {
504: valid = false;
505: errorMap
506: .putError(
507: "researchRiskStudyApprovalDate",
508: KraKeyConstants.ERROR_APPROVAL_DATE_REQUIRED);
509: }
510:
511: // If study is not approved, approval date and expiration date must be empty.
512: if (!KraConstants.RESEARCH_RISK_STUDY_STATUS_APPROVED
513: .equals(study
514: .getResearchRiskStudyApprovalStatusCode())) {
515: if (ObjectUtils.isNotNull(study
516: .getResearchRiskStudyApprovalDate())) {
517: valid = false;
518: errorMap
519: .putError(
520: "researchRiskStudyApprovalDate",
521: KraKeyConstants.ERROR_APPROVAL_DATE_REMOVE);
522: }
523: if (ObjectUtils.isNotNull(study
524: .getResearchRiskStudyExpirationDate())) {
525: valid = false;
526: errorMap
527: .putError(
528: "researchRiskStudyExpirationDate",
529: KraKeyConstants.ERROR_EXPIRATION_DATE_REMOVE);
530: }
531: }
532:
533: // If review status is 'exempt', exception number is required.
534: if (KraConstants.RESEARCH_RISK_STUDY_REVIEW_EXEMPT
535: .equals(study.getResearchRiskStudyReviewCode())
536: && StringUtils.isBlank(study
537: .getResearchRiskExemptionNumber())) {
538: valid = false;
539: errorMap
540: .putError(
541: "researchRiskExemptionNumber",
542: KraKeyConstants.ERROR_EXEMPTION_NUMBER_REQUIRED);
543: }
544:
545: // If review status in not 'exempt', exception number should be blank.
546: if (!KraConstants.RESEARCH_RISK_STUDY_REVIEW_EXEMPT
547: .equals(study.getResearchRiskStudyReviewCode())
548: && !StringUtils.isBlank(study
549: .getResearchRiskExemptionNumber())) {
550: valid = false;
551: errorMap
552: .putError(
553: "researchRiskExemptionNumber",
554: KraKeyConstants.ERROR_EXEMPTION_NUMBER_REMOVE);
555: }
556:
557: // Expiration date must not be earlier than approval date.
558: if (ObjectUtils.isNotNull(study
559: .getResearchRiskStudyApprovalDate())
560: && ObjectUtils.isNotNull(study
561: .getResearchRiskStudyExpirationDate())
562: && study
563: .getResearchRiskStudyExpirationDate()
564: .before(
565: study
566: .getResearchRiskStudyApprovalDate())) {
567: valid = false;
568: errorMap
569: .putError(
570: "researchRiskStudyExpirationDate",
571: KraKeyConstants.ERROR_EXPIRATION_DATE_TOO_EARLY);
572: }
573:
574: // If Human Subjects approval date is more than one year prior to the routing form creation date, the user must
575: // enter a more current date, or set the status to Pending.
576: if (researchRisk.getResearchRiskTypeCode().equals(
577: humanSubjectsActiveCode)
578: && ObjectUtils.isNotNull(study
579: .getResearchRiskStudyApprovalDate())) {
580: int dateDiff = SpringContext.getBean(
581: DateTimeService.class).dateDiff(
582: study.getResearchRiskStudyApprovalDate(),
583: humanSubjectsEarliestApprovalDate, false);
584: if (dateDiff > 0) {
585: // Seems counterintuitive that 'before' is the proper operator here - but it is.
586: valid = false;
587: errorMap
588: .putError(
589: "researchRiskStudyApprovalDate",
590: KraKeyConstants.ERROR_HUMAN_SUBJECTS_APPROVAL_DATE_TOO_OLD);
591: }
592: }
593:
594: // If Animals approval date is more than 3 years prior to the routing form creation date, the user must enter a more
595: // current date, or set the status to Pending.
596: if (researchRisk.getResearchRiskTypeCode().equals(
597: animalsActiveCode)
598: && ObjectUtils.isNotNull(study
599: .getResearchRiskStudyApprovalDate())) {
600: int dateDiff = SpringContext.getBean(
601: DateTimeService.class).dateDiff(
602: study.getResearchRiskStudyApprovalDate(),
603: animalsEarliestApprovalDate, false);
604: if (dateDiff > 0) {
605: valid = false;
606: errorMap
607: .putError(
608: "researchRiskStudyApprovalDate",
609: KraKeyConstants.ERROR_ANIMALS_APPROVAL_DATE_TOO_OLD);
610: }
611: }
612:
613: errorMap.removeFromErrorPath("researchRiskStudy[" + j++
614: + "]");
615: }
616:
617: errorMap.removeFromErrorPath("routingFormResearchRisk["
618: + i++ + "]");
619: }
620:
621: return valid;
622: }
623:
624: /**
625: * This method validates that a Budget can be lined to a RF. It checks the following:
626: * <ul>
627: * <li>/...</li>
628: * </ul>
629: *
630: * @param routingFormDocument The routingFormDocument that is being validated
631: * @param budgetDocumentHeaderId The doc header ID of the budget to be linked to this RF
632: * @param selectedBudgetPeriods An array containing the
633: * @param allPeriods
634: * @return valid Does the validation pass
635: */
636: public boolean processBudgetRoutingFormLink(
637: RoutingFormDocument routingFormDocument,
638: String[] selectedBudgetPeriods, boolean allPeriods,
639: boolean checkPeriods) {
640: boolean valid = true;
641: ErrorMap errorMap = GlobalVariables.getErrorMap();
642:
643: DocumentService documentService = SpringContext
644: .getBean(DocumentService.class);
645: BusinessObjectService businessObjectService = SpringContext
646: .getBean(BusinessObjectService.class);
647:
648: errorMap.addToErrorPath("document");
649:
650: try {
651: DictionaryValidationService dictionaryValidationService = SpringContext
652: .getBean(DictionaryValidationService.class);
653: dictionaryValidationService
654: .validateDocument(routingFormDocument);
655:
656: // see if the Budget Document Header ID is valid
657:
658: // This stinks, but it has to be done since Workflow uses Longs for document number.
659: try {
660: new Long(routingFormDocument
661: .getRoutingFormBudgetNumber());
662: } catch (NumberFormatException e) {
663: errorMap
664: .putError(
665: "routingFormBudgetNumber",
666: KraKeyConstants.ERROR_DOCUMENT_NUMBER_NOT_BUDGET_DOCUMENT,
667: new String[] { routingFormDocument
668: .getRoutingFormBudgetNumber() });
669: return false;
670: }
671:
672: if (documentService.documentExists(routingFormDocument
673: .getRoutingFormBudgetNumber())) {
674: Document document = documentService
675: .getByDocumentHeaderId(routingFormDocument
676: .getRoutingFormBudgetNumber());
677: if (BudgetDocument.class.isAssignableFrom(document
678: .getClass())) {
679: BudgetDocument budgetDocument = (BudgetDocument) document;
680:
681: // see if this user can vew/modify the budget
682: BudgetDocumentAuthorizer budgetDocumentAuthorizer = new BudgetDocumentAuthorizer();
683: Map budgetAuthorizationsMap = budgetDocumentAuthorizer
684: .getEditMode(budgetDocument,
685: GlobalVariables.getUserSession()
686: .getUniversalUser());
687: if ((!budgetAuthorizationsMap
688: .containsKey(AuthorizationConstants.EditMode.FULL_ENTRY) && !budgetAuthorizationsMap
689: .containsKey(AuthorizationConstants.EditMode.VIEW_ONLY))
690: || (budgetAuthorizationsMap
691: .containsKey(AuthorizationConstants.EditMode.FULL_ENTRY)
692: && !budgetAuthorizationsMap
693: .get(
694: AuthorizationConstants.EditMode.FULL_ENTRY)
695: .equals("TRUE")
696: && budgetAuthorizationsMap
697: .containsKey(AuthorizationConstants.EditMode.FULL_ENTRY) && !budgetAuthorizationsMap
698: .get(
699: AuthorizationConstants.EditMode.FULL_ENTRY)
700: .equals("TRUE"))) {
701: errorMap
702: .putError(
703: "routingFormBudgetNumber1",
704: KraKeyConstants.ERROR_SELECTED_PERIODS_CONSECUTIVE);
705: return false;
706: }
707:
708: // see if this budget is already linked to another RF
709: Map<String, Object> fieldValues = new HashMap<String, Object>();
710: fieldValues.put("routingFormBudgetNumber",
711: routingFormDocument
712: .getRoutingFormBudgetNumber());
713:
714: List<RoutingFormDocument> matching = (List<RoutingFormDocument>) businessObjectService
715: .findMatching(RoutingFormDocument.class,
716: fieldValues);
717:
718: for (RoutingFormDocument rfd : matching) {
719: if (!rfd.getDocumentNumber()
720: .equals(
721: routingFormDocument
722: .getDocumentNumber())) {
723: valid = false;
724: errorMap
725: .putError(
726: "routingFormBudgetNumber",
727: KraKeyConstants.ERROR_BUDGET_ALREADY_LINKED,
728: new String[] {
729: routingFormDocument
730: .getRoutingFormBudgetNumber(),
731: rfd
732: .getDocumentNumber() });
733: break;
734: }
735: }
736:
737: // see if Modular has been distributed
738:
739: } else {
740: valid = false;
741: errorMap
742: .putError(
743: "routingFormBudgetNumber",
744: KraKeyConstants.ERROR_DOCUMENT_NUMBER_NOT_BUDGET_DOCUMENT,
745: new String[] { routingFormDocument
746: .getRoutingFormBudgetNumber() });
747: }
748: } else {
749: valid = false;
750: errorMap
751: .putError(
752: "routingFormBudgetNumber",
753: KraKeyConstants.ERROR_DOCUMENT_NUMBER_NOT_EXIST,
754: new String[] { routingFormDocument
755: .getRoutingFormBudgetNumber() });
756: }
757:
758: // check selected periods
759: if (!allPeriods && checkPeriods) {
760: int nextPeriodNumberShouldBe = -1;
761: if (selectedBudgetPeriods != null
762: && selectedBudgetPeriods.length > 0) {
763: for (int i = 0; i < selectedBudgetPeriods.length; i++) {
764: if (i != 0
765: && Integer
766: .valueOf(selectedBudgetPeriods[i]) != nextPeriodNumberShouldBe) { // first time
767: valid = false;
768: errorMap
769: .putError(
770: "routingFormBudgetNumber1",
771: KraKeyConstants.ERROR_SELECTED_PERIODS_CONSECUTIVE);
772: break;
773: }
774: nextPeriodNumberShouldBe = Integer
775: .valueOf(selectedBudgetPeriods[i]) + 1;
776: }
777: } else {
778: valid = false;
779: errorMap.putError("routingFormBudgetNumber1",
780: KraKeyConstants.ERROR_AT_LEAST_ONE_PERIOD);
781: }
782: }
783: } catch (WorkflowException e) {
784: throw new RuntimeException(
785: "Exception validating budget to link", e);
786: }
787:
788: errorMap.removeFromErrorPath("document");
789: return valid;
790: }
791: }
|