模塊開發

簡介

OpenERP 採用 `三層架構 <http://en.wikipedia.org/wiki/Multitier_architecture#Three-tier_architecture>`_。 應用層本身被設計成核心和多個附加的模塊,這些模塊可以安裝,不用OpenERP創建一個特殊的配置。

OpenERP的核心和其他不同的模塊都是用 Python 寫的。 模塊的功能通過XML-RPC(或是NET-RPC,這取決於服務器端的配置)顯示出來。模塊也採用OpenERP ORM在關係型數據庫(PostgreSQL)中來持久化數據。當模塊安裝好後通過提供XML文件就可以在數據庫中插入數據。

Although modules are a simple way to structure a complex application, OpenERP modules also extend the system. Modules are also called addons (they could also have been called plugins).

在OpenERP的典型配置中,以下模塊是必須的:

  • base: 最基本的模塊。它無論何種情況下都必須安裝,被認爲是OpenERP核心的一部分。定義了 ir.property, res.company, res.request, res.currency,res.users, res.partner, 等等。

  • crm: 客戶關係管理和供應商關係管理。

  • sale: 銷售管理。

  • mrp: 製造資源管理。

通過使用Python, XML files,依賴OpenERP的ORM和它的延伸機制,新的模塊可以很容易快速的寫出。OpenERP的開源特性和它衆多的模塊也爲新模塊的開發提供很多的例子。

模塊結構

模塊

  1. 簡介

  2. 文件和文件夾結構
    1. __openerp__.py

    2. __init__.py

    3. XML 文件
      1. 操作

      2. Menu Entries

      3. Reports

      4. 嚮導

  3. 配置文件

模塊 - 文件和文件夾結構

所有模塊都應放到 server/addons 文件夾下。

按下面步驟創建新模塊:

  • 在 server/addons 文件夾下面創建模塊子文件夾

  • 創建模塊定義文件: __openerp__.py

  • 創建定義 objects  Python 文件

  • 創建包括(初始數據, 視圖, 菜單, 演示數據)的 .xml 文件

  • 創建包含 reports, wizards  workflows 的 xml文件(可選)

模塊 - 文件和目錄 - XML 文件

模塊目錄裏的XML文件用於修改數據庫結構,他們有很多的用途,我們可以列出來:

  • 初始化,實例化(demonstration)數據聲明(declaration)

  • 視圖聲明

  • 報表聲明

  • 嚮導聲明

  • 工作流聲明

OpenERP XML文件主要結構的更多細節在 XML 數據序列化 部分,如果你想學習更多關於*初始化* 和 示例數據 XML文件,可以查看這裏。 下面的部分只是關於特定的XML文件,如 following section are only related to XML specific to actions, menu entries, *操作、菜單、報表、嚮導  工作流 定義。

Python 模塊描述文件 __init__.py

** __init__.py 文件**

這個文件就像任何的Python模塊中一樣,在程序的開始運行。它負責導入程序所需的Python文件。

所以,如果你想創建一個“module.py”文件,它包括你的對象的描述,在這種情況下,你需要在__init__.py文件中寫一行:

import module

OpenERP 模塊描述文件 __openerp__.py

在已創建模塊的目錄下,你必須添加一個__openerp__.py文件。這個文件必須在Python的格式下,負責:

  1. 確定所需的XML文件,server在進行初始化時將從語法上分析這些文件。

  2. 確定該創建模塊的依賴模塊。

這個文件包括下面的值:

name

(英文)名稱.

version

模塊版本號, 2 位 (1.2 或 2.0).

description

模塊的描述,包含模塊的使用文檔。

author

模塊的作者

website

模塊的網站

license

模塊的授權協議(默認AGPL).

depends

列出該模塊所依賴的其他模塊,因爲base模塊包括模塊必須的視圖,報表等數據,所以base模塊應該在其他所有模塊的依賴中。

init

List of .xml files to load when the server is launched with the "--init=module" argument. Filepaths must be relative to the directory where the module is. OpenERP XML File Format is detailed in this section.

