Author: |
My Company |
License: |
no license |
Branch: |
14.0 |
Repository: |
twtrubiks/odoo-demo-addons-tutorial |
Dependencies: |
hr_expense,
and
web |
Languages: |
Markdown (178, 52.7%),
Python (56, 16.6%),
and
XML (104, 30.8%) |
Other branches: |
master |
<h1>介紹 AbstractModel</h1>
<p>建議觀看影片, 會更清楚:smile:</p>
<p><a href="https://youtu.be/jsMTVe12vRY">Youtube Tutorial - odoo 手把手教學 - AbstractModel</a></p>
<p>建議在閱讀這篇文章之前, 請先確保了解看過以下的文章 (因為都有連貫的關係)</p>
<p><a href="https://github.com/twtrubiks/odoo-demo-addons-tutorial/tree/master/demo_odoo_tutorial">odoo 手把手建立第一個 addons</a></p>
<p>主要介紹 demo<em>abstractmodel</em>tutorial</p>
<h2>說明</h2>
<p><code>AbstractModel</code> AbstractModel = BaseModel,</p>
<p>注意:exclamation::exclamation: AbstractModel <strong>不會</strong> 在資料庫中產生對應的 table.</p>
<p>AbstractModel 除了常常使用在之前介紹的 <a href="https://github.com/twtrubiks/odoo-demo-addons-tutorial/tree/master/demo_prototype_inheritance">demo<em>prototype</em>inheritance</a> 中,</p>
<p>也很常使用在 report 中 (自定義一些額外的邏輯),</p>
<p>可參考 odoo code 中的 <code>addons/sale/report/sale_report.py</code>,</p>
<p>```python
......
class SaleOrderReportProforma(models.AbstractModel):
<em>name = 'report.sale.report</em>saleproforma'
_description = 'Proforma Report'</p>
<pre><code>def _get_report_values(self, docids, data=None):
docs = self.env['sale.order'].browse(docids)
return {
'doc_ids': docs.ids,
'doc_model': 'sale.order',
'docs': docs,
'proforma': True
}
</code></pre>
<p>```</p>
<p>假如你的 report 有額外的邏輯, 可以將邏輯寫在 <code>_get_report_values</code> 中.</p>
<p>請一定要先了解 Transient Model, 如果不了解可參考 <a href="https://github.com/twtrubiks/odoo-demo-addons-tutorial/tree/master/demo_odoo_tutorial_wizard">demo<em>odoo</em>tutorial_wizard</a>.</p>
<p>開始今天的介紹:smile:</p>
<p>先來看 <a href="wizard/model_wizard.py">wizard/model_wizard.py</a></p>
<p>```python
class ReportWizard(models.TransientModel):
_name = 'report.wizard'
_description = "Report Wizard"</p>
<pre><code>date_start = fields.Date(string="Start Date", required=True, default=fields.Date.today)
date_end = fields.Date(string="End Date", required=True, default=fields.Date.today)
@api.multi
def download_report(self):
_logger.warning('=== CALL get_report ===')
data = {
'ids': self.ids,
'model': self._name,
'form': {
'date_start': self.date_start,
'date_end': self.date_end,
},
}
return self.env.ref('demo_abstractmodel_tutorial.action_report_abstractmodel').report_action(self, data=data)
</code></pre>
<p>......
```</p>
<p>頁面上會有一個按鈕觸發 <code>download_report</code>,</p>
<p><code>demo_abstractmodel_tutorial.action_report_abstractmodel</code> 為</p>
<p>addons name + report id (report id 後面會說明) <code>addons_name.report_id</code></p>
<p><code>report_action()</code> 會去 call <code>_get_report_values()</code>.</p>
<p><a href="wizard/model_wizard.xml">wizard/model_wizard.xml</a></p>
<p>```xml
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="custom_report_wizard">
<field name="name">Custom Report</field>
<field name="model">report.wizard</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Custom Report">
<group>
<group>
<field name="date_start"/>
</group>
<group>
<field name="date_end"/>
</group>
</group>
<footer>
<button name="download_report" string="Download Report" type="object" class="oe_highlight"/>
<button string="Cancel" special="cancel"/>
</footer>
</form>
</field>
</record></p>
<pre><code><act_window id="action_custom_report_wizard"
name="Action Custom Report"
res_model="report.wizard"
view_mode="form"
target="new"/>
<menuitem action="action_custom_report_wizard"
id="menu_custom_report_wizard"
parent="hr_expense.menu_hr_expense_reports"/>
</code></pre>
<p></odoo>
```</p>
<p>這邊定義了基本的 form, 並且將 menu 設定在 <code>hr_expense.menu_hr_expense_reports</code> 之下.</p>
<p><img src="https://i.imgur.com/BL4en9D.png" alt="alt tag"></p>
<p><img src="https://i.imgur.com/VnuJXrI.png" alt="alt tag"></p>
<p>剛剛前面提到 report id <code>action_report_abstractmodel</code> 在 <a href="reports/report.xml">reports/report.xml</a></p>
<p>```xml
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_wizard_template">
<t t-call="web.html_container">
<div class="header">
<h3 class="text-center">Expense Wizard Report</h3>
<h4 class="text-center">
<strong>From</strong>:
<t t-esc="date_start"/>
<strong>To</strong>:
<t t-esc="date_end"/>
</h4>
</div>
<div>
<table>
<thead>
<th class="text-center">Name</th>
<th class="text-center">Date</th>
<th class="text-center">Unit<em>amount</th>
</thead>
<tbody>
<t t-foreach="docs" t-as="doc">
<tr>
<td>
<span t-esc="doc['name']"/>
</td>
<td class="text-center">
<span t-esc="doc['date']"/>
</td>
<td class="text-center">
<span t-esc="doc['unit</em>amount']"/>
</td>
</tr>
</t>
</tbody>
</table>
</div>
</t>
</template></p>
<pre><code><report
id="action_report_abstractmodel"
string="Demo Report"
model="report.wizard"
report_type="qweb-pdf"
name="demo_abstractmodel_tutorial.report_wizard_template"
print_report_name="Demo Report"
/>
</code></pre>
<p></odoo>
```</p>
<p>分別設定了 template id <code>report_wizard_template</code> 以及 report id <code>action_report_abstractmodel</code>.</p>
<p><code>name</code> 的部份為 adddons name + template id.</p>
<p>也就是 <code>adddons_name.template_id</code>.</p>
<p>接著看 <a href="wizard/model_wizard.py">wizard/model_wizard.py</a> 的後半段,</p>
<p>```python
......
class ReportExpenseAbstractModel(models.AbstractModel):
<em>name = 'report.demo</em>abstractmodel<em>tutorial.report</em>wizard_template'
_description = 'Report Expense Wizard'</p>
<pre><code>@api.model
def _get_report_values(self, docids, data=None):
_logger.warning('=== CALL get_report_values ===')
date_start = data['form']['date_start']
date_end = data['form']['date_end']
docs = self.env['hr.expense'].search([
('date', '>=', date_start),
('date', '<=', date_end)], order='date asc')
return {
'doc_ids': data['ids'],
'doc_model': data['model'],
'date_start': date_start,
'date_end': date_end,
'docs': docs,
}
</code></pre>
<p>```</p>
<p>前面說過了 <code>report_action()</code> 會去 call <code>_get_report_values()</code>,</p>
<p>所以這邊定義了 <code>AbstractModel</code> 並且實作 <code>_get_report_values</code>.</p>
<p><code>_name</code> 這邊的比較特別, 要注意一下, 它的結構是由以下幾部份組成,</p>
<p>report + addons name + template id</p>
<p><code>report.addons_name.template_id</code></p>
<p>也就是 <code>report.demo_abstractmodel_tutorial.report_wizard_template</code>,</p>
<p>report 這個 prefix 很重要, 請不要任意的拿掉:exclamation::exclamation:</p>
<p><code>_get_report_values</code> 則是我們額外的邏輯, 最後將資料回傳給</p>
<p><code>report_wizard_template</code> 並且 render.</p>
<p><img src="https://i.imgur.com/XqmRovl.png" alt="alt tag"></p>