// metas: tsa: 2181: changed method name to reflect what is doing
  private boolean voidIt0() {
    if (!isActive()) throw new IllegalStateException("Allocation already reversed (not active)");

    //	Can we delete posting
    MPeriod.testPeriodOpen(
        getCtx(), getDateTrx(), X_C_DocType.DOCBASETYPE_PaymentAllocation, getAD_Org_ID());

    //	Set Inactive
    setIsActive(false);
    setDocumentNo(getDocumentNo() + "^");
    setDocStatus(DOCSTATUS_Reversed); // 	for direct calls
    if (!save() || isActive()) throw new IllegalStateException("Cannot de-activate allocation");

    //	Delete Posting
    Services.get(IFactAcctDAO.class).deleteForDocument(this);

    //	Unlink Invoices
    getLines(true);
    final Set<Integer> bpartnerIds = new HashSet<Integer>();
    for (int i = 0; i < m_lines.length; i++) {
      MAllocationLine line = m_lines[i];
      line.setIsActive(false);
      line.save();
      final int bpartnerId = line.processIt(true); // reverse
      bpartnerIds.add(bpartnerId);
    }
    updateBP(bpartnerIds);
    return true;
  } //	reverse
 /**
  * Get Lines
  *
  * @param requery if true requery
  * @return lines
  */
 public MAllocationLine[] getLines(boolean requery) {
   if (m_lines != null && m_lines.length != 0 && !requery) {
     set_TrxName(m_lines, get_TrxName());
     return m_lines;
   }
   //
   String sql = "SELECT * FROM C_AllocationLine WHERE C_AllocationHdr_ID=?";
   ArrayList<MAllocationLine> list = new ArrayList<MAllocationLine>();
   PreparedStatement pstmt = null;
   ResultSet rs = null;
   try {
     pstmt = DB.prepareStatement(sql, get_TrxName());
     pstmt.setInt(1, getC_AllocationHdr_ID());
     rs = pstmt.executeQuery();
     while (rs.next()) {
       MAllocationLine line = new MAllocationLine(getCtx(), rs, get_TrxName());
       line.setParent(this);
       list.add(line);
     }
   } catch (Exception e) {
     log.log(Level.SEVERE, sql, e);
   } finally {
     DB.close(rs, pstmt);
     rs = null;
     pstmt = null;
   }
   //
   m_lines = new MAllocationLine[list.size()];
   list.toArray(m_lines);
   return m_lines;
 } //	getLines
  /**
   * Before Delete.
   *
   * @return true if acct was deleted
   */
  @Override
  protected boolean beforeDelete() {
    String trxName = get_TrxName();
    if (trxName == null || trxName.length() == 0) log.warning("No transaction");
    if (isPosted()) {
      MPeriod.testPeriodOpen(
          getCtx(), getDateTrx(), MDocType.DOCBASETYPE_PaymentAllocation, getAD_Org_ID());
      setPosted(false);
      Services.get(IFactAcctDAO.class).deleteForDocument(this);
    }

    //	Unlink
    getLines(true);
    HashSet<Integer> bps = new HashSet<Integer>();
    for (int i = 0; i < m_lines.length; i++) {
      MAllocationLine line = m_lines[i];
      bps.add(line.getC_BPartner_ID());
      line.deleteEx(true, trxName);
    }
    updateBP(bps);
    return true;
  } //	beforeDelete
  /**
   * Complete Document
   *
   * @return new status (Complete, In Progress, Invalid, Waiting ..)
   */
  @Override
  public String completeIt() {
    //	Re-Check
    if (!m_justPrepared) {
      String status = prepareIt();
      if (!DocAction.STATUS_InProgress.equals(status)) return status;
    }

    m_processMsg =
        ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_COMPLETE);
    if (m_processMsg != null) return DocAction.STATUS_Invalid;

    //	Implicit Approval
    if (!isApproved()) approveIt();
    log.info(toString());

    //	Link
    getLines(false);
    final Set<Integer> bpartnerIds = new HashSet<Integer>();
    for (int i = 0; i < m_lines.length; i++) {
      final MAllocationLine line = m_lines[i];
      final int bpartnerId = line.processIt(false); // not reverse
      bpartnerIds.add(bpartnerId);
    }
    updateBP(bpartnerIds);

    //	User Validation
    String valid =
        ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_COMPLETE);
    if (valid != null) {
      m_processMsg = valid;
      return DocAction.STATUS_Invalid;
    }

    setProcessed(true);
    setDocAction(DOCACTION_Close);
    return DocAction.STATUS_Completed;
  } //	completeIt
  /**
   * Reverse current allocation (another allocation is produced) NOTE: this method is not saving
   * current object's modifications
   *
   * @see
   *     http://dewiki908/mediawiki/index.php/02181:_Verbuchungsfehler_bei_Zuordnungen_%282011092910000015%29
   */
  private void reverseCorrectIt0() {
    MAllocationHdr reversal = new MAllocationHdr(getCtx(), 0, get_TrxName());
    copyValues(this, reversal);

    //
    // 07570: Keep AD_Org of original document
    reversal.setAD_Org_ID(this.getAD_Org_ID());

    reversal.setDocumentNo(""); // let it generate a new document#
    reversal.setProcessing(false);
    reversal.setProcessed(false);
    reversal.setDocStatus(DOCSTATUS_Drafted);
    reversal.setDocAction(DOCACTION_Complete);
    reversal.setPosted(false);
    reversal.setReversal_ID(this.getC_AllocationHdr_ID());
    reversal.saveEx();

    this.setReversal_ID(reversal.getC_AllocationHdr_ID());
    saveEx();

    for (MAllocationLine line : this.getLines(true)) {
      MAllocationLine reversalLine = new MAllocationLine(reversal);
      MAllocationLine.copyValues(line, reversalLine);

      //
      // 07570: Keep AD_Org of original document
      reversalLine.setAD_Org_ID(line.getAD_Org_ID());

      reversalLine.setC_AllocationHdr_ID(reversal.getC_AllocationHdr_ID());
      reversalLine.setAmount(reversalLine.getAmount().negate());
      reversalLine.setDiscountAmt(reversalLine.getDiscountAmt().negate());
      reversalLine.setOverUnderAmt(reversalLine.getOverUnderAmt().negate());
      reversalLine.setWriteOffAmt(reversalLine.getWriteOffAmt().negate());
      reversalLine.setReversalLine_ID(line.getC_AllocationLine_ID());
      reversalLine.saveEx();

      line.setReversalLine_ID(reversalLine.getC_AllocationLine_ID());
      line.saveEx();
    }

    if (!reversal.processIt(DOCACTION_Complete)) {
      throw new AdempiereException(reversal.getProcessMsg());
    }
    reversal.setDocStatus(DOCSTATUS_Reversed);
    reversal.setDocAction(DOCACTION_None);
    reversal.saveEx();

    this.setDocStatus(DOCSTATUS_Reversed);
    this.setDocAction(DOCACTION_None);
  }
  /**
   * Prepare Document
   *
   * @return new status (In Progress or Invalid)
   */
  @Override
  public String prepareIt() {
    log.log(Level.INFO, "{0}", this);
    m_processMsg =
        ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_PREPARE);
    if (m_processMsg != null) return DocAction.STATUS_Invalid;

    //	Std Period open?
    MPeriod.testPeriodOpen(
        getCtx(), getDateAcct(), MDocType.DOCBASETYPE_PaymentAllocation, getAD_Org_ID());
    getLines(false);
    if (m_lines.length == 0) {
      m_processMsg = "@NoLines@";
      return DocAction.STATUS_Invalid;
    }

    // Stop the Document Workflow if invoice to allocate is as paid
    // @formatter:off
    // 04627: metas.ts: commenting out, because:
    // we want to allocate, even if the invoice is paid (in that case with amout=0), because a
    // customer might
    // inadvertedly overpay an invoice, but still this shall also be documented in the allocation
    //		if (this.getReversal_ID() <= 0) { // metas: tsa: 02181: check only if is not a reversal
    //		for (MAllocationLine line :m_lines)
    //		{
    //			if (line.getC_Invoice_ID() != 0)
    //			{
    //				final String whereClause = I_C_Invoice.COLUMNNAME_C_Invoice_ID + "=? AND "
    //								   + I_C_Invoice.COLUMNNAME_IsPaid + "=? AND "
    //								   + I_C_Invoice.COLUMNNAME_DocStatus + " NOT IN (?,?)";
    //				boolean InvoiceIsPaid = new Query(getCtx(), I_C_Invoice.Table_Name, whereClause,
    // get_TrxName())
    //				.setClient_ID()
    //				.setParameters(new Object[]{line.getC_Invoice_ID(), "Y", MInvoice.DOCSTATUS_Voided,
    // MInvoice.DOCSTATUS_Reversed})
    //				.match();
    //				if(InvoiceIsPaid)
    //					throw new  AdempiereException("@ValidationError@ @C_Invoice_ID@ @IsPaid@");
    //			}
    //		}
    //		}  // metas: tsa: 02181: check only if is not a reversal
    // @formatter:on
    //	Add up Amounts & validate
    BigDecimal approval = Env.ZERO;
    for (int i = 0; i < m_lines.length; i++) {
      MAllocationLine line = m_lines[i];
      approval = approval.add(line.getWriteOffAmt()).add(line.getDiscountAmt());
      //	Make sure there is BP
      if (line.getC_BPartner_ID() <= 0) {
        m_processMsg = "No Business Partner";
        return DocAction.STATUS_Invalid;
      }
    }
    setApprovalAmt(approval);
    //
    m_processMsg =
        ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_PREPARE);
    if (m_processMsg != null) return DocAction.STATUS_Invalid;

    m_justPrepared = true;
    if (!DOCACTION_Complete.equals(getDocAction())) setDocAction(DOCACTION_Complete);

    return DocAction.STATUS_InProgress;
  } //	prepareIt