data

List of .xml files to load when the server is launched with the "--update=module" launched. Filepaths must be relative to the directory where the module is. OpenERP XML File Format is detailed in this section.

demo

List of .xml files to provide demo data. Filepaths must be relative to the directory where the module is. OpenERP XML File Format is detailed in this section.

installable

True或是False,決定這個模塊是否可安裝。

images

List of .png files to provide screenshots, used on http://apps.openerp.com.

active

True或是False(默認是False),決定這個模塊在數據庫創建時是否安裝。

test

List of .yml files to provide YAML tests.

範例

以product模塊中的__openerp__.py爲例:

{
    "name" : "Products & Pricelists",
    "version" : "1.1",
    "author" : "Open",
    "category" : "Generic Modules/Inventory Control",
    "depends" : ["base", "account"],
    "init_xml" : [],
    "demo_xml" : ["product_demo.xml"],
    "update_xml" : ["product_data.xml", "product_report.xml", "product_wizard.xml",
                    "product_view.xml", "pricelist_view.xml"],
    "installable": True,
    "active": True
}

放置在init_xml中的文件必須要麼是和工作流相關,要麼是安裝軟件時裝載數據相關,或是和示例數據相關。

update_xml中的文件涉及到視圖,報表和嚮導。

Objects

所有OpenERP的資源都是對象,如menus,actions,reports,invoices,partners... OpenERP通過數據庫的對象關係映射(ORM,object relational mapping of a database)來控制信息存儲。OpenERP的對象名是層次結構的,例如:

  • account.transfer : a money transfer

  • account.invoice : an invoice

  • account.invoice.line : an invoice line

總之,第一個單詞是模塊的名字:account,stock,sale

ORM的其他優點有:

  • simpler relations : invoice.partner.address[0].city

  • objects have properties and methods: invoice.pay(3400 EUR),

  • inheritance, high level constraints, ...

操作一個對象比很多表要容易些。

/doc_static/6.1/_images/pom_3_0_3.png

The Physical Objects Model of [OpenERP version 3.0.3]

PostgreSQL

OpenERP的ORM是在PostgreSQL上構造的。在OpenERP上通過對象接口或是直接使用SQL語句查詢一個對象是可行的。

在PostgreSQL數據庫中直接進行讀寫是非常危險的,因爲可能會漏掉重要的步驟如約束檢查或是工作流的修改。

註解

The Physical Database Model of OpenERP

Pre-Installed Data

PostgreSQL表中的數據可以使用XML文件來進行插入或更新,使得於OpenERP對象數據一致。OpenERP XML文件的主要結構是:

<?xml version="1.0"?>
<openerp>
  <data>
    <record model="model.name_1" id="id_name_1">
      <field name="field1">
        "field1 content"
      </field>
      <field name="field2">
        "field2 content"
      </field>
      (...)
    </record>
    <record model="model.name_2" id="id_name_2">
        (...)
    </record>
    (...)
  </data>
</openerp>

Fields content are strings that must be encoded as UTF-8 in XML files.

下面是一個來自 OpenERP 的源碼的例子 (base_demo.xml 在 base 模塊中):

<record model="res.company" id="main_company">
    <field name="name">Tiny sprl</field>
    <field name="partner_id" ref="main_partner"/>
    <field name="currency_id" ref="EUR"/>
</record>
<record model="res.users" id="user_admin">
    <field name="login">admin</field>
    <field name="password">admin</field>
    <field name="name">Administrator</field>
    <field name="signature">Administrator</field>
    <field name="action_id" ref="action_menu_admin"/>
    <field name="menu_id" ref="action_menu_admin"/>
    <field name="address_id" ref="main_address"/>
    <field name="groups_id" eval="[(6,0,[group_admin])]"/>
    <field name="company_id" ref="main_company"/>
</record>

最後的字段定義的 admin user :

  • 登錄,密碼等字段比較直接.

  • ref屬性用於在records之間建立關係

