Workflow trong OpenERP

Thảo luận trong 'Workflow' bắt đầu bởi mrkhuongcc, 1/3/13.

  1. mrkhuongcc Member

    Xin phép các bậc tiền bối, cho em post bài hướng dẫn về workflow trong OpenERP


    Workflow trong hệ thống OpenERP là một cơ chế rất mạnh, nó có thể mô tả trạng thái của đối tượng qua các giai đoạn.

    Để dễ hình dung tác dụng của workflow bạn có thể theo dõi ví dụ đơn giản sau:
    s.png
    Ở trên là hình vẽ một workflow đơn giản về một order. Khi Order bắt đầu thì nó có trạng thái là “draft”, khi người dùng xác nhận (Confirm ) Order đó thì Order đó chuyển sang trạng thái “confirmed”. Sau đó Order sẽ kết thúc ở trạng thái “closed” hoặc “canceled” .
    Định nghĩa workflow:
    Workflow được định nghĩa trong file addons/base/ir/workflow/workflow.py. 3 class đầu tiên được định nghĩa trong file là workflow, wkf_activity and wkf_transition. Chúng tương ứng với 3 thành phần cần thiết để mô tả một workflow.
    1. Workflow:
    Cấu trúc chung của một file workflow:
    Mã (xml):
    1.  
    2. <?xml version="1.0" encoding="utf-8"?>
    3. <openerp>
    4.     <data>
    5.         <record model="workflow" id="workflow_id">
    6.             <field name="name">workflow.name</field>
    7.             <field name="osv">resource.model</field>
    8.             <field name="on_create">True|False</field>
    9.         </record>
    10.     </data>
    11. </openerp>
    12.  
    Trong đó:
    -Id: là identifier của workflow, mỗi workflow phải có id duy nhất.
    -Name: là tên của workflow. Phải theo đúng cú pháp của OpenERP qui định.
    -Osv: tên đối tượng mà chúng ta sử dụng workflow. Vd: nếu sử dụng workflow cho đối tượng “sale.order” thì <field name="osv">sale.order</field>
    -On_create: nếu True thì một thể hiện của workflow được tạo tự động khi đối tượng resource.model được tạo.


    2. Activity

    Lớp wkf_activity đại diện cho các node của workflow. Các node là các hành động sẽ được thực thi.

    Cấu trúc chung của một activity:
    Mã (xml):
    1.  
    2. <record model="worflow.activity" id="activity_id">
    3.             <field name="wkf_id" ref="workflow_id"/>
    4.             <field name="name">activity.name</field>
    5.          
    6.             <field name="split_mode">XOR|OR|AND</field>
    7.             <field name="join_mode">XOR|AND</field>
    8.             <field name="kind">dummy|function|subflow|stopall</field>
    9.          
    10.             <field name="action">(...)</field>
    11.             <field name="signal_send">(...)</field>
    12.             <field name="flow_start">True|False</field>
    13.             <field name="flow_stop">True|False</field>
    14. </record>
    15.  
    Trong đó:

    Split_mode:
    Capture.PNG
    Tại Node A có thể chuyển trạng thái đến các node con như Node A1, Node A2, Node A3. Việc chuyển trạng thái sang node con tuân thủ 3 phép toán:
    - - XOR: Chỉ hành động sang 1 nhánh con duy nhất.
    - - OR: không thực hiện hành động nào hoặc thực hiện nhiều hành động kế tiếp.

    -AND: chuyển sang thực hiện tất cả các hành động kế tiếp.
    join_mode:

    Capture.PNG

    Ngược lại với split_mode, Các nhánh cùng chuyển trạng thái về một node chung. Chỉ có 2 phép toán:
    -XOR: chỉ cần một node cha chuyển trạng thái thì đối tượng sẽ chuyển trạng thái.

    AND: Bắt buột tất cả các node cha chuyển trạng thái thì đối tượng mới chuyển trạng thái.

    Kind: loại hành động, gồm các loại sau:
    -DUMMY: không làm gì, là giá trị mặc định.
    -FUNCTION: Thực thi một hàm được khai báo.
    -SUBFLOW: thực thi workflow con.
    -STOPALL
    Action: là phương thức thực thi của đối tượng được định nghĩa trước.
    Flow_start: là node bắt đầu của workflow
    Flow_stop: là node kết thúc của workflow
    Ví dụ: activity trong sale_workflow.xml:
    Mã (xml):
    1. <!-- Activity -->
    2.         <record id="act_draft" model="workflow.activity">
    3.             <field name="wkf_id" ref="wkf_sale"/>
    4.             <field name="flow_start">True</field>
    5.             <field name="name">draft</field>
    6.         </record>
    7.         <record id="act_router" model="workflow.activity">
    8.             <field name="wkf_id" ref="wkf_sale"/>
    9.             <field name="name">router</field>
    10.             <field name="kind">function</field>
    11.             <field name="action">action_wait()</field>
    12.             <field name="split_mode">OR</field>
    13.         </record>
    14.         <record id="act_wait_invoice" model="workflow.activity">
    15.             <field name="wkf_id" ref="wkf_sale"/>
    16.             <field name="name">wait_invoice</field>
    17.         </record>
    18.         <record id="act_wait_ship" model="workflow.activity">
    19.             <field name="wkf_id" ref="wkf_sale"/>
    20.             <field name="name">wait_ship</field>
    21.         </record>
    22.  
    23.         <record id="act_done" model="workflow.activity">
    24.             <field name="wkf_id" ref="wkf_sale"/>
    25.             <field name="name">done</field>
    26.             <field name="flow_stop">True</field>
    27.             <field name="kind">function</field>
    28.             <field name="action">write({'state':'done'})</field>
    29.             <field name="join_mode">AND</field>
    30.         </record>
    31.         <record id="act_cancel" model="workflow.activity">
    32.             <field name="wkf_id" ref="wkf_sale"/>
    33.             <field name="name">cancel</field>
    34.             <field name="flow_stop">True</field>
    35.             <field name="kind">stopall</field>
    36.             <field name="action">action_cancel()</field>
    37.         </record>
    38.         <record id="act_cancel2" model="workflow.activity">
    39.             <field name="wkf_id" ref="wkf_sale"/>
    40.             <field name="name">cancel2</field>
    41.             <field name="flow_stop">True</field>
    42.             <field name="kind">stopall</field>
    43.             <field name="action">action_cancel()</field>
    44.         </record>
    45.         <record id="act_cancel3" model="workflow.activity">
    46.             <field name="wkf_id" ref="wkf_sale"/>
    47.             <field name="name">cancel3</field>
    48.             <field name="flow_stop">True</field>
    49.             <field name="kind">stopall</field>
    50.             <field name="action">action_cancel()</field>
    51.         </record>
    52.         <record id="act_invoice" model="workflow.activity">
    53.             <field name="wkf_id" ref="wkf_sale"/>
    54.             <field name="name">invoice</field>
    55.             <field name="kind">subflow</field>
    56.             <field name="subflow_id" search="[('name','=','account.invoice.basic')]"/>
    57.             <field name="action">action_invoice_create()</field>
    58.         </record>
    59.         <record id="act_invoice_except" model="workflow.activity">
    60.             <field name="wkf_id" ref="wkf_sale"/>
    61.             <field name="name">invoice_except</field>
    62.             <field name="kind">function</field>
    63.             <field name="action">action_invoice_cancel()</field>
    64.         </record>
    65.         <record id="act_invoice_end" model="workflow.activity">
    66.             <field name="wkf_id" ref="wkf_sale"/>
    67.             <field name="name">invoice_end</field>
    68.             <field name="kind">function</field>
    69.             <field name="action">action_invoice_end()</field>
    70.         </record>
    71.         <record id="act_invoice_cancel" model="workflow.activity">
    72.             <field name="wkf_id" ref="wkf_sale"/>
    73.             <field name="name">invoice_cancel</field>
    74.             <field name="flow_stop">True</field>
    75.             <field name="kind">stopall</field>
    76.             <field name="action">action_cancel()</field>
    77.         </record>
    78.         <record id="act_ship" model="workflow.activity">
    79.             <field name="wkf_id" ref="wkf_sale"/>
    80.             <field name="name">ship</field>
    81.             <field name="kind">function</field>
    82.             <field name="action">action_ship_create()</field>
    83.         </record>
    84.         <record id="act_ship_except" model="workflow.activity">
    85.             <field name="wkf_id" ref="wkf_sale"/>
    86.             <field name="name">ship_except</field>
    87.             <field name="kind">function</field>
    88.             <field name="action">write({'state':'shipping_except'})</field>
    89.         </record>
    90.         <record id="act_ship_end" model="workflow.activity">
    91.             <field name="wkf_id" ref="wkf_sale"/>
    92.             <field name="name">ship_end</field>
    93.             <field name="kind">function</field>
    94.             <field name="action">action_ship_end()</field>
    95.         </record>
    96.         <record id="act_ship_cancel" model="workflow.activity">
    97.             <field name="wkf_id" ref="wkf_sale"/>
    98.             <field name="name">ship_cancel</field>
    99.             <field name="flow_stop">True</field>
    100.             <field name="kind">stopall</field>
    101.             <field name="action">action_cancel()</field>
    102.         </record>
    103.  
    3. Transition





    Quá trình node là các điều kiện sẽ được thỏa mãn để chuyển từ hành động này đến hành động khác.

    Cấu trúc chung:
    Mã (xml):
    1.  
    2.         <record model="workflow.transition" id="transition_id">
    3.             <field name="act_from" ref="activity_id_1"/>
    4.             <field name="act_to" ref="activity_id_2"/>
    5.          
    6.             <field name="signal">(...)</field>
    7.             <field name="role_id" ref="role_id_1"/>
    8.             <field name="condition">(...)</field>
    9.          
    10.             <field name="trigger_model">(...)</field>
    11.             <field name"trigger_expr_id">(...)</field>
    12.         </record>
    13.  
    trong đó:

    -Act_from: nguồn của hành động, hay node hiện tại
    -Act_to: hành động đích hay node kế tiếp.
    -Condition: Điều kiện để quá trình chuyển đổi được thực thi.
    -Signal: nhận yêu cầu thực thi từ button
    -Role_id
    Trong đó act_from và act_to là bắt buộc.

    4.Tạo một workflow

    Ví dụ: tạo 1 workflow sau:


    Capture.PNG

    Định nghĩa States trong Object (tên columns bắt buộc phải là ‘state’)

    Mã (python):
    1. _columns={
    2.     ...
    3.     'state': fields.selection([
    4.         ('new','New'),
    5.         ('assigned','Assigned'),
    6.                             ('negotiation', 'Negotiation'),
    7.         ('won','Won'),
    8.         ('lost','Lost')], 'state',readonly=True),
    9.      
    10. }
    11.  
    Định nghĩa các phương thức sử dụng khi thay đổi trạng thái. Các phương thức này được định nghĩa trong Object.
    Mã (python):
    1.  
    2. def mymod_new(self, cr, uid, ids):
    3.     self.write(cr, uid, ids, {'state': 'new'})
    4.     return True
    5. def mymod_assigned(self, cr, uid, ids):
    6.     self.write(cr, uid, ids, {'state': 'assigned'})
    7.     return True
    8. def mymod_negotiation(self, cr, uid, ids):
    9.     self.write(cr, uid, ids, {'state':'negotiation'})
    10.     return True
    11. def mymod_won(self, cr, uid, ids):
    12.     self.write(cr, uid, ids, {'state': 'won'})
    13.     return True
    14. def mymod_lost(self, cr, uid, ids):
    15.     self.write(cr, uid, ids, {'state': 'lost'})
    16.     return True
    17.  
    Tạo file workflow xml:
    -Header
    Mã (xml):
    1.  
    2. <record id="wkf_mymod" model="workflow">
    3.             <field name="name">mymod.wfl</field>
    4.             <field name="osv">mymod.mymod</field>
    5.             <field name="on_create">True</field>
    6.         </record>
    7.  
    -Activity
    Mã (xml):
    1. <!-- Activity -->
    2.         <record id="act_new" model="workflow.activity">
    3.             <field name="wkf_id" ref="wkf_mymod"/>
    4.             <field name="flow_start">True</field>
    5.             <field name="name">new</field>
    6.     <field name="kind">function</field>
    7.             <field name="name">mymod_new()</field>
    8.         </record>
    9.      
    10.         <record id="act_assigned" model="workflow.activity">
    11.             <field name="wkf_id" ref="wkf_mymod"/>
    12.             <field name="name">assigned</field>
    13.             <field name="kind">function</field>
    14.             <field name="action">mymod_assigned()</field>
    15.         </record>
    16.      
    17.         <record id="act_negotiation" model="workflow.activity">
    18.             <field name="wkf_id" ref="wkf_mymod"/>
    19.             <field name="name">negotiation</field>
    20.     <field name="kind">function</field>
    21.             <field name="action">mymod_negotiation()</field>
    22.         </record>
    23.      
    24. <record id="act_won" model="workflow.activity">
    25.             <field name="wkf_id" ref="wkf_mymod"/>
    26.             <field name="name">won</field>
    27.     <field name="kind">function</field>
    28.             <field name="action">mymod_won()</field>
    29.     <field name="flow_stop">True</field>
    30.       </record>
    31.  
    32.         <record id="act_lost" model="workflow.activity">
    33.             <field name="wkf_id" ref="wkf_mymod"/>
    34.             <field name="name">lost</field>
    35.             <field name="kind">function</field>
    36.             <field name="action">mymod_lost()</field>
    37.             <field name="flow_stop">True</field>
    38.         </record>
    39.  
    -Transition

    y
    Mã (xml):
    1. <record id="t1" model="workflow.transition">
    2.             <field name="act_from" ref="act_new"/>
    3.             <field name="act_to" ref="act_assigned"/>
    4.             <field name="signal">mymod_assigned</field>
    5.         </record>
    6.  
    7.         <record id="t2" model="workflow.transition">
    8.             <field name="act_from" ref="act_assigned"/>
    9.             <field name="act_to" ref="act_negotiation"/>
    10.             <field name="signal">mymod_negotiation</field>
    11.         </record>
    12.  
    13.         <record id="t3" model="workflow.transition">
    14.             <field name="act_from" ref="act_negotiation"/>
    15.             <field name="act_to" ref="act_won"/>
    16.             <field name="signal">mymod_won</field>
    17.         </record>
    18.  
    19.         <record id="t4" model="workflow.transition">
    20.             <field name="act_from" ref="act_negotiation"/>
    21.             <field name="act_to" ref="act_lost"/>
    22.             <field name="signal">mymod_lost</field>
    23.         </record>
    24.  
    Workflow hoạt động thông qua sự kiện click vào button:
    Mã (xml):
    1. <group colspan="4" col="3">
    2.     <button name="mymod_assigned" string="Assigned" states="new"/>
    3.     <button name="mymod_negotiation" string="In Negotiation" states="assigned"/>
    4.     <button name="mymod_won" string="Won" states="negotiation"/>
    5.     <button name="mymod_lost" string="Lost" states="negotiation"/>
    6. </group>
    7.  
    Ở đây mỗi button sẽ có thuộc tính states=”X” có nghĩa là button sẽ hiện thị khi trạng thái của Object là X
    Bài viết còn nhiều sai sót rất mong nhận được sự góp ý

    More Threads in same category

  2. bruce.nguyen Active Member

    Dear khuongcc em: Bài viết quá tốt em, mong em chia sẻ nhiều hơn với diễn đàn. Cám ơn em
    mrkhuongcc thích bài này.
  3. Cám ơn anh đã chia sẻ!
    Anh cho em hỏi: "Có cách nào để xem data model của OpenERP ko? Và có tài liệu nào nói về Data model ko?"
  4. openerpvietnam Active Member

    Bạn có thể vào menu Settings - Technical - Database Structure - Models để xem hoặc bạn có thể dùng pgAdmin III của postgreSQL để xem cụ thể các data model với mỗi table tương ứng là 1 model (ví dụ : res.partner thì table tương ứng trong pgAdmin III là res_partner).
    Phan Nguyen Thanh Nhan and admin like this.
  5. Cám ơn các anh nhiều lắm :)
  6. minimum New Member

    Workflow trong openerp đôi khi cũng gặp tình trạng không thể chuyển state, tức là khi user action một thao tác nhưng sẽ không effect dc.
    Nếu vô tình gặp bug này, anh/ em vào database, tìm các table có prefix: wkf, thực hiện các câu lệnh sql dml để đưa record về đúng state in workflow.
    Vài dòng comment !!!!
    Phan Nguyen Thanh Nhan and admin like this.
  7. Quanvm Member

    Hi bạn minimun!
    Bạn có thể mô tả 1 vài trường hợp không thể chuyển state được không ?
  8. Chào các anh,
    Giữa các datamodels có realtionships, có cách nào để mình có thể xem đồng loạt các datamodels cùng với relationships ko?
  9. Lưu Quốc Anh New Member

    Mọi người ơi giúp mình với.Mình tạo 1 cái workflow đơn giản mình tạo 1 bảng tên : khoa_khoa có column state.
    state có 2 trạng thái new và confirm. Nếu là new thì mình cho confirm và kết thúc. mình tạo workflow như bên dưới nhưng mình click vào button thì nó không link
    được tới workflow mình tạo.

    <!-- 4.Create workflow-->
    <record model="workflow" id="workflow_id_khoa">
    <field name="name">khoa.wkf</field>
    <field name="osv">khoa.khoa</field>
    <field name="on_create">True</field>
    </record>

    <!-- Activity -->
    <record id="act_new_khoa" model="workflow.activity">
    <field name="wkf_id" ref="workflow_id_khoa"/>
    <field name="flow_start">True</field>
    <field name="name">new</field>
    <field name="kind">function</field>
    <field name="action">mykhoa_new()</field>
    </record>

    <record id="act_assigned_khoa" model="workflow.activity">
    <field name="wkf_id" ref="workflow_id_khoa"/>
    <field name="name">assigned</field>
    <field name="kind">function</field>
    <field name="action">mykhoa_confirm()</field>
    </record>

    <!-- transition -->
    <record id="t1" model="workflow.transition">
    <field name="act_from" ref="act_new_khoa"/>
    <field name="act_to" ref="act_assigned_khoa"/>
    <field name="signal">mykhoa_confirm</field>
    </record>

    <button name="mykhoa_confirm" string="confirm" states="new" icon="gtk-apply"/>

Chia sẻ trang này