Tinyerp - Technical Documentation / Book

  • April 2020
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View Tinyerp - Technical Documentation / Book as PDF for free.

More details

  • Words: 26,305
  • Pages: 186
1 1. Installation 1. Dependencies 2. Installation Steps 3. Upgrading Versions 4. Config files 1. Server's config file: ~/.terp_serverrc 2. Client's config file: ~/.terprc 5. Command line options 6. Shutting down the server 2. Translations 1. Translation in Reports 3. The client 4. Parameter settings of Modules 1. ModulesAdminBase 1. Management of access rights 2. The actions 3. Sequences 4. Requests 5. Customizing the menu 2. ModulesAdminCRM 3. ModulesAdminAccount 1. ModulesAdminAccountChart 2. ModulesAdminAccountCurrency 3. ModulesAdminAccountTax 4. ModulesAdminAccountImputations 4. ModulesAdminStock 5. ModulesAdminSale 6. Subscriptions 7. Audittrail 8. Configuring Projects 5. Architecture 1. Program structure 2. Objects 3. Views 4. Workflows 5. Reports 6. Services 6. Objects 1. Introduction 2. Definition 1. Fields 2. Default values 3. Constraints 4. Methods 5. Example 6. Inheritance 3. Access 1. Access types 2. Predefined Methods 3. Object Specific Methods 4. ObjectsWritingValues 4. Property Fields 7. Data loading 1. Introduction 2. Files loading

05/02/08

2 3. XML files structure 1. The data 2. IR Use 4. CSV Files 5. XML data files convention 6. Managing updates 8. Views 1. Introduction 2. File Format 3. Special Properties 4. Inheritancy in Views 5. Graphs in forms 9. Workflow 1. Introduction 2. Example of Workflows 1. Discount on orders 2. Purchase order and Invoice 3. Terminology 4. Define a Workflow 1. Workflow 2. The nodes (activities) 3. Transitions 5. Expressions 6. The notion of Roles 7. Error handling 10. Reports 1. Introduction 2. XSL:RML reports 1. XML Template 2. Introduction to RML 3. XSL:RML Stylesheet 3. Each reports with its own corporate header 4. Bar Codes 5. OpenOffice Report 6. Usual TAGS 7. How to add a new report 8. Customize report Header 11. Wizards 1. Introduction 2. Principles 3. How to add a new wizard 12. Events 1. Linking client events to actions 13. Information Repository (deprecated) 1. Introduction 2. Structure 3. Access Methods 14. MRPModule 1. Workcenters 2. Bill of Materials 3. Production Order 15. Modules 1. Writing a new module 2. Modules guidelines 3. Network management

05/02/08

3 16. Webservices 1. WebservicesIntro 2. WebservicesXMLRPC 3. An example in PHP 4. An example in Python 17. Misc 1. Load Balancing between servers 18. Multi − Company 19. Internationalization

05/02/08

4

1 Installation

05/02/08

5

1.1 Dependencies 1.1.1 The server The Tiny ERP server depends on the following packages: • python >= 2.3 : http://python.org • python2.3−xml • libxml2−python2.3 • libxslt1−python2.3 • PsycoPg : http://initd.org/projects/psycopg1 • Python Imaging Library : http://www.pythonware.com/products/pil/ (only if you use bitmap in reports) • Reportlab : http://reportlab.org • PostgreSQL: http://postgresql.org Optional, if you plan to render workflows: • PyParsing : http://pyparsing.sourceforge.net/ • PyDot : http://dkbza.org/pydot.html • graphviz: http://www.graphviz.org/ Have a look in the user manual for installation instructions.

1.1.2 The client The client depends on the following packages: • python >= 2.3 : http://python.org • GTK >= 2.6 : http://gtk.org Optional, for Windows users: • Win32Com : http://www.python.org/windows/win32com/

05/02/08

6

1.2 Installation Steps First check that all the required dependencies are installed. Then create the terp database. You have to make sure that your user has the correct credentials to create databases with postgres, for more information on this subject please refer to the PostgreSQL manual. $ createddb terp −−encoding=unicode Once the database created, you can start Tiny ERP. The content of the data base will automatically be created at the first start. $ ./tinyerp−server

05/02/08

7

1.3 Upgrading Versions The upgrade of version is automatic and don't need any special script. In fact, the server is able to rebuild automatically the data base and the data from a disturbed version. The tables are rebuilt from the actual data base in production. To rebuild these tables, the server uses the description of the objets and adds, modify or delete new fields. To ask the data base upgrade while having a new version installed, you need to do: −> terp_server.py −−update=all

You can also upgrade one or several modules: −> terp_server.py −−update=account,base

The data base are rebuilt because of the XML files. For more information on these functionalities, go to the section concerning XML files. You can also execute the server with −−init=all. The server rebuilds then the data of beginning and deletes all existing datas to come back in his basic configuration.

05/02/08

8

1.4 Config files Two configuration files are available: • one for the client: ~/.terprc • one for the server: ~/.terp_serverrc Those files follow the convention used by python's ConfigParser module . Those files are not necessary. If they are not found, the programs will start with the default configuration. The client configuration file is automatically generated upon the first start. That of the server can be automatically created with the command: tinyerp_server.py −s

05/02/08

9

1.4.1 Server's config file: ~/.terp_serverrc The server configuration file @.terp_serverrc@ is used to save server statup options. Here is the list of the available options: interface Address the server will be bound to port Port the server will listen on database Name of the database to use user Username used when connecting to the database translate_in File used to translate tinyerp to your language translate_out File used to export the language tinyerp use language Use this languages as the server's language. This must be specified as the language two letter code. verbose Will used debugged output This file is written on the disk when the option "−s" ou "−−save" has been put in parameter at the first start of the server. Here is the configuration by default for the server [options] verbose = False xmlrpc = True database = terp update = {} port = 8069 init = {} interface = 127.0.0.1 reportgz = False

05/02/08

10

1.4.2 Client's config file: ~/.terprc Here is the list of the available options:

login section login login name to use to connect to TinyERP server server address used by the server port port used by the server

path section share path used to find tinyERP's file pixmaps path used to fin tinyERP's pixmaps file

tip section autostart Should the client display tips at startup position Tip number the client will display

form section autosave Will the client automatically save the change you made to a record

printer section preview Preview report before printing softpath Path to the pdf previewer softpath_html Path to the html previewer path Command used to print

logging section logger log channels to display. List values are: @common@, @common.message@, @view@, @view.form@, @common.options@, @rpc.request@, @rpc.result@, @rpc.exception@ level logging level to show output

05/02/08

11

file used by the logger verbose set the log level to INFO

client section default_path Default path used by the client when saving/loading datas.

Default values [login] login = admin port = 8069 server = 192.168.1.4 [printer] path = none preview = True softpath = none [logging] output = stdout logger = verbose = True level = ERROR [form] autosave = False [client] default_path = /home/ged

05/02/08

12

1.5 Command line options The following options can be passed into the server with the line: −h, −−help Show this help screen and leave the program. −−version Show the number of the version and leave. −cFILE, −−config= FILE Use an alternative configuration file. By default, the server use the file ~/.terp_serverrc −s, −−save Save the server configurationin the file ~/.terp_serverrc. By default, the options given to the line order are not saved. −pPORT, −−port= PORT Specify the TCP port that the server must use. By default, the server uses the port 8069. −−interface= INTERFACE Specify the network interface that the server must use. In most of the case, you have to use the IP address of the computer on which is the server. By default, the server uses the interface localhost and can accept the connections only from the clients who are on the same computer. −dDATABASE, −−database= DATABASE Specify the name of the data base. −iMODULE, −−init= MODULE Initialize a module (use "all" for all modules). Attention: this option will delete all datas linked to this module! −uMODULE, −−update= MODULE Upgrade a module (use "all" for all modules). −v, −−verbose Active the verbose mode.

Relatives langages options These options allows you to use Tiny ERP through other langage (than english). Go to the section Traductions for more details on the system of translations. −lLANGUAGE, −−language= LANGUAGE Specify the langage of the translation file. Use this option in combination with the option −−i18n−export or −−i18n−import . −−i18n−export= FILEPATH Export all the sentences to translate in the file FILEPATH. The option '−l' must also be used. −−i18n−import= FILEPATH Import the file CSV FILEPATH. This file must contain all the translations for the choosen langage by the parameter −l. Don't forget to select in the client preferences the choosen langage.

05/02/08

13

1.6 Shutting down the server The easiest way the shut down the server is to send the SIG INT signal to the server. $ kill −2 pid where pid is the processus ID of the server.

05/02/08

14

2 Translations Tiny ERP is multi−langage. You can add as much as langages you want. Each user can work with the interface in his langage. Moreover, some ressources (text of reports, name of the products, ...) may also be translated. This section explain how to change the langage of the program for the users and how to add new langages to Tiny ERP. First of all, you have to know that all the labels of interface is stored in the server. In the same way, the translations are also stored in the server. By default, the english dictionnary is charged in the server, so if the users want to try Tiny ERP in other langage, you have to charge these langages (in the server). The method for this is explain in the next paragraph "To charge a translation file on the server". But it is not possible to store "everything" on the server. Indeed, the user gots some menus, buttons, etc... that must contain some text even before being connected to a server. These few words and sentences are translated using GETTEXT. The choosen langage by default for these ones is the langage of the computer in which the user is subscribe. As I said before, the system of translation in Tiny ERP isn't limited to interface texts: it works also for reports and the "content" of some fields (of data base). Obviously, all the data base fileds must not be translated. The fields where the content is multi−langage are marked by a flag:

How to change the langage of the interface user ? The langage is an user preference. To change the langage of the current user, you click on the menu: User > Preferences.

An administrator may also modify the preferences of the user (including the langage of the interface) in the menu: Administration > Users > Users. He has to choose an user and notch on "préférences".

Charge a file of translation on the server To import a file having translations, use the next order: ./tinyerp_server.py −−i18n−import=file.csv −lLANG

Note that the translation file must be encoded in UTF8!

05/02/08

15

2.1 Translation Reports TO get printscreen report in prefered language following methods are used. fields_view_get(cr, uid, view_type='tree', context=context) read(cr, uid, datas['ids'], result['fields'].keys(), context )

fields_view_get Description: This method is use for getting all fields from the current view. Signature def fields_view_get(self, cr, uid, view_id=None, view_type='form', context={}) Parameters * context is a dictionary that contains: {'lang':'prefered language'}