<field name="company_id" ref="main_company"/>

字段company_id是一個從user object到company object的many-to-one的關係,main_company是相關聯的id。

  • eval 屬性允許將一些 python 代碼放進 xml 中: 這裏 groups_id 字段是一個多對多(many2many)的關係. 對於這樣一個字段, "[(6,0,[group_admin])]" 的意思爲 : 刪除所有與當前用戶相關的組,並使用 [group_admin] 作爲新的關聯組 (and group_admin 是另一個記錄的 id ).

  • search 屬性允許你在不指定 xml id 的情況下. 查找相關的記錄. 你可以指定一個搜索條目來尋找想要查詢的字段. 條目是一個 tuple 的 lists 用於預定義的搜索方法, 如果有多個結果, 通常選中(第一個):

<field name="partner_id" search="[]" model="res.partner"/>

這是個在demo數據中使用search的典型例子。在這裏我們並不是真正想知道是哪個partner,所以我們給出了一個空的list。注意model屬性是在一般情況下必須要寫的。

記錄標籤

Description

T新數據的添加是通過record標籤實現的。它利用一個必備的屬性:model。Model是一個對象名稱,可以用來實現插入數據。record標籤內還有一個可選擇的屬性:id。如果使用了這個屬性,那麼在相同文件中,這個名字可以代替新創建的資源ID。

record標籤中包含field標籤。他們指出record的字段值(record’s fields value)。如果這個field沒有詳細說明,那麼它會使用默認值。

範例

<record model="ir.actions.report.xml" id="l0">
     <field name="model">account.invoice</field>
     <field name="name">Invoices List</field>
     <field name="report_name">account.invoice.list</field>
     <field name="report_xsl">account/report/invoice.xsl</field>
     <field name="report_xml">account/report/invoice.xml</field>
</record>
Field tag

對應的屬性如下:

name : (必需) : mandatory

field name

eval : (可選) : optional

將指定值進行添加的python表達式

ref

這個文件中涉及到已定義的id

model

用於查找的model

search

查詢

Function tag

一個功能標籤包含其他的功能標籤。

model : (必須有的) : mandatory

要調用的model

name : (必需) : mandatory

function的名稱

eval

估值(evaluate)要調用的方法的參數列表,不計cr和uid

範例

<function model="ir.ui.menu" name="search" eval="[[('name','=','Operations')]]"/>
Getitem tag

採用標籤最後一個子節點的子集.

type : (必需) : mandatory

int 或 list

index : (必需) : mandatory

int or string

範例

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

<getitem index="0" type="list">
    <function model="ir.ui.menu" name="search" eval="[[('name','=','Operations')]]"/>
</getitem>

i18n

改進翻譯
Translating in launchpad

翻譯由“Launchpad Web interface”管理。在這裏你會找到可譯項目的清單。

請在問問題前閱讀 FAQ

Translating your own module

在 5.0 版更改.

和之前4.2.x的版本不同,現在翻譯都是通過模塊來做。所以和之前整個系統中有一個特殊i18n文件夾不同的是,現在每一個模塊都有自己的i18n文件夾。此外,OpenERP可以處理.po文件作爲導入導出格式。當我們安裝或是更新一個模塊時,安裝語言的翻譯文件可以自動裝入系統中。OpenERP也可以產生一個.tgz文件歸檔,裏面包括爲每個選中模塊組織很好的.po文件。

[1]

http://www.gnu.org/software/autoconf/manual/gettext/PO-Files.html#PO-Files

Process

Defining the process

通過界面(interface)或是模塊recorder來定義進程。然後放置生成的XML文件在自己的模塊中。

Views

Technical Specifications - Architecture - Views

視圖是一種在客戶端顯示對象的方式。他們指示客戶端如何在屏幕上顯示對象數據。

視圖有兩種:

  • 表單視圖

  • 列表視圖

Lists是tree views中的特殊情形。

