模組互動
在上一章中,我們使用繼承來修改模組的行為。在我們的房地產場景中,我們希望更進一步,能夠為客戶生成發票。Odoo提供了一個開發票模組,因此直接從我們的房地產模組建立發票是很簡單的,也就是說,一旦某個房產設定為“已售出”,就會在Invoicing
應用程式中建立發票
一個具體示例: 記賬憑證(Account Move)
目標: 本節結束時:
建立一個
estate_account
模組建立房產時,為購買者開發票
預期效果動畫地址:https://www.odoo.com/documentation/14.0/zh_CN/_images/create_inv.gif
每當我們與另一個模組互動時,我們都需要記住模組化。如果我們打算將我們的應用程式賣給房地產代理,有些人可能想要發票功能,但有些人可能不想要。
連結模組(Link Module)
此類使用案例的常見方法是建立“連結”模組。在我們的案例中,該模組依賴estate
和account
,包括房產的發票建立邏輯。採用這種方式,estate
和account
模組可以獨立安裝。當兩者都安裝後,連結模組將提供新功能。
練習--建立連結模組
建立依賴estate
和account
的 estate_account
空殼模組,建立以後安裝該模組。你可能會注意到,Invoicing
應用也被安裝了。這是意料之中的,因為你的模組依賴它。 如果你解除安裝Invoicing
模組,你的模組也會被解除安裝。
說明:__init__.py
為空
重啟服務,安裝模組
建立發票
是時候生成發票了。我們希望為estate.property
模型新增功能,即我們希望在出售房產時新增一些額外的邏輯。
第一步,我們需要擴點選“Sold”按鈕時呼叫的操作。為此,我們需要在estate_account
模組中為建立一個模型,繼承estate.property
模型。現在,重寫操作,僅返回super
呼叫,拿個例子來說可能更清楚:
from odoo import models
class InheritedModel(models.Model):
_inherit = "inherited.model"
def inherited_action(self):
return super().inherited_action()
可以在這找個具體的示例
class AccountMove(models.Model):
_name = "account.move"
_inherit = ['portal.mixin', 'mail.thread', 'mail.activity.mixin', 'sequence.mixin']
_description = "Journal Entry"
#... 略
def action_invoice_paid(self):
''' Hook to be overrided called when the invoice moves to the paid state. '''
pass
class AccountMove(models.Model):
_inherit = 'account.move'
def action_invoice_paid(self):
""" When an invoice linked to a sales order selling registrations is
paid confirm attendees. Attendees should indeed not be confirmed before
full payment. """
res = super(AccountMove, self).action_invoice_paid()
self.mapped('line_ids.sale_line_ids')._update_registrations(confirm=True, mark_as_paid=True)
return res
練習--新增建立發票的第一步
- 在
estate_account
模組中的正確目錄建立estate_property.py
檔案 _inherit
estate.property
模組- 重寫
action_sold
方法(你可能已經將該方法命名為不同的名稱了) 以返回super
呼叫
提示: 為了確保它正常工作,新增一個print
或者除錯斷點到重寫的方法中。
新增以下檔案:
odoo14\custom\estate_account\models\__init__.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from . import estate_property
odoo14\custom\estate_account\models\estate_property.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from odoo import models
class InheritedEstateProperty(models.Model):
_inherit = "estate.property"
def set_property_sold(self):
return super().set_property_sold()
修改odoo14\custom\estate_account\__init__.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from . import models
它有效嗎?如果沒有,請檢查是否正確匯入了所有Python檔案。
如果重寫生效,我們可以繼續建立發票。不幸的是,沒有一種簡單的方法可以知道如何在Odoo中建立任何給定的物件。大多數時候,有必要檢視其模型,以找到所需的欄位並提供適當的值。
學習的一個好方法是看看其他模組是如何完成你想做的事情的。例如,銷售的一個基本流程是從銷售訂單建立發票。這看起來是一個很好的起點,因為它正是我們想要做的。花一些時間思考和理解建立發票方法。
為了建立了發票,我們需要以下資訊:
- 一個
partner_id
: 顧客 - 一個
move_type
: 它有幾個可能的值 journal_id
: the accounting journal
這足夠建立一個張空發票。
練習--新增發票建立第二步
重寫action_sold
,並建立一個空的 account.move
:
- 從當前的
estate.property
獲取partner_id
move_type
應該和Customer Invoice
對應
提示:
- 使用
self.env[model_name].create(values)
建立一個物件, 其中values
為一個字典。 create
方法不接受結果集作為欄位值。
修改odoo14\custom\estate_account\models\estate_property.py
def set_property_sold(self):
self.env['account.move'].create({})
return super().set_property_sold()
當房產設定為“已售出”時,你現在應該在Invoiceing/customer/Invoices
中建立一個新的客戶發票。
顯然,到目前為止,我們沒有任何發票行。要建立發票行,我們需要以下資訊:
name
:發票行的描述quantity
price_unit
此外,發票行需要連結到發票。將發票行連結到發票的最簡單、最有效的方法是在建立發票時包含所有行。為此在account.move
建立中包含invoice_line_ids
欄位,這是一個One2many
欄位。One2many
和Many2many
使用通用ORM方法中描述的特殊“commands”。這種格式是一個按順序執行的三元組列表,其中每個三元組都是要對結果集執行的命令。下面是一個在建立test.model
時包含一個One2many
欄位line_ids
的簡單示例:
def inherited_action(self):
self.env["test.model"].create(
{
"name": "Test",
"line_ids": [
(
0,
0,
{
"field_1": "value_1",
"field_2": "value_2",
},
)
],
}
)
return super().inherited_action()
練習--新增建立發票的第三步
建立account.move
時新增兩個發票行。每個售出的房產都將按照以下條件開具發票:
- 售價的6%
- 額外100.00行政費
提示:按照上面的示例在建立時新增invoice_line_ids
。對於每個發票行,我們需要一個 name
, quantity
和price_unit
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from odoo import models
from odoo.exceptions import UserError
class InheritedEstateProperty(models.Model):
_inherit = "estate.property"
def set_property_sold(self):
print('override set_property_sold')
journal = self.env['account.move'].with_context(default_move_type='out_invoice')._get_default_journal()
if not journal:
raise UserError('Please define an accounting sales journal for the company')
self.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': self.buyer_id,
'journal_id': journal.id, # company comes from the journal
'invoice_line_ids': [{
'name': 'Avaliable house 01',
'quantity': 1,
'price_unit': 0.6 * self.best_price
},{
'name': ' Administrative fees',
'quantity': 1,
'price_unit': 100
}]
})
return super().set_property_sold()
重啟服務,驗證效果