第十四章 与其他模块交互
在前一章节中,我们使用继承来修改模块的行为。在我们的房地产场景里,我们想多走一步能够为我们的客户生成发票。 odoo提供了发票模块,所以在我们的房地产模块中生成发票是方便的,也就是说,一旦一处房产被标记为卖出,一个发票就在发票模块里生成了。
具体例子: 账户移动(Account Move)
Note
Goal: at the end of this section:
- 新建一个estate_account模块
- 当房产被卖出,应该为买方开具发票
每当我们与另一个模块交互时,都要考虑到模块化。 如果我们将应用卖给真实的房地产代理商,有些希望有发票模块,而有些可能希望没有。
连接模块(Link Module)
通用方法是建立一个连接模块,我们的场景,该模块依赖于estate和account两个模块,并且在estate property中包含发票的创建逻辑。 这种方式,estate和account模块可以独立的安装,当两者都安装好之后,连接模块就可以提供新的特性。
练习:
创建一个连接模块
新建estate_account 模块,它依赖于estate
and account
modules, 现在它还只是一个空壳
当estate_account模块出现在列表中时,安装它!你会注意到Invoicing 应用程序也安装好了,这是因为我们的模块依赖它,如果你卸载了Invoicing应用,你的模块也将会被卸载。
Invoice Creation
是时候生成发票了,我们想给estate.property
模型添加功能,也就是说 我们想当房产被售出的时候添加一些额外的逻辑。 听着耳熟码? 如果不是你要回头去复习一下了,可能错过了一些东西;-)
第一步,我们需要扩展点击售出按钮的动作, 要做到这点,我们需要在estate_account模块中 新建一个estate.property模型的继承类。 然后重写action返回super call,也许一个例子能让这个事情更清晰:
from odoo import models
class InheritedModel(models.Model):
_inherit = "inherited.model"
def inherited_action(self):
return super().inherited_action()
A practical example can be found here.
练习:
创建发票的第一步
- 在
estate_account
模块中合适的目录下新建estate_property.py文件 - 继承
estate.property
模型. - 重写do_sold(你的方法名可能不一样)方法 to return the
super
call.
from odoo import models,fields,api
class EstateProperty(models.Model):
_inherit = "estate.property"
def do_sold(self):
print("do_sold in estate_account")
return super().do_sold()
Tip: 为了确认它工作,可以增加print语句或者设置断点在重载的方法里。
它工作码? 如果没有,请检查所有的python文件都正确的导入了。
如果重载的方法正常工作了,我们可以进一步去创建发票了。不幸的是,在odoo中没有太容易的办法去创建一个给定的对象,大多时候,去看一下模型的定义查找一下required字段并提供合适的值是必要的。
一个好办法是看看其他模块是怎么做到你想做的事情的。例如,一个基本的销售流程也会从销售订单创建发票。这貌似一个好的开始,因为这确实是我们想做的。 花点时间阅读并理解_create_invoices 方法,当你因为这个简单的任务看起来非常复杂而哭泣时,我们可以往前翻翻教程。
新建一个发票,我们就要下列信息:
- a
partner_id
: the customer - a
move_type
: it has several possible values
move_type = fields.Selection(selection=[
('entry', 'Journal Entry'),
('out_invoice', 'Customer Invoice'),
('out_refund', 'Customer Credit Note'),
('in_invoice', 'Vendor Bill'),
('in_refund', 'Vendor Credit Note'),
('out_receipt', 'Sales Receipt'),
('in_receipt', 'Purchase Receipt'),
], string='Type', required=True, store=True, index=True, readonly=True, tracking=True,
default="entry", change_default=True)
- a
journal_id
: the accounting journal 日志id? 关联到这个表 account_journal
这些足够创建一张发票了
练习:第二步创建发票
新建一章空的account.move 在重载的action_sold方法里。
- the
partner_id
从estate.property
中取 - the
move_type
should correspond to a ‘Customer Invoice’
Tips:
- 新建一个对象,用`self.env[model_name].create(values) values是一个字典
- create方法不接受记录集作为字段值。
from odoo import models,fields,api
class EstateProperty(models.Model):
_inherit = "estate.property"
def do_sold(self):
print("do_sold in estate_account")
values = {
"partner_id" : self.buyer.id,
"move_type" : 'out_invoice',
"journal_id" : 1
}
# journal_id account_journal
self.env["account.move"].create(values)
return super().do_sold()
当一个处房产被设置成“已售出”,在Invoicing / Customers / Invoices创建了一张新的客户发票。
很明显到目前为止,我们没有任何发票明细。 要创建发票明细信息,需要下列信息:
name
: a description of the linequantity
price_unit
发票明细信息需要链接到一张发票,最简单和有效的方法是在新建发票的时候包含所有的明细。 要做到这些,invoice_line_ids字段要在account.move中,这是一个一对多字段,一对多和多对多使用特殊的“命令”,使用人类容易阅读的格式在Command命名空间中。 在记录集上执行三元组命令,这个三元组命令以前是唯一的方法,但是现在使用命名空间代替了。 格式是放在一个列表中顺序的执行,这里有一个简单的例子包括One2many 字段 line_ids 在创建test.model的时候。
from odoo import Command
def inherited_action(self):
self.env["test.model"].create(
{
"name": "Test",
"line_ids": [
Command.create({
"field_1": "value_1",
"field_2": "value_2",
})
],
}
)
return super().inherited_action()
练习
创建发票的第三步
给account.move增加两个行信息,售出的每一处房产将按照以下条件开具发票:
- 6% of the selling price
- 额外的100美元的管理费用
Tip: 按照上面的例子增加 invoice_line_ids
对于每一行,我们需要 name
, quantity
and price_unit
.
from odoo import models, fields, api, Command
class EstateProperty(models.Model):
_inherit = "estate.property"
def do_sold(self):
print("do_sold in estate_account")
values = {
"partner_id" : self.buyer.id,
"move_type" : 'out_invoice',
"journal_id" : 1,
"invoice_line_ids": [
Command.create({
"name": "增值税",
"quantity": 1,
"price_unit": self.selling_price*0.06,
}),
Command.create({
"name": "额外的费用",
"quantity": 1,
"price_unit": 100,
})
],
}
# journal_id account_journal
self.env["account.move"].create(values)
return super().do_sold()
这一章可能是到目前为止最难的一章,但是它是最接近odoo实际开发的。下一章,我们将介绍Odoo的模板系统。
财务知识是不是要补一补?