/**
  * This method sums the amounts for a List of NonInvoiceds. This is used separately from
  * PaymentApplicationDocument.getTotalUnapplied()
  *
  * @return
  */
 private static KualiDecimal getSumOfNonInvoiceds(List<NonInvoiced> nonInvoiceds) {
   KualiDecimal sum = new KualiDecimal(0);
   for (NonInvoiced nonInvoiced : nonInvoiceds) {
     sum = sum.add(nonInvoiced.getFinancialDocumentLineAmount());
   }
   return sum;
 }
  public void testNonArLineOverFundsInvoice() {

    //  build the nonArLine
    NonInvoiced nonArLine = new NonInvoiced();
    nonArLine.setChartOfAccountsCode(NON_AR_CHART_CD);
    nonArLine.setAccountNumber(NON_AR_ACCOUNT_NBR);
    nonArLine.setFinancialObjectCode(NON_AR_OBJ_CD);
    nonArLine.setFinancialDocumentLineAmount(new KualiDecimal("500.00"));

    boolean result = true;

    // These cases are tested in PaymentApplicationDocumentTest

    //        //  test correctly funding from non-AR (to make sure it doesnt false-positive fail)
    //        result = PaymentApplicationDocumentRuleUtil.validateNonInvoiced(nonArLine, new
    // KualiDecimal("750.00"));
    //        assertTrue("Rule should pass.", result);
    //
    //        //  test overfunding from non-AR
    //        result = PaymentApplicationDocumentRuleUtil.validateNonInvoiced(nonArLine, new
    // KualiDecimal("250.00"));
    //        assertFalse("Rule should fail, since nonArLine is overfunded.", result);
    //
    //        //  test not allowing zero
    //        nonArLine.setFinancialDocumentLineAmount(new KualiDecimal("0.00"));
    //        result = PaymentApplicationDocumentRuleUtil.validateNonInvoiced(nonArLine, new
    // KualiDecimal("500.00"));
    //        assertFalse("Rules should fail, since nonArLine total is zero.", result);
    //
    //        //  test failing validateBO test
    //        nonArLine.setAccountNumber(NON_AR_ACCOUNT_NBR_BAD);
    //        nonArLine.setFinancialDocumentLineAmount(new KualiDecimal("500.00"));
    //        result = PaymentApplicationDocumentRuleUtil.validateNonInvoiced(nonArLine, new
    // KualiDecimal("500.00"));
    //        assertFalse("Rule should fail as nonsense account number is used.", result);

  }
  /**
   * This method...
   *
   * @param nonInvoiced
   * @param paymentApplicationDocument
   * @param totalFromControl
   * @return
   */
  private static boolean validateNonInvoicedLineAmount(
      NonInvoiced nonInvoiced,
      PaymentApplicationDocument paymentApplicationDocument,
      KualiDecimal totalFromControl) {
    MessageMap errorMap = GlobalVariables.getMessageMap();
    KualiDecimal nonArLineAmount = nonInvoiced.getFinancialDocumentLineAmount();
    // check that dollar amount is not zero before continuing
    if (ObjectUtils.isNull(nonArLineAmount)) {
      errorMap.putError(
          ArPropertyConstants.PaymentApplicationDocumentFields.NON_INVOICED_LINE_AMOUNT,
          ArKeyConstants.PaymentApplicationDocumentErrors.NON_AR_AMOUNT_REQUIRED);
      return false;
    } else {
      KualiDecimal cashControlBalanceToBeApplied = totalFromControl;
      cashControlBalanceToBeApplied =
          cashControlBalanceToBeApplied.add(paymentApplicationDocument.getTotalFromControl());
      cashControlBalanceToBeApplied.subtract(paymentApplicationDocument.getTotalApplied());
      cashControlBalanceToBeApplied.subtract(
          paymentApplicationDocument.getNonAppliedHoldingAmount());

      if (nonArLineAmount.isZero()) {
        errorMap.putError(
            ArPropertyConstants.PaymentApplicationDocumentFields.NON_INVOICED_LINE_AMOUNT,
            ArKeyConstants.PaymentApplicationDocumentErrors.AMOUNT_TO_BE_APPLIED_CANNOT_BE_ZERO);
        return false;
      } else if (nonArLineAmount.isNegative()) {
        errorMap.putError(
            ArPropertyConstants.PaymentApplicationDocumentFields.NON_INVOICED_LINE_AMOUNT,
            ArKeyConstants.PaymentApplicationDocumentErrors.AMOUNT_TO_BE_APPLIED_MUST_BE_POSTIIVE);
        return false;
      }
      //  check that we're not trying to apply more funds to the invoice than the invoice has
      // balance (ie, over-applying)
      else if (KualiDecimal.ZERO.isGreaterThan(
          cashControlBalanceToBeApplied.subtract(nonArLineAmount))) {
        errorMap.putError(
            ArPropertyConstants.PaymentApplicationDocumentFields.NON_INVOICED_LINE_AMOUNT,
            ArKeyConstants.PaymentApplicationDocumentErrors
                .NON_AR_AMOUNT_EXCEEDS_BALANCE_TO_BE_APPLIED);
        return false;
      }
    }
    return true;
  }
  /**
   * Validate non-ar/non-invoice line items on a PaymentApplicationDocument.
   *
   * @param nonInvoiced
   * @return
   */
  public static boolean validateNonInvoiced(
      NonInvoiced nonInvoiced,
      PaymentApplicationDocument paymentApplicationDocument,
      KualiDecimal totalFromControl)
      throws WorkflowException {
    MessageMap errorMap = GlobalVariables.getMessageMap();
    int originalErrorCount = errorMap.getErrorCount();

    //  validate the NonInvoiced BO
    String sNonInvoicedErrorPath = "nonInvoicedAddLine";
    errorMap.addToErrorPath(sNonInvoicedErrorPath);
    SpringContext.getBean(DictionaryValidationService.class).validateBusinessObject(nonInvoiced);
    errorMap.removeFromErrorPath(sNonInvoicedErrorPath);

    if (errorMap.getErrorCount() != originalErrorCount) {
      return false;
    }

    boolean isValid = true;

    // Required fields, so always validate these.
    nonInvoiced.refreshReferenceObject("account");
    if (ObjectUtils.isNull(nonInvoiced.getAccount())) {
      isValid &= false;
      putError(
          ArPropertyConstants.PaymentApplicationDocumentFields.NON_INVOICED_LINE_ACCOUNT,
          ArKeyConstants.PaymentApplicationDocumentErrors.NON_AR_ACCOUNT_INVALID,
          nonInvoiced.getAccountNumber());
    }
    isValid &=
        validateNonInvoicedLineItem(
            "chartOfAccountsCode",
            nonInvoiced.getChartOfAccountsCode(),
            Chart.class,
            ArPropertyConstants.PaymentApplicationDocumentFields.NON_INVOICED_LINE_CHART,
            ArKeyConstants.PaymentApplicationDocumentErrors.NON_AR_CHART_INVALID);
    isValid &=
        validateNonInvoicedLineItem(
            "accountNumber",
            nonInvoiced.getAccountNumber(),
            Account.class,
            ArPropertyConstants.PaymentApplicationDocumentFields.NON_INVOICED_LINE_ACCOUNT,
            ArKeyConstants.PaymentApplicationDocumentErrors.NON_AR_ACCOUNT_INVALID);
    isValid &=
        validateNonInvoicedLineItem(
            "financialObjectCode",
            nonInvoiced.getFinancialObjectCode(),
            ObjectCode.class,
            ArPropertyConstants.PaymentApplicationDocumentFields.NON_INVOICED_LINE_OBJECT,
            ArKeyConstants.PaymentApplicationDocumentErrors.NON_AR_OBJECT_CODE_INVALID);

    // Optional fields, so only validate if a value was entered.
    if (StringUtils.isNotBlank(nonInvoiced.getSubAccountNumber())) {
      isValid &=
          validateNonInvoicedLineItem(
              "subAccountNumber",
              nonInvoiced.getSubAccountNumber(),
              SubAccount.class,
              ArPropertyConstants.PaymentApplicationDocumentFields.NON_INVOICED_LINE_SUBACCOUNT,
              ArKeyConstants.PaymentApplicationDocumentErrors.NON_AR_SUB_ACCOUNT_INVALID);
    }
    if (StringUtils.isNotBlank(nonInvoiced.getFinancialSubObjectCode())) {
      isValid &=
          validateNonInvoicedLineItem(
              "financialSubObjectCode",
              nonInvoiced.getFinancialSubObjectCode(),
              SubObjectCode.class,
              ArPropertyConstants.PaymentApplicationDocumentFields.NON_INVOICED_LINE_SUBOBJECT,
              ArKeyConstants.PaymentApplicationDocumentErrors.NON_AR_SUB_OBJECT_CODE_INVALID);
    }
    if (StringUtils.isNotBlank(nonInvoiced.getProjectCode())) {
      isValid &=
          validateNonInvoicedLineItem(
              "code",
              nonInvoiced.getProjectCode(),
              ProjectCode.class,
              ArPropertyConstants.PaymentApplicationDocumentFields.NON_INVOICED_LINE_PROJECT,
              ArKeyConstants.PaymentApplicationDocumentErrors.NON_AR_PROJECT_CODE_INVALID);
    }

    isValid &=
        validateNonInvoicedLineAmount(nonInvoiced, paymentApplicationDocument, totalFromControl);

    return isValid;
  }