同一個對象有幾種視圖:首先定義的視圖樣式(tree,form,…)將會做爲它默認的樣式。那樣的話,當你雙擊一個菜單項時,就有一個默認的tree view和一個特定的view顯示差不多的信息。例如,products針對product變量有幾種視圖。

視圖都是在XML文件中進行描述的。

如果一個對象沒有定義視圖,那麼這個對象可以自己產生一個視圖來顯示它自己。這會限制開發者的工作,但是會導致較少的人們自己的視圖設計(ergonomic views)。

Usage example

當我們打開一張發票時,接下來是在客戶端上的操作:

  • 一個動作請求打開發票(它給出了一個對象的數據(account.invoice),視圖,域(例如僅僅是還未付款的發票))

  • 客戶端請求server,什麼樣的視圖由發票對象定義,哪些數據要顯示。

  • 客戶端通過視圖顯示錶單

/doc_static/6.1/_images/arch_view_use.png
To develop new objects

對新對象的設計限制到最低限度:創建對象並且有選擇的創建視圖來顯示他們。PostgreSQL的table數據不用手寫,因爲對象會自動創建它們(除非它們已經存在)。

Reports

OpenERP使用一個非常靈活和強大的報表系統。報表以PDF或是HTML的形式生成。報表是以數據層和表現層分開的原理進行設計的。

關於報表更多的細節在 Reporting 章節。

嚮導

這裏有個描述嚮導的.xml文件的例子:

<?xml version="1.0"?>
<openerp>
    <data>
     <wizard string="Employee Info"
             model="hr.employee"
             name="employee.info.wizard"
             id="wizard_employee_info"/>
    </data>
</openerp>

wizard用wizard標籤來聲明。想要知道更多關於wizard XML的信息可以查看“Add A New Wizard”這個章節。

或者你可以在菜單中通過使用下面的XML entry添加嚮導。

<?xml version="1.0"?>
</openerp>
     <data>
     <wizard string="Employee Info"
             model="hr.employee"
             name="employee.info.wizard"
             id="wizard_employee_info"/>
     <menuitem
             name="Human Resource/Employee Info"
             action="wizard_employee_info"
             type="wizard"
             id="menu_wizard_employee_info"/>
     </data>
</openerp>

Workflow

通過對象和視圖,我們可以很簡單的定義新的表單,lists/trees和它們間的交互。但是這還不夠:你還得定義這些對象間的動態關係。

舉個例子:

  • 在一般的情況下,一個已確定的銷售訂單必鬚生成一張發貨單。

  • 只是在確認發貨單已付款的前提下,纔會開出運送清單。

工作流使用圖表描述這些交互,一個或幾個工作流相關到對象。工作流是非必須的;一些對象就沒有工作流。

下面的工作流用於銷售訂單的例子。在一定的條件下,它必須產生髮貨單和出貨。

/doc_static/6.1/_images/arch_workflow_sale.png

在這張圖表中節點代表着要做的動作。

  • 創建發票

  • 取消銷售訂單

  • 生成裝貨單, ...

上面的箭頭代表條件:

  • 等待訂單獲得批准

  • 發票支付

  • 點擊取消按鈕,。。。

方格樣式的節點代表其他的工作流:

  • 發票

  • 發貨

OpenERP 模塊描述文件 : __openerp__.py

一般模塊

在已創建模塊的目錄下,你必須添加一個__openerp__.py文件。這個文件必須在Python的格式下,負責:

  1. 確定所需的XML文件,server在進行初始化時將從語法上分析這些文件。

  2. 1.確定已創建模塊的依賴。

這個文件包括下面的值:

name

(英文)名稱.

version

版本

description

描述

author

模塊的作者

website

模塊的網站

license

模塊的授權協議(默認AGPL).

depends

列出該模塊所依賴的其他模塊,因爲base模塊包括模塊必須的視圖,報表等數據,所以base模塊應該在其他所有模塊的依賴中。

init_xml

List of .xml files to load when the server is launched with the "--init=module" argument. Filepaths must be relative to the directory where the module is. OpenERP XML File Format is detailed in this section.