read Description List of fields ressources values. Signature def read(self, cr, uid, ids, fields=None, context={}) Parameters * ids: the list ressources identifiers to read. * fields (optionnal): the list of the interested fields. If we don't introduce something for this parameter, the function check all the fields * context (optional): the actual context. Returns A list of dictionaries (a dictionary per resource asked) of the form [{'name_of_the_field': value, ...}, ...] all methods on objects (fields_view_get, read) process context before sending the result using values in the ir.translation table.

05/02/08

16

To translate a new langage To translate or modify the translation of a langage already translated, you have to:

1. Export all the sentences to translate in a file CSV To export this file, use the order: ./tinyerp_server.py −−i18n−export=file.csv −lLANG

or LANG is the langage in which you want to translate the program.

2. to translate the last column of the file You can make a translaion for a langaga which has already been translated or for a new one. If you ask for a langage already translated, the sentences already translated will be written in the last column. For example, here are the first lines of a translation file (dutch): type field field model model model

name "account.account,code" "account.account,name" "account.account,name" "account.account,name" "account.account,name"

res_id 0 0 2 25 61

src Code Name Assets Results Liabilities

value Code Name Aktiva Salden Verbindlichkeiten

3. Import this file to Tiny ERP (as explained at the precedent section) Notes • It is advised to start these orders when the data base is empty because you could publish directly the file of translation. To create a new data base (named 'terp_test'), use the next orders: createdb terp_test −−encoding=unicode terp_server.py −−database=terp_test −−init=all

Alternatively, you could also delete your current data base using this order: dropdb terp createdb terp −−encoding=unicode terp_server.py −−init=all

