
# 单据转换插件手册
## 1.场景
单据转换,能够把A单据的数据,根据转换规则,转换生成B单据,单据转换过程中,会触发单据转换插件事件,允许自定义插件进行干预。
## 2.适用版本
金蝶云苍穹 4.0.004以上
## 3.单据转换步骤
- 读取源单到目标单之间的全部转换规则;
- 匹配转换规则的业务范围,确定适用于当前所选源单的转换规则;
- 提取转换规则上,字段映射页签及其他页签,使用到的源单字段;
- 根据源单内码,生成源单取数条件;
- 读取源单数据行:
- 只读取转换规则用到的源单字段;
- 如果源单是整单下推,则读取源单全部行;否则取源单所选行数据;
- 把单据头、单据体字段组合在一起,生成拉平后的源单数据行;
- 根据转换规则,数据范围的配置,对源单行数据,进行筛选,剔除不符合条件的行;
- 根据分单、分录行合并策略,对源单数据行进行分组;
- 根据分组后的源单数据行,生成目标单、目标单分录行;
- 逐行填写目标分录行、单据头字段值;
- 在目标单的关联子实体中,记录来源单据信息;
- 后续保存目标单时,会根据关联子实体中的来源单据信息,记录单据关联关系及反写;
- 如果没有在关联子实体中记录来源单据,则不记录单据关联关系,不能联查,也不能反写;
- 输出生成好的目标单数据包,完成单据转换
- 特别说明:单据转换,只是生成目标单数据包,并没有保存入库;
## 4.单据转换插件各事件的触发时机及用途
### 4.1.插件接口及基类
1. #### 单据转换插件接口
```java
package kd.bos.entity.botp.plugin;
public interface IConvertPlugIn {
/**
* 单据转换可选参数
* @return
*/
default OperateOption getOption() {
return OperateOption.create();
}
default void setOption(OperateOption option) {}
/**
* 开始执行转换规则之前,创建规则上挂的插件后,触发此事件
*
* @param opType
* @param srcMainType
* @param tgtMainType
* @param rule
* @remark
* 由 CreateConvertPlugAction 动作触发
*/
void setContext(ConvertOpType opType, BillEntityType srcMainType, BillEntityType tgtMainType, ConvertRuleElement rule);
// 代码顺序:按单据转换操作,各种执行场景,各场景中执行的活动进行排序;
// 阅读时,按照顺序,从上到下寻找适合的事件
// 各转换操作公共事件 *
/**
* 初始化变量事件,此时还没有开始编译规则
*
* @param e
* @remark
* 获取上下文信息,构建一些必须的变量
* 由 InitializeAction 动作触发
*/
default void initVariable(InitVariableEventArgs e){}
/**
* 编译数据筛选条件前事件:可追加定制条件,是否忽略规则原生的条件
*
* @param e 事件参数:包括本次下推的源单数据、是否忽略规则原生条件
* @remark
* 由 ConvertRuleCompiler 动作触发
*/
default void beforeBuildRowCondition(BeforeBuildRowConditionEventArgs e){}
/**
* 构建分单、行合并模式之前事件:调整分单、合并策略及依赖的字段
*
* @param e
* @remark
* 由 ConvertRuleCompiler 动作触发
*/
default void beforeBuildGroupMode(BeforeBuildGroupModeEventArgs e){}
/**
* 构建取数参数后事件:可在正式读取源单数据之前,添加额外的字段、过滤条件
*
* @param e
* @remark
* 由 BuildQueryParameterAction 动作触发
*/
default void afterBuildQueryParemeter(AfterBuildQueryParemeterEventArgs e){}
/**
* 取源单数据前事件:可在正式读取源单数据之前,修改取数语句、取数条件
*
* @param e
* @remark
* 由 LoadSourceDataAction 动作触发
*/
default void beforeGetSourceData(BeforeGetSourceDataEventArgs e){}
/**
* 取源单数据后事件:根据源单数据,获取其他定制的引用数据;也可以替换系统自动获取到的数据
*
* @param e
* @remark
* 由 RunDataConditionAction 动作触发
*/
default void afterGetSourceData(AfterGetSourceDataEventArgs e){}
/**
* 初始化创建目标单据数据包前事件 (暂未触发)
*
* @param e
* @remark
* 这个事件,只在选单时触发:
* 选单时,需要基于现有的目标单数据包,进行追加处理;
* 插件可以在此事件,获取到现有的目标单数据包,提前进行定制处理
*/
default void beforeCreateTarget(BeforeCreateTargetEventArgs e){}
/**
* 创建目标单据数据包后事件:把根据分单规则创建好的目标单,传递给插件
*
* @param e
* @remark
* 由 CreateLinkEntityRowsAction 动作触发
*/
default void afterCreateTarget(AfterCreateTargetEventArgs e){}
/**
* 目标字段赋值完毕后事件:插件可以在此基础上,继续填写目标字段值
*
* @param e
* @remark
* 由 MappingFieldAction 动作触发
*/
default void afterFieldMapping(AfterFieldMappingEventArgs e){}
/**
* 记录关联关系前事件:取消记录关联关系
*
* @param e
* @remark
* 由 FillLinkInfoAction 动作触发
*/
default void beforeCreateLink(BeforeCreateLinkEventArgs e){}
/**
* 记录关联关系后事件:根据系统自动记录的关联关系,进行相关数据的同步携带,如携带其他子单据体数据
*
* @param e
* @remark
* 由 FillLinkInfoAction 动作触发
*/
default void afterCreateLink(AfterCreateLinkEventArgs e){}
/**
* 单据转换后事件,最后执行:插件可以在这个事件中,对生成的目标单数据,进行最后的修改
*
* @param e
* @remark
* 由 MergePushResultAction 动作触发
*/
default void afterConvert(AfterConvertEventArgs e){}
// 选单前事件 *
/**
* 选单条件生成后,触发此事件:供插件追加选单条件
*
* @param e
*/
default void afterBuildDrawFilter(AfterBuildDrawFilterEventArgs e) {}
}
```
2. #### 单据转换插件基类`AbstractConvertPlugIn`,实现了转换插件接口`IConvertPlugin`
```java
public class AbstractConvertPlugIn implements IConvertPlugIn {
}
```
3. #### 创建并注册插件
自定义单据转换插件,必须扩展插件基类AbstractConvertPlugIn,绑定到单据转换规则上:

