Difference between revisions of "Hackers Guide to Documents"
(Google Translate) |
(google translate) |
||
| Line 85: | Line 85: | ||
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. | 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 | + | 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@ | 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. | |
| − | |||
== Einkaufs- und Verkaufsbelege == | == Einkaufs- und Verkaufsbelege == | ||
Revision as of 00:30, 28 July 2018
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 Belegnummernkreis (Fenster_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 data bank.
Columns
For the best you setup these following columns:
- DocumentNo (mandatory; 30 Zeichen)
- 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; Standardlogik 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; Referenz "_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 odel-method processIt(). This should invoke the accordingly method of DocEngine, which takes over the management of different status possibilties.
- http://www.adempiere.com/Document_Engine - u.a. links to Sourcecode of Doc_* classes
- http://www.adempiere.com/Development_Guidelines_in_German#Klasse_DocumentEngine - german introduction, written quite well
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 / Freigabe
Workflows erlauben auch, die Bearbeitung eines Dokumentes von einer vorherigen Freigabe abhängig zu machen. So können z.B. Rechnungen über 1.000,- € immer erst dem Vorgesetzten vorgelegt werden oder dergleichen.
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.
Einkaufs- und Verkaufsbelege
Wer einen Belegtyp hat, der Einkaufs- und Verkaufsbelege (AP und AR) unterschiedlich verbuchen soll, braucht auch noch dieses Feld. Bei dieser Art Belegen bietet es sich im Allgemeinen an, auch zwei getrennte Basisbelegtypen und ggf. zwei getrennte Fenster zu erzeugen. Die Fensterdefinitionen können weitgehend identisch sein bis auf den Eintrag "Verkaufstransaktion", der die Kontextvariable "IsSOTrx" setzt und sie somit unterscheidbar macht.
- isSOTrx (mandatory; boolean; im Fenster am besten gar nciht angezeigt oder mindestens schreibgeschützt)
Fenster, Tab & Felder
Das Fenster sollte auf den Fenstertyp "Transaktion" gesetzt werden. Dadurch wird die [History-Funktion] aktiviert. Diese sorgt dafür, das immer nur die aktuellen und nicht abgeschlossenen Dokumente angezeigt werden.
Bei der Konfiguration des Fensters sollten übrigens die folgenden Felder angezeigt werden (laut Dantam):
- Processed (set to "Read Only")
- DocStatus (set to "Read Only")
- DocAction
- Currency (wenn benutzt sollte es u.U. schreibgeschützt sein)
Für Dokumente, die Einkaufs- und Verkaufsbelege unterscheiden, bietet es sich an, diese zu kopieren und eine WHERE-Klasel einzuführen, so das man zwei Fenster für diese eigentlich unterschiedlichen Belegtypen hat. Man kann in der Fensterdefinition ein Fenster als Verkaufstransaktion definieren und somit eine Kontextvariable setzen, die in vielen Abfragen und Validierungen benutzt wird, um sicherzustellen, das alle Felder entsprechend angepasst funktionieren. Das erfordert natürlich bei der Erzeugung eigener Abfragen etwas Sorgfalt, aber es gibt ja genug bestehende Beispiele wie z.B. "Rechnung (Kunde)" und "Rechnung (Lieferant)".
Grnudsätzlich kann man einen Datensatz ausdrucken, indem man in der Toolbar auf den Button für einen entsprechenden Bericht klickt. Durch diesen wird dann ein Druckformat erzeugt, das man entsprechend anpassen kann. Will man oft eher einzelne Datensätze z.B. als Formular drucken als eine Liste von Sätzen, so bietet es sich an, den Druck-Button zu aktivieren, mit dem man einzelne Datensätze drucken kann. Das macht man, indem man im Fenster "Prozeß & Bericht" einen Eintrag macht. Diesen setzte man auf "Bericht" und gibt ggf. ein vorbereitetes Druckformat an. Dieses kann dann mit mit den Buttons für "Druck" und "Druckvorschau" gestartet werden, indem man es im Datensatz des Fensterregisters einträgt.
Hier gibt es übrigens ein kleines Problem. Das Fenster "Prozeß & Bericht" muss man im Systemmandanten einrichten, während man sein Druckformat ja zumeist vorher im normalen Mandanten vorbereitet hat. Man kann in diesem Fall das Druckformat freilassen. Es wird automatisch das gewählt, das das Feld "Standard" gesetzt hat.
Berichtsansicht benutzen, um mehr Spalten auszudrucken als in der Tabelle stehen
Eine Erweiterung gibt es noch, indem man in "Prozeß & Bericht" im Feld "Berichtsansicht" eine ebensolche einträgt. In diesem Fall wird ein Druckformat ausgewählt, das ebendiese Berichtsansicht ausgewählt hat. Hierdurch kann man die Auswahl des Druckformats noch weiter eingrenzen.
Insbesondere kann man hier auch eine Berichtsansicht angeben, die auf einer ganz anderen Tabelle basiert. Diese Tabelle sollte lediglich das Primärschlüsselfeld unseres Dokumentes beinhalten, weil hierdurch der ausgedruckte Datensatz heruasgefiltert wird. Ich habe das beispielsweise benutzt, um anstatt der im aktuellen Fenster bearbeiteten Tabelle ein Datenbank-View für den Ausdruck zu benutzen, das zwar auf ebendieser Tabelle basiert, ihnr per JOIN aber jede Menge weitere Daten hinzufügt. Diese grosse Menge an Informationen kann man dann (wenn man möchte) durch eine Berichtsansicht wieder einschränken und dann im Druckformat verarbeiten. Ein derartiges Druckformat erzeugt man im Fenster "Druckformat", wo man die Tabelle und die Ansicht bei der Neuanlage des Datensatzes einstellen kann. Dann erzeugt man die Felder mittels des automatischen Proßess-Knopfes hierfür und kann dann das Druckformat schon im Zielfenster einstellen und dort in der Druckansicht benutzen. Ist diese das erste Mal zu sehen, kann man es dann wie gewöhnlich entstandene Druckformate auch anpassen.
Drucken per Programm
Mit der folgenden Methode kann ich in meinem Model für die Tabelle BAY_InterestCalculation einen Ausdruck veranlassen, der auf einem View basiert, das RV_BAY_InterestCalculation heisst. Man kann diese Methode z.B. in completeIt() aufrufen, um dafür zu sorgen, das ein Dokument immer gedruckt wird, wenn es abgeschlossen wird. Man kann übrigens im Prozeßfenster einstellen, ob der Ausdruck sofort im Hintergrund oder erst mit Rückfrage geschieht.
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
Artikel, die Dokumente erklären
Basiserklärungen
- http://wiki.idempiere.org/en/Create_a_custom_document_class - recht neuer Artikel von Daniel Tamm im iDempiere Wiki, hat noch viele Lücken
- http://www.adempiere.com/How_to_create_a_new_document_with_specific_accounting
weiterführende Erklärungen
- http://www.adempiere.com/How_to_Activate_Document_Approval_Workflow
- http://www.adempiere.com/Document_Action_Dialog - Erklärung zum Action Button und dem davon aufgehenden Fenster
- http://www.adempiere.com/Document_Sequence - Document Sequence
- Erweiterungen
- http://www.adempiere.com/Enhance_Document_No_Formatting - Verbesserung der Dokumentnummerierung (hierdurch sind Kontextvariablen erlaubt)
- http://wiki.idempiere.org/en/NF001_Document_Sequence_Improved - Verbesserung bzgl. Organisationen und Neustart von Nummernkreisen
- http://www.adempiere.com/Sponsored_Development:_Document_Signing - Document Signing Erweiterung, augenscheinlich nie verwirklicht worden
Artikel, die ich als Quellen verwendet, aber bereits weitgehend hier eingearbeitet habe:
- http://www.adempiere.com/HOWTO_Process_Documents - erklärt recht gut die Benutzung der vorhandenen Dokumenttypen; weniger die Entwicklung neuer
- http://en.wikiversity.org/wiki/Adempiere_Technical_Training#Document_Process_Workflow - enthält kurze, aber aufschlussreiche Teile zum Thema, insbesondere "Document Process Workflow"
- http://www.adempiere.com/Document_Engine
- https://groups.google.com/forum/#!topic/idempiere/WtTlVL1ZjWw - kurzed Forumsthread darüber, wie man einen Workflow implementieren kann
Fenster, die mit Dokumenten zusammenhängen:
- http://wiki.idempiere.org/en/Document_Type_%28Window_ID-135%29
- http://wiki.idempiere.org/en/Document_Sequence_%28Window_ID-112%29
- http://wiki.idempiere.org/en/Unprocessed_Documents_%28All%29_%28Window_ID-53087%29
- http://wiki.idempiere.org/en/UnPosted_Documents_%28Window_ID-294%29
- http://wiki.idempiere.org/en/My_Unprocessed_Documents_%28Window_ID-53086%29
- http://wiki.idempiere.org/de/Workflow_%28Fenster_ID-113%29
(Was ist der Unterschied zwischen "unprocessed" und "unposted" und woher wissen diese Fenster, welche Tabellen sie absuchen sollen?)
- http://wiki.idempiere.org/en/Verify_Document_Types_%28Process_ID-233%29 - was macht dieser Prozeß? Er erzeugt wohl Open-Einträge für neue Dokumenttypen. Sonst noch was?
weitere Informationen
involvierte Klassen und 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
Beispiele für die Implementierung einiger DocAction-Methoden
getDocumentInfo()
Ergibt eine kurze aber eindeutige Bezeichnung des Datensatzes, die vor allem in Logzeilen und sonstigen Programm-Mitteilungen verwendet wird. Dieses Beispiel nutzt einen vorhandenen Documenttyp.
public String getDocumentInfo(){
MDocType dt = MDocType.get(getCtx(), getC_DocType_ID());
String msgreturn = dt.getNameTrl()+" "+getDocumentNo();
return msgreturn.toString();
}
createPDF()
Es gibt eine Methode, um das Dokument als PDF auszugeben. Diese wird - soweit ich gesehen habe - nur benutzt, um das Dokument per EMail zu versenden. Da man aber nie weiss, kann man das z.B. so wie folgend implementieren. Dabei kann man bei der Auswähl des Printformats natürlich auch genauer auswählen.
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);
}
}
