
# 一、需求背景 #
>用户在使用EAS单据转换规则(BOTP)时,BOTP中已提供的标准函数和[公式平台](https://wenku.my7c.com/link/s/MURkA),并不能完全满足在业务流转中的需要。
对于客户化开发的单据,还可以通过代码实现;但是对于标准产品的单据,如果反编译代码,则升级时相当麻烦。
因此系统提供了一种方案,方便大家进行扩展开发,解决此类问题;
>下面就带大家了解一下“**BOTP自定义函数解决方案**”
# 二、实现思路 #
## 1.实现原理 ##
>BOS 框架利用 Java 的反射技术,通过创建自定义公式类(class 实现指定的接口)实现公式逻辑,并在系统配置文件(xml)指定自定义公式类的全名,系统在运行时即会加载该类内容,从而实现 BOTP 公式自定义并且不会受升级影响。
## 2.环境说明 ##
>EAS6.0版本以上
## 3.应用场景 ##
>在单据配置BOTP时,经常需要根据一些组合条件获取指定的数据作为结果赋值到下游单据,例如以下场景:
1、单据下推生成下游单据时,需要根据传入的bostype和单据或基础资料编码作为参数获取到F7对象赋值到下游单据字段;
2、报销单生成凭证时需要根据费用类型从费用类型科目映射表中获取对应的科目;
# 三、实现步骤 #
>BOTP 自定义公式目前分为两种:
>1. 绑定目标实体(目标单据)的自定义公式;
>2. 面向所有实体(所有单据)的自定义公式;
## 1.绑定目标实体的自定义公式的实现实现步骤 ##
>通过该方法创建的自定义公式,只能被指定目标单据的 BOTP 规则引用。
>1. 在 BOS 创建一个类,实现接口 ==com.kingdee.bos.service.formula.api.IFormulaFunctions==。本文以 ==com.kingdee.eas.custom.utils.botp.formula.BotpCustomFormula== 为例。可运行的示例代码可以参考本文的 4.3 章节;
>2. 将目标实体(目标单据对应的实体 entity)的扩展属性 ==billFormulaClass== 设置为第 1 步创建的类的全名(包名+类名)==com.kingdee.eas.custom.utils.botp.formula.BotpCustomFormula==,如下图:

>3. 测试运行,打开目标单据是第 2 步指定的单据的 BOTP 单据转换规则,进入公式平台(脚
本编辑),通过“函数”页签可以看到我们刚增加的自定义公式。如下图:

>4. 测试实际的单据转换。
至此,绑定目标实体的自定义公式的开发全过程已完成。
## 2.面向所有实体(所有单据)的自定义公式的实现步骤 ##
>通过该方法创建的自定义公式,可以被任何单据的 BOTP 规则引用。
>1. 在 BOS 创建一个类,继承标准产品的类 ==com.kingdee.eas.base.dap.util.
ExtendFormulaFunctions==。可运行的示例代码可以参考本文的 4.3 章节;
>2. 修改客户端和服务端的 ServiceProviderImpl.xml 文件,该文件在 BOS 和 Server 的路径分
别为:
>BOS:
%Solution%\runtime\client\deploy\client\ServiceProviderImpl.xml
%Solution%\runtime\server\properties\ServiceProviderImpl.xml
EAS Server:
server\deploy\fileserver.ear\easWebClient\deploy\client\ServiceProviderImpl.xml
server\properties\ServiceProviderImpl.xml
用 xml 编辑器打开该文件,查找关键字“BOTP_EXTENDFUNCIONS”,将标记部分改成第
1 步创建的类名:
<configitem name="BOTP_EXTENDFUNCIONS">
<attribute key="providerName" value="==BotpCustomFormula=="/>
<attribute key="providerClassName"
value="==com.kingdee.eas.custom.utils.botp.formula.BotpCustomFormula=="/>
</configitem>
>3. 测试运行,进入 BOTP 规则的公式平台(脚本编辑),通过“函数”页签可以看到我们刚增加的自定义公式。
>4. 测试实际的单据转换。
>5. 至此,面向所有实体单据的自定义公式的开发全过程已完成。
## 3.自定义公式类代码 ##
>自定义公式类的可运行示例代码如下:
```JAVA
package com.kingdee.eas.custom.utils.botp.formula;
import java.util.List;
import java.util.Vector;
import com.kingdee.bos.BOSException;
import com.kingdee.bos.ContextUtils;
import com.kingdee.bos.framework.DynamicObjectFactory;
import com.kingdee.bos.kscript.KScriptException;
import com.kingdee.bos.service.formula.api.IFormulaFunctions;
import com.kingdee.bos.util.BOSObjectType;
import com.kingdee.eas.base.dap.util.ExtendFormulaFunctions;
/**
* 绑定目标实体的自定义公式
*/
public class BotpCustomFormula extends ExtendFormulaFunctions {
//用于存放公式的变量
private static Vector funcInfos;
public static final String __BOTgetOVByBosType = "__BOTgetOVByBosType";
static{
//加载类时定义自定义公式
funcInfos = new Vector();
//FuncInfo()的第一个参数是公式名,第二个参数是公式所在的分类(可随便取名),第三个参数是公式的描述信息(在 BOTP 公式平台显示)
funcInfos.add(new FuncInfo(__BOTgetOVByBosType, "自定义公式", "通过业务单元的BosType 和编码获取对应的值对象(F7)\n__BOTgetOVByBosType(String number, String bosType),返回值为 IObjectValue。"));
}
/**
* 运行时 BOTP 公式平台加载自定义公式时,就是从该返回值里取公式的名称的
* @return 所有自定义公式的名称
*/
public String[] getAllFuncNames(){
String as[] = new String[funcInfos.size()];
f