How to create a new document with specific accounting

From ADempiere
Revision as of 05:10, 27 September 2008 by Kzmp (Talk)

Jump to: navigation, search
This Wiki is read-only for reference purposes to avoid broken links.

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 complete the following 6 steps. For this example it is assumed that the new document behaves similarly to an invoice but generates different accounting transactions:


1. Login with SuperUser/System and System Administrator's role. Go to Application Dictionary -> References and choose the C_DocType DocBaseType reference. Select the List Validation tab and add a new entry. For Search Key we need a 3 capital letter code that identifies our new document base. For our example we will add 'PTK'. So we will have:

     Search Key:PTK
     Name:DOCTYPE_PTCheck

2. Go to Application Dictionary -> Validation Rules and select the C_DocType AR/AP Invoices and Credit Memos validation rule. Add 'PTK' to the list of valid choices so it becomes:

     C_DocType.DocBaseType IN ('ARI', 'API','ARC','APC','PTK') AND C_DocType.IsSOTrx='@IsSOTrx@'

3. Create a new document type. Login with your client's administrator's login. For GardenWorld this is GardenAdmin/GardenAdmin and GardenWorld Admin Role. Go to Performance Analysis->Accounting Rules->Document Type and create a new document type. For document base type choose DOCTYPE_PTCheck.

4. 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";

5. There is a class in Adempiere X_C_DocType.java (lokated in base/src org.compiere.model) which contains all document types in the system. You need to regenerate that class in order to let Adempiere know about your new document type. To regenerate it simply run GenerateModel with the appropriate arguments. For example when the following arguments are passed to GenerateModel:

     "D:\\eclipseworkspace\\customl_340\\base\\src\\org\\compiere\\model\\" "org.compiere.model" "'D'" "'C_DocType'" "Client"

it will regenerate the X_C_DocType and I_C_DocType classes in the directory D:\\eclipseworkspace\\customl_340\\base\\src\\org\\compiere\\model\\ and in package org.compiere.model (Search the wiki for Create your customization environment for more inoformation on customizing Adempiere). If you omit this step at some point you may have troubles bcause certain functionality relies on having all document types specified in X_C_DocType.java (closing periods I think is one of them).

6. 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 Doc_Invoice.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 in the Doc_Invoice.java (since our document behaves similarly to an invoice):


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);
}

The "Revenue CR" comment marks the code that searches the Credit account (P_Revenue in the example) and the "Receivables DR" comment marks the code that searches the Debit account (BankAsset in the example).

The fact.createLine statement uses a format like this:

fact.createLine (p_lines[i],p_lines[i].getAccount(ProductCost.ACCTTYPE_P_Revenue, as),getC_Currency_ID(), dAmt, amt);


where p_lines[i].getAccount(ProductCost.ACCTTYPE_P_Revenue, as) is the method that searches the account needed for posting. This method, in turn, calls the getValidCombination_ID method in the class Doc.java.


How to written by Fabian Aguilar from OFB Consulting ltda