• If you translate the program in a new lanage or modify a current translation, send the translation file to [email protected] attached by a file credits.txt. We will publish this translation on our website (http://tinyerp.org). • It is possible to translate only a part of Tiny ERP, to continu a translation already begun, or even to correct few sentences of a translation file.

05/02/08

17

3 The client The type of message Differents types of messages can be analysed: • rpc

♦ exception ♦ request ♦ result • common ♦ message ♦ option • view ♦ form ♦ tree If you want to analyse several types of message, you can divide them with a comma in the arguments of the user; tinyerp.py −drpc.result,rpc.request −lDEBUG

This request can post the XML−RPC tasks sent to the server and the results given back.

Levels of logs Some levels are available. You can, for example, log only the messages that are coming from an alert or an error. The available levels are: • DEBUG • INFO • WARNING • ERROR • CRITICAL The user argument concern the minimum level to log. So, if you select DEBUG, you obtain all the messages. If you select WARNING, you obtain the messages from the following levels; WARNING, ERROR, CRITICAL.

File of configuration; Options The options are: logging.logger list of the namespace to log separated by a comma. Value by default: none. logging.level level of log. Value by default: WARNING Example (~/.terprc): [logging] output = stdout logger = rpc.request,common.message verbose = False

05/02/08

18 level = INFO

We can also use the next parameters to the order: • −l level ou −−log−level=level • −d channels ou −−log=channels Go to tinyerp.py −−help for more details...

Option verbose The option verbose allows you to log at the level 'INFO'. this option is the same as the option −−log−level=INFO In the file of onfiguration: logging.verbose: True

Also available as parameter at the line: −v, −−verbose

Examples Requests XML−RPC To log the requests XML−RPC but not the responses: ./terp.py −−log=rpc.request −−log−level=debug

To log all events XML−RPC (requests, responses, exceptions): ./terp.py −−log=rpc −−log−level=debug

To log the requests and the exceptions but not the responses: ./terp.py

−−log=rpc.request,rpc.exception −−log−level=info

05/02/08

19

4 Parameter settings of Modules The differents modules of Tiny ERP can be installed or not according to the needs. All the modules are in the repertoty: '/addons' of the server. You have to copy/delete the repertories to install or delete the Tiny ERP modules. Some modules depend on other modules. See the file addons/module/__terp__.py for more information on the dependences. Here is an example of __terp__.py: { »···"name" : "Tiny TERP Accounting", »···"version" : "1.0", »···"depends" : ["base"], »···"init_xml" : [ "account_workflow.xml", "account_data.xml", "account_demo.xml"], »···"update_xml" : [ "account_view.xml", "account_report.xml", "account_wizard.xml"], }

When initializing a module, the files in the init_xml list are evaluated in turn the the files in update_xml are evaluated. When updating a module only the files from update_xml are evaluated.

05/02/08

20

4.1 ModulesAdminBase This module is the only one who needs to be installed in Tiny ERP (mandatory).

05/02/08

21

4.1.1 Management of access rights Three concepts are differentiated into Tiny ERP; 1. The users: person identified by his login/password 2. The groups: define the access rights of the ressources 3. The roles: determine the roles/duties of the users

The users They represent physical persons. These are identified with a login and a password. A user may belong to severel groups and may have several roles. A user must have an action. This action is executed when the user connects to the program with his login and password. An exampleof action would; open the menu at 'Operations'. The preferences of the user are available with the preference icon. You can, for example, through these preferences, determine the langage of work of this user. By default, English is set up. A user can modify his own preferences while he's working on Tiny ERP. For that, he clicks on this menu; User > Preference.

The groups The groups determine the access rights to the different ressources. There is three types of right: • The reading access: reading of a file, • The writing access: recording & creation, • The execution access: the buttons of workflows or wizards. A user can belong to several groups. If he belongs to some groups, we use always the group with the highest rights for a selected ressource.

The roles The roles define a hierarchical structure in tree. They represent the different posts of the company. The bigest role has automatically the rights of all its wires. Example: • CEO

05/02/08

22 ♦ Technical manager ◊ Chief of the project ⋅ Developpers ⋅ Testers ♦ Commercial manager ◊ Salers ◊ ... If we want to valid the test of a program (=role Testers), it may be done by a user having one of the following roles: Testers, Chief of the project, Technical manager, CEO. The roles are used for the transitions of Workflow actions in the confirmation actions, choice or validation. Their implication will be detailed in the Workflow section.

05/02/08

23

4.1.2 The actions The actions define the reactions of a user in front of some events; login of a new user, double−click on an invoice, click on the action button, ... It exists different type of simple actions: • Window: opening of a new window • Report: The prints of a report ♦ Custom Report: The personalized reports ♦ RML Report: The XSL:RML reports • Wizard: The startings of a Wizard • Execute: The execution of a method on the server side • Group: Gather some actions in one group The actions are used for the next events; • User connection • The user double−click on the menu • The user click on the icon 'print' or 'action'

Example of events Into Tiny ERP, all the actions are described and not configured. Two examples are briefly describe here: • Opening of a window when double−click in the menu • User connection Opening of the menu When the user open the option of the menu "Operations > Partners > Partners Contact"., the next steps are done to give to the user information on the action to undertake. 1. Search the action in the IR. 2. Execution of the action 1. If the action is the type Opening the Window; it indicates to the user that a new window must be opened for a selected object and it gives you the view (form or list) and the filed to use (only the pro−forma invoice). 2. The user asks the object and receives information necessary to trace a form; the fields description and the XML view. User connection When a new user is connected to the sever, the client must search the action to use for the first screen of this user. Generally, this action is; open the menu in the 'Operations' section. The steps are: 1. Reading of a user file to obtain ACTION_ID 2. Reading of the action and execution of this one

05/02/08

24

The 'Window' actions They indicate at the user that he has to open a new window in a new 'onglet'.

The fields Action Name The action name Action Type Always 'ir.actions.act_window' View Ref The view used for showing the object Model The model of the objet to post Type of View The type of view (Tree/Form) Domain Value The domaine that decreases the visible datas with this view

The view The view describes how is traced the edition form or the datas tree/list. The views are from type 'Form' or 'Tree' according to whether they represent a form for the edition or a list/tree for a global datas view. A form can be asked by an action opening in mode 'Tree'. The form is open in the list mode (like the user push on 'switch view').

The domain This notion allows you to regulate which ressourcesare visible in a selected view.(restriction) For example, in the invoice case, you can define an action that opens a view that shows only invoices not paid. The domains are written in python; list of tuples. The tuples have three elements; • the field on which the test must be done

05/02/08

25 • the operator used for the test (<, >, =, like) • the tested value For example, if you want to obtain only 'Draft' invoice, use the following domain; [('state','=','draft')] In the case of a simple view, the domain define the ressources which are the roots of the tree. The other ressources, even if they are not from a part of the domain will be posted if the user develop the branches of the tree.

05/02/08

26

4.1.3 Sequences Two objects are defined to generate sequences of numbers; • ir.sequence: Sequences of numbers • ir.sequence.type: Type of sequences These numbers are used, for example, to; • generate the number of the next invoice, • generate the number of the next refund, • generate continuous numbers for batches, ...

Principle The ressources which need a sequence number record a name and a code in the types of sequences. This operation is generally done once by the installation, at the first start of the server. Several sequences can be defined for every type. When the ressource (invoice, location, ...) needs a sequence number, this one is generated by an active sequence corresponding to the asked type.

The fields Sequence Name the name of the sequence, Sequence Code the defined code in the types of sequences Active As all forms having an 'active' case, the numbers of sequences can be activated or unactivated notching or not this case. Next Number The next number Increment Number The step for the sequence Example; • prefix = LOT • nextnumber = 1000 • suffix = TS • increment = 10 The next generated number will be 'LOT1000TS'. The next one will be 'LOT1010TS', ...

05/02/08

27

4.1.4 Requests Objects defined res_request The requests res_request_link The objects linked to requests res_request_history The history of all the requests

Principle Sometimes, you just wish that an action inform a user that something has happened. When you have to do this, just use the request object. This object allows you to send small pieces of information to any user about ongoing events. It also allows you to link an object to the request you wish to sent.

The fields In the table request you can find the following fields: name The request description active Activate or deactivate the request req_ref The request reference req_type The type of the request, must be one of the following: 'remind' or 'info'. req_priority The priority of the request. It must be one of the following: '0', '1' or '2', the higher the number the higher the priority. req_summary A small summary of the request state The state of the request, must be one of the following: 'draft', 'wait', 'active', 'close'. act_from the user who emitted the request act_to the user who received the request act_title the action's result act_date the when the action was triggered ref_partner_id the partner the request is about ref_doc1 the first reference for the request ref_doc2 the second reference for the request req_history all the request history

05/02/08

28 Creating a request is just as simple as (taken from the project module) : request = self.pool.get('res.request') request.create(cr, uid, {'name' : "Task '%s' closed" % task.name, 'req_ref' : 'project:task:%d' % task.id, 'req_type' : 'info', 'req_priority' : str(task.priority), 'state' : 'wait', 'req_summary' : "Task '%s' closed by %s" % (task.name, task.user_id.name), 'act_from' : task.user_id.id, 'act_to' : task.project_id.manager.id, 'ref_doc1' : 'project.task,%d'% (task.id,), 'ref_doc2' : 'project.project,%d'% (task.project_id.id,), 'act_title' : "Task '%s' closed" % (task.name,), })

05/02/08

29

4.1.5 Customizing the menu It's easy (but tricky) to grant grained access to menu based on the user's groups. First of all, you should know that if a menu is not granted to any group then it is accessible to everybody ! If you want to grant access to some groups just go to Menu > Administration > Menus > Grant Access to menu and select the groups that can use this menu item.

Beware ! If the superuser does not belong to one of ther group, he will not be able to reach this menu again.

05/02/08

30

4.2 ModulesAdminCRM

The parameter setting of the module CRM allows you to define; • the partners category • the sales canals • the customer's state of mind • the case categories • automatic segmentations

The partners categories The categories are used to segment/classify the various partners. A same partner can be included in several categories. These ones are defined according to the needs of the company. Few examples; • Customer Activity 1 • Very Important Customer • Textile Supplier • Newsletter Tiny ERP The categories can be assigned manually (Newsletter, Textile Supplier) or automatically with the automatic segmentations tool. An example would 'Very Important Customer', based on the amount of the partner's purchase. Once the categories are defined, they can be used in the partners files.

05/02/08

31

The sale canals The sale canals indicate the various methods of sale and communication between the partner and the company. Few examples; • Website / Email • Shop 1 • Phone • A residence The canals are used when there are contacts with the partner in the form like the sale/ppurchase opportunities and the Help−desk. You can, for example, make some analysis on different canals; sales pipeline, ...

The states of mind The states of mind define a level of value on the partner option opposite to the company; Dissatisfied −> Normal −> Satisfied. At every state of mind, we assign a selected value in this level. These values are making calculations on a certain period. Level of value: Very dissatisfied Dissatisfied Normal Satisfied Very satisfied

0.0 2.0 5.0 6.3 10.0

In the different interactions with the customer, the Tiny ERP users can marked his state of mind according to their contacts having with the customer. The program is able to calculate the staat of mind of the customer depending on the last interactions with the same customer. So, if the customer has made three orders. 2005/01/01 2005/01/20 2005/03/10

Order 1 Sale opportunity 2 Helpdesk 3

Dissatisfied Normal Very satisfied

2.0 5.0 10.0

The program can calculate, with the automatic segmentation, that the customer has a state of mind of 6.3. This number is taking part of other parameters, the intervals between the tasks, the reductions, ... This system can be very useful to send, for example, a promotion every month to the customers who are not happy.

The types of categories These categories classify sales opportunities and the technical tasks of the Helpdesk. Example of HelpDesk; • Problem with the hardware, • Problem of configuration, • Bug, ...

05/02/08

32 Example of sales opportunities; • Website, • ERP integration, • store, ...

05/02/08

33

4.3 ModulesAdminAccount Three ressources must be configured for the accounting • the account charges • the various currencies used • the various applicable taxes

05/02/08

34

4.3.6 ModulesAdminAccountChart The best method to create a new account chart is to write it directly in the XML file. So, this one will be simply reusable. With this intention, consult the section on the data download. Tiny ERP may used several account charts at the same time. With this intention, we use some different views of the same accounts. Into Tiny ERP, the accounts are structured hierarchically with the type of accounts 'VIEW'. These can't be used in the transactions, they are only used to structure the real accounts. So, it is possible to make two different views of the same accounts. Here is a simple example; • Shop 1 (*) ♦ Actives Mg 1 (*) ◊ Fortis Bank 1 ◊ Cash 1 ♦ Incomes Mg 1 ♦ Expenses Mg 1 • Shop 2 (*) ♦ Actives Mg 2 (*) ◊ Fortis Bank 2 ◊ Cash 2 ♦ Incomes Mg 2 ♦ Expenses Mg 2 These accounts may be presented differently with other accounts views but using the same real accounts; income, expenses, money cash. • Actives (*) ♦ Shop 1 (*) ◊ Fortis Bank 1 ◊ Cash 1 • Shop 2 (*) ♦ Fortis Bank 2 ♦ Cash 2 • Incomes (*) ♦ Incomes Mg 1 ♦ Incomes Mg 2 • Expenses (*) ♦ Expenses Mg 2 ♦ Expenses Mg 2 In these representations, the accounts marked with (*) are from the type 'view'.

05/02/08

35

4.3.7 ModulesAdminAccountCurrency

The accounting is multi−currencies. As a preliminary every currencies must be defined with their rate relative to the default one. An account can be only in one currency. It is better to have an account tree by currency but you can mix several accounts of different currencies in the accounting. The used fields Relative Change Rate Relative change rate compared to the unity (in this case; the EURO). Digits Number of figures after the comma for the amounts written in this currency. Computational accuracy Precision of the amounts calculation in this currency.

05/02/08

36

4.3.8 ModulesAdminAccountTax The taxes are used, by example, in the definition of a product or in the invoice lines. The various taxes must be encode beforehand. There exists several modes of calculation for the taxes; • Percentage • Fixe • Code Python • None The taxes can be applicable or not according to some criteria: partners, amount, number of pieces. Two application tests are available; • Always applicable • Applicable according to a python code which will be executed for the test.

The dependencies In some countries, the taxes can be composed or depended of another taxe. We can define a relation between the different taxes. During a sale, if we specify a tax, the sub−taxes are also calculated. It is possible to define a tax which regroup two others; • Taxe on the screen ♦ VAT (21%) ♦ Recup (1.52 EUR) On the invoice, you can specify 'Taxe on the screen' and the two taxes will automatically get inside the accounting. You have to define: |Name of the taxe|Type|Amount|Parent| |Taxe on the screen|None|0|| |VAT (21%)|Percentage|0.21|Taxe on the screen| |Recup (1.52 EUR)|Fixed|1.52|Taxe on the screen| You can also use this system if one tax must be ventilated on several accounts.

The accounts Two accounts are mandatory for the taxes; paid and collected taxes. These two may be identical for the same tax or not.

Taxes domain Some taxes are only effective under certain forms. We define then their own domain. For example, the auction houses in Belgium are subjected at the law of the margin sale. The VAT is not deductible and can be invoiced with sale expenses. (percentage of adjudication). These taxes are then defined with the domain 'auction'. They are only used by the auction module.

The calculated taxes Some taxes are more difficul than a simple multiplication or addition. It is possible to transfer a python code that counts the value of the applicable taxes on the unit amount and/or a another python code that determines if the tax is

05/02/08

37 applicable or not. The value of the variable result is used as the amount of the tax and as the boolean indicating if the tax must be computed. Some informations are accessible: • price_unit : the unit price of the product • address : the address partner or False ___Example___; the SACEM impose royalties on the works allocated more than 2500 EUR of 10% and of 5% if the price is over 50.000 EUR. Code to calculate the taxe; result = 0.0 if price_unit>=50000: »··result=price_unit*0.05 elif price_unit>=2500: »··result=price_unit*0.1

Test code if applicable; result = price_unit>=2500

___Example___; The screen tax to calculate a tax pc with python_code

05/02/08

38

The compute code to calculate tax (at the end the result variable is the tax): result =0.0 if price_unit>100: result = 5 + price_unit * 0.06 else: result= price_unit * 0.10

To define the tax in Main Menu go : Menu/Definitions/Accounting/Tax.

05/02/08

39

4.3.9 ModulesAdminAccountImputations Sale order Incomes account: product preference or the one by default Taxe account: taxe collected from the taxe definition Credit account: partners preferences

Purchase order Expense account: product preference or the one by default Taxe account: taxe paid from the taxe definition Flow account: partners preferences

Inventory Stock account: product preference (inventory account) Stock losses account: product preference Stock benefit account: product preference

The movements The accounts inventory from the movements are taken in account only in the case of an exit ot an entry in the location that belongs to the company. The internal movements don't generate transactions. Stock account: product preference (inventory account) Stock losses account: product preference Stock benefit account: product preference

A payment Credit/flow account: partner preferences Cash account: manual

05/02/08

40

4.4 ModulesAdminStock Introduction to the stock management Tiny ERP introduce a new concept for the stock management. As for the accounting, the stock management uses a double−entry system; there is no batches apparition in the stock but only moves from a location to another. The stock manages the suppliers and the customers. So, when you order merchandise to the supplier, the supplier location receives automaticaly the batch. When you receive the merchandise of the supplier the batch moves from the supplier location to the "My Stock" location. Moreover, the stock management of Tiny ERP is represented by a tree. We can deliver baches in a specify warehouse or deliver batches in the rack 3 that is situated at the level 2 of the warehouse. Even, the suppliers and customers locations may be structured according to their geographical localization, their volume, ... This representation allows you to manage uneasy situations in other ERP; • location of materiels • consigned stock • stored merchandises of our suppliers

To create a structural location The location are structured in tree. Thanks to the use of the double−entry system, you can/must also structure the customers and suppliers stock. As an exemple we will use this use case: • different suppliers • different customers with some of them renting merchandise • two warehouses ♦ one with two stages ♦ the other with a consigned stock in the warehouse 1 of the carrefour customer A structure that can manage these situations; • suppliers ♦ textile suppliers ♦ it suppliers • customers ♦ european customers ♦ non european customers • company ♦ rented materials ♦ warehouse 1 ◊ output ◊ stock 1 ⋅ level 1 ⋅ level 2 ◊ stock 2 ⋅ carrefour stock ⋅ others materials

05/02/08

41

You can obviously make prints or stock valorisations on each account (called locations).

The warehouses Tiny ERP is multi−warehouses. Into Tiny ERP, the batches are stored in the locations. The warehouses define which locations are in a warehouse. A warehouse uses 3 different locations (that may be the same or not). 1. the stock location; indicates the stock warehouse 2. the output location; indicates the place where the batches are getting out 3. the input location; indicates the place where arrive the batches

An example of the location structure for a warehouse; • Warehouse ♦ OUTPUT ♦ STOCK ◊ Level 1 ⋅ Room 1.1 ⋅ Room 1.2 ◊ Level 2 ◊ INPUT

05/02/08

42

4.5 ModulesAdminSale Tiny ERP is multi points of sale. A point of sale is different from a warehouse. It is a place where the sale transactions are done, a warehouse is the article location and may be different from a point of sale.

The attributes Shop Name the name of a point of sale Pricelist the pricelist by default of this point of sale. This list is partner dependent. Project A point of sale can be associated to a project. (not mandatory) Default Payment The default payment method for this point of sale. This method is used in several circumstances; into an order form for this point of sale, if any method of payment is specified, this one will be used in this POS by default. Account Payment All methods of payment accepted for this POS. A method of payment is an account, generally with the cash type of your account chart. Warehouse

05/02/08

43

A POS is associated to a warehouse. When there is an order in this POS, the merchandise is delivered from this location.

05/02/08

44

4.6 Subscriptions

Modules that plan to use subscription All modules that plans to use subscription with references to their documents have to fill in these tables: • subscription.document: describe objects that can be referenced. • subscription.document.fields: describe fields of this object that have to be changed when copying. Example: account_subscription.xml: <delete model="subscription.document" search="[]"/> ======================================================= Subscription Views ======================================================= Invoice account.invoice

05/02/08

45

Invoice Date date_invoice date
Invoice Due Date date_due date


05/02/08

46

4.7 Audittrail Module Audittrail TinyERP gives you the opportunity to trace any call (read/write/create/unlink) to the database. This can be usefull to check who tempered with the stock or deleted invoices. How it works: when registering an audittrail rule, TinyERP replaces the traced method by a method that will first create an audittrail log line and then execute the regular method. Audittrail rules can be registered for any object (except audittrail.log) on all or any specific user(s) For example, to trace any modification on invoices, go the the administration menu −> Audittrail −> Rules

Let's create a new rule named "test" which will record any write/create/delete on account.invoice for users "admin" and "demo".

05/02/08

47

To make a rule active (so that it logs events) its state has to be "Subscribed" (don't forget to make a few modifications on an invoice to feed the logs in this test) Now, if we take a look at the administration menu −> Audittrail −> Logs, and search for all log lines we will see all modifications made to invoices

05/02/08

48

If you subscribe a rule on, an object that is part of a module which normally loads after audittrail, don't forget to update Audittrail depends to include that module or next time the server starts, the rule's state will be set back to draft

If you make changes on a subscribed rule, unsubcribe it and subcribe it again after having saved the changes or those changes won't apply

05/02/08

49

5 Architecture

05/02/08

50

5.1 Program structure The core of the sever is formed by the following modules: • An object database (ORM) • A workflow system integrated with the Object database • A wizard system • A report system (based on reportlab) • A service to export the objects (XML−RPC)

Server/client, XML−RPC Tiny ERP is a based on a client/server architecture. They communicate using the XML−RPC protocol. XML−RPC is a very simple protocol which allows the client to do remote procedure calls. The function called, his arguments, and the result are transported using HTTP and encoded using XML. for more infos on XML−RPC, consult:http://www.xml−rpc.com/

Client The logic of Tiny ERP is configured on the server side. The client is very simple; it is only used to post datas (forms, lists, trees) and to send back the result to the server. The updates and the addition of new functionalities don't need the clients to be frequently upgraded, it makes Tiny ERP easier to maintain. The client doesn't understand what he posts. Even actions like 'Click on the print icon' are sent to the server to ask how to react. The client operation is very simple; when a user makes an action (save a form, open a menu, print, ...) he sends this action to the server. This one sends to the client the new action to execute. There are three types of action; • Open a window (form or tree) • Print a document • Execute a wizard

05/02/08

51

5.2 Objects All Tiny ERP ressources are objects: menus, actions, reports, invoices, partners, ... Tiny ERP is based on a object relational mapping of a database to control the information. Object names are hierarchical, as in the following examples: • account.transfer : a money transfer • account.invoice : an invoice • account.invoice.line : an invoice line Generally, the first word is the name of the module: account, stock, sale. Other advantages of an ORM; • simpler relations : invoice.partner.address[0].city • objects have properties and methods: invoice.pay(3400 EUR), • inheritance, high level constraints, ... It is easier to manipulate one object (example, a partner) than several tables (partner address, categories, events, ...) The Physical Objects Model of TinyERP version 3.0.3

05/02/08

52

05/02/08

53

PostgreSQL The ORM of Tiny ERP is constructed over PostgreSQL. It is thus possible to query the object used by Tiny ERP using the object interface or by directly using SQL statements. But it is dangerous to write or read directly in the PostgreSQL database, as you will shortcut important steps like constraints checking or workflow modification. The Physical Database Model of TinyERP • TinyERP version 3.2.0rc2 • TinyERP version 3.2.0rc1 • TinyERP version 3.0.3 • TinyERP version 2.1.3

05/02/08

54

5.3 Views Views are a way to represent the objects on the client side. It indicates to the client how to lay out the data coming from the objects on the screen. There are two types of views: • form views • tree views Lists are simply a particular case of tree views. The same object may have several views; thus, the products have several different views according to the product variants or not, the first defined view of a kind will be used as the default for its kind, that way you can have a default tree view (that will as the view of a one2many) and a specialized view with more or less information that will appear when some double click on a menu item. Views are described in XML. If no view has been defined for an object, the object is able to generate a view to represent itself. This can limit the developper's work but result in less ergonomic views.

Usage example When you open an invoice, here is the chain of operations followed by the client: • An action asks to open the invoice (it gives the datas on the object (account.invoice), the view, the domain (only invoices not paid) • The client asks (with XML−RPC) to the server what views are defined for the invoice object and what are the datas he must show. • The client displays the form according to the view

05/02/08

55

To develop new objects The design of new objects is restricted to the minimum: create the objects and optionally create the views to represent them. The PostgreSQL tables do not have to be written by hand because the objects are able to automatically create them (or adapt them in case they already existed).

05/02/08

56

5.4 Workflows The objects and the views allow you to define very simply new forms, lists/trees and interactions between them. But it is not enough you have to define the dynamics of these objects. Few examples: • a confirmed sale order must generate an invoice, according to certain conditions • an paid invoice must, only under certain conditions, start the shipping order The workflows describe with graphs these interactions. One or several workflows may be associated to the objetcs. Workflow are not mandatory some objects don't have workflows. Below, an example workflow use for sale orders. It must generate invoices and shippings according to some conditions.

In this graph, the nodes represent the actions to do:

05/02/08

57

• create an invoice, • cancel the sale order, • generate the shipping order, ... The arrows are the conditions; • waiting for the order validation, • invoice paid, • click on the cancel button, ... The squared nodes represent other Workflows; • the invoice • the shipping

05/02/08

58

5.5 Reports Tiny ERP uses a flexible and powerfull reporting system. Reports are generated either in PDF or in HTML. Reports are designed on the principle of separation between the data layer and the presentation layer. We first generate an XML file containing all the data needed by the report. This file is then processed using an XSL stylesheet to produce an RML file which, in turn, is processed to produce either a PDF document or an HTML file.

05/02/08

59

5.6 Services Services are python code methods. Some services are grouped

List of services Service: workflow • Object: workflow.wkf_service.workflow_service ♦ Methods ◊ workflow_service.trg_write ◊ workflow_service.trg_delete ◊ workflow_service.trg_create ◊ workflow_service.trg_validate

Services group: web−services • Service: object_proxy ♦ Object: osv.osv.osv_pool ◊ Methods ⋅ osv_pool.obj_list ⋅ osv_pool.exec_workflow ⋅ osv_pool.execute ⋅ osv_pool.execute_cr • Service: common ♦ Object: service.web_services.common ◊ Methods ⋅ common.ir_get ⋅ common.ir_set ⋅ common.ir_del ⋅ common.about ⋅ common.login • Service: object ♦ Object: service.web_services.objects_proxy ◊ Methods ⋅ objects_proxy.execute ⋅ objects_proxy.exec_workflow • Service: wizard ♦ Object: service.web_services.wizard ◊ Methods ⋅ wizard.execute ⋅ wizard.create • Service: report ♦ Object: service.web_services.report_spool ◊ Methods ⋅ report_spool.report ⋅ report_spool.report_get ⋅ report_spool.report_check

05/02/08

60

Services group: report • Service: report.custom ♦ Object: report.custom.report_custom ◊ Methods ⋅ report_custom.create ⋅ report_custom.args_get ⋅ report_custom.result • Service: report.workflow.instance.graph ♦ Object: base.ir.workflow.print_instance.report_graph ◊ Methods ⋅ report_graph.create ⋅ report_graph.args_get ⋅ report_graph.result • Service: report.account.recall.receivable ♦ Object: account.report.report_recall.report_custom ◊ Methods ⋅ report_custom.create ⋅ report_custom.args_get ⋅ report_custom.result • Service: report.account.journal ♦ Object: account.report.print_journal.report_custom ◊ Methods ⋅ report_custom.create ⋅ report_custom.args_get ⋅ report_custom.result • Service: report.hr.timesheet.allweeks ♦ Object: hr.report.timesheet.report_custom ◊ Methods ⋅ report_custom.create ⋅ report_custom.args_get ⋅ report_custom.result • Service: report.hr.timesheet.bymonth ♦ Object: hr.report.bymonth.report_custom ◊ Methods ⋅ report_custom.create ⋅ report_custom.args_get ⋅ report_custom.result • Service: report.crm.case ♦ Object: crm.report.report_businessopp.report_custom ◊ Methods ⋅ report_custom.create ⋅ report_custom.args_get ⋅ report_custom.result • Service: report.project.tasks.gantt ♦ Object: project.report.gantt_report.report_tasks ◊ Methods ⋅ report_tasks.create ⋅ report_tasks.args_get ⋅ report_tasks.result • Service: report.project.project.gantt ♦ Object: project.report.gantt_report.report_projects ◊ Methods ⋅ report_projects.create

05/02/08

61

⋅ report_projects.args_get ⋅ report_projects.result • Service: report.res.partner.address ♦ Object: report.interface.report_rml ◊ Methods ⋅ method report_rml.create ⋅ method report_rml.args_get ⋅ method report_rml.result • Service: report.res.partner.ids ♦ Object: report.interface.report_rml ◊ Methods ⋅ report_rml.create ⋅ report_rml.args_get ⋅ report_rml.result • Service: report.account.invoice ♦ Object: report.interface.report_rml ◊ Methods ⋅ report_rml.create ⋅ report_rml.args_get ⋅ report_rml.result • Service: report.account.invoice.list ♦ Object: report.interface.report_rml ◊ Methods ⋅ report_rml.create ⋅ report_rml.args_get ⋅ report_rml.result • Service: report.account.transfer ♦ Object: report.interface.report_rml ◊ Methods ⋅ report_rml.create ⋅ report_rml.args_get ⋅ report_rml.result • Service: report.network.material.list ♦ Object: report.interface.report_rml ◊ Methods ⋅ report_rml.create ⋅ report_rml.args_get ⋅ report_rml.result • Service: report.network.network.list ♦ Object: report.interface.report_rml ◊ Methods ⋅ report_rml.create ⋅ report_rml.args_get ⋅ report_rml.result • Service: report.network.network.list2 ♦ Object: report.interface.report_rml ◊ Methods ⋅ report_rml.create ⋅ report_rml.args_get ⋅ report_rml.result • Service: report.stock.packing.list ♦ Object: report.interface.report_rml ◊ Methods ⋅ report_rml.create

05/02/08

62

⋅ report_rml.args_get ⋅ report_rml.result • Service: report.stock.shipping.list ♦ Object: report.interface.report_rml ◊ Methods ⋅ report_rml.create ⋅ report_rml.args_get ⋅ report_rml.result • Service: report.stock.lot.overview ♦ Object: report.interface.report_rml ◊ Methods ⋅ report_rml.create ⋅ report_rml.args_get ⋅ report_rml.result • Service: report.stock.location.overview ♦ Object: report.interface.report_rml ◊ Methods ⋅ report_rml.create ⋅ report_rml.args_get ⋅ report_rml.result • Service: report.purchase.order ♦ Object: report.interface.report_rml ◊ Methods ⋅ report_rml.create ⋅ report_rml.args_get ⋅ report_rml.result • Service: report.sale.order ♦ Object: report.interface.report_rml ◊ Methods ⋅ report_rml.create ⋅ report_rml.args_get ⋅ report_rml.result • Service: report.project.report ♦ Object: report.interface.report_rml ◊ Methods ⋅ report_rml.create ⋅ report_rml.args_get ⋅ report_rml.result

Service: wizard.res.partner.sms_send • Object: base.res.partner.wizard.wizard_sms.part_sms ♦ Methods ◊ part_sms.execute

Service: wizard.res.partner.spam_send • Object: base.res.partner.wizard.wizard_spam.part_email ♦ Methods ◊ part_email.execute

05/02/08

63

Service: wizard.res.partner.clear_ids • Object: base.res.partner.wizard.wizard_clear_ids.wiz_clear_ids ♦ Methods ◊ wiz_clear_ids.execute

Service: wizard.account.journal • Object: account.wizard.wizard_journal.wiz_journal ♦ Methods ◊ wiz_journal.execute

Service: wizard.account.move.line.reconcile • Object: account.wizard.wizard_reconcile.wiz_reconcile ♦ Methods ◊ wiz_reconcile.execute

Service: wizard.account.invoice.split • Object: account.wizard.wizard_invoice_split.wiz_reconcile ♦ Methods ◊ wiz_reconcile.execute

Service: wizard.account.invoice.refund • Object: account.wizard.wizard_refund.wiz_refund ♦ Methods ◊ wiz_refund.execute

Service: wizard.account.move.line.check • Object: account.wizard.wizard_verify.wiz_check ♦ Methods ◊ wiz_check.execute

Service: wizard.hr.si_so • Object: hr.wizard.sign_in_out.wiz_si_so ♦ Methods ◊ wiz_si_so.execute

Service: wizard.campaign.partner.email_send • Object: marketing.campaign.wizard.wizard_campaign_email.part_email ♦ Methods ◊ method part_email.execute

05/02/08

64

Service: name:wizard.campaign.partner.add • Object: marketing.campaign.wizard.wizard_campaign_partner_add.part_add ♦ Methods ◊ part_add.execute

Service: wizard.campaign.partner.sms_send • Object: marketing.campaign.wizard.wizard_campaign_sms.part_sms ♦ Methods ◊ part_sms.execute

Service: wizard.project.wiz_bill • Object: project.wizard.billing.wiz_bill ♦ Methods ◊ wiz_bill.execute

Service: wizard.project.wiz_copy • Object: project.wizard.proj_copy.wiz_copy ♦ Methods ◊ wiz_copy.execut

Service: wizard.project.wiz_copy • Object: project.wizard.proj_copy.wiz_copy ♦ Methods ◊ wiz_copy.execute

Service: wizard.project.wiz_deactivate • Object: project.wizard.proj_inactivate.wiz_deactivate ♦ Methods ◊ wiz_deactivate.execute

05/02/08

65

6 Objects

05/02/08

66

6.1 Introduction All the ERP datas are accessible as "objects". As an exemple, there is a res.partner object to access the datas concerning the partners, an account.invoice object for the ones concerning the invoices, etc... Please note that there is an object for every type of ressource, and not an object per ressource. We have thus a res.partner object to manage all the partners and not a res.partner object per partner. If we talk in "oriented object" terms, we could also say that there is an object per level. The direct consequences is that all the objects methods have a common parameter: the "ids" parameter. This one specify on which ressources (for example: on which partner) the method must be applicated. Precisily, this parameter contains a list of ressource ids on which the method must be applied. For example, if we have two partners with the identifiers 1 and 5, and we want to applicate the res_partner's method "send_email", we will write something like: res_partner.send_email(... , [1, 5], ...)

We will see the exactly syntax of object method calls further in this document. In the following operation, we will see how to define a new object. Then, we will check out the different methods to do it.

05/02/08

67

6.2 Definition To define a new object, you have to describe a new python class. This class must inherit from the osv class in the osv module. The first line of the object definition will always be of the form: class name_of_the_object(osv.osv): ...

An object is defined by declaring some fields with predefined names in the class. Two of them are required (_name and _columns), the rest is optional. The predefined fields are: _auto Default value: True. _columns (required) The object fields. See the fields section for details. _constraints The constraints on the object. See the constraints section for details. _defaults The default values for some of the object's fields. See the default value section for details. _name (required) Name of the object. Default value: None. _table Name of the SQL table. Default value: the value of the _name field above of which the dots ( . ) are replaced by underscores ( _ ). _rec_name Name of the field in which the name of every ressource is stored. Default value: 'name'. Note: by default, the name_get method simply returns the content of this field. _order Name of the fields used to sort the results of the search and read methods. Default value: 'id'. _inherits The list of osv objects the object inherits from. This list must be given in a python dictionary of the form: {'name_of_the_parent_object': 'name_of_the_field', ...}. Default value: {}. _sequence Name of the SQL sequence that manages the ids for this object. Default value: None. _sql SQL code executed upon creation of the object (if _auto is True) _log_access Determine whether or not the write access to the ressource must be logged. If true, four fields will be created in the SQL table: create_uid, create_date, write_uid, write_date. Those fields represent respectively the id of the user who created the record, the creation date of record, the id of the user who last modified the record, and the date of that last modification. This data may be obtained by using the perm_read method.

05/02/08

68

6.2.1 Fields Objects may contain different types of fields. Those types can be divided into two categories: simple types and relation types. The simple types are integers, floats, booleans, strings, etc. The relation types are used to represent relations between objects. Here is the list of the available types: boolean a boolean (true, false) integer an integer float a floating point number. The optional parameter digits define the precision and scale of the number. The scale being the number of digits after the decimal point whereas the precision is the total number of significant digits in the number (before and after the decimal point). If the parameter digits is not present, the number will be a double precision floating point number. Warning: these floating−point numbers are inexact (not every value can be converted to their representation) and this can lead to rounding errors. You should always use the digits parameter for monetary amounts. Example: 'rate' : fields.float('Relative Change rate',digits=(12,6)),

char a string of limited length. The size parameter determines its size. text a text field with no limit in length. date a date datetime allows to store a date and the time of day in the same field. binary a binary chain function a field whose value is calculated by a function (rather than being stored in the database). Parameters: fnct, arg=None, fnct_inv=None, fnct_inv_arg=None, type='float', fnct_search=None, obj=None, method=False, where • type is the function return type • method whether the field is computed by a method (of an object) or a global function • fcnt is the function or method that will compute the field value. If method is true, the signature of the method must be: def fnct(self, cr, uid, ids, field_name, arg, context) otherwise (if it is a global function), it should be: def fnct(cr, table, ids, field_name, arg, context) Either way, it must return a dictionary of values of the form {id: value, ...} selection a field which allows the user to make a selection between various predefined values Format of the selection parameter: tuple of tuples of strings of the form: (('key_or_value', 'string_to_display'), ... )

05/02/08

69

Example: 'state': fields.selection((('n','Unconfirmed'),('c','Confirmed')),'State', required=True)

one2one Parameters: obj many2one Parameters: obj Optional parameters: • ondelete: What should happen when the resource this field points to is deleted. Predefined value: "cascade" Default value: "null" Example: 'commercial': fields.many2one('res.users', 'Commercial'),

one2many Parameters: obj, fields_id Example: 'address': fields.one2many('res.partner.address', 'partner_id', 'Contacts'),

many2many Parameters: obj, rel, id1, id2 where • obj is the other object which belongs to the relation • rel is the table that makes the link • id1 and id2 are the fields' names used in the relation table Example: 'category_id': fields.many2many( 'res.partner.category', 'res_partner_category_rel', 'partner_id', 'category_id', 'Categories'),

reference Parameters: string, selection, size where • string is the English name of the field • selection is either: ♦ a function that returns a list of tuple ♦ a list of tuples designating which model the field may reference to. Example: def _links_get(self, cr, uid): cr.execute('select object,name from res_request_link order by priority')

05/02/08

70

return cr.fetchall() ... 'ref':fields.reference('Document Ref 2', selection=_links_get, size=128), ...

Note: If you wish to use the reference field in one of your modules, you must add your object to the list of referencable objects. This action is done using a few lines of xml as in: Project Task project.task

Common parameters to all field types change_default Whether or not the user can define default values on other fields depending on the value of this field. Default value: False. Example: (in res.partner.address) 'zip': fields.char('Zip', change_default=True, size=24), In this case, it means users will be able to set default values for any field of the contact form depending on the value of the 'zip' field. For example, the user could have the program automatically set the city field to 'Brussels' if the zip is 1200 and to 'Namur' if the zip is 5000. readonly Whether the field is editable or not. Default value: False. required Whether the field is required or not. The program will refuse to save a resource if a required field is left blank. Default value: False. states This parameter permits to define attributes for this field that will only be available in some states of the resource. Format: {'name_of_the_state': list_of_attributes} where list_of_attributes is a list of tuples of the form [('name_of_attribute', value), ...] Default value: {}. Example: (in account.transfer) 'partner_id': fields.many2one('res.partner', 'Partner', states={'posted':[('readonly',True)]}), string The label of the field. Default value: 'unknown'. Example: 'tested': fields.boolean('Tested'), Note: Strings containing non−ASCII characters must use python unicode objects. Example: (in french) 'tested': fields.boolean(u'Testé'),

05/02/08

71

translate Whether or not the content of this field should be translated (ie managed by the translation system). Default value: False.

size Default value: None. priority Default value: 0. domain Default value: []. invisible Default value: context Default value: ''. selection Default value: None.

05/02/08

72

6.2.2 Default values The special attribute _defaults allows you to define default values for one or several fields of an object. Because default values do not have to be static (they could, for example, depend on the values of resources already created), you have to define "default values functions" and not simple "scalar" default values. To define default values for an object fields, you have to define a dictionary of the form: {'name_of_the_field': function, ...} These functions take 4 parameters (obj, cr, uid, context) and can return any simple type (boolean, integer, string, etc.). • obj: the osv object corresponding to the type of resource being created • cr: a database cursor • uid: the user ID of the person creating the record • context: the current context (given by the client) Default values are usually declared by using python's anonymous functions (also known as lambda functions). If you want more information about lambda functions, please refer to the python tutorial or python manual.

Example Here is the declaration of default values for the "sale.order" object: _defaults = { 'date_order': lambda *a: time.strftime('%Y−%m−%d'), 'state': lambda *a: 'draft', 'user_id': lambda obj, cr, uid, context: uid }

05/02/08

73

6.2.3 Constraints Tiny ERP objects can optionally have custom integrity/validity constraints. In case such a constraint is transgressed, the data modification which broke the constraint is cancelled and an error message appears on the screen.

Format Constraints can be defined by using the _constraints attribute. If defined, it should be a list of tuples (a tuple per constraint) of the form: [(method, 'error message', list_of_field_names), ...]

where • method is an object method used to check the constraint. This method must have the following signature: def _name_of_the_method(self, cr, uid, ids): −> True|False

• error message is the error message displayed to the user if the constraint check fails. • list_of_field_names is the list of the names of the fields that will be added to the error message. It should help the user understand why the constraint check failed.

Example Here is the definition of the integrity constraint for the object "account.move": def _constraint_sum(self, cr, uid, ids): cr.execute('SELECT a.currency_id FROM account_move m, account_move_line l, account_account a WHERE m.id=l.move_id AND l.account_id=a.id AND m.id IN ('+','.join(map(str, ids))+') GROUP BY a.currency_id') if len(cr.fetchall())>=2: return True cr.execute('SELECT abs(SUM(l.amount)) FROM account_move m LEFT JOIN account_move_line l ON (m.id=l.move_id) WHERE m.id IN ('+','.join(map(str, ids))+')') res = cr.fetchone()[0] return res<0.01 _constraints = [ (_constraint_sum, 'Error: the sum of all amounts should be zero.', ['name']) ]

05/02/08

74

6.2.4 Methods All objects define a set of methods as we will see in the section "6.3.2 predefined methods". Of course, you can also add your own methods to a particular object. To define such a method you only have to add it to source of the python class you're writing. All the defined methods on an object are accessible from the outside (other objects or RPC), but don't forget the python convention that makes private method prefixed with an underscore

05/02/08

75

6.2.5 Example Here is an example of the definition of an object. More particulary, here is the definition of the object res.partner.

class res_partner(osv.osv): def _credit_get(self, cr, uid, ids, prop, unknow_none, unknow_dict): res={} for id in ids: acc = ir.ir_get(cr, uid, [('meta','res.partner'),('name','account.receivable')],[ cr.execute('select sum(amount) from account_move_line where account_id=%d and pa res[id]=cr.fetchone()[0] or 0.0 return res

def _credit_search(self, cr, uid, obj, name, args): if not len(args): return [] where = ' and '.join(map(lambda x: '(sum(amount)'+x[1]+str(x[2])+')',args)) cr.execute('select partner_id from account_move_line where account_id in (select id fr res = cr.fetchall() if not len(res): return [('id','=','0')] return [('id','in',map(lambda x:x[0], res))]

def _debit_get(self, cr, uid, ids, prop, unknow_none, unknow_dict): res={} for id in ids: acc = ir.ir_get(cr, uid, [('meta','res.partner'),('name','account.payable')],[ cr.execute('select sum(amount) from account_move_line where account_id=%d and res[id]=cr.fetchone()[0] or 0.0 return res

def _debit_search(self, cr, uid, obj, name, args): if not len(args): return [] where = ' and '.join(map(lambda x: '(sum(amount)'+x[1]+str(x[2])+')',args)) cr.execute('select partner_id from account_move_line where account_id in (select id fr res = cr.fetchall() if not len(res): return [('id','=','0')] return [('id','in',map(lambda x:x[0], res))]

_name = "res.partner" _auto=True _columns = { 'name': fields.char('Name', size=64, required=True), 'name2': fields.char('Corporation Type', size=64), 'parent_id': fields.many2one('res.partner','Main Company'), 'commercial': fields.many2one('res.users','Commercial'), 'child_ids': fields.one2many('res.partner', 'parent_id', 'Partner Ref.'), 'ref': fields.char('Identifiant', size=64), 'lang':fields.char('Langage',size=2), 'vat':fields.char('VAT',size=32), 'bank':fields.char('Bank account',size=64), 'website':fields.char('Website',size=64), 'comment':fields.text('Notes'), 'address': fields.one2many('res.partner.address', 'partner_id', 'Contacts'), 'category_id': fields.many2many('res.partner.category', 'res_partner_category_rel', 'p 'events': fields.one2many('res.partner.event', 'partner_id', 'events'), 'credit': fields.function(_credit_get, fnct_search=_credit_search, method=True, string 'debit': fields.function(_debit_get, fnct_search=_debit_search, method=True, string='D } def name_search(self, cr, user, name, args=[], operator='ilike'): ids = self.search(cr, user, [('name',operator,name)]+ args)

05/02/08

76

6.2.6 Inheritancy Objects may be inherited in some custom or specific modules. It is better to inherit an object to add/modify some fields. It is done with: _inherit='object.name' Example: class custom_material(osv.osv): _name = 'network.material' _inherit = 'network.material' _columns = { 'manuf_warranty': fields.boolean('Manufacturer warranty?'), } _defaults = { 'manuf_warranty': lambda *a: False, } custom_material()

In this example, the 'custom_material' will add a new field 'manuf_warranty' to the object 'network.material'. You can also modify the definition of an already existing field from the parent object.

05/02/08

77

ids += self.search(cr, user, [('ref','=',name)]+ args) return self.name_get(cr, user, ids) def _email_send(self, cr, uid, ids, email_from, subject, body, on_error=None): emails = self.read(cr, uid, ids, ['email']) for email in emails: if email['email']: tools.email_send(email_from, email['email'], subject, body, on_error) return True

def email_send(self, cr, uid, ids, email_from, subject, body, on_error=''): while len(ids): self.pool.get('ir.cron').create(cr, uid, {'uid':uid, 'name':'Send Partner Emai ids = ids[16:] return True

def address_get(self, cr, uid, ids, adr_pref=['default']): cr.execute('select type,id from res_partner_address where partner_id in ('+','.join(ma res = cr.fetchall() adr = dict(res) result = {} for a in adr_pref: result[a] = adr.get(a, adr.get('default', res[0][1])) return result res_partner()

05/02/08

78

6.3 Access

05/02/08

79

6.3.1 Access types There are several ways to execute methods on the objects. All the ways share a common point: you have to get an access point first. The different available ways are: * to access it directly * by the netservice * by xmlrpc

Direct access (direct reference towards the object) In the osv's object methods, we may reach another object with the get method of the pool attribute. self.pool.get('name_of_the_object')

for example: partner_object = self.pool.get('res.partner')

Calling a method on the partner object we just recovered has the following form: partner_object.name_of_the_method(parameters_for_that_method)

This kind of access is only possible inside objects, and thus, locally on the server. Ref: osv/orm.py

Netservice access Outside of an object but inside the server nevertheless (for example in the reports and wizards), we can reach an object access point with the command: service = netsvc.LocalService("object_proxy")

Calling an object method will then have the form: result = service.execute(user_id, object_name, method_name, parameters)

Ref: osv/osv.py

XML−RPC access From the network (LAN or internet), to reach an access point to the objects use the following command: sock = xmlrpclib.ServerProxy('http://server_address:port_number/xmlrpc/object')

and the call to the method itself is made by: result = sock.execute(user_id, password, object_name, method_name, parameters)

Réf: service/web_services.py

05/02/08

80

6.3.2 Predefined Methods The predefined methods may be classified into 5 categories: the basic methods, methods to manipulate default values, methods to get the permissions, methods to return the fields and views, and finally those naming the ressource.

Basic methods (create, search, read, browse, write, unlink) create Description Create a new ressource Signature def create(self, cr, uid, vals, context={}) Parameters • vals: a dictionary of values for every field. This dictionary must use this form: {'name_of_the_field': value, ...} • context (optional): the actual context. Returns the id of the newly created resource.

search Description Search all the resources which satisfy certain criteria Signature def search(self, cr, uid, args, offset=0, limit=2000) Parameters • args: a list of tuples containing the search criteria. This list must be of the form: [('name_of_the_field', 'operator', value), ...]. The available operators are: ♦ =, >, <, <=, >= ♦ like, ilike ♦ child_of • offset (optional): does not return the first offset results. • limit (optional): the maximum number of results to gat back. Returns the list of ids of matching resources

read Description List of fields ressources values. Signature def read(self, cr, uid, ids, fields=None, context={}) Parameters • ids: the list ressources identifiers to read. • fields (optionnal): the list of the interested fields. If we don't introduce something for this parameter, the function check all the fields. • context (optional): the actual context.

05/02/08

81

Returns A list of dictionaries (a dictionary per resource asked) of the form [{'name_of_the_field': value, ...}, ...]

browse Description Return one or several ressources with the objects form. These object fields can be reached directly with the pointed notation ("object.name_of_the_field"). The "relations" fields are also automatically evaluated to allow you to recover the values in the "neighbors" objects. Example Let's take the case of a partner (object 'res.partner') and of a partner contact (object 'res.partner.address'). Let's suppose that we know the identifier of a partner contact (name contact_id) and we want to recover his name and the account number of the company he works for. Knowing that the object res.partner contains (amongst other things) the field 'bank':fields.char('Bank account',size=64), and the object res.partner.address contains (amongst other thing) the fields 'partner_id': fields.many2one('res.partner', 'Partner', required=True), 'name': fields.char('Contact Name', size=64), the most simple way to procced is to use the browse method: addr_obj = self.pool.get('res.partner.address').browse(cr, uid, contact_id) so, to recover the two fields that interest us, you have to write: nom = addr_obj.name compte = addr_obj.partner_id.bank Signature def browse(self, cr, uid, select, offset=0, limit=2000) Parameters • select: this parameter accept the datas of several types: ♦ a figure, identifier of a ressource ♦ a list if figures (liste of identifiers) • offset (optional): the number of result to pass. • limit (optional): the maximum number of results to return. Returns • if an integer (identifier) has been passed as select parameter, return an object having the properties described here above. • if a list of integer (identifiers) has been passed, return the object list. Remarque This method is only useful locally (on the server itself) and not with the other intefaces !!

05/02/08

82

write Description Writes values in one or several fields of one or several ressources Signature def write(self, cr, uid, ids, vals, context={}) Parameters • ids: the ressources identifiers list to modify. • vals: a dictionary with values to write. This dictionary must be with the form: {'name_of_the_field': value, ...}. • context (optional): the actual contaxt. Returns True

unlink Description Delete one or several ressources Signature def unlink(self, cr, uid, ids) Parameters • ids: the identifiers ressources list to delete. Returns True

Methods to manipulate the default values(default_get, default_set) default_get Description Get back the value by default for one or several fields. Signature def default_get(self, cr, uid, fields, form=None, reference=None) Parameters • fields: the fields list which we want to recover the value by default. • form (optional): TODO • reference (optional): TODO Returns dictionary of the default values of the form {'field_name': value, ... }

default_set Description Change the default value for one or several fields. Signature

05/02/08

83

def default_set(self, cr, uid, field, value, for_user=False) Parameters • field: the name of the field that we want to change the value by default. • value: the value by default. • for_user (optional): boolean that determinates if the new default vlaue must be available only for the current user or for all the users. Returns True

Methods to manipulate the permissions (perm_read, perm_write) perm_read Description Signature def perm_read(self, cr, uid, ids) Parameters • ids: an integer list Returns a list of dictionaries with the following keys • level : access level • uid : user id • gid : group id • create_uid : user who created the ressource • create_date: date when the ressourece was created • write_uid : last user who change the ressource • write_date : date of the last change to the ressource

perm_write Description Signature def perm_write(self, cr, uid, ids, fields) Parameters Returns

Methods to generate the fields and the views (fields_get, distinct_field_get, fields_view_get) fields_get Description Signature

05/02/08

84

def fields_get(self, cr, uid, fields = None, context={}) Parameters • fields: a list of fields that interest us, if None, all the fields • context: context['lang'] Result

fields_view_get Description Signature def fields_view_get(self, cr, uid, view_id=None, view_type='form', context={}) Parameters Result

distinct_field_get Description Signature def distinct_field_get(self, cr, uid, field, value, args=[], offset=0, limit=2000) Parameters Result

Methods concerning the name of the ressources (name_get, name_search) name_get Description Signature def name_get(self, cr, uid, ids, context={}) Parameters Result a list of tuples of the form [(id, name), ...] Example (in res.partner.address) def name_get(self, cr, user, ids, context={}): if not len(ids): return [] res = [] for r in self.read(cr, user, ids, ['name','zip','city']): addr = str(r['name'] or '') if r['name'] and (r['zip'] or r['city']): addr += ', ' addr += str(r['zip'] or ) + ' ' + str(r['city'] or ) res.append((r['id'], addr)) return res

05/02/08

85

name_search Description Signature def name_search(self, cr, uid, name='', args=[], operator='ilike', context={}) Parameters Result

05/02/08

86

To use a specific method to an object is making by the same way of the predefined methods. The different types of access sawn before stay available. It is good to keep the uses of Python; • the methods beginning with '_' are private

05/02/08

87

6.3.4 ObjectsWritingValues

Object writing Values One2many Argument: [(ID1, ID2, ID3)]

Where • ID1: the type of operation (link, create, remove, ...) • ID2: the ID of the ressource (in case of a modification or unlink) • ID3: the values Different values for ID1: • 0: create • 1: write • 2: unlink • 6: set the link to a list of IDs (ID3) Example:

Example in XML files Installation and Training, 8 hours 75.00 8

where tva21 is the ref of a tax previously defined (id="tva21").

Example in objects: Link: self.create(cr, uid, {'invoice_line_tax_id': [(6, 0, [1234])]})

Create: self.create(cr, uid, {'invoice_line_tax_id': [(0,0, {'name':'Hello', 'Price':45.6})]})

05/02/08

88

6.4 Property Fields Properties have been introduced in version 3.4 of Tiny ERP to replace the deprecated ir_set system. Properties are special fields of ressources that describe

Declaring a property A property is a special field: fields.property. class res_partner(osv.osv): _name = 'res.partner' _inherit = 'res.partner' _columns = { 'property_product_pricelist': fields.property( 'product.pricelist', type='many2one',. relation='product.pricelist',· string="Sale Pricelist",· method=True, view_load=True, group_name="Pricelists Properties"), } res_partner() Then you have to create the default value in a .XML file for this property: property_product_pricelist ="[('model','=','res.partner'), TIP: if the default value points to a ressource from another module, you can use the ref function like this:

Putting properties in forms To add properties in forms, just put the <properties/> tag in your form. This will automatically add all properties fields that are related to this object. The system will add properties depending on your rights. (some people will be able to change a specific property, others not). Properties are displayed by section, depending on the group_name attribute. (It is rendered in the client like a separator tag).

05/02/08

89

How does this work ? The fields.property class inherits from fields.function and override the read and write method. The type of this field is many2one, so in the form a property is represented like a many2one function. But the value of a property is stored in the ir.property class/table as a complete record. The stored value is a field of type reference (not many2one) because each property may points to a different object. If you edit properties values (from the administration menu), these are represented like a field of type reference. When you read a property, the program gives you the property attached to the instance of object you are reading. It this object has no value, the system will give you the default property. The definition of a property is stored in the ir.model.fields class like any other fields. In the definition of the property, you can add groups that are allowed to change to property.

Using properties or normal fields When you want to add a new feature, you will have to choose to implement it as a property or as normal field. Use a normal field when you inherit from an object and want to extend this object. Use a property when the new feature is not related to the object but to an external concept. Here are a few tips to help you choose between a normal field or a property: Normal fields extend the object, adding more features or data. A property is a concept that is attached to an object and have special features: • Different value for the same property depending on the company • Rights management per field • It's a link between ressources (many2one)

Example 1: Account Receivable The default "Account Receivable" for a specific partner is implemented as a property because: • This is a concept related to the account chart and not to the partner, so it is an account property that is visible on a partner form. Rights have to be managed on this fields for accountants, these are not the same rights that are applied to partner objects. So you have specific rights just for this field of the partner form: only accountants may change the account receivable of a partner. • This is a multi-company field: the same partner may have different account receivable values depending on the company the user belongs to. In a multi-company system, there is one account chart per company. The account receivable of a partner depends on the company it placed the sale order. • The default account receivable is the same for all partners and is configured from the general property menu (in administration). Note: one interresting think is that properties avoid spagetthi codes. The account module depends on the partner (base) module. But you can install the partner (base) module without the accounting module. If you add a field that points to an account in the partner object, both objects will depend on each other. It's much more difficult to maintain and code (for instance, try to remove a table when both tables are pointing to each others.)

05/02/08

90

Example 2: Product Times The product expiry module implements all delays related to products: removal date, product usetime, ... This module is very useful for food industries. This module inherits from the product.product object and add new fields to it: class product_product(osv.osv): _inherit = 'product.product' _name = 'product.product' _columns = { 'life_time': fields.integer('Product lifetime'), 'use_time': fields.integer('Product usetime'), 'removal_time': fields.integer('Product removal time'), 'alert_time': fields.integer('Product alert time'), } product_product()

This module add simple fields to the product.product object. We did not used properties because: • We extend a product, the life_time field is a concept related to a product, not to another object. • We do not need a right management per fields, the different delays are managed by the same people that manage all products.

05/02/08

91

7 Data loading

05/02/08

92

7.1 Introduction At the Tiny ERP installation, two steps are necessary to create and feed the data base: 1. Create the SQL tables 2. Insert the different datas in the tables The creation (or modification in the case of an upgrade) of SQL tables is automated thanks to the description of objects in the server. Into Tiny ERP, all the logic of the application is stored in the data base. We find for example: • the definitions of the reports, • the object default values, • the form description of the interface client, • the relations between the menu and the client buttons, ... There must be a mecanism to describe, modify and reload the different datas. These datas are represented into a set of XML files that can eventually be loaded at the start of the program in order to fill in the tables.

05/02/08

93

7.2 Files loading Introduction All the modules of the program must be accompanied with __terp__.py file in its main directory. Here is an example of a __terp__.py file for the account module. { "name" : "Tiny TERP Accounting", "version" : "0.1", "depends" : ["base"], "init_xml" : [ "account_workflow.xml", "account_data.xml"], "update_xml" : [ "account_view.xml", "account_report.xml"], }

The fields name The name of the module, an arbitrary english name.

version The version of the module. This version is not the same version as the Tiny ERP version. The modules evolve indenpendently of the program.

depends The list of modules this module depends upon. The dependencies are very important because they determinate the order in which the different modules are loaded. For example, if the workflow of the sale order (module:sale) uses the workflow of an invoice (module:account), it is important to create the account workflow before the sale order workflow.

init_xml The XML files loaded when the server is started with the argument: −−init=module. Generally, there is: • the description of workflows (convention: modulename_workflow.xml) • some usefull data (convention: modulename_data.xml) • demonstration data (convention: modulename_demo.xml)

update_xml The XML files to loaded when the server is started with the argument: −−update=modulename. If the server is executed with the argument −−init=modulename, the files 'update_xml' are also downloaded. We generally find: • the views description (convention: modulename_view.xml)

05/02/08

94

• the reports description (convention: modulename_report.xml)

05/02/08

95

7.3 XML files structure The XML files have the following structure: ...

05/02/08

96

7.3.1 The data

record tag The addition of new data is made with the record tag. This one takes a mandatory attribute : model. Model is the object name where the insertion has to be done. The tag record can also take an optional attribute: id. If this attribute is given, a variable of this name will be able to be used later on in the same file to make reference to the new created ressource ID. A record tag may contain field tags. They indicate the record's fields value. If a field is not specified the default value will be used.

Example account.invoice Invoices List account.invoice.list account/report/invoice.xsl account/report/invoice.xml

field tag The attributes that may conatain the field tag are the followings: name mandatory attribute indicating the field name eval python expression that indicating the value to add ref reference to an id defined in this file

function tag model name eval should evaluate to the list of parameters of the method to be called, excluding cr and uid

Example

getitem tag Takes a subset of the evaluation of the last child node of the tag. type int or list index int or string (a key of a dictionary)

05/02/08

97

Example Evaluates to the first element of the list of ids returned by the function node

05/02/08

98

7.3.2 IR Use The ir_set tag allows you to insert new values in the information repository. This tag must contain several field tags.

field tags attributes: name and eval

The attributes are those defined by the access methods to the information repository. We must provide him with several attributes: keys, args, name, value, // isobject, replace, meta. optional fields

Example

name="keys" eval="[('action','client_print_multi'),('res_model','account.invoice')]"/> name="args" eval="[]"/> name="name">Print Invoices
name="value" eval="'ir.actions.report.xml,'+str(l0)"/> name="isobject" eval="True"/> name="replace" eval="False"/>

05/02/08

99

7.4 Importing from a CSV Instead of using .XML file, you can import .CSV files. It is simpler but the migration system does not migrate the data imported from the .CSV files. It is like the noupdate attribute in .XML files. It is also more difficult to keep track of relations between resources and it is slower at the installation of the server. Use this only for demo data that will never been upgraded from one version of Tiny ERP to another. The name of the object is the name of the file before the first dot. You must use one file per object to import. For example, to import a file with partners (including their multiple contacts and events), the file must be named like one of the following example: • res_partner.csv • res_partner.tiny_demo.csv • res_partner.tiny.demo.csv For the name of the object, use underscores (_) instead of dots. (.)

Structure of the CSV file Have a look at the user manual for a complete description on how to construct your .CSV file. Usefull info: • Separator of field: , • Quote of fields: " • Encoding to use: UTF-8

Export demo data and import it from a module You can import .CSV file that have been exported from the Tiny ERP client. This is interesting to create your own demo module. But both formats are not exactly the same, mainly due to the conversion: Structured Data -> Flat Data -> Structured Data.

• The name of the column (first line of the .CSV file) use the end user term in his own language when you export from the client. If you want to import from a module, you must convert the first column using the fields names. Example, from the partner form: Name,Code,Contacts/Contact Name,Contacts/Street,Contacts/Zip becomes name,ref,address/name,address/street,address/zip

05/02/08

100

• When you export from the Tiny ERP client, you can select any many2one fields and their children relation. When you import from a module, Tiny ERP tries to recreate the relation between the two resources. For example, do not export something like this from a sale order form - otherwise Tiny ERP will not be able to import your file: Order Description,Partner/Name,Partner/Payable,Partner/Address/Name • To find the link for a many2one or many2many field, the server use the name_search function when importing. So, for a many2one field, it is better to export the field 'name' or 'code' of the related resource only. Use the more unique one. Be sure that the field you export is searchable by the name_search function. (the 'name' column is always searchable). Order Description,Partner/Code • Change the title of the column for all many2many or many2one fields. It's because you export the related resource and you import a link on the resource. Example from a sale order: Partner/Code should become partner_id and not partner_id/code. • Many2many fields. If all the exported data contains 0 or 1 relation on each many2many fields, there will be no problem. Otherwise, the export will result in one line per many2many. The import function expect to get all many2many relations in one column, separated by a comma. So, you have to make to transformation. For example, if the categories "Customer" and "Supplier" already exists : name,category_id Smith,"Customer,Supplier" If you want to create these two categories you can try : name,category_id Smith,"Customer,Supplier" This does not work as expected: a category "Customer, Supplier" is created. The solution is to create an empty line with only the second category: name,category_id Smith,Customer ,Supplier (Note the comma before "Supplier"). • Readonly fields. Do not try to import readonly fields like the amount receivable or payable for a partner. Otherwise, Tiny ERP will not accept to import your file. • Exporting trees. You can export and import tree structures using the parent field. You just have to take care of the import order. The parent have to be created before his children.

Use record id like in xml file: It's possible to define an id for each line of the csv file. This allow to define references between records: id, name, parent_id:id record_one, Father, record_two, Child, record_one

05/02/08

101

7.5 XML data files convention The ressources are placed in different files according to their uses. By convention; modulename_workflow.xml modulename_view.xml modulename_data.xml modulename_report.xml modulename_demo.sql

the definitions of workflows the views the important datas to download the reports declarations the useful datas for the demo version

The workflow files have to be loaded before the datas ! Otherwise, the ressource created won't be integrated inside the workflow because the later is not yet defined.

05/02/08

102

7.6 Managing updates

Managing updates and migrations Tiny ERP has a built'in migration and upgrade system which allows updates to be nearly (or often) automatic. This system also allows to easily incorporate custom modules.

Table/Object structure When you run tinyerp−server with option −−init or −−update, the table structure are updated to match the new description that is in .py files. Fields that are removed are not removed in the postgresql database not to lose data. So, simply running −−update or −−init, will upgrade your table structure. It's important to run −−init=module the first time you install the module. Next time, you must use the −−update=module argument instead of the init one. This is because init loads ressources that are loaded only once and never upgraded (eg: ressources with no id="" attribute or within a noupdate="1" tag).

Data Some data is automatically loaded at the installation of Tiny ERP: • views, actions, menus, • workflows, • demo data This data is also migrated to a new version if you run −−update or −−init.

Workflows Workflows are also upgraded automatically. If some activities are removed, the documents states evolves automatically to the preceding activities. That ensure that all documents are always in valid states. You can freely remove activities in your XML files with the unlink method. If workitems are in this activity, they will evolve to the preceding unlinked activity. And after the activity will be removed.

Things to care about during development Since version 3.0.2 of Tiny ERP, you can not use twice the same 'id="..."' during resource creation in your XML files, unless they are in two different modules. Resources which don't contain an id are created (and updated) only once; at the installation of the module or when you use the −−init argument. If a resource has an id and this resource is not present anymore in the next version of the XML file, Tiny ERP will automatically remove it from the database. If this resource is still present, Tiny ERP will update the modifications to this resource. If you use a new id, the resource will be automatically created at the next update of this module. Use explicit id declaration !, Example:

05/02/08

103

• view_invoice_form, • view_move_line_tree, • action_invoice_form_open, ... It is important to put id="...." to all record that are important for the next version migrations. For example, do not forget to put some id="..." on all workflows transitions. This will allows Tiny ERP to know which transition has been removed and which transition is new or updated.

Custom modules For example, if you want to override the view of an object named 'invoice_form' in your xml file (id="invoice_form"). All you have to do is redefine this view in your custom module with the same id. You can prefix ids with the name of the module to reference an id defined in another module. Example: ...

This will override the invoice form view. You do not have to delete the old view, like in 3.0 versions of Tiny ERP. Note that it is often better to use view inherytancy instead of overwritting views. In this migration system, you do not have to delete any ressource. The migration system will detect if it is an update or a delete using id="..." attributes. This is important to preserve references duing migrations.

Demo datas Demo datas do not have to be upgraded; because they are probably modified, deleted, ... by users. So, to avoid demo data to be upgraded, you can put a noupdate="1" attribute in the tag of your .xml data files.

05/02/08

104

8 Views Views are used to represent objects on the client side.

05/02/08

105

8.1 Introduction As all data of the program is stored in objects, as explained in the Objects section, how are these objects exposed to the user ? We will try to answer this question in this section. First of all, let's note that every resource type uses its own interface. For example, the screen to modify a partner's data is not the same as the one to modify an invoice. Then, you have to know that the Tiny ERP user interface is dynamic, it means that it is not described "statically" by some code, but dynamically built from XML descriptions of the client screens. From now on, we will call these screen descriptions views. A notable characteristic of these views is that they can be edited at any moment (even during the program execution). After a modification to a displayed view has occurred, you simply need to close the tab corresponding to that 'view' and re−open it for the changes to appear.

Views principles Views describe how each object (type of resource) is displayed. More precisely, for each object, we can define one (or several) view(s) to describe which fields should be drawn and how. There are two types of views: 1. form views 2. tree views

Form views The field disposition in a form view always follows the same principle. Fields are distributed on the screen following the rules below: • By default, each field is preceded by a label, with its name. • Fields are placed on the screen from left to right, and from top to bottom, according to the order in which they are declared in the view. • Every screen is divided into 4 columns, each column being able to contain either a label, or an "edition" field. As every edition field is preceded (by default) by a label with its name, there will be two fields (and their respective labels) on each line of the screen. The green and red zones on the screen−shot below, illustrate those 4 columns. They designate respectively the fields and their labels.

05/02/08

106

Views also support more advanced placement options: • A view field can take the place of several columns. For example, the light blue zone on the screen−shot below is, in fact, the only field of a "one to many". We will come back later on this note, but let's see that he takes the whole width of the screen and not only one column. • We can also make the opposite operation: take a columns group and divide it in as many columns as desired. The surrounded blue zones of the screen above are good examples. Precisely, the blue framework up and on the right side takes the place of two columns, but contains 4 columns. As we can see it below in the orange zone of the screen, there is also a way to distribute the fields of an object on different tabs.

05/02/08

107

Tree views These views are used when we work in list mode (in order to visualize several resources at once) and in the search screen. These views are simpler than the form views and thus have less options. The different options of views will be detailed into the next section. Tree views can define colors for each row of the tree. To do this, you have to add the attribute color like this sample;

Colors are separated by ';'.

05/02/08

108

8.2 File Format The common structure to all the XML files of Tiny ERP is described in the XMLFiles section The files describing the views are also of the form: [view definitions]

The view definitions contain mainly three types of tags: • tags with the attribute model="ir.ui.view", which contain the view definitions themselves • tags with the attribute model="ir.actions.act_window", which link actions to these views • <menuitem> tags, which create entries in the menu, and link them with actions New : You can precise groups for whom the menu is accessible using the groups attribute in menuitem tag. New : You can now add shortcut using the shortcut tag. Example : <shortcut name="Draft Purchase Order (Proposals)" model="purchase.order" logins="demo" menu="m"/> Note that you should add an id attribute on the menuitem which is refered by menu attribute. sale.order.form sale.order form
...


Default value for the priority field : 16. When not specified the system will use the view with the lower priority.

Special tags
...
The form tag defines a new view form, it takes a string attribute that defines the tab name for this view. <notebook> With notebooks you can distribute the view fields on different tabs (each one defined by a page tag). You can use the tabpos properties to set tab at: up, down, left, right. <page string="Order Line"> ... defines a new notebook page for the view. • string: defines the name of the page.

05/02/08

109

force a return to the line even if all the columns of the view are not filled in.

Related Documents