BOTP自定义公式解决方案

v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VML);} .shape {behavior:url(#default#VML);}

<!--[if !supportLists]-->

原来的BOTP自定义公式解决方案只介绍了绑定目标实体的BOTP公式开发方法,现已加入面向所有实体(单据)的BOTP公式开发方法,应用场景如,要做一个根据BosType和ID获取值对象的公式,该公式很明显就是对所有实体通用的。开发方案详见下面正文,原解决方案见附件V1.0部分。

====================正文=============================

1.    <!--[endif]-->需求背景

运行时BOTP公式平台提供的函数较少,如果要实现比较复杂或个性化的逻辑,譬如通过物料编码从其他单据取出对应数量,运行时的公式平台就显得捉襟见肘了。对于客户化开发的单据,还可以通过写硬代码实现。但是对于标准产品的单据,如果反编译代码,则升级时相当麻烦。而自定义公式方案正是为了解决此难题而生。

<!--[if !supportLists]-->2.    <!--[endif]-->实现原理

BOS框架利用Java的反射技术,通过创建自定义公式类(class实现指定的接口)实现公式逻辑,并在系统配置文件(xml)指定自定义公式类的全名,系统在运行时即会加载该类内容,从而实现BOTP公式自定义并且不会受升级影响。

<!--[if !supportLists]-->3.    <!--[endif]-->环境说明

本方案在EAS60SP1上测试验证过,其他版本可参考。

<!--[if !supportLists]-->4.    <!--[endif]-->实现方法

BOTP自定义公式目前分为两种:

<!--[if !supportLists]-->1.       <!--[endif]-->绑定目标实体(目标单据)的自定义公式;

<!--[if !supportLists]-->2.       <!--[endif]-->面向所有实体(所有单据)的自定义公式

<!--[if !supportLists]-->4.1.       <!--[endif]-->绑定目标实体的自定义公式实现方法

通过该方法创建的自定义公式,只能被指定目标单据的BOTP规则引用。

<!--[if !supportLists]-->1.       <!--[endif]-->在BOS创建一个类,实现接口com.kingdee.bos.service.formula.api.IFormulaFunctions。本文以com.kingdee.eas.custom.gz.utils.botp.formula. BotpCustomFormula为例。可运行的示例代码可以参考本文的4.3章节;

<!--[if !supportLists]-->2.       <!--[endif]-->将目标实体(目标单据对应的实体entity)的扩展属性billFormulaClass设置为第1步创建的类的全名(包名+类名)com.kingdee.eas.custom.gz.utils.botp.formula. BotpCustomFormula,如下图:


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


<!--[if !supportLists]-->4.       <!--[endif]-->测试实际的单据转换。

至此,绑定目标实体的自定义公式的开发全过程已完成。

<!--[if !supportLists]-->4.2.       <!--[endif]-->面向所有实体(所有单据)的自定义公式

通过该方法创建的自定义公式,可以被任何单据的BOTP规则引用。

<!--[if !supportLists]-->1.       <!--[endif]-->在BOS创建一个类,继承标准产品的类com.kingdee.eas.base.dap.util. ExtendFormulaFunctions。可运行的示例代码可以参考本文的4.3章节;

<!--[if !supportLists]-->2.       <!--[endif]-->修改客户端和服务端的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步创建的类名:

    <!-- BOTP扩展公用函数-->

    <configitem name="BOTP_EXTENDFUNCIONS">

      <attribute key="providerName" value="BotpCustomFormula"/>

      <attribute key="providerClassName" value="com.kingdee.eas.custom.gz.utils.botp.formula.BotpCustomFormula"/>

</configitem>

<!--[if !supportLists]-->3.       <!--[endif]-->测试运行,进入BOTP规则的公式平台(脚本编辑),通过“函数”页签可以看到我们刚增加的自定义公式。

<!--[if !supportLists]-->4.       <!--[endif]-->测试实际的单据转换。

<!--[if !supportLists]-->5.       <!--[endif]-->至此,面向所有实体单据的自定义公式的开发全过程已完成。

<!--[if !supportLists]-->4.3.       <!--[endif]-->自定义公式类代码

自定义公式类的可运行示例代码如下:

package com.kingdee.eas.custom.gz.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;

/**

* @author House

* @email yyh2001@gmail.com

* @createdate 2010-5-31

* @lastupdate 2010-5-31

*/

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。 \nDeveloped by GZ Kingdee Development Dept.."));

         }

        

         /**

         * 运行时BOTP公式平台加载自定义公式时,就是从该返回值里取公式的名称的

         * @author Yang Yihao. Just call me House.

         * @date since 2007-9-6

         * @Email: dejavu.house@gmail.com

         * @return 所有自定义公式的名称

         */

         public String[] getAllFuncNames()

         {

                   String as[] = new String[funcInfos.size()];

                   for(int i = 0; i < funcInfos.size(); i++)

                   as[i] = ((FuncInfo)funcInfos.get(i)).funcName;

                   return as;

         }

        

         /**

         * 运行时BOTP公式平台加载自定义公式时,就是从该返回值里取公式的分类的(看运行时的界面就很好理解)

         * @author Yang Yihao. Just call me House.

         * @date since 2007-9-6

         * @Email: dejavu.house@gmail.com

         * @param s

         * @return

         */

         public String getFuncCategory(String s)

         {

                   if(s == null)

                            return null;

                   for(int i = 0; i < funcInfos.size(); i++)

                            if(s.equals(((FuncInfo)funcInfos.get(i)).funcName))

                                     return ((FuncInfo)funcInfos.get(i)).funcCategory;

                   return null;

         }

        

         /**

         * 获取公式的描述

         * @author Yang Yihao. Just call me House.

         * @date since 2007-9-6

         * @Email: dejavu.house@gmail.com

         * @param s

         * @return

         */

         public String getFuncDesc(String s)

         {

                   if(s == null)

                   return null;

                   for(int i = 0; i < funcInfos.size(); i++)

                   if(s.equals(((FuncInfo)funcInfos.get(i)).funcName))

                   return ((FuncInfo)funcInfos.get(i)).funcDesc;

                   return null;

         }

        

         public boolean existFunction(String s)

         {

                   if(s == null)

                   return false;

                   for(int i = 0; i < funcInfos.size(); i++)

                   if(s.equals(((FuncInfo)funcInfos.get(i)).funcName))

                   return true;

                   return false;

         }

        

         /**

         * 运行公式时调用此方法,公式的具体逻辑就写在这里

         * @author Yang Yihao. Just call me House.

         * @date since 2007-9-6

         * @Email: dejavu.house@gmail.com

         * @param func 公式名称

         * @param paramList 公式的参数

         * @return 公式结果

         * @throws KScriptException

         */

         public Object evalFunction(String func, List paramList) throws KScriptException

         {

                   //判断用户是选了哪个公式

                   if(func != null && func.equals(__BOTgetOVByBosType))

                   {

                            //这里可以写满足各式各样需求的代码

                            if(paramList != null && paramList.size() == 3)

                            {

                                     String number = (String) paramList.get(1);

                                     String bosType = (String) paramList.get(2);

                                     try

                                     {

                                               return DynamicObjectFactory.getLocalInstance(ContextUtils.getContextFromSession()).getValue(BOSObjectType.create(bosType), "where number='" + number + "'");

                                     }

                                     catch (BOSException e)

                                     {

                                               e.printStackTrace();

                                     }

                            }

                            else

                                     return null;

                   }

                  

                   return null;

         }

}