update_xml

List of .xml files to load when the server is launched with the "--update=module" launched. Filepaths must be relative to the directory where the module is. OpenERP XML File Format is detailed in this section.

installable

True或是False,決定這個模塊是否可安裝。

active

True或是False(默認是False),決定這個模塊在數據庫創建時是否安裝。

例子

以product模塊中的__openerp__.py爲例:

{
    "name" : "Products & Pricelists",
    "version" : "1.1",
    "author" : "Open",
    "category" : "Generic Modules/Inventory Control",
    "depends" : ["base", "account"],
    "init_xml" : [],
    "demo_xml" : ["product_demo.xml"],
    "update_xml" : ["product_data.xml","product_report.xml", "product_wizard.xml","product_view.xml", "pricelist_view.xml"],
    "installable": True,
    "active": True
}

放置在init_xml中的文件必須要麼是和工作流相關,要麼是安裝軟件時裝載數據相關,或是和示例數據相關。

update_xml中的文件涉及到視圖,報表和嚮導。

Profile 模塊

一個profile的目的是在數據庫創建後直接使用一組模塊來初始化OpenERP。這個profile是一種特殊的模塊,它不包含代碼,只是 依賴於其他的模塊 

爲了創建一個新的profile,你需要在server/addons裏建一個新目錄(可以給它取名爲profile_modulename)。在新目錄裏放一個空的__init__.py文件和__openerp__.py。這個文件的結構是:

{
     "name":"''Name of the Profile'',
     "version":"''Version String''",
     "author":"''Author Name''",
     "category":"Profile",
     "depends":[''List of the modules to install with the profile''],
     "demo_xml":[],
     "update_xml":[],
     "active":False,
     "installable":True,
}

例子

我們以文件server/bin/addons/profile_manufacturing/__openerp__.py中的代碼爲例,它對應着OpenERP中的manufacturing industry profile。

{
     "name":"Manufacturing industry profile",
     "version":"1.1",
     "author":"Open",
     "category":"Profile",
     "depends":["mrp", "crm", "sale", "delivery"],
     "demo_xml":[],
     "update_xml":[],
     "active":False,
     "installable":True,
}

創建模塊

Getting the skeleton directory

你可以從其他任意模塊中複製文件__openerp__.py和__init__.py到一個新目錄來創建一個新模塊。

Ubuntu中一個例子:

$ cd ~/workspace/stable/stable_addons_5.0/
$ mkdir travel
$ sudo cp ~/workspace/stable/stable_addons_5.0/hr/__openerp__.py ~/workspace/stable/stable_addons_5.0/travel
sudo cp ~/workspace/stable/stable_addons_5.0/hr/__init__.py ~/workspace/stable/stable_addons_5.0/travel

你如果想修改這個目錄,你需要設置自己的權限在這個目錄上:

$ sudo chown -R `whoami` travel

進入新模塊的目錄,裏面有個框架結構,你仍需要去更改模塊定義裏面的東西。

Changing the default definition

爲了更改模塊“travel”裏面的默認設置,我們需要進入“travel”目錄,編輯__openerp__.py文件。

$ cd travel
$ gedit __openerp__.py

文件裏面類似下面:

{
  "name" : "Human Resources",
  "version" : "1.1",
  "author" : "Tiny",
  "category" : "Generic Modules/Human Resources",
  "website" : "http://www.openerp.com",
  "description": """
  Module for human resource management. You can manage:
  * Employees and hierarchies
  * Work hours sheets
  * Attendances and sign in/out system

  Different reports are also provided, mainly for attendance statistics.
  """,
  'author': 'Tiny',
  'website': 'http://www.openerp.com',
  'depends': ['base', 'process'],
  'init_xml': [],
  'update_xml': [
      'security/hr_security.xml',
      'security/ir.model.access.csv',
      'hr_view.xml',
      'hr_department_view.xml',
      'process/hr_process.xml'
  ],
  'demo_xml': ['hr_demo.xml', 'hr_department_demo.xml'],
  'installable': True,
  'active': False,
  'certificate': '0086710558965',
}

