SuiteCRM 的这套 hook 机制还是挺灵活的。就是文档有的少,大部分靠摸索。
部署时,只能在工作日晚上,或者周末没人使用时才能部署。异常痛苦。
关联记录存储时相关的 hook
这个属于 Module Hooks,即模块级的 Hook。
- after_relationship_add
- after_relationship_delete
除了关系的添加和删除,实际上应该还有收款记录的值修改需要监听。
- after_save
看起来,在合同模块添加 Hook,不如在收款记录模块添加 Hook 更方便管理。因为统计函数能够复用。
后续补充:
这里还是想简单了。关系的添加和收款金额变更这两种情况可以加到收款记录模块的 logic hook 中。
但是,关系的删除,只能加到合同模块的 logic hook 中,因为关系删除的同时,通常也把收款记录删除了。所以不能放到收款记录模块中。
记录展示时相关的 hook
上面是通过更新增加的自定义统计字段实现的回款率计算,还有一种方式是在展示合同时,才查询的做法:
- process_record:Fired when a record is processed ready to be displayed in list views or dashlets. 及在列表展示时触发
- after_retrieve:Fired after a record is retrieved from the DB. 需要注意,这个可能会触发多次。相当于每次从数据库去读取时,都会触发。实际测试,在 Account 详情页,刷新一次,被触发三次这个钩子。
这种做法,是平时自己写程序时的标准做法。
但是,SuiteCRM 由于钩子机制不可控。
我觉得用来做简单的数据格式化,没问题。要是用来触发关联记录查询,就得防止造成数据库的查询压力。
如何确认关联关系的名称
即 relationship name.
比如,合同模块关联了收款模块,一条合同记录会关联多条收款记录。
那么就需要在 logic hook 中知道这个关系的名称是什么,否则无法获取相关的数据。
查看方法一:
使用管理员账号,在系统管理中,工作室 - 相关模块 - 关联关系。
这里就能看到对应的关联名称,即对应模块。
例如,合同与收款记录的关联关系名为:
aos_contracts_skgl_shoukuanguanli_1
查看方法二:
进入 SuiteCRM 项目代码根目录,查看代码文件:
cache/modules/skgl_shoukuanguanli/skgl_shoukuanguanlivardefs.php
这个非内置模块,估计是基于中文名字的拼音自动生成的。
在代码中搜索 relationship 关键词,就能找到跟合同 Contract 的相关信息。
'aos_contracts_skgl_shoukuanguanli_1' =>
array (
'name' => 'aos_contracts_skgl_shoukuanguanli_1',
'type' => 'link',
'relationship' => 'aos_contracts_skgl_shoukuanguanli_1',
'source' => 'non-db',
'module' => 'AOS_Contracts',
'bean_name' => 'AOS_Contracts',
'vname' => 'LBL_AOS_CONTRACTS_SKGL_SHOUKUANGUANLI_1_FROM_AOS_CONTRACTS_TITLE',
'id_name' => 'aos_contracts_skgl_shoukuanguanli_1aos_contracts_ida',
),
对应的,在 cache/modules/AOS_Contracts/AOS_Contractsvardefs.php 中看到的关系信息是:
'aos_contracts_skgl_shoukuanguanli_1' =>
array (
'name' => 'aos_contracts_skgl_shoukuanguanli_1',
'type' => 'link',
'relationship' => 'aos_contracts_skgl_shoukuanguanli_1',
'source' => 'non-db',
'module' => 'skgl_shoukuanguanli',
'bean_name' => 'skgl_shoukuanguanli',
'side' => 'right',
'vname' => 'LBL_AOS_CONTRACTS_SKGL_SHOUKUANGUANLI_1_FROM_SKGL_SHOUKUANGUANLI_TITLE',
),
小知识: AOS 前缀
从上面的关系信息中可以看到,合同模块的名字为 AOS_Contracts。而合同和联系人分别是 Account 和 Contact。为何有的带 AOS 前缀,有的不带呢?suitecrm AOS prefix 代表什么?
在 SuiteCRM 中,AOS(Advanced OpenSales)是一个模块,用于管理销售、报价和发票等相关业务。AOS prefix 是指 AOS 模块中用于标识相关数据库表的前缀。在 SuiteCRM 中,数据库表名通常使用特定的前缀来标识所属的模块。AOS prefix 是 AOS 模块相关表的前缀,它通常为 "aos_"。例如,AOS 模块中的报价表的完整数据库表名可能是 "aos_quotes",其中 "aos_" 就是 AOS prefix。
通过使用前缀,SuiteCRM 可以确保不同模块的数据库表之间不会发生冲突,并提供更好的模块化和数据结构管理。
如何判断具体是哪个 relationship 发生了变化
以 after_relationship_add 触发为例,单单判断了事件名是否是 after_relationship_add 是不够的。还需要判断具体是新增了哪种关联关系。
例如,合同模块就好多个关联关系,不能因为一个不相关的关系建立,就每次都把收款记录都重新统计一遍。
参考 ChatGPT 给出的建议:
在 after_relationship_add
触发器中,$arguments
参数包含以下键值对:
-
module
: 触发关联操作的模块名。 -
related_module
: 被关联的模块名。 -
related_id
: 被关联记录的 ID。 -
relationship
: 关联关系的名称。 -
related_bean
: 被关联记录的 Bean 对象。
而通过 github 上的参考代码,结合实际,发现用 related_module 来判断非常合适。以联系人关联的客户为例:
public function addPayment($bean, $event, $arguments)
{
$GLOBALS['log']->fatal('event: ' . $event);
$GLOBALS['log']->fatal('related module: ' . $arguments['related_module']);
if ($arguments['related_module'] == 'Accounts') {
// do something
}
}
自定义字段
使用自定义字段前,必须显示拉取一次么?
$project->custom_fields->retrieve();
调试
网上查到的代码真是千差万别,只能本地搭建一套开发环境,一点点打印日志调试了。 我觉得直接在服务器上重新部署一个测试版本的更简单方便。
调试前的备份
- 备份数据库
- 备份项目目录
after_save 失败
应该是 $argument 参数,不包含 related_module 这个 key。
果然是这个问题,将这行代码删除即可。
after_relationship_delete 失败
现象是,读取不到相关联的合同。
这里不单是关联关系删除了,同时回款记录也删除了。
所以读取不到关联关系也很合理。
正确的做法应该是,去合同模块那里去实现一个 after_relationship_delete 的钩子。
参考
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式