# 推单与拉单后端开发步骤

1 推单与拉单参数vo定义

2 定义推单与拉单接口

3 开发推单与拉单实现类，根据上游下游数据调用转单接口进行转单

4 接口与实现类配置文件开发

5 转换规则配置

6 根据转换规则调用测试

# 推单与拉单参数VO demo

```java

/**
 * 推单与拉单参数vo
 * 自己生成一下 get set 方法
 */
public class PullBillParamVO {

    // 源单据类型
    private String srcBillOrTranstype;

    // 目标单据类型
    private String destBillOrTranstype;

    // 源单据主键
    private String[] sourceBillVOPks;

    // 源单据vo实体全类名  比如请购单 aggvo 要用聚合类 : nc.vo.pu.m20.entity.PraybillVO
    private String sourceBillVOName;

}

```

# 推单与拉单接口demo

```java
import nc.vo.pub.BusinessException;
import nc.vo.pubapp.pattern.model.entity.bill.AbstractBill;

/**
 * 推单与拉单接口
 */
public interface IDemoPullBillFromLastBill {

    /**
     * 根据推单与拉单参数进行转换数据
     * @param paramVO
     * @return
     * @param <E>
     * @param <T>
     * @throws BusinessException
     */
    public  <E, T extends AbstractBill> T[] pullBillFromLastBill(PullBillParamVO paramVO) throws BusinessException, ClassNotFoundException;


}

```



# 推单与拉单实现类 demo

```java

import nc.bs.framework.common.NCLocator;
import nc.itf.uap.pf.IPfExchangeService;
import nc.md.persist.framework.IMDPersistenceQueryService;
import nc.vo.pu.m20.entity.PraybillItemVO;
import nc.vo.pub.AggregatedValueObject;
import nc.vo.pub.BusinessException;
import nc.vo.pub.CircularlyAccessibleValueObject;
import nc.vo.pubapp.pattern.model.entity.bill.AbstractBill;

import java.util.Collection;

/**
 * 推单与拉单服务
 */
public class DemoPullBillFromLastBillImpl implements IDemoPullBillFromLastBill {

    // 转单接口
    protected IPfExchangeService pfSer = NCLocator.getInstance().lookup(IPfExchangeService.class);

    private static IMDPersistenceQueryService service;

    @Override
    public <E, T extends AbstractBill> T[] pullBillFromLastBill(PullBillParamVO paramVO) throws BusinessException, ClassNotFoundException {

        //1 入参数校验
        validatePullBillParameters(paramVO);
        // 根据入参获取sourcevo
        AggregatedValueObject[] srourceBillVOS = getSourceBillVOS(paramVO);

        //2 前规则: 可以处理根据sourcevo 或者入参处理一些业务逻辑
        this.addBeforeRule(paramVO);

        //3 执行单据vo转换
        AggregatedValueObject[] vos = pfSer.runChangeDataAry(paramVO.getSrcBillOrTranstype(), paramVO.getDestBillOrTranstype(), srourceBillVOS, null);

        //4 后规则
        this.addAfterRule(paramVO,vos);

        return (T[]) vos;
    }

    /**
     * 入参校验
     * @param paramVO
     * @throws BusinessException
     */
    private void validatePullBillParameters(PullBillParamVO paramVO) throws BusinessException {
        if (paramVO == null) {
            throw new BusinessException("参数对象 paramVO 不能为空");
        }
        if (paramVO.getSourceBillVOPks() == null || paramVO.getSourceBillVOPks().length == 0) {
            throw new BusinessException("源单据主键数组 sourceBillVOPks 不能为空或长度为0");
        }
        if (paramVO.getSourceBillVOName() == null || paramVO.getSourceBillVOName().trim().isEmpty()) {
            throw new BusinessException("源单据VO类名 sourceBillVOName 不能为空");
        }
        if (paramVO.getSrcBillOrTranstype() == null || paramVO.getSrcBillOrTranstype().trim().isEmpty()) {
            throw new BusinessException("源单据类型 srcBillOrTranstype 不能为空");
        }
        if (paramVO.getDestBillOrTranstype() == null || paramVO.getDestBillOrTranstype().trim().isEmpty()) {
            throw new BusinessException("目标单据类型 destBillOrTranstype 不能为空");
        }
    }
    
    /**
     * 获取源单据vos
     * @param paramVO
     * @throws BusinessException
     */
    private AggregatedValueObject[] getSourceBillVOS(PullBillParamVO paramVO) throws BusinessException {
        String[] sourceBillVOPks = paramVO.getSourceBillVOPks();
        String sourceBillVOName = paramVO.getSourceBillVOName();
        Class<?> sourceBillVOClass = null;
        try {
            sourceBillVOClass = Class.forName(sourceBillVOName);
        } catch (ClassNotFoundException e) {
            throw new BusinessException("找不到指定的类: " + sourceBillVOName, e);
        }
        //查询源单据vos
        Collection collection = getQueryService().queryBillOfVOByPKs(sourceBillVOClass, sourceBillVOPks, false);
        AggregatedValueObject[] billvos = (AggregatedValueObject[]) collection.toArray(new AggregatedValueObject[0]);
        if (billvos == null || billvos.length == 0) {
            throw new BusinessException("找不到指定的单据: " + sourceBillVOPks);
        }
        return billvos;
    }

    /**
     * 后规则
     */
    private void addAfterRule(PullBillParamVO paramVO,AggregatedValueObject[] destVOS) {

    }

    /**
     * 前规则
     */
    private void addBeforeRule(PullBillParamVO paramVO) {

    }

    /**
     * 获取查询服务
     * @return service
     */
    private IMDPersistenceQueryService getQueryService() {
        if (service == null){
            service = NCLocator.getInstance().lookup(IMDPersistenceQueryService.class);
        }
        return service;
    }

}

```

# 接口与实现类配置文件示例

以下结构不允许更改，以下结构不允许更改，以下结构不允许更改。仅能改动全路径的内容

```xml
<?xml version="1.0" encoding="gb2312"?>
<module name="模块编码">
	<public>
		<component priority="0" singleton="true" remote="true" tx="CMT" supportAlias="true">
			<interface>IDemoPullBillFromLastBill的全路径</interface>
			<implementation>DemoPullBillFromLastBillImpl的全路径</implementation>
		</component>
	</public>
</module>
```





# 推单与拉单调用接口demo

```java
		//推单与拉单参数vo
		PullBillParamVO pullBillParamVO = new PullBillParamVO();

		pullBillParamVO.setSrcBillOrTranstype("源单据类型 => 根据用户输入的动态进行替换");  //请购单
		pullBillParamVO.setDestBillOrTranstype("目标单据类型 => 根据用户输入的动态进行替换"); //采购订单
		pullBillParamVO.setSourceBillVOName("源单据vo实体全类名 (比如)=>(nc.vo.pu.m20.entity.PraybillVO) => 根据用户输入的动态进行替换");
		pullBillParamVO.setSourceBillVOPks(new String[]{"源单据主键 => 根据用户输入的动态进行替换"});

		//执行转单
		AbstractBill[] abstractBills = iDemoPullBillFromLastBill.pullBillFromLastBill(pullBillParamVO);
```



# 推单与拉单转换规则配置

位置（两个，可选）: 

1 动态建模平台 =》 流程管理 =》 流程设计 =》 单据转换规则

2 动态建模平台 =》 应用工厂 =》 高阶定制 =》 配置项设置
