PSI开源进销存实施指南PSI开源进销存实施指南
使用手册
系统管理
二次开发
使用手册
系统管理
二次开发
  • 实施配置
    • 解决方案
    • 主菜单维护
    • 码表设置
    • 自定义表单
    • 视图开发助手
    • 系统数据字典
    • FId一览
  • 编码开发

    • 独立模块
      • 如何新增一个模块

自定义表单


在PSI开源进销存中,自定义表单是指具有如下特征的业务单据:

  • 有单号,且单号全局唯一

  • 单据是主从结构,即一个主表+多个子表,其中最常见的是一个主表+一个子表的结构

创建自定义表单后,通过权限管理设置使用者权限,然后用主菜单维护把自定义表单挂接在主菜单中

重要提醒

自定义表单的应用的第一步实际上是数据库建模。自定义表单能快速创建业务单据,但是具体到每张业务单据,其后台的数据库表结构是需要根据业务需求做仔细的数据库建模的。

主表字段引用码表数据

业务单据中引用码表数据,这是一个显而易见的的常用功能。正是因为这个功能,系统数据才能共享和流转。

  • 业务单据中保存码表数据的id,由此实现引用的基本功能。这类似数据库主外键关系。

  • 业务单据中除了保存码表数据的id之外,还会保存码表的编码(code)和名称(name)。这是冗余数据,但是简化了系统设计。存在码表数据修改后的不一致问题,但是可以通过id来后台维护统一的途径。

业务单据中保存码表id、code和name的惯例

  • 保存id的字段名称,可以自由命名,但是习惯上以id结尾,例如:supplier_id

  • 保存code和name的字段名称的命名规律是:id字段名_code和id字段名_name。例如:当保存id的字段名为supplier_id的时候,code和name对应的名称分别为supplier_id_code和supplier_id_name。本约定由程序自动生成,不可调整。

  • 一个字段当其值来源被设为引用码表的时候,该字段就被用来保存id,并自动生成code和name字段。注意:code和name字段在元数据中不可见,只存在于数据库表结构中。同时,该字段的编辑器需要指定为psi_codetable_formfield,以便正确地创建UI。

每个业务单据都自带的字段:业务员(biz_user_id),就是典型的业务单据中保存码表id、code和name,参考该字段,可以帮助理解。

更复杂的引用码表数据场景

上述是引用了码表的id、code和name字段。更复杂的场景需要引用码表更多的数据,例如:在采购订单中,用户录入完供应商字段,希望把供应商的联系人、收货地址和电话一并引用过来,并保存在采购订单中。

这是就需要设置码表引用,并建立码表字段和表单字段的对应关系。

明细表字段引用码表数据

明细表字段引用码表数据和主表字段略有不同。差异的原因是:当明细字段引用码表的时候,后台不自动创建code和name字段,所有的字段需要手工创建。

下面以业务单据引用物料这个码表为例,做一个详细说明。

物料这个码表,在给业务单据引用的时候,并不是直接使用t_goods这个表,而是数据库视图v_goods。用数据库视图的原因是:物料计量单位并不在t_goods表中,而业务单据中引用物料通常需要一并引用计量单位。这种使用数据库视图来形成一个码表的做法,是一个基础的应用技巧。

我们假设业务单据需要引用物料的id、编码(code)、名称(name)、规格型号(spec)和计量单位(unit_name)这五个属性的值。

  1. 在业务单据的明细表中创建五个字段:goods_id、goods_code、goods_name、goods_spec、 unit_name

  2. goods_id的属性对用户可见设置为:对用户不可见。 这样在UI上用户就不能看见了。

  3. goods_code是核心字段,其值来源设置为:引用码表。

  4. goods_name、goods_spec和unit_name这三个字段是只读性质的,把其编辑器类型设置为:displayfield

  5. 设置码表引用中的字段对应关系,如下图所示

子表索引1表示是第一个明细表,表单字段名goods_code上面我们创建的表单字段。