class FuncInfo {

        

         public void setFuncName(String name)

         {

                   funcName = name;

         }

    public void setFuncDesc(String desc)

    {

             funcDesc = desc;

    }

    public void setFuncCatetory(String category)

    {

             funcCategory = category;

    }

    String funcName;

    String funcCategory;

    String funcDesc;

    public FuncInfo(String name, String category, String desc)

    {

             super();

                   funcName = name;

                   funcCategory = category;

                   funcDesc = desc;

    }

    public FuncInfo()

    {

             super();

    }

}

<!--[if !supportLists]-->5.    <!--[endif]-->鸣谢

感谢开发部兄弟们的支持!

===================V1.0============================

(以下内容引用自杨毅浩的“BOTP自定义公式解决方案.pdf”,加以补充完善)
一、业务场景:
运行时BOTP的公式平台提供的函数较少,如果要实现比较复杂的逻辑,譬如通过物料编码从其他单据取出对应数量,运行时的公式平台就显得捉襟见肘了。对于客户开发的单据,可以通过写代码实现。但是对于标准产品的单据,如果反编译代码,则升级时相当麻烦。而自定义公式方案正是为了解决此难题而生。它可以通过写代码在BOTP公式平台挂上自定义的公式,公式内容由程序员自由决定,而不会受升级影响。
注意:只适用于EASBOS530或以上版本
二、原理:(业务人员只需重点关注步骤3、4、5)
1.在BOS自定义一个类,实现com.kingdee.bos.service.formula.api.IFormulaFunctions接口。(该类必须位于com.kingdee.bos.service.formula.api此包下,因为要引用此包里的非公共类)
类的定义参考如下:
package com.kingdee.bos.service.formula.api;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import com.kingdee.bos.kscript.KScriptException;
/**
* BOTP自定义公式demo
* @author Yang Yihao. Just call me House.
* @date since 2007-9-6
* @Email: dejavu.house@gmail.com
*/
public class CustomBTPFunctionDemo implements IFormulaFunctions
{
//用于存放公式的变量
private static Vector funcInfos;

static
{
//加载类时定义自定义公式
funcInfos = new Vector();
//FuncInfo()的第一个参数是公式名,第二个参数是公式所在的分类(可随便取名),第三个参数是公式的描述信息(在BOTP公式平台显示)
funcInfos.add(new FuncInfo("helloLiuXun", "HelloWorld", "Wish the
Telecom project would complete soon."));
}
/**
* 运行时BOTP公式平台加载自定义公式时,就是从该返回值里取公式的名称的
* @author Yang Yihao. Just call me House.
* @date since 2007-9-6
* @Email: dejavu.house@gmail.com
* @return 所有自定义公式的名称
*/
public String[] getAllFuncNames()
{
String as[] = new String[funcInfos.size()];
for(int i = 0; i < funcInfos.size(); i++)
as[i] = ((FuncInfo)funcInfos.get(i)).funcName;
return as;
}
/**
* 运行时BOTP公式平台加载自定义公式时,就是从该返回值里取公式的分类的(看运
行时的界面就很好理解)
* @author Yang Yihao. Just call me House.
* @date since 2007-9-6
* @Email: dejavu.house@gmail.com
* @param s
* @return
*/
public String getFuncCategory(String s)
{
if(s == null)
return null;
for(int i = 0; i < funcInfos.size(); i++)
if(s.equals(((FuncInfo)funcInfos.get(i)).funcName))
return ((FuncInfo)funcInfos.get(i)).funcCategory;
return null;
}
/**
* 获取公式的描述
* @author Yang Yihao. Just call me House.
* @date since 2007-9-6
* @Email: dejavu.house@gmail.com
* @param s
* @return
*/
public String getFuncDesc(String s) {
if(s == null)
return null;
for(int i = 0; i < funcInfos.size(); i++)
if(s.equals(((FuncInfo)funcInfos.get(i)).funcName))
return ((FuncInfo)funcInfos.get(i)).funcDesc;
return null;
}
public boolean existFunction(String s)
{
if(s == null)
return false;
for(int i = 0; i < funcInfos.size(); i++)
if(s.equals(((FuncInfo)funcInfos.get(i)).funcName))
return true;
return false;
}
/**
* 运行公式时调用此方法,公式的具体逻辑就写在这里
* @author Yang Yihao. Just call me House.
* @date since 2007-9-6
* @Email: dejavu.house@gmail.com
* @param func 公式名称
* @param paramList 公式的参数
* @return 公式结果
* @throws KScriptException
*/
public Object evalFunction(String func, List paramList) throws
KScriptException
{
//判断用户是选了哪个公式
if(func != null && func.equals("helloLiuXun"))
{
//这里可以写满足各式各样需求的代码
if(paramList != null && paramList.size() > 0)
{
StringBuffer sb = new StringBuffer(10);
for(Iterator iter = paramList.iterator(); iter.hasNext();)
{
sb.append(iter.next()).append(",");
}
return sb.toString();
}
else
return "Congratulations";
}
return "TheEnd";
}
}

2.在BOTP目标单据的实体(entity)上加上扩展属性“billFormulaClass”,属性值设为第1步创建的类的全名(含包名)。如下图:

此 扩展属性 要在 表头实体 的 基础信息 页签中添加,表体实体是不存在billFormulaClass这个扩展属性的) 此 扩展属性 要在 表头实体 的 基础信息 页签中添加,表体实体是不存在billFormulaClass这个扩展属性的)



3.运行时,在BOTP规则设置的“公式平台”->“公式元素”->“函数”页签里可以看到自定义的函数:

helloLiuXun()就是自定义公式。 helloLiuXun()就是自定义公式。

4.设置BOTP公式的格式如下:


参数用半角双引号括起来,可以传多参数,参数间用半角逗号隔开 参数用半角双引号括起来,可以传多参数,参数间用半角逗号隔开

5.恭喜,令人兴奋的结果完全满足你个性化的需求!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值