Hackers Guide to Documents

From iDempiere en

Modes of document characteristics

Document number

If a table has a column with the title DocumentNo, it will be treated automatically in a special way. In the first usage of the table a sequence will be installed, which takes care of a consecutively document numeration. This document number can be edited more precisly in Document Sequence (Window ID-112). It can be set as a determinded initial value or it can preserve a prefix or a suffix. Document numbers can also have a context variable where a date can be fit, e.g.Rechnung 00001/2014" (s.e.g. en:NF001_Document_Sequence_Improved).

Model

For a document type, which implements its own logic, you need to write a model. This means you create its own plugin, where you write a java class, the so-called model class (M*). This has to be derived from a predeterminded basis class (X_*). In turn this will be created with the help of the tool GenerateModel from the table definition of the database.

Columns

For the best you setup these following columns:

  • DocumentNo (mandatory; 30 character)
  • DateDoc (mandatory)
  • DateAcct (mandatory)
  • Doc_User_ID (either a column or a getter-methode, which reads out a column like SalesRep_ID or standard logic, e.g. '@$C_Currency_ID@').
  • C_Currency_ID (mandatory; standard logic e.g. "@$C_Currency_ID@')
  • DocAction (mandatory; 2 characters; default 'CO'; pushbutton; reference "_Document Action"; here will be a process indicated, which indicates the according workflow of our document type)
  • DocStatus (mandatory; 2 characters; default 'DR'; list reference; reference "_Document Status" )
  • processed (mandatory; default 'N')
  • processing (mandatory; default 'N') - after Dantam's article is a varchar(1), supposely the pushbutton. For example in C_Invoice is the same process inscribed like in DocAction. But until now I have no idea why you need two columns.
  • isApproved (mandatory; default 'Y')

What does DocumentEngine do in the process?

Document actions will be done by the class DocEngine. Who wants to conduct a status operation, can do this best with the model method processIt(). This should invoke the respective method of DocEngine, which takes over the management of different status options.

Workflow

You can install a receipt-Workflow which defines the change between several status values. You define a Workflow with three nodes: Start, Prepare and Complete. The two last ones will be combined with the last receipt action, therewith these take action. Then you definde a transition which in each case from Start to Prepare and from Prepare to Complete.

This defined Workflow provides for properly done documents. It serves for further experiments.

Reversing documents

Who wants to reverse documents, requires these following columns in addition:

  • Reversal_ID (reference type table, as a reference you need to register new created table reference, which close about my whole table and can be assorted after DocumentNo)

I never tried this reversal. Probably you need to configure an accordingly Workflow. Besides this you should be very careful, if you want to reverse booked documents.

Reactivating Documents

I would like to reactivate my document, after it is finalizied. In addition I created a further node 'Reactivate' and attached this with the accordingly receipt action. Then I definded a second transition with the start to Reactivate. The first transition has a condition, which only takes action, if 'Doc-Action = 'CO. Besides this the first transition obtains a small order of numbers, which executes first.

As a matter of principle the reactivating requires a reversal of the effects of the document. This implementation is not needed, but I recommend you this.

Approval / release

Workflows also allow to make the processing of a document dependent on a previous release. Thus, e.g. Invoices over 1.000, - € are always submitted to the superior or the like.

More about Workflows

taken from http://en.wikiversity.org/wiki/Adempiere_Technical_Training#Document_Process_Workflow:

Every document has a defined process – the workflow is started with the Process button:
These workflows have a defined start context (the document) and a responsible.

  • Start (Draft)
    • Auto
    • Prepare (In Progress)
      • Complete (Completed)

If you want to customize a workflow for a document:

  • for all clients
    • add customized node/transitions and/or inactivate standard transitions
  • for a client or organization
    • make changes on System workflow with entity type <> Dictionary/Adempiere
    • execute process “Workflow to Client”

Booking Document

A document that can generate its own posting lines must contain the following fields:

  • Posted (mandatory; boolean; default 'N')
  • ProcessedOn (integer)
  • C_DocType_ID (mandatory; Table; reference C_DocType)

The corresponding logic is activated by the presence of the "Posted" field. In this case, after completing a document, an update class matching the model is used to carry out the update. For this there is the convention that this ends on "_Doc". Within the iDempiere kernel, the name of this class (based on this convention) is automatically determined. In ADempiere this was also the case for own classes. In iDempiere, which no longer allows core access to our plugin classes through the OSGi packages, there is a factory for that purpose.

Document base type

Our new document type must also have an entry in the database. However, we first have to think about which basic type he belongs to. This base type is used for sorting and grouping document types, in particular for the document type input fields. In addition, the period can be opened or closed in the period control (in the calendar) for each individual basic document category. Although, interestingly enough, it is not necessarily mandatory, it still makes sense to set up a document base type for your own accounting document class.

The base document type consists of an entry in the reference list "C_DocType DocBaseType" and always has three letters. If you want, you can set up a type "DOC" for all your documents here. However, it makes more sense to create your own basic types for each document type you create. Then, a selection field in the window can be validated to filter for this basic type and the user will always be able to generate their own derivations later.

For some base types of the standard iDempiere, multiple base types work with objects of the same table. For example, by splitting "API Accounts Payable Invoice" and "ARI Accounts Receivable Invoice" ensures that incoming and outgoing invoices are never mixed. Although both are in the same table and use much the same business logic, they each have their own windows and are also distinguished by the field "isSOTrx" (and the different base document type). Due to the two basic document types, a simple validation on the input field for the document type is enough, so that you can only select sales document types for customers and vice versa.

After you have created the basic document categories (in the system client), you should now call the process "Check Document Types" in the client. This creates a document type for each base document type and also directly creates corresponding period entries in the calendar.

The automatically generated document types can be viewed in the "Document type" window and adjusted if necessary. It is recommended to activate number management and specify (or create) a document number range.

In this window you can now derive even more document types from its basic document category. This has different purposes:

  • First of all, this can serve the in-house grouping of documents. Anyone who thinks in his business that a bill of goods is different from a service bill and a foreign bill, in turn, differently and a freight bill, can divide this so without much trouble.
  • You can specify your own print format (in this window) and make the printed receipt look very different.
  • You can group direct bookings (batches) using the direct posting type (fee type depending on the translation) and only allow specific bookings for certain document types. Thus, the freight invoice can be posted to the account for freight, the foreign invoice to the account for customs, etc.

Next, you should create a validation rule. This gets the name "C_DocType MyPatementName" and as SQL-Code something like the following line:

 C_DocType.DocBaseType IN ('ARZ', 'APZ') AND C_DocType.IsSOTrx='@IsSOTrx@'  AND C_DocType.AD_Client_ID=@#AD_Client_ID@

Of course, you can omit the part with IsSOTrx if we do not have a separate document type for input and output windows. This part of the formula ensures that we can use identical field definitions for incoming and outgoing documents. The two windows then differ only in that the context variable "IsSOTrx" is set when the window is opened. This will then control everything else. This value can be set in the window definition.

Purchase and sales documents

If you have a document category that is supposed to post different purchasing and sales documents (AP and AR), you also need this field. With this type of document, it is generally appropriate to also generate two separate basic document types and possibly two separate windows. The window definitions can be largely identical except for the "Sales Transaction" entry, which sets the context variable "IsSOTrx" and thus makes it distinguishable.

  • isSOTrx (mandatory; boolean, in the window best not displayed nciht or at least write-protected)

Windows, tabs & fields

The window should be set to the window type "Transaction". This turns on [History]. This ensures that only the current and incomplete documents are displayed.

Incidentally, when configuring the window, the following fields should be displayed (according to Dantam):

  • Processed (set to "Read Only")
  • DocStatus (set to "Read Only")
  • DocAction
  • Currency (if used, it may be read-only)

For documents that differentiate purchasing and sales documents, it makes sense to copy them and introduce a WHERE clause, so that you have two windows for these actually different document types. You can define a window as a sales transaction in the window definition, and thus set a context variable that is used in many queries and validations to ensure that all fields work properly. Of course, this requires some care in generating your own queries, but there are enough existing examples, such "Invoice (Customer)" and "Invoice (Supplier)".

Print

Basically, you can print a record by clicking on the button in the toolbar for a report. This will then create a print format that you can adjust accordingly. If you often want to have individual data sets, for example As a form print as a list of sentences, so it is useful to activate the print button, with which you can print individual records. This is done by making an entry in the Process & Report window. This was set to "Report" and indicates, if necessary, a prepared print format. This can then be started with the buttons for "Print" and "Print preview" by entering it in the window register record.

By the way, there is a little problem here. You have to set up the "Process & Report" window in the system client, whereas most of the time you have prepared your print format in the normal client. You can release the print format in this case. It is automatically selected the one that has set the field "Standard".

Use Report View to print more columns than shown in the table

An extension can be added by entering a similar entry in the field "Report view" in "Process & Report". In this case, a print format is selected that has selected this report view. This allows you to narrow the selection of the print format even further.

In particular, one can also specify a report view based on a completely different table. This table should only contain the primary key field of our document because it will filter out the printed record. I used this, for example, to use a database view instead of the table edited in the current window for the expression, which, while based on that same table, adds a lot of additional data via JOIN. This large amount of information can then be restricted (if you like) through a report view and then processed in print format. Such a print format is created in the window "Print format", where you can set the table and the view when creating the record. Then you create the fields by means of the automatic process button for this purpose and can then set the print format already in the target window and use it there in the print view. If this is the first time to see, then you can customize it as usual resulting print formats.

Print by program

In my model for the BAY_InterestCalculation table, I can use the following method to get an expression based on a view called RV_BAY_InterestCalculation. One can use this method e.g. in completeIt () to make sure that a document is always printed when it completes. Incidentally, one can set in the process window whether the printout happens immediately in the background or only with consultation.

 public void print() {
   int viewTable = MTable.getTable_ID("RV_" + Table_Name);
   MPrintFormat format = new Query(getCtx(), MPrintFormat.Table_Name, MPrintFormat.COLUMNNAME_AD_Table_ID
     + "=? AND " + MPrintFormat.COLUMNNAME_IsDefault + "=? ", get_TrxName()).setParameters(viewTable, "Y")
     .first();
   MQuery query = new MQuery(get_Table_ID());
   query.addRestriction(get_KeyColumns()[0], MQuery.EQUAL, get_ID());
   PrintInfo info = new PrintInfo(getDocumentInfo(), get_Table_ID(), get_ID());
   ReportEngine re = new ReportEngine(getCtx(), format, query, info, get_TrxName());
   re.print();
 }

Links

Articles that explain documents

Basic statements

Further explanations

Articles that I use as sources, but have already incorporated much here:

Windows related to documents:

(What is the difference between "unprocessed" and "unposted" and how do these windows know which tables to scan?)

Further information

involved classes and interfaces

MSetup

Create the list of document type for new Client ( Method createAccounting ).

org.compiere.server.AcctProcessor

Background process running on the JBoss server that perform the accounting document posting process.

org.compiere.grid.ed.VDocAction

Define hardcoded in dynInit method the list of possible transitions, and transitions by table

Examples of implementing some DocAction methods

getDocumentInfo()

Returns a short but unique name of the record, which is mainly used in log lines and other program messages. This example uses an existing document type.

 public String getDocumentInfo(){
   MDocType dt = MDocType.get(getCtx(), getC_DocType_ID());
   String msgreturn = dt.getNameTrl()+" "+getDocumentNo();
   return msgreturn.toString();
 }

createPDF()

There is a method to output the document as a PDF. This will - as far as I've seen - only used to send the document by email. But because you never know, you can do that, e.g. as follows. Of course you can also choose more precisely when selecting the print format.

 public File createPDF (){
   try{
     StringBuilder msgfile = new StringBuilder().append(get_TableName()).append(get_ID()).append("_");
     File temp = File.createTempFile(msgfile.toString(), ".pdf");
     return createPDF (temp);
   }catch (Exception e){
     log.severe("Could not create PDF - " + e.getMessage());
   }
   return null;
 }
 
 public File createPDF (File file){
   MPrintFormat format = MPrintFormat.get(getCtx(), 0, get_Table_ID());
   MQuery query=new MQuery(get_Table_ID());
   query.addRestriction(get_KeyColumns()[0],MQuery.EQUAL,get_ID());
   PrintInfo info = new PrintInfo(getDocumentNo(),get_Table_ID(),0);
   ReportEngine re = new ReportEngine(getCtx(), format, query, info, get_TrxName());
   
   if(format.getJasperProcess_ID() > 0){
     // JasperReports Print Format
     ProcessInfo pi = new ProcessInfo ("", format.getJasperProcess_ID());
     pi.setRecord_ID(get_ID());
     pi.setIsBatch(true);
     ServerProcessCtl.process(pi, null);
     return pi.getPDFReport();
   }else{
     // Standard Print Format (Non-Jasper)
     return re.getPDF(file);
   }
 }
Cookies help us deliver our services. By using our services, you agree to our use of cookies.