完成上述设置后,表单五个字段:goods_id、 goods_code、 goods_name、 goods_spec、unit_name中就只有goods_code这个字段是用户通过UI录入的,其他字段由系统根据码表引用中的字段对应关系自动赋值。

关于数据冗余字段

引用码表数据的时候,在业务单据本身上创建了很多冗余字段,这样做有如下的一些设计考量:

  1. 简化自定义表单展示数据的逻辑,同时提高运行速度。这是典型的空间换时间的做法。

  2. 既然是冗余字段,就存在码表数据变更后,数据不一致的问题。可以通过保存的id来同步数据,这需要额外的二次开发。

举一个这种冗余设计的应用场景,某个长期供应商,在合作两年后发生了公司名称变更。前两年的历史单据中的供应商名称通常是不应该改为新的名称的。所以,是否同步历史数据是需要根据业务仔细分析的。

编程扩展自定义表单

用户除了使用配置元数据的方式来扩展自定义表单之外,还可以通过编程来进一步扩展自定义表单。

编程扩展自定义表单不是万能方法,遇到自定义表单不能实现的需求,最终采用手工编码是不可避免的。

前端编程扩展

前端主要是扩展按钮。使用自定义表单中的业务按钮和Mixin(业务按钮扩展库)就能自由新增按钮。

事实上,自定义表单现有的新建、编辑等按钮操作的实现方式就是上述方式。可以通过阅读现有的代码来理解如果扩展按钮。

从技术原理来说,Mixin可以扩展自定义表单前端代码的所有内部方法,但是这目前还处于技术预研阶段,尚不推荐使用。

后端编程扩展

指定自定义表单的业务逻辑类名,就能扩展后台PHP代码。这个设计思路和码表的自定义业务逻辑的方法是一致的。

业务逻辑切入点处理函数说明
新建单据afterAdd函数返回null表示可以继续执行新建操作;
返回字符串则会作为提示信息返回给用户,同时不执行新建操作(数据库事务会回滚)
编辑单据afterUpdate函数返回null表示可以继续执行编辑操作;
返回字符串则会作为提示信息返回给用户,同时不执行编辑操作(数据库事务会回滚)
删除单据beforeDelete函数返回null表示可以执行删除操作;
返回字符串则会作为提示信息返回给用户,同时不执行删除操作(数据库事务会回滚)
获取默认值getDefaultValues函数返回null表示无默认值;
返回array,array中的键是字段名称,对应的就是该字段的默认值
尚未实现
审核单据afterCommit函数返回null表示可以执行审核操作; 返回字符串则会作为提示信息返回给用户,同时不执行审核操作(数据库事务会回滚)
取消审核单据beforeCancelCommit函数返回null表示可以执行取消审核操作; 返回字符串则会作为提示信息返回给用户,同时不执行取消审核操作(数据库事务会回滚)

范例代码见: Demo

业务扩展类需要使用#[FormPlugin]这个Attribute来标注,避免诸如把码表的扩展类被误设置为表单的扩展类。

表单状态

表单状态是业务单据中重要的后台字段,用于控制工作流。

表单状态(数据库字段名:bill_status),其值取自系统数据字典t_sysdict_sln0000_form_status,这是系统的默认实现,可以根据具体的业务需求调整为自行设计的其他系统数据字典,但是要遵循如下规则:

状态值说明
-1-1表示全部单据,用于主界面查询条件中使用,实际单据中不存储该值
00表示单据处于待审核状态,该状态下,单据实质上草稿状态,可以被编辑和删除
10001000表示单据已经被审核,该状态下,单据不能再被编辑和删除,是正式生效的业务单据
大于1000留给用户扩展,建议从2000开始使用

-1、0和1000这三个值在数据字典中必须存在,且不能改变其上述含义

自定义表单中使用审核来表示单据正式生效,可以参与到业务工作流中了(例如:审核的采购订单才可以生成采购入库单)。
如果要做类似OA系统中的工作流的流转,建议使用审批来表达。

上一页面
码表设置
下一页面
视图开发助手