Author: |
My Company |
License: |
no license |
Branch: |
master |
Repository: |
twtrubiks/odoo-demo-addons-tutorial |
Dependencies: |
account |
Languages: |
Markdown (103, 52.0%),
Python (37, 18.7%),
and
XML (58, 29.3%) |
<h1>odoo 觀念 - multi company</h1>
<p>建議觀看影片, 會更清楚:smile:</p>
<p><a href="https://youtu.be/u8u0eRzY8kg">Youtube Tutorial - odoo 手把手教學 - multi company - part1</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>本篇文章主要介紹 odoo 中的 multi company 的一小部份:smile:</p>
<p>因為 multi company 的方法有很多種.</p>
<h2>說明</h2>
<p>首先, odoo 在 Multi-company 的設計上是有很多想法以及方法的,</p>
<p>可參考官方文件 <a href="https://www.odoo.com/documentation/14.0/developer/howtos/company.html">Multi-company Guidelines</a> 觀看.</p>
<p>(補充一下, 從 odoo13 開始, Multi-company 的概念有改動, 但不影響本篇的教學:relaxed:)</p>
<p>今天主要是要介紹 fields 中的一個參數 <code>company_dependent=True</code>,</p>
<p>這個參數主要是為了 Multi-company 設計的.</p>
<p>寫法很簡單, 就是在 model 中加入參數即可</p>
<p><a href="https://github.com/twtrubiks/odoo-demo-addons-tutorial/blob/master/demo_multi_company/models/model.py">models/model.py</a></p>
<p>```python
......</p>
<p>class DemoCompany(models.Model):
_name = 'demo.company'
_description = 'Demo Company'</p>
<pre><code>name = fields.Char('Description', required=True)
property_account_receivable_id = fields.Many2one('account.account',
company_dependent=True,
string="Account Receivable",
domain="[('internal_type', '=', 'receivable'), ('deprecated', '=', False)]",
required=True)
company_id = fields.Many2one('res.company', string='Company', required=True, readonly=True, default=lambda self: self.env.user.company_id)
</code></pre>
<p>......
```</p>
<p>主要就是 <code>property_account_receivable_id</code> 中的 <code>company_dependent=True</code>.</p>
<p>在 view 的介面底下是可以看到這個欄位</p>
<p><img src="https://i.imgur.com/fRZ4ioI.png" alt="alt tag"></p>
<p>如果你有多公司, 切換到其他的公司, 你會發現這個欄位有可能會變空的.</p>
<p>(切換公司時, 內容也會不一樣, 注意這邊是相同的 record)</p>
<p><img src="https://i.imgur.com/HCFwDd3.png" alt="alt tag"></p>
<p>但你在 db 中的 <code>demo_company</code> 不會有 <code>property_account_receivable_id</code> 的欄位</p>
<p><img src="https://i.imgur.com/fz0aK8h.png" alt="alt tag"></p>
<p>這邊你可能會覺得很奇怪, 但這就是他特別的地方:smile:</p>
<p>那他會存在哪裡呢:question:</p>
<p>他會存在 <code>ir_property</code> 中</p>
<p><img src="https://i.imgur.com/I9T8uVx.png" alt="alt tag"></p>
<p>在後台的部份, 也可以看到 <code>ir_property</code> 的東西</p>
<p>路徑在 <code>Technical -> Parameters -> Company Properties</code></p>
<p><img src="https://i.imgur.com/Xf55Oip.png" alt="alt tag"></p>
<p>裡面的值, 紀錄著 model 和 id</p>
<p><img src="https://i.imgur.com/k3VIApY.png" alt="alt tag"></p>
<p>然後請把 Resource(res_id) 手動清空,</p>
<p><img src="https://i.imgur.com/AZir7v0.png" alt="alt tag"></p>
<p>等下要示範使用以下的 code 來取值</p>
<p><code>python
self.env['ir.property'].with_context(force_company=self.company_id.id).get('property_account_receivable_id', 'demo.company')
</code></p>
<p>要清空的原因是因為其他的 Company Properties 很多是使用 code 的方式產生的</p>
<p>原始碼中的 <code>odoo/addons/account/models/chart_template.py</code></p>
<p><code>python
@api.multi
def generate_properties(self, acc_template_ref, company):
......
PropertyObj = self.env['ir.property']
todo_list = [
('property_account_receivable_id', 'res.partner', 'account.account'),
('property_account_payable_id', 'res.partner', 'account.account'),
('property_account_expense_categ_id', 'product.category', 'account.account'),
('property_account_income_categ_id', 'product.category', 'account.account'),
('property_account_expense_id', 'product.template', 'account.account'),
('property_account_income_id', 'product.template', 'account.account'),
]
</code></p>
<p><code>property_account_receivable_id</code> <code>property_account_payable_id</code> ... 都是 code 產生的.</p>
<p>(這些透過 code 產生的值 res_id 都是 False)</p>
<p>而 Resource(res<em>id) 清空的原因則是因為原始碼中的 `odoo/addons/base/models/ir</em>property.py`</p>
<p>```python
......</p>
<p>def <em>get</em>property(self, name, model, res<em>id):
domain = self.</em>get<em>domain(name, model)
if domain is not None:
domain = [('res</em>id', '=', res<em>id)] + domain
#make the search with company</em>id asc to make sure that properties specific to a company are given first
return self.search(domain, limit=1, order='company_id')
return self.browse(())</p>
<p>......
```</p>
<p>通常 domain 這邊的 res_id 會是 False. (如果有值就會被過濾掉)</p>
<p>```python
class DemoCompany(models.Model):
_name = 'demo.company'
_description = 'Demo Company'</p>
<pre><code>......
def action_get_default_account(self):
default_account = self.env['ir.property'].with_context(force_company=self.company_id.id).get('property_account_receivable_id', 'demo.company')
_logger.warning(default_account)
_logger.warning(self.property_account_receivable_id)
_logger.warning('============= HELLO ==================')
</code></pre>
<p>```</p>
<p>點選這個按鈕可以觸發這個 function</p>
<p><img src="https://i.imgur.com/X5xPuZ5.png" alt="alt tag"></p>
<p>你會發現輸出一樣的資訊</p>
<p>一個是透過 company<em>id 找出當下對應的 model 中的 `property</em>account<em>receivable</em>id`,</p>
<p>另一個則是直接呼叫 model 中的 <code>property_account_receivable_id</code>.</p>
<p><img src="https://i.imgur.com/k5KTLXH.png" alt="alt tag"></p>
<p>當你嘗試著新增 record, 你會發現 <code>property_account_receivable_id</code> 預設都會有值</p>
<p>(這也是為甚麼我和大家說要清空 res_id 的原因, 因為 odoo 的 code 中是這樣設定的, 前面有說明)</p>
<p><img src="https://i.imgur.com/e4vLm0A.png" alt="alt tag"></p>