4. #### 附:自定义单据转换插件示例
```java
package kd.bos.plugin.sample.bill.billconvert.bizcase;
import kd.bos.entity.BillEntityType;
import kd.bos.entity.botp.ConvertOpType;
import kd.bos.entity.botp.ConvertRuleElement;
import kd.bos.entity.botp.plugin.AbstractConvertPlugIn;
import kd.bos.entity.botp.plugin.args.AfterBuildQueryParemeterEventArgs;
import kd.bos.entity.botp.plugin.args.AfterConvertEventArgs;
import kd.bos.entity.botp.plugin.args.AfterCreateLinkEventArgs;
import kd.bos.entity.botp.plugin.args.AfterCreateTargetEventArgs;
import kd.bos.entity.botp.plugin.args.AfterFieldMappingEventArgs;
import kd.bos.entity.botp.plugin.args.AfterGetSourceDataEventArgs;
import kd.bos.entity.botp.plugin.args.BeforeBuildGroupModeEventArgs;
import kd.bos.entity.botp.plugin.args.BeforeBuildRowConditionEventArgs;
import kd.bos.entity.botp.plugin.args.BeforeCreateLinkEventArgs;
import kd.bos.entity.botp.plugin.args.BeforeCreateTargetEventArgs;
import kd.bos.entity.botp.plugin.args.BeforeGetSourceDataEventArgs;
import kd.bos.entity.botp.plugin.args.InitVariableEventArgs;
/**
* 演示单据转换插件事件的触发时机
*
* @author rd_JohnnyDing
*
*/
public class BillConvertEventSample extends AbstractConvertPlugIn {
/**
* 演示如何获取上下文信息
*/
private void getContext(){
// 源单主实体
BillEntityType srcMainType = this.getSrcMainType();
// 目标单主实体
BillEntityType tgtMainType = this.getTgtMainType();
// 转换规则
ConvertRuleElement rule = this.getRule();
// 转换方式:下推、选单
ConvertOpType opType = this.getOpType();
}
/**
* 初始化变量事件
*
* @param e
* @remark
* 获取上下文信息,构建一些必须的变量
*/
@Override
public void initVariable(InitVariableEventArgs e) {
this.printEventInfo("initVariable", "");
}
/**
* 构建取数参数后事件
*
* @param e
* @remark
* 添加额外的字段、过滤条件
*/
@Override
public void afterBuildQueryParemeter(AfterBuildQueryParemeterEventArgs e) {
this.printEventInfo("afterBuildQueryParemeter", "");
}
/**
* 编译数据筛选条件前事件
*
* @param e
* @remark
* 设置忽略规则原生的条件,改用插件定制条件,或者在规则条件基础上,追加定制条件
*
*/
@Override
public void beforeBuildRowCondition(BeforeBuildRowConditionEventArgs e) {
this.printEventInfo("beforeBuildRowCondition", "");
}
/**
* 取源单数据前事件
*
* @param e
* @remark
* 修改取数语句、取数条件
*/
@Override
public void beforeGetSourceData(BeforeGetSourceDataEventArgs e) {
this.printEventInfo("beforeGetSourceData", "");
}
/**
* 取源单数据后事件
*
* @param e
* @remark
* 根据源单数据,获取其他定制的引用数据;也可以替换系统自动获取到的数据
*/
@Override
public void afterGetSourceData(AfterGetSourceDataEventArgs e) {
this.printEventInfo("afterGetSourceData", "");
}
/**
* 构建分单、行合并模式之前事件
*
* @param e
* @remark
* 调整分单、合并策略及依赖的字段
*/
@Override
public void beforeBuildGroupMode(BeforeBuildGroupModeEventArgs e) {
this.printEventInfo("beforeBuildGroupMode", "");
}
/**
* 初始化创建目标单据数据包前事件
*
* @param e
* @remark
* 这个事件,只在选单时触发:
* 选单时,需要基于现有的目标单数据包,进行追加处理;
* 插件可以在此事件,获取到现有的目标单数据包,提前进行定制处理
*/
@Override
public void beforeCreateTarget(BeforeCreateTargetEventArgs e) {
this.printEventInfo("beforeCreateTarget", "");
}
/**
* 创建目标单据数据包后事件
*
* @param e
* @remark
* 这个事件,只在下推时触发,把根据分单规则创建好的目标单,传递给插件
*/
@Override
public void afterCreateTarget(AfterCreateTargetEventArgs e) {
this.printEventInfo("afterCreateTarget", "");
}
/**
* 目标字段赋值完毕后事件
*
* @param e
* @remark
* 插件可以在此基础上,继续填写目标字段值
*/
@Override
public void afterFieldMapping(AfterFieldMappingEventArgs e) {
this.printEventInfo("afterFieldMapping", "");
}
/**
* 记录关联关系前事件
*
* @param e
* @remark
* 取消记录关联关系
*/
@Override
public void beforeCreateLink(BeforeCreateLinkEventArgs e) {
this.printEventInfo("beforeCreateLink", "");
}
/**
* 记录关联关系后事件
*
* @param e
* @remark
* 根据系统自动记录的关联关系,进行相关数据的同步携带,如携带其他子单据体数据
*/
@Override
public void afterCreateLink(AfterCreateLinkEventArgs e) {
this.printEventInfo("afterCreateLink", "");
}
/**
* 单据转换后事件,最后执行
*
* @param e
* @remark
* 插件可以在这个事件中,对生成的目标单数据,进行最后的修改
*/
@Override
public void afterConvert(AfterConvertEventArgs e) {
this.printEventInfo("afterConvert", "");
}
private void printEventInfo(String eventName, String argString){
String msg = String.format("%s : %s", eventName, argString);
System.out.println(msg);
}
}
```
### 4.2.插件事件
单据转换插件,提供如下插件事件:
| 事件 | 触发时机 |
| ------------------------ | ---------------------------- |
| initVariable | 初始化变量事件 |
| afterBuildQueryParemeter | 构建取数参数后事件 |
| beforeBuildRowCondition | 编译数据筛选条件前事件 |
| beforeGetSourceData | 取源单数据前事件 |
| afterGetSourceData | 取源单数据后事件 |
| beforeBuildGroupMode | 构建分单、行合并模式之前事件 |
| beforeCreateTarget | 暂未触发 |
| afterCreateTarget | 创建目标单据数据包后事件 |
| afterFieldMapping | 目标字段赋值完毕后事件 |
| beforeCreateLink | 记录关联关系前事件 |
| afterCreateLink | 记录关联关系后事件 |
| afterConvert | 单据转换完毕事件,最后执行 |
1. #### initVariable 事件
- 事件触发时机
- 开始运行转换规则,创建好了转换规则上绑定的单据转换插件之后,即触发此事件。插件可以在此事件中,对本地变量进行初始化。
- 此事件发生时,源单主实体、目标单主实体、转换规则都已经确定,可以基于这些上下文信息,初始化本地变量。
- 一些通用的单据转换业务插件,需要自动适应各种单据,这个事件就显得比较重要:
- 可以在转换规则执行前,让通用插件了解到当前的上下文,初始化一些变量,决定后续业务逻辑。
- 插件可以利用如下方法,获取到源单、目标单主实体、反写规则:
```java
private void getContext(){
// 源单主实体
BillEntityType srcMainType = this.getSrcMainType();
// 目标单主实体
BillEntityType tgtMainType = this.getTgtMainType();
// 转换规则
ConvertRuleElement rule = this.getRule();
// 转换方式:下推、选单
ConvertOpType opType = this.getOpType();
}
```
- 代码模板
```java
package kd.bos.plugin.sample.bill.billconvert.template;
import kd.bos.entity.botp.plugin.AbstractConvertPlugIn;
import kd.bos.entity.botp.plugin.args.InitVariableEventArgs;
public class InitVariable extends AbstractConvertPlugIn {
@Override
public void initVariable(InitVariableEventArgs e) {
// TODO 在此添加业务逻辑
}
}
```
- 示例
- 案例说明
1. 需要开发一个通用单据转换插件,把目标单单据体上的金额字段值,合计到单据头上;
2. 不同的单据上,单据体、单据头上的金额字段标识不同;
3. 暂时只支持采购费用发票、销售费用发票;
- 实现方案
1. 捕获 `initVariable`事件,确认源单、目标单,单据体、单据头各金额字段标识;
2. 在`afterCreateLink`事件,根据单据体金额字段,合计单据头金额字段,并换算本位币金额;
- 实例代码
```java
package kd.bos.plugin.sample.bill.billconvert.bizcase;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.Date;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.utils.StringUtils;
import kd.bos.entity.ExtendedDataEntity;
import kd.bos.entity.botp.plugin.AbstractConvertPlugIn;
import kd.bos.entity.botp.plugin.args.AfterCreateLinkEventArgs;
import kd.bos.entity.botp.plugin.args.InitVariableEventArgs;
public class InitVariableSample extends AbstractConvertPlugIn {
/ 目标单主实体标识 */
private String targetEntityNumber;
/ 目标单单据体标识 */
private String key_entryentity;
private boolean isOtherBill = false;
/ 字段标识,单据头.价税合计_原币*/
private String key_AllAmountOri;
/ 字段标识,单据体.价税合计_原币*/
private String key_AllAmountOri_D;
/ 字段标识,单据头.价税合计_本位币*/
private String key_AllAmount;
/ 字段标识,单据头.不含税金额_原币*/
private String key_AmountOri;
/ 字段标识,单据体.不含税金额_原币*/
private String key_AmountOri_D;
/ 字段标识,单据头.不含税金额_本位币*/
private String key_Amount;
/ 字段标识,单据头.税额_原币*/
private String key_TaxAmountOri;
/ 字段标识,单据体.税额_原币*/
private String key_TaxAmountOri_D;
/ 字段标识,单据头.税额_本位币*/
private String key_TaxAmount;
/**
* 初始化事件:根据目标单,确定价税合计金额等字段标识
*/
@Override
public void initVariable(InitVariableEventArgs e) {
this.targetEntityNumber = this.getTgtMainType().getName();
this.setAmountKey();
}
/**
* 关联关系已经记录,并重算了反写控制字段值之后,触发此事件
*
* @remark
* 金额字段,是反写控制字段:
* 反写控制字段,需要记录从每条源单行携带过来的值,然后自动合计到单据体字段上;
* 用户手工修改单据体上的反写控制字段时,会根据原始携带量分配、反写到源单
*
* 因此,如果要依赖于反写控制字段值进行运算,必须在afterCreateLink事件之后
*
*/
@Override
public void afterCreateLink(AfterCreateLinkEventArgs e) {
if (this.isOtherBill){
// 其他未知的单据,不合计金额
return;
}
ExtendedDataEntity[] billDataEntitys = e.getTargetExtDataEntitySet().FindByEntityKey(this.targetEntityNumber);
// 逐单合计单据头金额字段值
for(ExtendedDataEntity billDataEntity : billDataEntitys){
this.calcAmount(billDataEntity);
}
}
/**
* 根据目标单,设置含税价格等字段标识
*/
private void setAmountKey() {
if (StringUtils.equals(this.targetEntityNumber, "iv_purexpinv")){
// 采购费用发票
this.key_entryentity = "entryentity";
//价税合计
this.key_AllAmountOri = "amountori";
this.key_AllAmountOri_D = "amountori";
this.key_AllAmount = "amount";
//不含税金额
this.key_AmountOri = "headauxpriceori";
this.key_AmountOri_D = "headauxpriceori";
this.key_Amount = "headauxprice";
//税额
this.key_TaxAmountOri = "deductibletaxori";
this.key_TaxAmountOri_D = "deductibletaxori";
this.key_TaxAmount = "deductibletax";
}
else if (StringUtils.equals(this.targetEntityNumber, "iv_saleexpinv")){
// 销售费用发票
this.key_entryentity = "entryentity";
//价税合计
this.key_AllAmountOri = "aftertotaltaxfor";
this.key_AllAmountOri_D = "allamountori";
this.key_AllAmount = "aftertotaltax";
//不含税金额
this.key_AmountOri = "headauxpriceori";
this.key_AmountOri_D = "amountori";
this.key_Amount = "headauxprice";
//税额
this.key_TaxAmountOri = "taxamount";
this.key_TaxAmountOri_D = "detailtaxamountori";
this.key_TaxAmount = "taxamountori";
}
else {
// 其他单据:不在此插件中计算价税合计
isOtherBill = true;
}
}
/**
* 计算价税合计
*
* @param billDataEntity
*/
private void calcAmount(ExtendedDataEntity billDataEntity){
long currencyID = (long) billDataEntity.getValue("currencyid_id"); // 原币
long mainCurrencyID =(long) billDataEntity.getValue("mainbookstdcurrid_id"); // 本币
long exchangeTypeID = (long) billDataEntity.getValue("exchangetype_id"); // 换算类型
Date date = (Date) billDataEntity.getValue("date"); // 业务日期
// 取当日汇率
BigDecimal rate = new BigDecimal("0");
if (currencyID > 0 && mainCurrencyID > 0) {
rate = this.getExchangeBusRate(currencyID, mainCurrencyID, exchangeTypeID, date);
}
// 把汇率回填到单据上
billDataEntity.setValue("exchangerate", rate);
// 开始合计金额:逐行循环,汇总到变量上
BigDecimal taxAmountOriH = new BigDecimal("0"); // 单据头.税额
BigDecimal noTaxAmountOriH = new BigDecimal("0"); // 单据头.不含税金额
BigDecimal totalTaxAmountOriH = new BigDecimal("0"); //单据头.价税合计
DynamicObjectCollection entryRows = (DynamicObjectCollection)billDataEntity.getValue(this.key_entryentity);
for (DynamicObject entryRow : entryRows){
taxAmountOriH = taxAmountOriH.add(entryRow.getBigDecimal(key_TaxAmountOri_D)); // 原币 单据体.税额
noTaxAmountOriH = noTaxAmountOriH.add(entryRow.getBigDecimal(key_AmountOri_D)); // 原币 单据体.不含税金额
totalTaxAmountOriH = totalTaxAmountOriH.add(entryRow.getBigDecimal(key_AllAmountOri_D)); // 原币 单据体.价税合计
}
// 填写单据头.原币各金额
billDataEntity.setValue(key_TaxAmountOri, taxAmountOriH);
billDataEntity.setValue(key_AmountOri, noTaxAmountOriH);
billDataEntity.setValue(key_AllAmountOri, totalTaxAmountOriH);
// 本位币各金额 :原币金额 * 汇率 (四舍五入,10位小数)
MathContext mc = new MathContext(10, RoundingMode.HALF_UP);
billDataEntity.setValue(key_TaxAmount, taxAmountOriH.multiply(rate, mc));
billDataEntity.setValue(key_Amount, noTaxAmountOriH.multiply(rate, mc));
billDataEntity.setValue(key_AllAmount, totalTaxAmountOriH.multiply(rate, mc));
}
/**
* 取当日汇率
* @return
*/
private BigDecimal getExchangeBusRate(long currencyId1, long currencyId2, long exchangeType, Date date){
// 略过取汇率的逻辑,直接返回 1
return new BigDecimal("1");
}
}
```
2. #### afterBuildQueryParemeter 事件
- 事件触发时机
- 系统根据转换规则上的字段映射关系,确认好了需要加载的源单字段之后,触发此事件,并传入需转换的源单行过滤条件`( FID in [1,2,3,4] )`。
- 插件可以在此事件中,增加需要加载的源单字段,调整源单行取数条件。
- 代码模板
```java
package kd.bos.plugin.sample.bill.billconvert.template;
import kd.bos.entity.botp.plugin.AbstractConvertPlugIn;
import kd.bos.entity.botp.plugin.args.AfterBuildQueryParemeterEventArgs;
public class AfterBuildQueryParemeter extends AbstractConvertPlugIn {
@Override
public void afterBuildQueryParemeter(AfterBuildQueryParemeterEventArgs e) {
// TODO 在此添加业务逻辑
}
}
```
- 事件参数
```java
public class AfterBuildQueryParemeterEventArgs extends ConvertPluginEventArgs{
/**
*预计会加载的源单字段及其别名;
*/
public Map <String, String> getSrcFldAlias();
/**
*添加插件需要用到的源单字段;
*传入字段标识,如textfield;
*如果要取源单基础资料字段的引用属性,要传入基础资料字段标识及其引用属性,如basedatafield.name;
*不需要在前面带单据体标识;
*/
public void addSrcField(String fullPropName);
/**
*系统根据传入的源单内码,生成的源单取数条件,插件可以调整此集合中的条件对象;
*/
public List <QFilter> getQFilters();
}
```
- 示例
- 案例说明
1. 源单有单据编号、业务日期、金额字段
2. 需要把这三个字段值,拼成一个字符串,填写到目标单内容字段上;
3. 业务日期格式化为`yyyy-MM-dd`,金额带币别
- 实现方案
1. 捕获 `afterBuildQueryParemeter` 事件,要求加载源单单据编号、业务日期、金额、币别字段
2. 捕获 `afterFieldMapping` 事件,取源单字段值,格式化后填写在目标单上
- 实例代码
```java
package kd.bos.plugin.sample.bill.billconvert.bizcase;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.entity.ExtendedDataEntity;
import kd.bos.entity.botp.plugin.AbstractConvertPlugIn;
import kd.bos.entity.botp.plugin.args.AfterBuildQueryParemeterEventArgs;
import kd.bos.entity.botp.plugin.args.AfterFieldMappingEventArgs;
import kd.bos.entity.botp.runtime.ConvertConst;
public class AfterBuildQueryParemeterSample extends AbstractConvertPlugIn {
private final static String KEY_BILLNO = "billno";
private final static String KEY_DATE = "date";
private final static String KEY_AMOUNT = "amount";
private final static String KEY_CURRENCYNAME = "currency.name";
private final static String KEY_CONTENT = "content";
/**
* 在开始读取源单数据前,触发此事件
* @remark
* 在此事件中,要求加载插件要用到的源单字段
*/
@Override
public void afterBuildQueryParemeter(AfterBuildQueryParemeterEventArgs e) {
e.addSrcField(KEY_BILLNO); // 单据编号
e.addSrcField(KEY_DATE); // 业务日期
e.addSrcField(KEY_AMOUNT); // 金额
e.addSrcField(KEY_CURRENCYNAME); // 币别.名称 currency.name
}
/**
* 目标单字段值,携带完毕后,触发此事件
* @remark
* 在此事件中,自行取源单字段值,格式化后填写到目标单
*/
@SuppressWarnings("unchecked")
@Override
public void afterFieldMapping(AfterFieldMappingEventArgs e) {
// 取目标单,单据头数据包 (可能会生成多张单,是个数组)
String targetEntityNumber = this.getTgtMainType().getName();
ExtendedDataEntity[] billDataEntitys = e.getTargetExtDataEntitySet().FindByEntityKey(targetEntityNumber);
SimpleDateFormat timesdf = new SimpleDateFormat("yyyy-MM-dd");
// 逐单处理
for(ExtendedDataEntity billDataEntity : billDataEntitys){
// 取当前目标单,对应的源单行