How to create a new document with specific accounting
In order to generate a new document within ADempiere that has a specific accounting to be generated upon completion of the document, it is necessary to follow these 3 steps. For this example it is assumed that the new document behaves similarly to an invoice but generates different accounting transactions:
1. Create a new Base Document using the system/system login. In C_DocType DocBaseType
we need a 3 capital letter code that identifies our new document base. In this example we will use PTK, then:
search key:PTK name:DOCTYPE_PTCheck
2. In the java class Doc.java, ADempiere defines the documents supported by the application. We need to add the following statement:
public static final String DOCTYPE_NInvoice = "PTK";
3. Every document table has a class that defines how the accounting transactions are generated. For instance the tables C_Order and C_Invoice have the corresponding and related classes Doc_Order.java and DocInvoice.java. Within these classes you will find a method named "createFacts". This method contains the logic for the document accounting generation.
In reviewing the method you will find the following structure for each document:
if (getDocumentType().equals("A_Type_of_Document") {
} else if (getDocumentType().equals("Another_Type_Of_Document") ) {
}
In order to add accounting for our newly added document (PTCheck) we need to add the following:
else if (getDocumentType().equals(DOCTYPE_PTCheck)) //PTK
{
BigDecimal grossAmt = getAmount(Doc.AMTTYPE_Gross); BigDecimal serviceAmt = Env.ZERO; // Header Charge CR BigDecimal amt = getAmount(Doc.AMTTYPE_Charge); if (amt != null && amt.signum() != 0) fact.createLine(null, getAccount(Doc.ACCTTYPE_Charge, as), getC_Currency_ID(), null, amt); // TaxDue CR for (int i = 0; i < m_taxes.length; i++) { amt = m_taxes[i].getAmount(); if (amt != null && amt.signum() != 0) { FactLine tl = fact.createLine(null, m_taxes[i].getAccount(DocTax.ACCTTYPE_TaxDue, as), getC_Currency_ID(), null, amt); if (tl != null) tl.setC_Tax_ID(m_taxes[i].getC_Tax_ID()); } } // Revenue CR for (int i = 0; i < p_lines.length; i++) { amt = p_lines[i].getAmtSource(); BigDecimal dAmt = null; if (as.isTradeDiscountPosted()) { BigDecimal discount = p_lines[i].getDiscount(); if (discount != null && discount.signum() != 0) { amt = amt.add(discount); dAmt = discount; } } fact.createLine (p_lines[i], p_lines[i].getAccount(ProductCost.ACCTTYPE_P_Revenue, as), getC_Currency_ID(), dAmt, amt); if (!p_lines[i].isItem()) { grossAmt = grossAmt.subtract(amt); serviceAmt = serviceAmt.add(amt); } } // Set Locations FactLine[] fLines = fact.getLines(); for (int i = 0; i < fLines.length ; i++) { if (fLines[i] != null) { fLines[i].setLocationFromOrg(fLines[i].getAD_Org_ID(), true); // from Loc fLines[i].setLocationFromBPartner(getC_BPartner_Location_ID(), false); // to Loc } } // Receivables DR int receivables_ID = getValidCombination_ID(Doc.ACCTTYPE_BankAsset, as); int receivablesServices_ID = getValidCombination_ID (Doc.ACCTTYPE_BankAsset, as); if (m_allLinesItem || !as.isPostServices() || receivables_ID == receivablesServices_ID) { grossAmt = getAmount(Doc.AMTTYPE_Gross); serviceAmt = Env.ZERO; } else if (m_allLinesService) { serviceAmt = getAmount(Doc.AMTTYPE_Gross); grossAmt = Env.ZERO; } if (grossAmt.signum() != 0) fact.createLine(null, MAccount.get(getCtx(), receivables_ID), getC_Currency_ID(), grossAmt, null); if (serviceAmt.signum() != 0) fact.createLine(null, MAccount.get(getCtx(), receivablesServices_ID), getC_Currency_ID(), serviceAmt, null);
}
la fraccion de codigo que comienza con el comentario de CR, busca la cuenta especifica linea a linea para el credito, la fraccion que comienda con DR lo hace para el debito
si nos fijamos bien en el codigo, el posteo de cada cuenta se realiza con una linea muy similar a esta
fact.createLine (p_lines[i],p_lines[i].getAccount(ProductCost.ACCTTYPE_P_Revenue, as),getC_Currency_ID(), dAmt, amt);
aqui lo que nos interesa es lo sgte p_lines[i].getAccount(ProductCost.ACCTTYPE_P_Revenue, as) ese metodo va a buscar la cuenta correspondiente que se necesita para el posteo que se esta ejecutando este metodo finalmente hace alucion al metodo getValidCombination_ID encontrado en la clase doc.java.
este medoto posee sqls simples que buscan en cada tabla por tipo de documento, la cuenta que le indiquemos, es muy facil de modificar y agregar nuevas cuentas por documentos, en el caso de que las necesitemos.