/**
  * This method calculates the total credits for the customers.
  *
  * @param cgMapByCustomer
  * @param knownCustomers
  */
 private void calculateTotalCreditsForCustomers(
     Map<String, List<ContractsGrantsInvoiceDocument>> cgMapByCustomer,
     Map<String, ContractsAndGrantsAgingReport> knownCustomers) {
   Set<String> customerIds = cgMapByCustomer.keySet();
   KualiDecimal credits = KualiDecimal.ZERO;
   for (String customer : customerIds) {
     ContractsAndGrantsAgingReport agingReportDetail =
         pickContractsGrantsAgingReportDetail(knownCustomers, customer);
     List<ContractsGrantsInvoiceDocument> cgDocs = cgMapByCustomer.get(customer);
     if (ObjectUtils.isNotNull(cgDocs) && !cgDocs.isEmpty()) {
       credits = KualiDecimal.ZERO;
       for (ContractsGrantsInvoiceDocument cgDoc : cgDocs) {
         Collection<CustomerCreditMemoDocument> creditDocs =
             customerCreditMemoDocumentService.getCustomerCreditMemoDocumentByInvoiceDocument(
                 cgDoc.getDocumentNumber());
         if (ObjectUtils.isNotNull(creditDocs) && !creditDocs.isEmpty()) {
           for (CustomerCreditMemoDocument cm : creditDocs) {
             for (CustomerCreditMemoDetail cmDetail : cm.getCreditMemoDetails()) {
               credits = credits.add(cmDetail.getCreditMemoItemTotalAmount());
             }
           }
         }
       }
     }
     agingReportDetail.setTotalCredits(credits);
     totalCredits = totalCredits.add(credits);
   }
 }
  @Override
  public void recalculateCustomerCreditMemoDocument(
      CustomerCreditMemoDocument customerCreditMemoDocument,
      boolean blanketApproveDocumentEventFlag) {
    KualiDecimal customerCreditMemoDetailItemAmount;
    BigDecimal itemQuantity;

    String invDocumentNumber =
        customerCreditMemoDocument.getFinancialDocumentReferenceInvoiceNumber();
    List<CustomerCreditMemoDetail> customerCreditMemoDetails =
        customerCreditMemoDocument.getCreditMemoDetails();

    if (!blanketApproveDocumentEventFlag) {
      customerCreditMemoDocument.resetTotals();
    }

    for (CustomerCreditMemoDetail customerCreditMemoDetail : customerCreditMemoDetails) {
      // no data entered for the current credit memo detail -> no processing needed
      itemQuantity = customerCreditMemoDetail.getCreditMemoItemQuantity();
      customerCreditMemoDetailItemAmount = customerCreditMemoDetail.getCreditMemoItemTotalAmount();
      if (ObjectUtils.isNull(itemQuantity)
          && ObjectUtils.isNull(customerCreditMemoDetailItemAmount)) {
        if (!blanketApproveDocumentEventFlag) {
          customerCreditMemoDetail.setDuplicateCreditMemoItemTotalAmount(null);
        }
        continue;
      }

      // if item amount was entered, it takes precedence, if not, use the item quantity to re-calc
      // amount
      if (ObjectUtils.isNotNull(customerCreditMemoDetailItemAmount)) {
        customerCreditMemoDetail.recalculateBasedOnEnteredItemAmount(customerCreditMemoDocument);
      } // if item quantity was entered
      else {
        customerCreditMemoDetail.recalculateBasedOnEnteredItemQty(customerCreditMemoDocument);
        if (!blanketApproveDocumentEventFlag) {
          customerCreditMemoDetailItemAmount =
              customerCreditMemoDetail.getCreditMemoItemTotalAmount();
        }
      }

      if (!blanketApproveDocumentEventFlag) {
        customerCreditMemoDetail.setDuplicateCreditMemoItemTotalAmount(
            customerCreditMemoDetailItemAmount);
        boolean isCustomerInvoiceDetailTaxable =
            accountsReceivableTaxService.isCustomerInvoiceDetailTaxable(
                customerCreditMemoDocument.getInvoice(),
                customerCreditMemoDetail.getCustomerInvoiceDetail());
        customerCreditMemoDocument.recalculateTotals(
            customerCreditMemoDetailItemAmount, isCustomerInvoiceDetailTaxable);
      }
    }

    //  force the docHeader docTotal
    customerCreditMemoDocument
        .getFinancialSystemDocumentHeader()
        .setFinancialDocumentTotalAmount(customerCreditMemoDocument.getCrmTotalAmount());
  }
  @Override
  public boolean isThereNoDataToSubmit(CustomerCreditMemoDocument customerCreditMemoDocument) {
    boolean isSuccess = true;
    KualiDecimal customerCreditMemoDetailItemAmount;
    BigDecimal itemQuantity;
    List<CustomerCreditMemoDetail> customerCreditMemoDetails =
        customerCreditMemoDocument.getCreditMemoDetails();

    for (CustomerCreditMemoDetail customerCreditMemoDetail : customerCreditMemoDetails) {
      // no data entered for the current credit memo detail -> no processing needed
      itemQuantity = customerCreditMemoDetail.getCreditMemoItemQuantity();
      customerCreditMemoDetailItemAmount = customerCreditMemoDetail.getCreditMemoItemTotalAmount();
      if (ObjectUtils.isNotNull(itemQuantity)
          || ObjectUtils.isNotNull(customerCreditMemoDetailItemAmount)) {
        isSuccess = false;
        break;
      }
    }
    return isSuccess;
  }
  @Override
  public void completeCustomerCreditMemo(CustomerCreditMemoDocument creditMemo) {

    //  retrieve the document and make sure its not already closed, crash if so
    String invoiceNumber = creditMemo.getFinancialDocumentReferenceInvoiceNumber();
    CustomerInvoiceDocument invoice;
    try {
      invoice = (CustomerInvoiceDocument) documentService.getByDocumentHeaderId(invoiceNumber);
    } catch (WorkflowException e) {
      throw new RuntimeException(
          "A WorkflowException was generated when trying to load Customer Invoice #"
              + invoiceNumber
              + ".",
          e);
    }
    if (!invoice.isOpenInvoiceIndicator()) {
      throw new UnsupportedOperationException(
          "The CreditMemo Document #"
              + creditMemo.getDocumentNumber()
              + " attempted to credit "
              + "an Invoice [#"
              + invoiceNumber
              + "] that was already closed.  This is not supported.");
    }

    // this needs a little explanation.  we have to calculate manually
    // whether we've written off the whole thing, because the regular
    // code uses the invoice paid applieds to discount, but since those
    // are added but not committed in this transaction, they're also not
    // visible in this transaction, so we do it manually.
    KualiDecimal openAmount = invoice.getOpenAmount();

    Integer paidAppliedItemNumber = 0;

    //  retrieve the customer invoice details, and generate paid applieds for each
    List<CustomerCreditMemoDetail> details = creditMemo.getCreditMemoDetails();
    for (CustomerCreditMemoDetail detail : details) {
      CustomerInvoiceDetail invoiceDetail = detail.getCustomerInvoiceDetail();

      //   if credit amount is zero, do nothing
      if (detail.getCreditMemoLineTotalAmount().isZero()) {
        continue;
      }

      //  if credit amount is greater than the open amount, crash and complain
      if (detail
          .getCreditMemoLineTotalAmount()
          .abs()
          .isGreaterThan(invoiceDetail.getAmountOpen())) {
        throw new UnsupportedOperationException(
            "The credit detail for CreditMemo Document #"
                + creditMemo.getDocumentNumber()
                + " attempted "
                + "to credit more than the Open Amount on the Invoice Detail.  This is not supported.");
      }

      //  retrieve the number of current paid applieds, so we dont have item number overlap
      if (paidAppliedItemNumber == 0) {
        paidAppliedItemNumber =
            paidAppliedService.getNumberOfInvoicePaidAppliedsForInvoiceDetail(
                invoiceNumber, invoiceDetail.getInvoiceItemNumber());
      }

      //  create and save the paidApplied
      InvoicePaidApplied invoicePaidApplied = new InvoicePaidApplied();
      invoicePaidApplied.setDocumentNumber(creditMemo.getDocumentNumber());
      invoicePaidApplied.setPaidAppliedItemNumber(paidAppliedItemNumber++);
      invoicePaidApplied.setFinancialDocumentReferenceInvoiceNumber(invoiceNumber);
      invoicePaidApplied.setInvoiceItemNumber(invoiceDetail.getInvoiceItemNumber());
      invoicePaidApplied.setUniversityFiscalYear(universityDateService.getCurrentFiscalYear());
      invoicePaidApplied.setUniversityFiscalPeriodCode(
          universityDateService.getCurrentUniversityDate().getUniversityFiscalAccountingPeriod());
      invoicePaidApplied.setInvoiceItemAppliedAmount(detail.getCreditMemoLineTotalAmount().abs());
      openAmount = openAmount.subtract(detail.getCreditMemoLineTotalAmount().abs());
      businessObjectService.save(invoicePaidApplied);
    }

    //   if its open, but now with a zero openamount, then close it
    if (invoice.isOpenInvoiceIndicator() && KualiDecimal.ZERO.equals(openAmount)) {
      customerInvoiceDocumentService.addCloseNote(
          invoice, creditMemo.getDocumentHeader().getWorkflowDocument());
      invoice.setOpenInvoiceIndicator(false);
      invoice.setClosedDate(dateTimeService.getCurrentSqlDate());
      documentService.updateDocument(invoice);
    }
  }