你可能會更改任意你覺得正確的東西,像下面這樣:

{
    "name" : "Travel agency module",
    "version" : "1.1",
    "author" : "Tiny",
    "category" : "Generic Modules/Others",
    "website" : "http://www.openerp.com",
    "description": "A module to manage hotel bookings and a few other useful features.",
    "depends" : ["base"],
    "init_xml" : [],
    "update_xml" : ["travel_view.xml"],
    "active": True,
    "installable": True
}

注意“active”字段變成了true。

Changing the main module file

Now you need to update the travel.py script to suit the needs of your module. We suggest you follow the Flash tutorial for this or download the travel agency module from the 20 minutes tutorial page.

The documentation below is overlapping the two next step in this wiki tutorial,
so just consider them as a help and head towards the next two pages first...

travel.py文件應該看起來是這樣:

from osv import osv, fields

class travel_hostel(osv.osv):
       _name = 'travel.hostel'
       _inherit = 'res.partner'
       _columns = {
       'rooms_id': fields.one2many('travel.room', 'hostel_id', 'Rooms'),
       'quality': fields.char('Quality', size=16),
       }
       _defaults = {
       }
travel_hostel()

理想情況下,你會拷貝那些代碼幾次來創建你所需要的實體(travel_airport, travel_room, travel_flight)。這就是你的對象的數據庫結構,但是你真的不需要擔心數據庫端。當你安裝模塊時,這個文件會爲你創建系統架構。

Customizing the view

接下來你可以編輯視圖。編輯custom_view.xml文件,像這樣:

<openerp>
<data>
    <record model="res.groups" id="group_compta_user">
            <field name="name">grcompta</field>
    </record>
    <record model="res.groups" id="group_compta_admin">
            <field name="name">grcomptaadmin</field>
    </record>
    <menuitem name="Administration" groups="admin,grcomptaadmin"
                    icon="terp-stock" id="menu_admin_compta"/>
</data>
</openerp>

就像你看到的,這是個accounting系統的例子。

定義視圖就是定義訪問你的模塊時的用戶界面。這裏定義的這些字段已經是一個完整的界面。然而,由於做這個的複雜性,我們建議,再一次,從鏈接http://www.openerp.com/download/modules/5.0/下載travel agent模塊。

下次你可以使用其他的文件來定義不同的視圖,並且在你的basic/admin視圖中分開它們。

Action creation

Linking events to action

可用類型的事件是:

  • client_print_multi (print from a list or form)

  • client_action_multi (action from a list or form)

  • tree_but_open (double click on the item of a tree, like the menu)

  • tree_but_action (action on the items of a tree)

從事件到動作的映射是:

<record model="ir.values" id="ir_open_journal_period">
    <field name="key2">tree_but_open</field>
    <field name="model">account.journal.period</field>
    <field name="name">Open Journal</field>
    <field name="value" eval="'ir.actions.wizard,%d'%action_move_journal_line_form_select"/>
    <field name="object" eval="True"/>
</record>

如果你雙擊journal/period (object: account.journal.period),將會打開一個選中的嚮導(id=”action_move_journal_line_form_select”).

只是當用戶點擊特定的對象時,你可以使用res_id字段來允許這個動作。

<record model="ir.values" id="ir_open_journal_period">
    <field name="key2">tree_but_open</field>
    <field name="model">account.journal.period</field>
    <field name="name">Open Journal</field>
    <field name="value" eval="'ir.actions.wizard,%d'%action_move_journal_line_form_select"/>
    <field name="res_id" eval="3"/>
    <field name="object" eval="True"/>
</record>

當用戶點擊account.journal.period n°3時,這個動作將會觸發。

當你聲明嚮導,報表或是菜單時,ir.values的創建會自動由下面的標籤完成:

  • <wizard... />

  • <menuitem... />

  • <report... />

所以一般不需要自己加映射。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章