本文介绍了财务系统中出纳模块的四种单据(付款单、收款单、付款退款单、收款退款单)及其字段映射和单据转换的常见问题与解决方案。针对无法直接在单据转换规则中实现字段携带和多单据体映射的问题,提出了使用单据转换插件的解决方案,并详细说明了如何编写Python脚本处理单据转换的复杂场景,包括字段映射、行对应逻辑、以及如何在转换完成后处理下游单据数据。同时,还讨论了当自定义单据需要下推这四种单据时,如何通过插件处理源单明细与明细信息的对应问题,并提供了相应的Python示例代码。
系统中有出纳模块有4个"神奇的单据":付款单、收款单、付款退款单、收款退款单。
大家知道,这四个单据中都有2个单据体页签(明细和源单明细),通常用源单明细来关联上游业务,通过明细信息推出下游业务。系统这样设计肯定是有他的道理,这里我们不去议论。
在实际应用过程中,我们经常遇到如下场景,比较为难:
Q1.标准的XXX单据可以下推付款单,但是我想在明细里面加字段,只修改单据转换规则,无法实现字段携带?
A1:在字段映射中,只允许设置"一对单据体"之间的字段映射,通俗来讲,字段映射中配置了的字段只能涉及到上游或者下游单据中的一个单据体,不支持多单据体映射,如有需要必须通过单据转换插件来处理。
对于问题Q1,可以这样处理:
1.在源单明细中增加自定义字段,先把字段映射至源单明细。
2.然后通过单据转换插件携带至明明细信息(这个地方必须考虑源单明细的行与明细信息的行如何对应,若源单明细与明细行数一致,完全是行对行,则可以通过单据体序号进行对应关联),下面有示例代码。
Q2:自定义二开单据(或其他标准单据未实现下推以上4种单据)需要下推以上4种单据,配置单据转换时,如果字段映射至明细信息,则无法实现联查反写,如果映射至源单明细,则明细信息页签不会自动生成数据?
A2:单据转换只能设置一个关联实体(由下游单据的单据关联配置决定)用于支持联查反写,同时表单服务策略也只对单据头和关联实体有效。那么这种场景有2种处理方案。
方案一、通过单据转换插件来处理(建议,灵活性更高),思路如下:
1.先配置单据转换规则,完成上游单据至源单明细的转换。
2.在单据转换插件中,根据下推下来的源单明细数据,自动构建出明细信息。
方案二、如果只涉及到付款业务,可利用付款申请单,先用自定义单据下推付款申请单,然后用标准功能付款申请单下推付款单/收款退款单,该方案灵活性不高,而且要考虑增加一个付款申请环节是否会影响业务流程规划,也很容易遇到问题Q1。
下面就以上述场景(Q2-方案一,源单明细直接映射至明细,若需要根据源明细合并生成明细,自行修改逻辑),分享一下Python单据转换插件,根据实际情况稍作修改后即可解决Q1。
1.该脚本用法:在单据转换规则中,插件策略->注册Python脚本。
2.若实现了下推付款单的Python脚本,下推其他3种单据的场景,实现方法类似,依葫芦画瓢即可。
3.参考代码如下(网页有缩进格式问题,如需复制,请下载附件):
#引入clr运行库
import clr
#添加对cloud插件开发的常用组件的引用
clr.AddReference('System')
clr.AddReference('System.Data')
clr.AddReference('Kingdee.BOS')
clr.AddReference('Kingdee.BOS.Core')
clr.AddReference('Kingdee.BOS.App')
clr.AddReference('Kingdee.BOS.Contracts')
clr.AddReference('Kingdee.BOS.DataEntity')
clr.AddReference('Kingdee.BOS.ServiceHelper')
#导入cloud基础库中的常用实体对象(分命名空间导入,不会递归导入)
from Kingdee.BOS import *
from Kingdee.BOS.Core import *
from Kingdee.BOS.Core.Bill import *
from Kingdee.BOS.Orm.DataEntity import *
from Kingdee.BOS.Contracts import *
from Kingdee.BOS.App import *
from Kingdee.BOS.Core.DynamicForm.PlugIn import *
from Kingdee.BOS.Core.DynamicForm.PlugIn.ControlModel import *
from System import *
from System.Data import *
from System.Text import *
from System.Collections import *
from Kingdee.BOS.App.Data import *
from System.Collections.Generic import List
from Kingdee.BOS.ServiceHelper import *
#PS:此事件在表单服务策略之前触发,若需要先代码处理,再利用表单服务策略,则在此事件中对下游单据做处理即可。
#本示例代码案例未用此事件,这里分享单据转换插件顺带分享一下。
def OnAfterCreateLink(e):
headEntity=e.TargetExtendedDataEntities.FindByEntityKey("FBillHead");
for entity in headEntity:
billObj=entity.DataEntity;
#自己单据处理逻辑......
def AfterConvert(e):#单据转换完成后触发的事件,在表单服务策略之后,获取推出来的下游单据数据包,对其做二次处理
headEntity = e.Result.FindByEntityKey("FBillHead");#获取生成的所有下游单据
for entity in headEntity:#循环每一个下游单据,这里是下游单据的完整数据包
setBase_WFYHZH(entity.DataEntity);#自定义处理下游单据的方法
def setBase_WFYHZH(billObj):
entityRows = billObj["PAYBILLENTRY"];#获取到明细实体数据包,Orm实体标识
SRCentityRows = billObj["PAYBILLSRCENTRY"];#获取到源单明细实体数据包,Orm实体标识
i=0;
sumAmtyf=0;
sumAmtsf=0;
sumAmtfk=0;
entityRows.Clear();#构建明细单据体时,先清空原来的数据,系统默认有1行空白行,问题Q1不加这个
for srcRow in SRCentityRows:
#构建明细行
#问题Q1将这2行改成,newRow=entityRows[i];请考虑源单明细和明细行数不一致的问题,自行添加处理逻辑
newRow=DynamicObject(entityRows.DynamicCollectionItemPropertyType);
entityRows.Add(newRow);#添加到明细行数据包中
#下面将源单明细字段赋值给明细字段,使用的是实体属性标识,问题Q1只需要构建自定义携带的字段
entityRows[i]["Seq"] = i+1;#行序号赋值
entityRows[i]["FPOSTDATE"] = billObj["DATE"];
entityRows[i]["OPPOSITEBANKACCOUNT"] = srcRow["F_YDDFYHZH"];
entityRows[i]["OPPOSITECCOUNTNAME"] = srcRow["F_YDDFZHMC"];
entityRows[i]["OPPOSITEBANKNAME"] = srcRow["F_YDDFKHH"];
entityRows[i]["SETTLEPAYAMOUNTFOR"] = srcRow["REALPAYAMOUNT"];
entityRows[i]["PAYTOTALAMOUNTFOR"] = srcRow["REALPAYAMOUNT"];
entityRows[i]["REALPAYAMOUNTFOR"] = srcRow["REALPAYAMOUNT"];
entityRows[i]["PAYAMOUNTFOR_E"] = srcRow["REALPAYAMOUNT"];
#普通字段,直接赋值即可,特别说明:基础资料/赋值资料字段,需要按照如下2行进行赋值(字段数据包+ID)
#字段的"实体属性标识_Id",即字段的内码
entityRows[i]["PURPOSEID_Id"] = srcRow["FPAYPURPOSEID_Id"];
entityRows[i]["PURPOSEID"] = srcRow["FPAYPURPOSEID"];
entityRows[i]["SETTLETYPEID_Id"] = srcRow["SRCSETTLETYPEID_Id"];
entityRows[i]["SETTLETYPEID"] = srcRow["SRCSETTLETYPEID"];
entityRows[i]["FCOSTID_Id"] = srcRow["F_FYXM_Id"];
entityRows[i]["FCOSTID"] = srcRow["F_FYXM"];
entityRows[i]["PAYTOTALAMOUNT"] = srcRow["FPLANPAYAMOUNTLOC"];
entityRows[i]["REALPAYAMOUNT"] = srcRow["FREALPAYAMOUNTLOC"];
entityRows[i]["PAYAMOUNT_E"] = srcRow["FREALPAYAMOUNTLOC"];
entityRows[i]["FMATERIALID_Id"] = srcRow["FSRCMATERIALID_Id"];
entityRows[i]["FMATERIALID"] = srcRow["FSRCMATERIALID"];
entityRows[i]["PRICEUNITID_Id"] = srcRow["SRCPRICEUNITID_Id"];
entityRows[i]["PRICEUNITID"] = srcRow["SRCPRICEUNITID"];
entityRows[i]["PRICE"] = srcRow["SRCPRICE"];
entityRows[i]["QTY"] = srcRow["SRCQTY"];
entityRows[i]["FPURCHASEORDERNO"] = srcRow["FPURORDERNO"];
entityRows[i]["FMATERIALSEQ"] = srcRow["FSRCMATERIALSEQ"];
entityRows[i]["FORDERENTRYID"] = srcRow["FSRCORDERENTRYID"];
entityRows[i]["TaxAmt"] = srcRow["FTAXAMOUNT"];
entityRows[i]["RecType"] = '1';
entityRows[i]["FRuZhangType"] = '1';
entityRows[i]["FPayType"] = 'A';
entityRows[i]["F_ora_Text"] = srcRow["SRCBILLNO"];
#注意:Python插件中用"+="好像会报错,大家可以试试,不行的话,就写全,问题也不大!
sumAmtyf=sumAmtyf+Double(entityRows[i]["PAYTOTALAMOUNTFOR"]);
sumAmtsf=sumAmtsf+Double(entityRows[i]["REALPAYAMOUNTFOR"]);
sumAmtfk=sumAmtfk+Double(entityRows[i]["PAYAMOUNTFOR_E"]);
i=i+1;
#下面给单据头的总金额字段赋值
billObj["PAYTOTALAMOUNTFOR"]=sumAmtyf;
billObj["REALPAYAMOUNTFOR"]=sumAmtsf;
billObj["PAYAMOUNTFOR"]=sumAmtyf;
#=================代码结束=================
Python单据转换插件下推付款单示例.rar(1.15KB)