Ver código fonte

Merge remote-tracking branch 'origin/master'

wangjun 3 semanas atrás
pai
commit
698270b942
24 arquivos alterados com 2195 adições e 36 exclusões
  1. 45 4
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/fi/cas/opplugin/PayBillToolUtil.java
  2. 15 1
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/fi/cas/task/AgentpaybillQueryStatusTast.java
  3. 16 1
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/fi/cas/task/PayQueryStatusTast.java
  4. 37 0
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/constant/BillConstant.java
  5. 38 0
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/constant/BillTypeConstants.java
  6. 52 0
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/constant/ErPrintSetConstant.java
  7. 19 0
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/constant/ErPrintUserConstant.java
  8. 50 0
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/constant/ErReimBurseBillConstant.java
  9. 110 0
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/constant/HandInReceiveTicketConstant.java
  10. 71 0
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/entity/MergePrintEntity.java
  11. 106 0
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/util/ErFindRelationBillUtils.java
  12. 160 0
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/util/PrintPdfUtil.java
  13. 241 0
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/util/ReceiveTicketUtils.java
  14. 54 0
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/form/ErDailyVehicleBillEdit.java
  15. 41 0
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/form/ErTicketMailPlugin.java
  16. 614 0
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/form/HandInReceiveTicketPlugin.java
  17. 57 0
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/ErPrintSetOp.java
  18. 0 14
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/PrepayBillOpPlugin.java
  19. 62 0
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/ReimBurseBillReceiveTicketOp.java
  20. 120 2
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/SRMHelperUtils.java
  21. 71 0
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/validator/ReimBurseBillReceiveTicketValidator.java
  22. 56 0
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/workflow/TaskApproverWorkflowPlugin.java
  23. 45 2
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/task/WriteBackPayResult2SRMTask.java
  24. 115 12
      code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/webapi/SRMSynPayApiPlugin.java

+ 45 - 4
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/fi/cas/opplugin/PayBillToolUtil.java

@@ -162,9 +162,9 @@ public class PayBillToolUtil {
             data.put("OP_ACNT_LIST", OP_ACNT_LIST);
             //结算方式
             if(info.getDynamicObject("settletype") != null) {
-                data.put("SETTLE_TYPE", info.getDynamicObject("settletype").getString("name"));
+                data.put("settletype", info.getDynamicObject("settletype").getString("name"));
             } else {
-                data.put("SETTLE_TYPE", "");
+                data.put("settletype", "");
             }
 
             //无用字段
@@ -492,7 +492,28 @@ public class PayBillToolUtil {
             //存入日志表
             saveAgentlog(payBillEntity, qjjson, apiResult, "1");
 
-            JSONObject cbsReturnJson = new JSONObject(apiResult);
+            JSONObject esbReturnJson = new JSONObject(apiResult);
+            if(esbReturnJson.get("responseData") == null){
+                errMsg.append("单据号:").append(billNum).append(",推送资金系统失败,");
+                errMsg.append("错误号:").append("XXXXXXX");
+                errMsg.append(",错误原因:").append("未正常返回responseData参数");
+                errMsg.append("\r\n");
+
+                return errMsg.toString();
+            }
+
+            JSONArray esbJSONArray = esbReturnJson.getJSONArray("responseData");
+            if(esbJSONArray == null || esbJSONArray.length() == 0){
+                errMsg.append("单据号:").append(billNum).append(",推送资金系统失败,");
+                errMsg.append("错误号:").append("XXXXXXX");
+                errMsg.append(",错误原因:").append("未正常返回responseData参数");
+                errMsg.append("\r\n");
+
+                return errMsg.toString();
+            }
+
+            JSONObject cbsReturnJson = esbJSONArray.getJSONObject(0);
+
             /************************************************************/
 
             if (cbsReturnJson == null) {
@@ -708,7 +729,27 @@ public class PayBillToolUtil {
             //存入日志表
             savelog(payBillEntity, qjjson, apiResult);
 
-            JSONObject cbsReturnJson = new JSONObject(apiResult);
+            JSONObject esbReturnJson = new JSONObject(apiResult);
+            if(esbReturnJson.get("responseData") == null){
+                errMsg.append("单据号:").append(billNum).append(",推送资金系统失败,");
+                errMsg.append("错误号:").append("XXXXXXX");
+                errMsg.append(",错误原因:").append("未正常返回responseData参数");
+                errMsg.append("\r\n");
+
+                return errMsg.toString();
+            }
+
+            JSONArray esbJSONArray = esbReturnJson.getJSONArray("responseData");
+            if(esbJSONArray == null || esbJSONArray.length() == 0){
+                errMsg.append("单据号:").append(billNum).append(",推送资金系统失败,");
+                errMsg.append("错误号:").append("XXXXXXX");
+                errMsg.append(",错误原因:").append("未正常返回responseData参数");
+                errMsg.append("\r\n");
+
+                return errMsg.toString();
+            }
+
+            JSONObject cbsReturnJson = esbJSONArray.getJSONObject(0);
             /************************************************************/
 
             if (cbsReturnJson == null) {

+ 15 - 1
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/fi/cas/task/AgentpaybillQueryStatusTast.java

@@ -81,7 +81,21 @@ public class AgentpaybillQueryStatusTast extends AbstractTask {
 
             log.info("单据号:" + billNum + "返回参数" + apiResult);
 
-            JSONObject cbsReturnJson = new JSONObject(apiResult);
+//            JSONObject cbsReturnJson = new JSONObject(apiResult);
+
+            JSONObject esbReturnJson = new JSONObject(apiResult);
+            if(esbReturnJson.get("responseData") == null){
+                log.info("单据号:" + billNum + ", 未正常返回responseData参数");
+                return;
+            }
+
+            JSONArray esbJSONArray = esbReturnJson.getJSONArray("responseData");
+            if(esbJSONArray == null || esbJSONArray.length() == 0){
+                log.info("单据号:" + billNum + ", 未正常返回responseData参数");
+                return;
+            }
+
+            JSONObject cbsReturnJson = esbJSONArray.getJSONObject(0);
             /************************************************************/
 
             log.info("单据号:"+billNum+"返回参数"+cbsReturnJson.toString());

+ 16 - 1
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/fi/cas/task/PayQueryStatusTast.java

@@ -12,6 +12,7 @@ import kd.bos.orm.query.QFilter;
 import kd.bos.schedule.executor.AbstractTask;
 import kd.bos.servicehelper.BusinessDataServiceHelper;
 import kd.bos.servicehelper.operation.SaveServiceHelper;
+import org.json.JSONArray;
 import org.json.JSONObject;
 
 import java.io.IOException;
@@ -77,7 +78,21 @@ public class PayQueryStatusTast extends AbstractTask {
 
             log.info("单据号:" + billNum + "返回参数" + apiResult);
 
-            JSONObject cbsReturnJson = new JSONObject(apiResult);
+//            JSONObject cbsReturnJson = new JSONObject(apiResult);
+
+            JSONObject esbReturnJson = new JSONObject(apiResult);
+            if(esbReturnJson.get("responseData") == null){
+                log.info("单据号:" + billNum + ", 未正常返回responseData参数");
+                return;
+            }
+
+            JSONArray esbJSONArray = esbReturnJson.getJSONArray("responseData");
+            if(esbJSONArray == null || esbJSONArray.length() == 0){
+                log.info("单据号:" + billNum + ", 未正常返回responseData参数");
+                return;
+            }
+
+            JSONObject cbsReturnJson = esbJSONArray.getJSONObject(0);
             /************************************************************/
 
 

+ 37 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/constant/BillConstant.java

@@ -0,0 +1,37 @@
+package nckd.jimin.jyyy.fi.common.constant;
+
+public interface BillConstant {
+
+    /**
+     * 编码
+     */
+    String ID = "id";
+    /**
+     * 编码
+     */
+    String KEY_NUMBER = "number";
+
+    /**
+     * 编码
+     */
+    String KEY_BILLNO = "billno";
+
+    /**
+     * 名称
+     */
+    String KEY_NAME = "name";
+    /**
+     * 状态
+     */
+    String KEY_STATUS = "status";
+    /**
+     * 是否可用
+     */
+    String KEY_ENABLE = "enable";
+
+    /**
+     * 单据状态
+     */
+    String KEY_BILLSTATUS = "billstatus";
+
+}

+ 38 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/constant/BillTypeConstants.java

@@ -0,0 +1,38 @@
+package nckd.jimin.jyyy.fi.common.constant;
+
+public interface BillTypeConstants {
+
+    String HRPI_PERSON = "hrpi_person";
+
+    String HRPI_BASELOCATION = "hrpi_baselocation";
+
+    String HBSS_WORKPLACE = "hbss_workplace";
+
+    String GL_VOUCHER = "gl_voucher";
+
+    String CAS_PAYBILL = "cas_paybill";
+
+    String BEI_ELECRECEIPT = "bei_elecreceipt";
+
+    /**
+     * 费用报销单
+     */
+    String ER_DAILYREIMBURSEBILL = "er_dailyreimbursebill";
+    /**
+     * 对公报销单
+     */
+    String ER_PUBLICREIMBURSEBILL = "er_publicreimbursebill";
+    /**
+     * 差旅报销单
+     */
+    String ER_TRIPREIMBURSEBILL = "er_tripreimbursebill";
+    /**
+     * er_checkingpaybill
+     */
+    String ER_CHECKINGPAYBILL = "er_checkingpaybill";
+
+    /**
+     * 预付单
+     */
+    String ER_PREPAYBILL = "er_prepaybill";
+}

+ 52 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/constant/ErPrintSetConstant.java

@@ -0,0 +1,52 @@
+package nckd.jimin.jyyy.fi.common.constant;
+
+public interface ErPrintSetConstant extends BillConstant{
+
+    /**
+     * 单据实体
+     */
+    String ENTITYID = "nckd_printset";
+
+    /**
+     * 公司
+     */
+    String KEY_NCKD_ORG = "nckd_org";
+
+    interface BillPtSetEntry{
+
+        String ENTITYID = "nckd_billptsetentry";
+        /**
+         * 单据类型
+         */
+        String KEY_NCKD_BILLTYPE = "nckd_billtype";
+        /**
+         * 打印单据封面
+         */
+        String KEY_NCKD_ISPTCOVER = "nckd_isptcover";
+        /**
+         * 打印凭证
+         */
+        String KEY_NCKD_ISPTVOUCHER = "nckd_isptvoucher";
+        /**
+         * 打印电子回单
+         */
+        String KEY_NCKD_ISPTRECEIPT = "nckd_isptreceipt";
+        /**
+         * 单据封面顺序
+         */
+        String KEY_NCKD_COVERORDER = "nckd_coverorder";
+        /**
+         * 凭证打印顺序
+         */
+        String KEY_NCKD_VOUCHERORDER = "nckd_voucherorder";
+        /**
+         * 电子回单顺序
+         */
+        String KEY_NCKD_RECEIPTORDER = "nckd_receiptorder";
+
+        /**
+         * 备注
+         */
+        String KEY_NCKD_REMARK = "nckd_remark";
+    }
+}

+ 19 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/constant/ErPrintUserConstant.java

@@ -0,0 +1,19 @@
+package nckd.jimin.jyyy.fi.common.constant;
+
+public interface ErPrintUserConstant extends BillConstant{
+
+    /**
+     * 单据实体
+     */
+    String ENTITYID = "nckd_printuser";
+
+    /**
+     * 扫描点
+     */
+    String KEY_NCKD_SCANTYPE = "nckd_scantype";
+
+    /**
+     * 人员
+     */
+    String KEY_NCKD_BOS_USER = "nckd_bos_user";
+}

+ 50 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/constant/ErReimBurseBillConstant.java

@@ -0,0 +1,50 @@
+package nckd.jimin.jyyy.fi.common.constant;
+
+public interface ErReimBurseBillConstant extends BillConstant{
+
+    String ENTITYID = "er_dailyreimbursebill";
+
+    /**
+     * 共享审核人
+     */
+    String KEY_NCKD_TASKAPPROVER = "nckd_taskapprover";
+    /**
+     * 交票人
+     */
+    String KEY_NCKD_HANDIN_PERSON = "nckd_handin_person";
+    /**
+     * 交票时间
+     */
+    String KEY_NCKD_HANDIN_DATE = "nckd_handin_date";
+    /**
+     * 收票人
+     */
+    String KEY_NCKD_RECEIPT_PERSON = "nckd_receipt_person";
+
+    /**
+     * 收票时间
+     */
+    String KEY_NCKD_RECEIPT_DATE = "nckd_receipt_date";
+
+    /**
+     * 快递单号
+     */
+    String KEY_NCKD_TRACKING_NUMBER = "nckd_tracking_number";
+
+    String KEY_COMPANY = "company";
+
+    interface OPERATE{
+        /**
+         * 交票操作
+         */
+        String HANDIN_TICKET = "nckd_handin_ticket";
+
+        /**
+         * 收票操作
+         */
+        String RECEIVE_TICKET = "nckd_receive_ticket";
+
+    }
+
+
+}

+ 110 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/constant/HandInReceiveTicketConstant.java

@@ -0,0 +1,110 @@
+package nckd.jimin.jyyy.fi.common.constant;
+
+public interface HandInReceiveTicketConstant {
+    /**
+     * 扫描单据
+     */
+    String KEY_NCKD_SCANNUMBER = "nckd_scannumber";
+    /**
+     * 扫描点
+     */
+    String KEY_NCKD_SCANTYPE = "nckd_scantype";
+
+    String ENTITY_NCKD_TICKET_MAIL = "nckd_ticket_mail";
+
+
+    interface SCANBILLENTRY{
+
+        /**
+         * 分录标识
+         */
+        String ENTITYID = "nckd_scanbill_entry";
+
+        /**
+         * 单据编号
+         */
+        String KEY_NCKD_NUMBER = "nckd_number";
+
+        /**
+         * 扫描状态
+         */
+        String KEY_NCKD_STATUS = "nckd_status";
+
+        /**
+         * 单据ID
+         */
+        String KEY_NCKD_BILLID = "nckd_billid";
+
+        /**
+         * 单据类型
+         */
+        String KEY_NCKD_FORMID = "nckd_formid";
+
+        /**
+         * 公司
+         */
+        String KEY_NCKD_COMPANY = "nckd_company";
+
+    }
+
+
+
+
+
+    interface OPERATE{
+        /**
+         * 交票操作
+         */
+        String HANDIN_TICKET = "nckd_handin_ticket";
+
+        /**
+         * 收票操作
+         */
+        String RECEIVE_TICKET = "nckd_receive_ticket";
+
+        /**
+         * 打印操作
+         */
+        String MERGEPRINT = "nckd_mergeprint";
+
+        /**
+         * 邮寄
+         */
+        String NCKD_MAIL = "nckd_mail";
+
+        /**
+         * 退邮
+         */
+        String NCKD_CANCELMAIN = "nckd_cancelmain";
+
+        /**
+         * 查看凭证
+         */
+        String NCKD_VIEW_VOUCHER = "nckd_view_voucher";
+        /**
+         * 查看电子回单
+         */
+        String NCKD_VIEW_ELECRECEIPT = "nckd_view_elecreceipt";
+
+        /**
+         * 刷新
+         */
+        String NCKD_REFRESH = "nckd_refresh";
+
+        String NCKD_IMAGEPREVIEW = "nckd_imagepreview";
+
+
+    }
+
+    interface METEDATAFLAG{
+        /**
+         * 打印单据详情Flex
+         */
+        String NCKD_FLEX_TARGETBILL = "nckd_flex_targetbill";
+        /**
+         * 打印单据详情Flex
+         */
+        String NCKD_ENTRY_TOOLBARAP = "nckd_entry_toolbarap";
+
+    }
+}

+ 71 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/entity/MergePrintEntity.java

@@ -0,0 +1,71 @@
+package nckd.jimin.jyyy.fi.common.entity;
+
+import java.util.List;
+
+public class MergePrintEntity {
+
+    /**
+     * 单据类型
+     */
+    private String formId;
+
+    /**
+     * 打印模板ID
+     */
+    private String templateId;
+
+    /**
+     * 打印单据ID
+     */
+    private List<Object> pkIds;
+
+    /**
+     * 打印顺序
+     */
+    private int index;
+
+    public MergePrintEntity(String formId, String templateId, List<Object> pkIds) {
+        this.formId = formId;
+        this.templateId = templateId;
+        this.pkIds = pkIds;
+    }
+
+    public MergePrintEntity(String formId, String templateId, List<Object> pkIds, int index) {
+        this.formId = formId;
+        this.templateId = templateId;
+        this.pkIds = pkIds;
+        this.index = index;
+    }
+
+    public String getFormId() {
+        return formId;
+    }
+
+    public void setFormId(String formId) {
+        this.formId = formId;
+    }
+
+    public String getTemplateId() {
+        return templateId;
+    }
+
+    public void setTemplateId(String templateId) {
+        this.templateId = templateId;
+    }
+
+    public List<Object> getPkIds() {
+        return pkIds;
+    }
+
+    public void setPkIds(List<Object> pkIds) {
+        this.pkIds = pkIds;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public void setIndex(int index) {
+        this.index = index;
+    }
+}

+ 106 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/util/ErFindRelationBillUtils.java

@@ -0,0 +1,106 @@
+package nckd.jimin.jyyy.fi.common.util;
+
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.ext.fi.ai.DapVoucherUtil;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.QueryServiceHelper;
+import kd.bos.servicehelper.botp.BFTrackerServiceHelper;
+import kd.bos.util.CollectionUtils;
+import nckd.jimin.jyyy.fi.common.constant.BillTypeConstants;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class ErFindRelationBillUtils {
+
+    /**
+     * 查询费用单据关联下游单据
+     * @param billId
+     * @param billType
+     * @return
+     */
+    public static Map<String ,Set<Object>> getRelationBelowBillMap(String billId,String billType){
+        Map<String ,Set<Object>> relationBillMap = new HashMap<>();
+        // 查询付款处理
+        Set<Object> casPaybillSet = getBotpRelationId(billType, BillTypeConstants.CAS_PAYBILL, Long.parseLong(billId), true);
+
+        if(CollectionUtils.isNotEmpty(casPaybillSet)){
+            relationBillMap.put(BillTypeConstants.CAS_PAYBILL,casPaybillSet);
+
+            // 凭证
+            Set<Long> voucherSet = DapVoucherUtil.getBuildVch(casPaybillSet, BillTypeConstants.CAS_PAYBILL);
+            relationBillMap.put(BillTypeConstants.GL_VOUCHER,voucherSet.stream().map(r->(Object)r).collect(Collectors.toSet()));
+
+            //电子回单
+            Set<Object> casPayBillElecReceipt = getCasPayBillElecReceipt(casPaybillSet);
+            relationBillMap.put(BillTypeConstants.BEI_ELECRECEIPT,casPayBillElecReceipt);
+        }
+
+        return relationBillMap;
+    }
+
+
+    /**
+     * 查询Botp单据
+     * @param billType 来源单据
+     * @param destBillType 目标单据
+     * @param billId 来源单据ID
+     * @param isPositive 发给想
+     * @return
+     */
+    public static Set<Object> getBotpRelationId(String billType , String destBillType , Long billId , boolean isPositive){
+        Set<Long> idSet = null ;
+        // 下游单据
+        if(isPositive){
+            Map<String, HashSet<Long>> targetBillMap = BFTrackerServiceHelper.findTargetBills( billType , new Long[] { billId });
+            if(targetBillMap.containsKey(destBillType)){
+                idSet = targetBillMap.get(destBillType);
+            }
+            // 上游单据
+        } else{
+            Map<String, HashSet<Long>> sourceBillMap = BFTrackerServiceHelper.findSourceBills( billType , new Long[] { billId });
+            if(sourceBillMap.containsKey(destBillType)){
+                idSet = sourceBillMap.get(destBillType);
+            }
+        }
+        if(!Objects.isNull(idSet)){
+            return QueryServiceHelper.query(destBillType , "id" , new QFilter("id" , QCP.in , idSet).toArray())
+                    .stream()
+                    .map(r -> r.get("id"))
+                    .collect(Collectors.toSet());
+        }
+        return null ;
+    }
+
+
+    /**
+     * 获取付款处理电子回单信息
+     * @param casPayBillIdList
+     * @return
+     */
+    public static Set<Object> getCasPayBillElecReceipt(Set<Object> casPayBillIdList){
+        Set<Object> elecReceiptSet = new HashSet<Object>();
+        // 付款处理的交易明细ID
+        DynamicObjectCollection casPayBillCol = QueryServiceHelper.query("cas_paybill",
+                "id,billno,bankcheckentity.edetailid",
+                new QFilter[]{new QFilter("id", "in", casPayBillIdList)});
+        if(casPayBillCol != null && casPayBillCol.size() > 0){
+            Set<Long> transDetailIds = casPayBillCol
+                    .stream()
+                    .filter(r -> r.getLong("bankcheckentity.edetailid") != 0)
+                    .map(r -> r.getLong("bankcheckentity.edetailid"))
+                    .collect(Collectors.toSet());
+
+            DynamicObjectCollection elecReceiptCol = QueryServiceHelper.query("bei_elecreceipt",
+                    "id,matchdetailentry.e_transdetailid",
+                    new QFilter("matchdetailentry.e_transdetailid", QCP.in, transDetailIds).toArray());
+            // 电子回单信息
+            if(elecReceiptCol != null && elecReceiptCol.size() > 0){
+                Set<Object> elecReceiptIdSet = elecReceiptCol.stream().map(r -> r.get("id")).collect(Collectors.toSet());
+                elecReceiptSet.addAll(elecReceiptIdSet);
+            }
+        }
+        return elecReceiptSet ;
+    }
+}

+ 160 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/util/PrintPdfUtil.java

@@ -0,0 +1,160 @@
+package nckd.jimin.jyyy.fi.common.util;
+
+import kd.bos.dataentity.resource.ResManager;
+import kd.bos.exception.KDBizException;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.print.api.PrintContext;
+import kd.bos.print.api.PrintTask;
+import kd.bos.print.api.PrintWork;
+import kd.bos.print.core.service.PrtAttach;
+import kd.bos.print.core.service.PrtAttach.AttachDetail;
+import kd.bos.print.service.BosPrintServiceHelper;
+import kd.bos.servicehelper.print.NotePrintService;
+import kd.bos.session.EncreptSessionUtils;
+import kd.bos.url.UrlService;
+import kd.bos.util.ExceptionUtils;
+import org.apache.commons.io.IOUtils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+public class PrintPdfUtil {
+    private static Log logger = LogFactory.getLog(PrintPdfUtil.class);
+
+    /**
+     *  获取打印模板的pdf  支持新旧
+     * @param pageId pageId
+     * @param formId 单据类型
+     * @param templateId 模板id
+     * @param printType 1.billForm单据   2. querylist查询    3.report报表     4.dynamic 动态表单
+     * @param type 1.旧模板 2.新模板
+     * @param pkIds 单据id
+     * @return
+     */
+    public static byte[] getPrintByte(String pageId, String formId, String templateId, List<Object> pkIds, String printType, int type) {
+        byte[] returnBytes = null;
+        try {
+            if (type == 1) {
+                NotePrintService printService = new NotePrintService();
+                if (pkIds == null) {
+                    Object object = new Object();
+                    pkIds = new ArrayList<>(1);
+                    pkIds.add(object);
+                }
+                returnBytes = printService.createSinglePdf(pageId, formId, templateId, pkIds.get(0));
+            }
+            if (type == 2) {
+                returnBytes =  getNewPrintByte(pageId, formId, templateId, pkIds, printType);
+            }
+        } catch (Exception e) {
+            throw e;
+        }
+        return returnBytes;
+    }
+
+    /**
+     *  获取新打印模板的pdf
+     * @param pageId pageId
+     * @param formId 单据类型
+     * @param templateId 模板id
+     * @param printType 1.billForm单据   2. querylist查询    3.report报表     4.dynamic 动态表单
+     * @param pkIds 单据id
+     * @return
+     * @throws IOException
+     */
+    public static byte[] getNewPrintByte(String pageId, String formId, String templateId, List<Object> pkIds, String printType) {
+        PrintWork work = new PrintWork();
+        work.setPageId(pageId);
+        work.setPrintLang(PrintContext.get().getLang());
+        // 导出类型 1. pdf  2.xls
+        work.setExpType("1");
+        PrintTask task = new PrintTask();
+        task.setFormId(formId);
+        task.setPageId(pageId);
+        //task.setPrintType(printType);
+        task.setTplId(templateId);
+        task.setPkIds(pkIds);
+        work.add(task);
+        List<String> urls = new ArrayList<String>(2);
+        PrtAttach prtAttach = BosPrintServiceHelper.execPrint(work);
+        List<AttachDetail> attachDetails = prtAttach.getAttachDetail();
+        for (AttachDetail attachDetail : attachDetails) {
+            String xString   = attachDetail.getFilePath();
+			/*String string  =  UrlService.getDomainContextUrl() + URLEncoder.encode(xString,ComonConstant.ENCODE);
+			String downloadUrl = EncreptSessionUtils.encryptSession(string);*/
+            urls.add(xString);
+        }
+        try {
+            if (urls.size() > 0) {
+                //InputStream inputStream = FileServiceFactory.getAttachmentFileService().getInputStream(urls.get(0));
+                //execPrint方法改为获取临时文件流
+                InputStream inputStream = BosPrintServiceHelper.getFileInputStream(urls.get(0));
+                ByteArrayOutputStream bos = new ByteArrayOutputStream();
+                try {
+                    IOUtils.copy(inputStream, bos);
+                } finally {
+                    closeInputStreamQuietly(inputStream);
+                }
+                return bos.toByteArray();
+            }
+            return null;
+        } catch (Exception e) {
+            String message = String.format(ResManager.loadKDString("%1$s获取新打印模板的pdf失败:%2$s", "ArchiveOpService_9", "fi-aef-opplugin") ,formId, ExceptionUtils.getExceptionStackTraceMessage(e));
+            throw new KDBizException(message);
+        }
+    }
+
+    public static String getNewPrintUrl(String pageId, String formId, String templateId, List<Object> pkIds, String printType , String accessToken) {
+        try{
+            PrintWork work = new PrintWork();
+            work.setPageId(pageId);
+            work.setPrintLang(PrintContext.get().getLang());
+            // 导出类型 1. pdf  2.xls
+            work.setExpType("1");
+            PrintTask task = new PrintTask();
+            task.setFormId(formId);
+            task.setPageId(pageId);
+            //task.setPrintType(printType);
+            task.setTplId(templateId);
+            task.setPkIds(pkIds);
+            work.add(task);
+            PrtAttach prtAttach = BosPrintServiceHelper.execPrint(work);
+            List<AttachDetail> attachDetails = prtAttach.getAttachDetail();
+            if(attachDetails != null && attachDetails.size() > 0){
+                String url = UrlService.getDomainContextUrl() + "/tempfile/download.do?" + attachDetails.get(0).getFilePath() + "&accessToken=" + accessToken;
+                logger.info("临时地址为" + url);
+                return EncreptSessionUtils.encryptSession(url);
+            }
+        }catch (Exception e){
+            logger.error("获取单据打印url失败" , e);
+            throw new KDBizException("获取单据打印url失败");
+        }
+
+        return "" ;
+    }
+    /**
+     * 关闭 OutputStream 流
+     */
+    public static void closeOutputStreamQuietly(OutputStream output) {
+        try {
+            if (output != null)
+                output.close();
+        } catch (Exception e) {
+        }
+    }
+
+    /**
+     * 关闭 InputStream 流
+     */
+    public static void closeInputStreamQuietly(InputStream input) {
+        try {
+            if (input != null)
+                input.close();
+        } catch (Exception e) {
+        }
+    }
+}

+ 241 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/common/util/ReceiveTicketUtils.java

@@ -0,0 +1,241 @@
+package nckd.jimin.jyyy.fi.common.util;
+
+import com.kingdee.bos.util.backport.Collections;
+import kd.bos.cache.CacheFactory;
+import kd.bos.cache.TempFileCache;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.dataentity.resource.ResManager;
+import kd.bos.dataentity.utils.StringUtils;
+import kd.bos.db.DB;
+import kd.bos.db.DBRoute;
+import kd.bos.db.SqlParameter;
+import kd.bos.exception.KDBizException;
+import kd.bos.fileservice.FileServiceFactory;
+import kd.bos.form.IFormView;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.print.matchtpl.*;
+import kd.bos.servicehelper.AttachmentServiceHelper;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.PrintServiceHelper;
+import kd.bos.servicehelper.QueryServiceHelper;
+import kd.bos.util.CollectionUtils;
+import kd.bos.web.actions.utils.FilePathUtil;
+import nckd.jimin.jyyy.fi.common.constant.ErPrintSetConstant;
+import nckd.jimin.jyyy.fi.common.constant.BillTypeConstants;
+import nckd.jimin.jyyy.fi.common.entity.MergePrintEntity;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static java.util.Comparator.comparing;
+
+public class ReceiveTicketUtils {
+    private static Log logger = LogFactory.getLog(ReceiveTicketUtils.class);
+
+    /**
+     * 打印模板编码合并打印
+     * @param view
+     * @param tplNumberList
+     * @param fileName
+     * @return
+     */
+    public static String mergePrintPdf(IFormView view , List<MergePrintEntity> tplNumberList , String fileName){
+        List<byte[]> mergeArray = new ArrayList<>();
+        tplNumberList.sort(comparing(MergePrintEntity::getIndex));
+
+        for (MergePrintEntity print : tplNumberList) {
+            if(StringUtils.isEmpty(print.getFormId()) || CollectionUtils.isEmpty(print.getPkIds())) {
+                continue;
+            }
+            for(Object printBillId : print.getPkIds()){
+
+                // 电子回单获取附件
+                if(BillTypeConstants.BEI_ELECRECEIPT.equals(print.getFormId())){
+                    byte[] printBuff = getElecReceiptPrintUrl(printBillId);
+                    mergeArray.add(printBuff);
+                } else{
+                    if(StringUtils.isNotEmpty(print.getTemplateId())){
+                        String tplType = getTplTypeById(print.getTemplateId());
+
+                        int tplParamType = "A".equalsIgnoreCase(tplType)?1:2;
+                        byte[] printBuff = PrintPdfUtil.getPrintByte(view.getPageId(),print.getFormId(),print.getTemplateId(),
+                                Collections.singletonList(printBillId),"billForm",tplParamType);
+                        mergeArray.add(printBuff);
+                    }
+                }
+            }
+
+        }
+
+        if(CollectionUtils.isNotEmpty(mergeArray)){
+            byte[] bytes = PrintServiceHelper.mergeMultiPdf(mergeArray);//拼接文件流
+            ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
+            TempFileCache tfc = CacheFactory.getCommonCacheFactory().getTempFileCache();
+            // 设置临时文件有效时间
+            return tfc.saveAsUrl(fileName+".pdf", bin, 60 * 60 * 2);//文件流生成临时文件
+        }
+        return "";
+    }
+
+    public static String getPrintTemplateId(String appId,String formId, Object billId) {
+        TplMatcherParam param = new TplMatcherParam();
+        param.setEntityId(formId);//表单id
+        List<Object> pkIds = new ArrayList<>(1);
+        pkIds.add(billId);
+        param.setPkIds(pkIds);//单据内码集合
+        param.setViewType(ViewType.LIST);
+        //param.setAppId(appId);//应用id
+        TplMatcherUtil matcherUtil = new TplMatcherUtil(param);
+
+        MatcherResult matcherResult = matcherUtil.runMatcher();
+        Map<Object, Set<MatcherTpl>> pkTplMap = matcherResult.getPkTplMap();
+        if(pkTplMap.containsKey(billId)){
+            Set<MatcherTpl> matcherTpls = pkTplMap.get(billId);
+            if(matcherTpls.size() > 1){
+                throw new KDBizException("单据存在多条打印模板,请在模板条件中维护。");
+            }
+            return matcherTpls.iterator().next().getTplId();
+        }
+
+        throw new KDBizException("单据没有匹配的打印模板。");
+    }
+
+
+    public static String getTplTypeById(String tplId) {
+        String sql = "select ftype from t_svc_printmeta where fid=?";
+        SqlParameter[] sqlParams = new SqlParameter[]{new SqlParameter("fid", 12, tplId)};
+        String ftype = (String) DB.query(DBRoute.basedata, sql, sqlParams, (dSet) -> {
+            return dSet.next() ? dSet.getString("ftype") : null;
+        });
+        return ftype;
+    }
+
+    /**
+     * 获取打印模板配置
+     * @param formId
+     * @param companyId
+     * @return
+     */
+    public static List<MergePrintEntity> getPrintPdfConfig(String formId , Object billId,Object companyId){
+        List<MergePrintEntity> mergePrintList = new ArrayList<>();
+        // 查询公司为空的打印配置
+        DynamicObject printSetConfig = getPrintSetConfig(companyId);
+        if(printSetConfig == null){
+            throw new KDBizException("未找到公司配置的打印配置信息。");
+        }
+        // 查询单据对应的分录
+        DynamicObjectCollection billEntryCol = printSetConfig.getDynamicObjectCollection(ErPrintSetConstant.BillPtSetEntry.ENTITYID);
+        List<DynamicObject> billEntryList = billEntryCol.stream()
+                .filter(r -> StringUtils.equals(formId, r.getString(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_BILLTYPE)))
+                .collect(Collectors.toList());
+        if(CollectionUtils.isEmpty(billEntryList)){
+            throw new KDBizException("请先在打印配置中维护单据信息。");
+        }
+
+        if(billEntryList.size() > 1){
+            throw new KDBizException("打印配置中单据存在多条配置。");
+        }
+
+        Map<String, Set<Object>> relationBelowBillMap = ErFindRelationBillUtils.getRelationBelowBillMap(billId.toString(), formId);
+        DynamicObject billConfigEntry = billEntryList.get(0);
+        if(billConfigEntry.getBoolean(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_ISPTCOVER)){
+            String printTemplateId = getPrintTemplateId(null, formId, billId);
+            mergePrintList.add(new MergePrintEntity(formId,printTemplateId, Collections.singletonList(billId),billConfigEntry.getInt(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_COVERORDER)));
+        }
+        if(billConfigEntry.getBoolean(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_ISPTVOUCHER)){
+            if(relationBelowBillMap.containsKey(BillTypeConstants.GL_VOUCHER)){
+                Set<Object> voucherIdList = relationBelowBillMap.get(BillTypeConstants.GL_VOUCHER);
+                for(Object voucherId : voucherIdList){
+                    String printTemplateId = getPrintTemplateId(null, BillTypeConstants.GL_VOUCHER, voucherId);
+                    mergePrintList.add(new MergePrintEntity(BillTypeConstants.GL_VOUCHER,printTemplateId, Collections.singletonList(voucherId),billConfigEntry.getInt(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_VOUCHERORDER)));
+                }
+            }
+        }
+        if(billConfigEntry.getBoolean(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_ISPTRECEIPT)){
+            if(relationBelowBillMap.containsKey(BillTypeConstants.BEI_ELECRECEIPT)){
+                Set<Object> elecReceipt = relationBelowBillMap.get(BillTypeConstants.BEI_ELECRECEIPT);
+                // 电子回单特殊处理,直接打印附件
+                mergePrintList.add(new MergePrintEntity(BillTypeConstants.BEI_ELECRECEIPT,null, elecReceipt.stream().collect(Collectors.toList()),billConfigEntry.getInt(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_RECEIPTORDER)));
+            }
+        }
+        return mergePrintList;
+    }
+
+    /**
+     * 获取打印配置,优先用当前公司匹配,如果没有合适的使用全集团的
+     * @param companyId
+     * @return
+     */
+    public static DynamicObject getPrintSetConfig(Object companyId){
+        DynamicObjectCollection companyConfigCol = QueryServiceHelper.query(ErPrintSetConstant.ENTITYID, ErPrintSetConstant.ID, new QFilter[]{
+                new QFilter(ErPrintSetConstant.KEY_NCKD_ORG, QCP.equals, companyId),
+                new QFilter(ErPrintSetConstant.KEY_STATUS, QCP.equals, "C"),
+                new QFilter(ErPrintSetConstant.KEY_ENABLE, QCP.equals, Boolean.TRUE)
+        });
+        if(CollectionUtils.isNotEmpty(companyConfigCol)){
+
+            if(companyConfigCol.size() > 1){
+                throw new KDBizException("公司存在多条打印配置,请维护数据后再操作。");
+            }
+            return BusinessDataServiceHelper.loadSingle(companyConfigCol.get(0).get(ErPrintSetConstant.ID),ErPrintSetConstant.ENTITYID);
+        }else{
+            DynamicObjectCollection groupConfig = QueryServiceHelper.query(ErPrintSetConstant.ENTITYID, ErPrintSetConstant.ID,new QFilter[]{
+                    QFilter.isNull(ErPrintSetConstant.KEY_NCKD_ORG).or(new QFilter(ErPrintSetConstant.KEY_NCKD_ORG,QCP.equals,0L)),
+                    new QFilter(ErPrintSetConstant.KEY_STATUS, QCP.equals, "C"),
+                    new QFilter(ErPrintSetConstant.KEY_ENABLE, QCP.equals, Boolean.TRUE)
+            });
+            if(CollectionUtils.isNotEmpty(groupConfig)){
+                if(groupConfig.size() > 1){
+                    throw new KDBizException("存在多条全集团配置,请维护数据后再操作。");
+                }
+                return BusinessDataServiceHelper.loadSingle(groupConfig.get(0).get(ErPrintSetConstant.ID),ErPrintSetConstant.ENTITYID);
+            }
+        }
+        return null ;
+    }
+
+    /**
+     * 获取电子回单文件,已开会沟通,从附件中获取
+     * @param receiptId
+     * @return
+     */
+    public static byte[] getElecReceiptPrintUrl(Object receiptId){
+        List<Map<String, Object>> attachments = AttachmentServiceHelper.getAttachments(BillTypeConstants.BEI_ELECRECEIPT, receiptId, "attachmentpanel");
+        if(attachments.size() > 1){
+            throw new KDBizException("电子回单文件存在多个,请修复数据后再打印。");
+        }
+        Object relativeUrl = attachments.get(0).get("relativeUrl");
+        if (StringUtils.isNotBlank(relativeUrl)) {
+            try{
+                String path = FilePathUtil.dealPath(relativeUrl.toString(), "attach");
+                InputStream inputStream = FileServiceFactory.getAttachmentFileService().getInputStream(path);
+                ByteArrayOutputStream  outputStream = new ByteArrayOutputStream();
+                return getBytes(inputStream,outputStream);
+            }catch (Exception e){
+                logger.error("getElecReceiptPrintUrl_getBytes_error",e);
+                throw new KDBizException("获取电子回单文件异常:" + e.getMessage());
+            }
+        }
+        return null;
+    }
+
+    public static byte[] getBytes(InputStream inputStream, ByteArrayOutputStream outputStream) throws IOException {
+        int b;
+        while ((b= inputStream.read())!=-1){
+            outputStream.write(b);
+        }
+        byte[] bytes1 = outputStream.toByteArray();
+        return bytes1;
+    }
+}

+ 54 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/form/ErDailyVehicleBillEdit.java

@@ -0,0 +1,54 @@
+package nckd.jimin.jyyy.fi.plugin.form;
+
+import kd.bos.bill.AbstractBillPlugIn;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.QueryServiceHelper;
+
+import java.util.EventObject;
+
+/**
+ * 外办申请单扩展插件
+ */
+public class ErDailyVehicleBillEdit extends AbstractBillPlugIn {
+
+    @Override
+    public void afterCreateNewData(EventObject e) {
+        super.afterCreateNewData(e);
+        initVehiclecity();
+
+    }
+
+    /**
+     * 外办城市默认赋值
+     */
+    protected void initVehiclecity(){
+        // 申请人 -> HR人员 -> 常驻工作地 -> 工作地
+        DynamicObject dataEntity = this.getModel().getDataEntity(true);
+        DynamicObject applier = dataEntity.getDynamicObject("applier");
+        if(applier == null){
+            return;
+        }
+        DynamicObject hrPerson = QueryServiceHelper.queryOne("hrpi_person", "id", new QFilter[]{
+                new QFilter("number", QCP.equals, applier.getString("number")),
+                new QFilter("iscurrentversion", QCP.equals, Boolean.TRUE)
+        });
+
+        if(hrPerson == null){
+            return;
+        }
+        DynamicObject baseLocation = QueryServiceHelper.queryOne("hrpi_baselocation", "location.city.id", new QFilter[]{
+                new QFilter("person", QCP.equals, hrPerson.getLong("id")),
+                new QFilter("iscurrentversion", QCP.equals, Boolean.TRUE)
+        });
+
+        if(baseLocation == null){
+            return;
+        }
+        long cityId = baseLocation.getLong("location.city.id");
+        if(cityId != 0L){
+            getModel().setItemValueByID("vehiclecity",cityId);
+        }
+    }
+}

+ 41 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/form/ErTicketMailPlugin.java

@@ -0,0 +1,41 @@
+package nckd.jimin.jyyy.fi.plugin.form;
+
+import kd.bos.entity.operate.result.OperationResult;
+import kd.bos.form.events.AfterDoOperationEventArgs;
+import kd.bos.form.events.BeforeDoOperationEventArgs;
+import kd.bos.form.operate.FormOperate;
+import kd.bos.form.plugin.AbstractFormPlugin;
+import nckd.jimin.jyyy.fi.common.constant.ErReimBurseBillConstant;
+
+public class ErTicketMailPlugin extends AbstractFormPlugin {
+
+    private static final String CONFIRM = "confirm";
+    @Override
+    public void beforeDoOperation(BeforeDoOperationEventArgs args) {
+        super.beforeDoOperation(args);
+        FormOperate operateKey = (FormOperate) args.getSource();
+        if(CONFIRM.equals(operateKey.getOperateKey())){
+
+        }
+    }
+
+    @Override
+    public void afterDoOperation(AfterDoOperationEventArgs args) {
+        super.afterDoOperation(args);
+
+        String operateKey = args.getOperateKey();
+        OperationResult operationResult = args.getOperationResult();
+        if(operationResult != null && operationResult.isSuccess()){
+
+            if(CONFIRM.equals(operateKey)){
+                String trackingNumber = (String)this.getModel().getValue(ErReimBurseBillConstant.KEY_NCKD_TRACKING_NUMBER);
+                getView().returnDataToParent(trackingNumber);
+                getView().close();
+            }
+        }
+    }
+
+    protected void updateBill(){
+
+    }
+}

+ 614 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/form/HandInReceiveTicketPlugin.java

@@ -0,0 +1,614 @@
+package nckd.jimin.jyyy.fi.plugin.form;
+
+import com.kingdee.util.StringUtils;
+import kd.bos.algo.DataSet;
+import kd.bos.bill.BillShowParameter;
+import kd.bos.bill.OperationStatus;
+import kd.bos.cache.CacheFactory;
+import kd.bos.cache.TempFileCache;
+import kd.bos.context.RequestContext;
+import kd.bos.dataentity.OperateOption;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.dataentity.metadata.IDataEntityProperty;
+import kd.bos.dataentity.resource.ResManager;
+import kd.bos.entity.datamodel.events.PropertyChangedArgs;
+import kd.bos.entity.operate.result.OperationResult;
+import kd.bos.ext.fi.ai.DapBuildVoucherCommonUtil;
+import kd.bos.form.CloseCallBack;
+import kd.bos.form.FormShowParameter;
+import kd.bos.form.ShowType;
+import kd.bos.form.control.EntryGrid;
+import kd.bos.form.control.Toolbar;
+import kd.bos.form.control.events.BeforeItemClickEvent;
+import kd.bos.form.control.events.ItemClickEvent;
+import kd.bos.form.control.events.RowClickEvent;
+import kd.bos.form.control.events.RowClickEventListener;
+import kd.bos.form.events.AfterDoOperationEventArgs;
+import kd.bos.form.events.BeforeDoOperationEventArgs;
+import kd.bos.form.events.ClosedCallBackEvent;
+import kd.bos.form.events.PreOpenFormEventArgs;
+import kd.bos.form.operate.FormOperate;
+import kd.bos.form.plugin.AbstractFormPlugin;
+import kd.bos.image.pojo.ImageSysInfo;
+import kd.bos.image.pojo.ViewImageVo;
+import kd.bos.imageplatform.util.SSCImageUtils;
+import kd.bos.list.ListShowParameter;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.PrintServiceHelper;
+import kd.bos.servicehelper.QueryServiceHelper;
+import kd.bos.servicehelper.image.ImageServiceNewHelper;
+import kd.bos.servicehelper.operation.OperationServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import kd.bos.servicehelper.permission.PermissionServiceHelper;
+import kd.bos.url.UrlService;
+import kd.bos.util.CollectionUtils;
+import nckd.jimin.jyyy.fi.common.constant.BillTypeConstants;
+import nckd.jimin.jyyy.fi.common.constant.ErPrintUserConstant;
+import nckd.jimin.jyyy.fi.common.constant.ErReimBurseBillConstant;
+import nckd.jimin.jyyy.fi.common.constant.HandInReceiveTicketConstant;
+import nckd.jimin.jyyy.fi.common.entity.MergePrintEntity;
+import nckd.jimin.jyyy.fi.common.util.ErFindRelationBillUtils;
+import nckd.jimin.jyyy.fi.common.util.ReceiveTicketUtils;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class HandInReceiveTicketPlugin extends AbstractFormPlugin implements RowClickEventListener {
+
+    private static Log log = LogFactory.getLog(HandInReceiveTicketPlugin.class);
+
+    private static final String CLOSECALLBACK_MAIL = "closecallback_mail";
+
+    @Override
+    public void registerListener(EventObject e) {
+        super.registerListener(e);
+        EntryGrid entryGrid = this.getControl(HandInReceiveTicketConstant.SCANBILLENTRY.ENTITYID);
+        entryGrid.addRowClickListener(this);
+
+        Toolbar toolbar = this.getControl(HandInReceiveTicketConstant.METEDATAFLAG.NCKD_ENTRY_TOOLBARAP);
+        toolbar.addItemClickListener(this);
+    }
+
+    @Override
+    public void beforeBindData(EventObject e) {
+        super.beforeBindData(e);
+        // 显示当前扫描点
+        DynamicObjectCollection scanTypeCol = getScanType();
+        getModel().setValue(HandInReceiveTicketConstant.KEY_NCKD_SCANTYPE,scanTypeCol.get(0).getString(ErPrintUserConstant.KEY_NCKD_SCANTYPE));
+    }
+
+    @Override
+    public void preOpenForm(PreOpenFormEventArgs e) {
+        super.preOpenForm(e);
+        DynamicObjectCollection scanTypeCol = getScanType();
+
+        if(CollectionUtils.isEmpty(scanTypeCol)){
+            e.setCancel(true);
+            e.setCancelMessage("请先配置用户登记后再操作。");
+            return;
+        }
+
+        if(scanTypeCol.size() > 1){
+            e.setCancel(true);
+            e.setCancelMessage("用户登记存在多条有效数据,请处理后再操作。");
+            return;
+        }
+    }
+
+    @Override
+    public void propertyChanged(PropertyChangedArgs e) {
+        super.propertyChanged(e);
+        IDataEntityProperty property = e.getProperty();
+        String name = property.getName();
+        switch (name){
+            case HandInReceiveTicketConstant.KEY_NCKD_SCANNUMBER:
+                propertyChangedScanNumber(e);
+                break;
+        }
+
+    }
+
+    protected void propertyChangedScanNumber(PropertyChangedArgs e){
+        // 查询单据
+        String scanNumber = (String)this.getModel().getValue(HandInReceiveTicketConstant.KEY_NCKD_SCANNUMBER);
+        if(StringUtils.isEmpty(scanNumber)){
+            return;
+        }
+        // 判断编码是否存在
+        DynamicObjectCollection entryEntity = getModel().getEntryEntity(HandInReceiveTicketConstant.SCANBILLENTRY.ENTITYID);
+        Optional<DynamicObject> findNumberOp = entryEntity.stream()
+                .filter(r -> scanNumber.equals(r.getString(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_NUMBER))).findFirst();
+        if(findNumberOp.isPresent()){
+            return;
+        }
+
+        String[] findBillArray = new String[]{BillTypeConstants.ER_PUBLICREIMBURSEBILL,BillTypeConstants.ER_DAILYREIMBURSEBILL,
+                BillTypeConstants.ER_TRIPREIMBURSEBILL,BillTypeConstants.ER_CHECKINGPAYBILL,BillTypeConstants.ER_PREPAYBILL};
+        for(String billType : findBillArray){
+            Boolean isFind = loadBillInfo(billType, scanNumber);
+            if(isFind){
+                return;
+            }
+        }
+
+    }
+
+    protected Boolean loadBillInfo(String billlType , String billNo){
+        String selector = String.join(",",ErReimBurseBillConstant.ID,ErReimBurseBillConstant.KEY_BILLNO,ErReimBurseBillConstant.KEY_COMPANY,
+                ErReimBurseBillConstant.KEY_NCKD_HANDIN_PERSON,ErReimBurseBillConstant.KEY_NCKD_RECEIPT_PERSON);
+        DynamicObject tripReimBurseBill = BusinessDataServiceHelper.loadSingle(billlType,selector,
+                new QFilter(ErReimBurseBillConstant.KEY_BILLNO, QCP.equals, billNo).toArray());
+        if(tripReimBurseBill != null){
+            addScanBillEntry(tripReimBurseBill.getString(ErReimBurseBillConstant.KEY_BILLNO),getReceiptStatus(tripReimBurseBill),
+                    tripReimBurseBill.get(ErReimBurseBillConstant.ID), billlType,
+                    tripReimBurseBill.getDynamicObject(ErReimBurseBillConstant.KEY_COMPANY).getPkValue());
+            return true;
+        }
+        return false;
+    }
+
+
+    protected String getReceiptStatus(DynamicObject billInfo){
+        // 未交票
+        if(billInfo.getDynamicObject(ErReimBurseBillConstant.KEY_NCKD_HANDIN_PERSON) == null){
+            return "handin_incomplete";
+        }
+        //未收票
+        if(billInfo.getDynamicObject(ErReimBurseBillConstant.KEY_NCKD_HANDIN_PERSON) != null
+                && billInfo.getDynamicObject(ErReimBurseBillConstant.KEY_NCKD_RECEIPT_PERSON) == null){
+            return "receipt_incomplete";
+        }
+        //已收票
+        if(billInfo.getDynamicObject(ErReimBurseBillConstant.KEY_NCKD_HANDIN_PERSON) != null
+                && billInfo.getDynamicObject(ErReimBurseBillConstant.KEY_NCKD_RECEIPT_PERSON) != null){
+            return "receipt_complete";
+        }
+        return "";
+    }
+
+
+    protected void addScanBillEntry(String number, String status, Object billId, String formId, Object companyId){
+        int newEntryRow = this.getModel().createNewEntryRow(HandInReceiveTicketConstant.SCANBILLENTRY.ENTITYID);
+        getModel().setValue(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_NUMBER,number,newEntryRow);
+        getModel().setValue(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_STATUS,status,newEntryRow);
+        getModel().setValue(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_BILLID,billId,newEntryRow);
+        getModel().setValue(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_FORMID,formId,newEntryRow);
+        getModel().setItemValueByID(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_COMPANY,companyId,newEntryRow);
+        getView().updateView(HandInReceiveTicketConstant.SCANBILLENTRY.ENTITYID);
+    }
+
+    protected DynamicObjectCollection getScanType(){
+        long currUserId = RequestContext.get().getCurrUserId();
+        // 查询用户登记
+        return QueryServiceHelper.query(ErPrintUserConstant.ENTITYID, ErPrintUserConstant.KEY_NCKD_SCANTYPE, new QFilter[]{
+                new QFilter(ErPrintUserConstant.KEY_NCKD_BOS_USER, QCP.equals, currUserId),
+                new QFilter(ErPrintUserConstant.KEY_STATUS, QCP.equals, "C"),
+                new QFilter(ErPrintUserConstant.KEY_ENABLE, QCP.equals, Boolean.TRUE),
+        });
+    }
+
+    @Override
+    public void beforeItemClick(BeforeItemClickEvent evt) {
+        super.beforeItemClick(evt);
+        String itemKey = evt.getItemKey();
+
+        if(HandInReceiveTicketConstant.OPERATE.NCKD_MAIL.equals(itemKey) || HandInReceiveTicketConstant.OPERATE.NCKD_CANCELMAIN.equals(itemKey)
+            || HandInReceiveTicketConstant.OPERATE.NCKD_VIEW_VOUCHER.equals(itemKey) || HandInReceiveTicketConstant.OPERATE.NCKD_VIEW_ELECRECEIPT.equals(itemKey)
+            || HandInReceiveTicketConstant.OPERATE.NCKD_IMAGEPREVIEW.equals(itemKey)){
+            String checkMsg = checkSelectSingle();
+            if(!StringUtils.isEmpty(checkMsg)) {
+                getView().showTipNotification(checkMsg);
+                evt.setCancel(true);
+                return;
+            }
+        }
+
+        switch (itemKey){
+            case HandInReceiveTicketConstant.OPERATE.NCKD_MAIL:
+                beforeMail(evt);
+                break;
+            case HandInReceiveTicketConstant.OPERATE.NCKD_CANCELMAIN:
+                beforeCancleMail(evt);
+                break;
+            case HandInReceiveTicketConstant.OPERATE.NCKD_IMAGEPREVIEW:
+                beforeImagePreview(evt);
+                break;
+        }
+    }
+
+    protected void beforeMail(BeforeItemClickEvent evt){
+
+        DynamicObject selectRow = getSelectRows().get(0);
+        // 快递编号为空
+        DynamicObject billInfo = BusinessDataServiceHelper.loadSingle(selectRow.getString(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_BILLID),
+                selectRow.getString(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_FORMID), ErReimBurseBillConstant.KEY_NCKD_TRACKING_NUMBER);
+
+        if(!StringUtils.isEmpty(billInfo.getString(ErReimBurseBillConstant.KEY_NCKD_TRACKING_NUMBER))){
+            getView().showTipNotification("不允许重复邮寄。");
+            evt.setCancel(true);
+            return;
+        }
+    }
+    protected void beforeCancleMail(BeforeItemClickEvent evt){
+        // 快递编号为空
+        DynamicObject billInfo = getSelectBillInfo(ErReimBurseBillConstant.KEY_NCKD_TRACKING_NUMBER);
+
+        if(StringUtils.isEmpty(billInfo.getString(ErReimBurseBillConstant.KEY_NCKD_TRACKING_NUMBER))){
+            getView().showTipNotification("单据没有进行邮寄操作。");
+            evt.setCancel(true);
+            return;
+        }
+
+    }
+
+    protected void beforeImagePreview(BeforeItemClickEvent evt){
+        // 进行权限校验
+
+    }
+
+
+    @Override
+    public void itemClick(ItemClickEvent evt) {
+        super.itemClick(evt);
+
+        String itemKey = evt.getItemKey();
+
+        switch (itemKey){
+            case HandInReceiveTicketConstant.OPERATE.NCKD_MAIL:
+                doMail();
+                break;
+            case HandInReceiveTicketConstant.OPERATE.NCKD_CANCELMAIN:
+                doCancleMail();
+                break;
+            case HandInReceiveTicketConstant.OPERATE.NCKD_VIEW_VOUCHER:
+                doViewVouhcer();
+                break;
+            case HandInReceiveTicketConstant.OPERATE.NCKD_VIEW_ELECRECEIPT:
+                doViewElecReceipt();
+            case HandInReceiveTicketConstant.OPERATE.NCKD_REFRESH:
+                doRefresh();
+                break;
+            case HandInReceiveTicketConstant.OPERATE.NCKD_IMAGEPREVIEW:
+                doImagePreview();
+                break;
+        }
+    }
+
+    protected void doImagePreview(){
+        String userID = String.valueOf(RequestContext.get().getUserId());
+        String userName = String.valueOf(RequestContext.get().getUserName());
+
+        ImageSysInfo enableImageSysInfo = null;
+        DynamicObject selectBillInfo = getSelectBillInfo(String.join(",",ErReimBurseBillConstant.ID,ErReimBurseBillConstant.KEY_NUMBER));
+        String billType = selectBillInfo.getDataEntityType().getName();
+        try {
+            enableImageSysInfo = SSCImageUtils.getEnableImageSysInfo();
+        } catch (Exception e) {
+            log.error("获取影像系统异常:" + e.getMessage());
+        }
+        String imageSys;
+        if (enableImageSysInfo == null) {
+            imageSys = ResManager.loadKDString("无启用的影像系统配置,请联系系统管理员。", "ImageReview_0", "bos-image-formplugin", new Object[0]);
+            getView().showTipNotification(imageSys);
+            return;
+        }
+
+        imageSys = enableImageSysInfo.getNumber();
+        log.info("获取到的imagesys:{}" , imageSys);
+        ViewImageVo viewImageVo = new ViewImageVo();
+        viewImageVo.setBillId(selectBillInfo.getString(ErReimBurseBillConstant.ID));
+        viewImageVo.setUserId(userID);
+        viewImageVo.setUserName(userName);
+        viewImageVo.setMobile(false);
+        viewImageVo.setBilltype(billType);
+        viewImageVo.setImageSys(imageSys);
+        viewImageVo = ImageServiceNewHelper.viewPhoto(viewImageVo);
+        if (viewImageVo.getUrl() == null) {
+            getView().showTipNotification(viewImageVo.getMessage());
+            return;
+        }
+        String url = viewImageVo.getUrl();
+        String message = viewImageVo.getMessage();
+        if (kd.bos.util.StringUtils.isNotEmpty(message)) {
+            getView().showMessage(message);
+            return;
+        }
+        getView().openUrl(url);
+    }
+
+    protected void doViewVouhcer(){
+        DynamicObject selectRow = getSelectRows().get(0);
+        Map<String, Set<Object>> relationBelowBillMap = ErFindRelationBillUtils.getRelationBelowBillMap(selectRow.getString(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_BILLID),
+                selectRow.getString(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_FORMID));
+        if(relationBelowBillMap.containsKey(BillTypeConstants.GL_VOUCHER)){
+            Set<Object> voucherIdSet = relationBelowBillMap.get(BillTypeConstants.GL_VOUCHER);
+            if(CollectionUtils.isNotEmpty(voucherIdSet)){
+                if(voucherIdSet.size() == 1){
+                    Object voucherId = voucherIdSet.iterator().next();
+                    BillShowParameter showParameter = new BillShowParameter();
+                    showParameter.setPkId(voucherId);
+                    showParameter.setFormId(BillTypeConstants.GL_VOUCHER);
+                    showParameter.getOpenStyle().setShowType(ShowType.MainNewTabPage);
+                    DataSet ds = QueryServiceHelper.queryDataSet("TraceVoucher_queryvoucher", BillTypeConstants.GL_VOUCHER, "org", new QFilter[]{new QFilter("id", "=", voucherId)}, null);
+                    long orgId = ds.iterator().next().getLong("org");
+                    long userId = Long.parseLong(RequestContext.get().getUserId());
+                    int checkPermission = PermissionServiceHelper.checkPermission(userId, "DIM_ORG", orgId, "83bfebc8000017ac", BillTypeConstants.GL_VOUCHER, "4715a0df000000ac");
+                    Boolean isbizvoucher = DapBuildVoucherCommonUtil.getEnableBizVoucherSystemParam(orgId);
+                    if (checkPermission != 1 || isbizvoucher) {
+                        showParameter.setStatus(OperationStatus.VIEW);
+                    } else {
+                        showParameter.setStatus(OperationStatus.EDIT);
+                    }
+                    showParameter.setHasRight(true);
+                    this.getView().showForm(showParameter);
+                }else{
+                    ListShowParameter showParameter = new ListShowParameter();
+                    showParameter.setBillFormId(BillTypeConstants.GL_VOUCHER);
+                    showParameter.getOpenStyle().setShowType(ShowType.MainNewTabPage);
+                    showParameter.setShowFilter(false);
+                    showParameter.setShowQuickFilter(false);
+                    for(Object voucherId : voucherIdSet){
+                        showParameter.addLinkQueryPkId(voucherId);
+                    }
+                    showParameter.getCustomParams().put("org", "");
+                    showParameter.getCustomParams().put("booktype", "");
+                    this.getView().showForm(showParameter);
+                }
+            }else{
+                this.getView().showTipNotification(ResManager.loadKDString("单据没有关联的凭证。", "TraceVoucher_2", "bos-ext-fi"));
+            }
+        }else{
+            this.getView().showTipNotification(ResManager.loadKDString("单据没有关联的凭证。", "TraceVoucher_2", "bos-ext-fi"));
+        }
+    }
+
+    protected void doViewElecReceipt(){
+        DynamicObject selectRow = getSelectRows().get(0);
+
+        Map<String, Set<Object>> relationBelowBillMap = ErFindRelationBillUtils.getRelationBelowBillMap(selectRow.getString(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_BILLID),
+                selectRow.getString(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_FORMID));
+        if(!relationBelowBillMap.containsKey(BillTypeConstants.BEI_ELECRECEIPT) || CollectionUtils.isEmpty(relationBelowBillMap.get(BillTypeConstants.BEI_ELECRECEIPT))){
+            getView().showTipNotification("");
+            return;
+        }
+        List<byte[]> mergeArray = new ArrayList<>();
+        Set<Object> elecReceiptIdSet = relationBelowBillMap.get(BillTypeConstants.BEI_ELECRECEIPT);
+        for(Object elecReceiptId : elecReceiptIdSet){
+            byte[] bytes = ReceiveTicketUtils.getElecReceiptPrintUrl(elecReceiptId);
+            mergeArray.add(bytes);
+        }
+
+        byte[] bytes = PrintServiceHelper.mergeMultiPdf(mergeArray);//拼接文件流
+
+        String fileName = String.format("单据%s电子回单文件文件预览");
+        TempFileCache tfc = CacheFactory.getCommonCacheFactory().getTempFileCache();
+        // 设置临时文件有效时间
+        String tempUrl = tfc.saveAsFullUrl(fileName + ".pdf", bytes, 60 * 60 * 2);//文件流生成临时文件
+        String url = null;
+        try {
+            url = URLEncoder.encode(tempUrl, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        String previewurl = UrlService.getAttachmentPreviewUrl(url);
+        getView().openUrl(previewurl);
+    }
+
+
+
+    protected void doRefresh(){
+
+        int entryRowCount = getModel().getEntryRowCount(HandInReceiveTicketConstant.SCANBILLENTRY.ENTITYID);
+        int[] allRow = new int[entryRowCount];
+        for(int i = 0 ; i< entryRowCount ; i++){
+            allRow[i] = i ;
+        }
+        reloadEntryRow(allRow);
+    }
+
+    protected void doMail(){
+
+        FormShowParameter parameter = new FormShowParameter();
+        parameter.setFormId(HandInReceiveTicketConstant.ENTITY_NCKD_TICKET_MAIL);
+        CloseCallBack callBack = new CloseCallBack(this,CLOSECALLBACK_MAIL);
+        parameter.setCloseCallBack(callBack);
+        parameter.getOpenStyle().setShowType(ShowType.Modal);
+        getView().showForm(parameter);
+    }
+
+    protected void doCancleMail(){
+        DynamicObject billInfo = getSelectBillInfo(String.join(",",ErReimBurseBillConstant.KEY_BILLNO,ErReimBurseBillConstant.KEY_NCKD_TRACKING_NUMBER));
+        billInfo.set(ErReimBurseBillConstant.KEY_NCKD_TRACKING_NUMBER,null);
+        SaveServiceHelper.save(new DynamicObject[]{ billInfo });
+        getView().showSuccessNotification("退邮成功。");
+    }
+
+
+
+    protected DynamicObject getSelectBillInfo(String selector){
+        DynamicObject selectRow = getSelectRows().get(0);
+        // 快递编号为空
+       return BusinessDataServiceHelper.loadSingle(selectRow.getString(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_BILLID),
+                selectRow.getString(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_FORMID), selector);
+    }
+
+
+
+    @Override
+    public void beforeDoOperation(BeforeDoOperationEventArgs args) {
+        super.beforeDoOperation(args);
+        FormOperate operate = (FormOperate)args.getSource();
+        String operateKey = operate.getOperateKey();
+        String checkMsg = checkSelectSingle();
+        switch (operateKey){
+            case HandInReceiveTicketConstant.OPERATE.MERGEPRINT:
+                if(!StringUtils.isEmpty(checkMsg)){
+                    getView().showTipNotification(checkMsg);
+                    args.setCancel(true);
+                    return;
+                }
+                beforeDoPrint(args);
+                break;
+        }
+    }
+
+    protected void beforeDoPrint(BeforeDoOperationEventArgs args){
+        DynamicObject billInfo = getSelectBillInfo(ErReimBurseBillConstant.KEY_BILLSTATUS);
+        List<String> status = Arrays.asList("E", "F", "G");
+        if(!status.contains(billInfo.getString(ErReimBurseBillConstant.KEY_BILLSTATUS))){
+            getView().showTipNotification(String.format("单据%s打印失败:只有审核通过、等待付款、已付款状态的单据允许打印。",billInfo.getString(ErReimBurseBillConstant.KEY_BILLNO)));
+            args.setCancel(true);
+            return;
+        }
+    }
+
+    @Override
+    public void afterDoOperation(AfterDoOperationEventArgs args) {
+        super.afterDoOperation(args);
+        String operateKey = args.getOperateKey();
+        OperationResult operationResult = args.getOperationResult();
+
+        if( operationResult != null
+                && (!operationResult.isSuccess() || operationResult.getSuccessPkIds().size() == 0)){
+            return;
+        }
+        switch (operateKey) {
+            case HandInReceiveTicketConstant.OPERATE.HANDIN_TICKET:
+                executeOperateBill(operateKey, "交票");
+                break;
+            case HandInReceiveTicketConstant.OPERATE.RECEIVE_TICKET:
+                executeOperateBill(operateKey, "收票");
+                break;
+            // 打印
+            case HandInReceiveTicketConstant.OPERATE.MERGEPRINT:
+                doMergetPrint();
+                break;
+        }
+    }
+
+    @Override
+    public void entryRowDoubleClick(RowClickEvent evt) {
+        RowClickEventListener.super.entryRowDoubleClick(evt);
+        EntryGrid entryGrid = (EntryGrid)evt.getSource();
+        String entryKey = entryGrid.getEntryKey();
+        int row = evt.getRow();
+
+        if(StringUtils.equals(entryKey,HandInReceiveTicketConstant.SCANBILLENTRY.ENTITYID)){
+            // 获取单据信息
+            DynamicObject billEntry = getModel().getEntryRowEntity(HandInReceiveTicketConstant.SCANBILLENTRY.ENTITYID, row);
+            BillShowParameter parameter = new BillShowParameter();
+            parameter.setFormId(billEntry.getString(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_FORMID));
+            parameter.setStatus(OperationStatus.VIEW);
+            parameter.getOpenStyle().setShowType(ShowType.InContainer);
+            parameter.getOpenStyle().setTargetKey(HandInReceiveTicketConstant.METEDATAFLAG.NCKD_FLEX_TARGETBILL);
+            getView().showForm(parameter);
+        }
+    }
+
+    @Override
+    public void entryRowClick(RowClickEvent evt) {
+        RowClickEventListener.super.entryRowClick(evt);
+    }
+
+    protected String checkSelectSingle(){
+        List<DynamicObject> selectRows = getSelectRows();
+        if(selectRows.size() == 0){
+            return "请选择要执行的数据。";
+        }
+        if(selectRows.size() > 1){
+            return "仅允许选择一条数据进行操作。";
+        }
+        return "";
+    }
+
+    protected void doMergetPrint() {
+        DynamicObject selectRow = getSelectRows().get(0);
+        Object companyId = selectRow.getDynamicObject(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_COMPANY).getPkValue();
+        String formId = selectRow.getString(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_FORMID);
+        String billId = selectRow.getString(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_BILLID);
+
+        // 通过打印配置获取单据打印信息
+        List<MergePrintEntity> printPdfConfig = ReceiveTicketUtils.getPrintPdfConfig(formId,Long.valueOf(billId),companyId);
+        String printFileName = String.format("%s报销信息打印",selectRow.getString(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_NUMBER));
+        String downloadUrl = ReceiveTicketUtils.mergePrintPdf(getView(), printPdfConfig, printFileName);
+        getView().download(downloadUrl);
+        getView().showSuccessNotification("打印成功。");
+    }
+
+    protected void reloadEntryRow(int[] indexArray){
+        for(int index : indexArray){
+            DynamicObject entryRowEntity = getModel().getEntryRowEntity(HandInReceiveTicketConstant.SCANBILLENTRY.ENTITYID, index);
+            DynamicObject billInfo = BusinessDataServiceHelper.loadSingle(entryRowEntity.getString(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_BILLID),
+                    entryRowEntity.getString(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_FORMID),
+                    String.join(",", ErReimBurseBillConstant.KEY_NCKD_HANDIN_PERSON, ErReimBurseBillConstant.KEY_NCKD_RECEIPT_PERSON));
+            entryRowEntity.set(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_STATUS,getReceiptStatus(billInfo));
+        }
+        getView().updateView(HandInReceiveTicketConstant.SCANBILLENTRY.ENTITYID);
+    }
+
+    @Override
+    public void closedCallBack(ClosedCallBackEvent event) {
+        super.closedCallBack(event);
+        String actionId = event.getActionId();
+        Object returnData = event.getReturnData();
+        if(CLOSECALLBACK_MAIL.equals(actionId)){
+            if(returnData == null || StringUtils.isEmpty(returnData.toString())){
+                return;
+            }
+            DynamicObject billInfo = getSelectBillInfo(ErReimBurseBillConstant.KEY_NCKD_TRACKING_NUMBER);
+            billInfo.set(ErReimBurseBillConstant.KEY_NCKD_TRACKING_NUMBER,returnData);
+            SaveServiceHelper.save(new DynamicObject[]{ billInfo });
+        }
+    }
+
+    protected void executeOperateBill(String operate, String operateName){
+        List<DynamicObject> selectRowList = getSelectRows();
+        EntryGrid entryGrid = this.getControl(HandInReceiveTicketConstant.SCANBILLENTRY.ENTITYID);
+
+        if(selectRowList.size() <= 0){
+            return;
+        }
+        // 按照单据类型分组来执行
+        Map<String, List<DynamicObject>> formIdMap = selectRowList.stream().collect(Collectors.groupingBy(r -> r.getString(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_FORMID)));
+
+        OperationResult opResult =new OperationResult();
+
+        for(Map.Entry<String, List<DynamicObject>> row : formIdMap.entrySet()){
+            String billFormId = row.getKey();
+            List<DynamicObject> billList = row.getValue();
+            List<Object> selectRowIdList = billList.stream().map(r -> r.get(HandInReceiveTicketConstant.SCANBILLENTRY.KEY_NCKD_BILLID)).collect(Collectors.toList());
+            // 调用操作
+            OperationResult operationResult = OperationServiceHelper.executeOperate(operate, billFormId, selectRowIdList.toArray(), OperateOption.create());
+
+            opResult.mergeOperateResult(operationResult);
+
+        }
+
+        // 全部成功弹出消息提示,否则弹出操作提示框
+        if(opResult.isSuccess()){
+            getView().showSuccessNotification(String.format("执行【%1$s】操作成功!",operateName));
+        }else{
+            getView().showOperationResult(opResult);
+        }
+
+        //刷新分录
+        reloadEntryRow(entryGrid.getSelectRows());
+    }
+
+    protected List<DynamicObject> getSelectRows(){
+        List<DynamicObject> selectRowList = new ArrayList<>();
+        EntryGrid entryGrid = this.getControl(HandInReceiveTicketConstant.SCANBILLENTRY.ENTITYID);
+        int[] selectRows = entryGrid.getSelectRows();
+        for(int rowIndex : selectRows){
+            selectRowList.add(getModel().getEntryRowEntity(HandInReceiveTicketConstant.SCANBILLENTRY.ENTITYID,rowIndex));
+        }
+        return selectRowList;
+    }
+}

+ 57 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/ErPrintSetOp.java

@@ -0,0 +1,57 @@
+package nckd.jimin.jyyy.fi.plugin.operate;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.dataentity.resource.ResManager;
+import kd.bos.entity.ExtendedDataEntity;
+import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.AddValidatorsEventArgs;
+import kd.bos.entity.plugin.PreparePropertysEventArgs;
+import kd.bos.entity.validate.AbstractValidator;
+import nckd.jimin.jyyy.fi.common.constant.ErPrintSetConstant;
+
+public class ErPrintSetOp extends AbstractOperationServicePlugIn {
+
+    @Override
+    public void onPreparePropertys(PreparePropertysEventArgs e) {
+        super.onPreparePropertys(e);
+        e.getFieldKeys().add(ErPrintSetConstant.BillPtSetEntry.ENTITYID);
+        e.getFieldKeys().add("seq");
+        e.getFieldKeys().add(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_ISPTCOVER);
+        e.getFieldKeys().add(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_COVERORDER);
+        e.getFieldKeys().add(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_ISPTVOUCHER);
+        e.getFieldKeys().add(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_VOUCHERORDER);
+        e.getFieldKeys().add(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_ISPTRECEIPT);
+        e.getFieldKeys().add(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_RECEIPTORDER);
+    }
+
+    @Override
+    public void onAddValidators(AddValidatorsEventArgs e) {
+        super.onAddValidators(e);
+        e.getValidators().add(new AbstractValidator() {
+            @Override
+            public void validate() {
+                ExtendedDataEntity[] dataEntities = getDataEntities();
+                for(ExtendedDataEntity data : dataEntities){
+                    DynamicObject dataEntity = data.getDataEntity();
+                    DynamicObjectCollection entryCol = dataEntity.getDynamicObjectCollection(ErPrintSetConstant.BillPtSetEntry.ENTITYID);
+                    for(DynamicObject entry : entryCol){
+                        if(entry.getBoolean(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_ISPTCOVER)
+                                && entry.getLong(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_COVERORDER) == 0L){
+                            this.addErrorMessage(data, String.format("第%s行单据封面顺序不允许为空。",entry.getString("seq")));
+                        }
+                        if(entry.getBoolean(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_ISPTVOUCHER)
+                                && entry.getLong(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_VOUCHERORDER) == 0L){
+                            this.addErrorMessage(data, String.format("第%s行凭证打印顺序不允许为空。",entry.getString("seq")));
+                        }
+                        if(entry.getBoolean(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_ISPTRECEIPT)
+                                && entry.getLong(ErPrintSetConstant.BillPtSetEntry.KEY_NCKD_RECEIPTORDER) == 0L){
+                            this.addErrorMessage(data, String.format("第%s行电子回单顺序不允许为空。",entry.getString("seq")));
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+}

+ 0 - 14
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/PrepayBillOpPlugin.java

@@ -1,14 +0,0 @@
-package nckd.jimin.jyyy.fi.plugin.operate;
-
-import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
-import kd.bos.logging.Log;
-import kd.bos.logging.LogFactory;
-
-/**
- * 表单标识:预付单(nckd_er_prepaybill_ext)
- * @author wanghaiwu_kd
- * @date 2025/04/29
- */
-public class PrepayBillOpPlugin extends AbstractOperationServicePlugIn {
-    private static final Log logger = LogFactory.getLog(PrepayBillOpPlugin.class);
-}

+ 62 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/ReimBurseBillReceiveTicketOp.java

@@ -0,0 +1,62 @@
+package nckd.jimin.jyyy.fi.plugin.operate;
+
+import kd.bos.context.RequestContext;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.AddValidatorsEventArgs;
+import kd.bos.entity.plugin.PreparePropertysEventArgs;
+import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import nckd.jimin.jyyy.fi.common.constant.ErReimBurseBillConstant;
+import nckd.jimin.jyyy.fi.plugin.operate.validator.ReimBurseBillReceiveTicketValidator;
+
+import java.util.Arrays;
+import java.util.Date;
+
+public class ReimBurseBillReceiveTicketOp extends AbstractOperationServicePlugIn {
+
+    @Override
+    public void onPreparePropertys(PreparePropertysEventArgs e) {
+        super.onPreparePropertys(e);
+        e.getFieldKeys().add(ErReimBurseBillConstant.KEY_BILLSTATUS);
+        e.getFieldKeys().add(ErReimBurseBillConstant.KEY_NCKD_HANDIN_PERSON);
+        e.getFieldKeys().add(ErReimBurseBillConstant.KEY_NCKD_HANDIN_DATE);
+        e.getFieldKeys().add(ErReimBurseBillConstant.KEY_NCKD_RECEIPT_PERSON);
+        e.getFieldKeys().add(ErReimBurseBillConstant.KEY_NCKD_RECEIPT_DATE);
+    }
+
+    @Override
+    public void onAddValidators(AddValidatorsEventArgs e) {
+        super.onAddValidators(e);
+        e.getValidators().add(new ReimBurseBillReceiveTicketValidator());
+    }
+
+    @Override
+    public void beginOperationTransaction(BeginOperationTransactionArgs e) {
+        super.beginOperationTransaction(e);
+        String operationKey = e.getOperationKey();
+        DynamicObject[] dataEntities = e.getDataEntities();
+        String billtype = this.billEntityType.getName();
+        Arrays.stream(dataEntities).forEach(bill -> doHandInReceiptTicket(bill.getPkValue(),billtype,operationKey));
+    }
+
+    protected void doHandInReceiptTicket(Object billId , String billType,String operationKey){
+
+        DynamicObject billInfo = BusinessDataServiceHelper.loadSingle(billId, billType, String.join(",", ErReimBurseBillConstant.KEY_NCKD_HANDIN_PERSON,
+                ErReimBurseBillConstant.KEY_NCKD_HANDIN_DATE, ErReimBurseBillConstant.KEY_NCKD_RECEIPT_PERSON, ErReimBurseBillConstant.KEY_NCKD_RECEIPT_DATE));
+        long currUserId = RequestContext.get().getCurrUserId();
+        Date now = new Date();
+        if(operationKey.equals(ErReimBurseBillConstant.OPERATE.HANDIN_TICKET)){
+            billInfo.set(ErReimBurseBillConstant.KEY_NCKD_HANDIN_PERSON,currUserId);
+            billInfo.set(ErReimBurseBillConstant.KEY_NCKD_HANDIN_DATE,now);
+        }
+
+        if(operationKey.equals(ErReimBurseBillConstant.OPERATE.RECEIVE_TICKET)){
+            billInfo.set(ErReimBurseBillConstant.KEY_NCKD_RECEIPT_PERSON,currUserId);
+            billInfo.set(ErReimBurseBillConstant.KEY_NCKD_RECEIPT_DATE,now);
+        }
+        SaveServiceHelper.save(new DynamicObject[]{ billInfo });
+    }
+
+}

+ 120 - 2
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/SRMHelperUtils.java

@@ -223,6 +223,124 @@ public class SRMHelperUtils {
         }
     }
 
+    /**
+     * 回写审批结果
+     * @param srmBillNo
+     * @return
+     */
+    public static Map<String,String> writeApproveStatus(String srmBillNo, String documentType) {
+        Map<String,String> returnMap = new HashMap<>();
+        //获取token
+        Map<String,String> tokenMap = getSRMToken();
+        if (!"0".equals(tokenMap.get("code"))) {//未获取到token
+            returnMap.put("code", "1");
+            returnMap.put("msg", tokenMap.get("msg"));
+
+            return returnMap;
+        }
+        String token = tokenMap.get("msg").toString();
+
+        Map<String, String> mapentity = CommonHelperUtils.getCommonParams("SRM");
+        if(mapentity == null ){
+            logger.info("SRMHelperUtils:nckd_entryentity is null");
+
+            returnMap.put("code", "1");
+            returnMap.put("msg", "未配置SRM系统对接参数!");
+            return returnMap;
+        }
+
+        String serverUrlApi = mapentity.get("apiserverurl");
+        String writeBillStatusApi = mapentity.get("apiwritebillstatus");
+        String userName = mapentity.get("username");//用户名(srm提供)
+        String interfaceCode = mapentity.get("interfacecodewritebillstatus");//接口编码(srm提供,不同接口编码不同)
+        String externalSysCode = mapentity.get("externalsyscode");//外部系统(srm提供)
+        String applicationCode = mapentity.get("applicationcode");//应用(srm提供)
+        String applicationGroupCode = mapentity.get("applicationgroupcode");//应用组(srm提供)
+
+        if(StringUtils.isEmpty(serverUrlApi) || StringUtils.isEmpty(writeBillStatusApi) || StringUtils.isEmpty(userName)
+                || StringUtils.isEmpty(interfaceCode) ||StringUtils.isEmpty(externalSysCode)
+                || StringUtils.isEmpty(applicationCode) || StringUtils.isEmpty(applicationGroupCode)){
+            returnMap.put("code", "1");
+            returnMap.put("msg", "请检查是否配置SRM参数:服务地址、回写审批状态接口、用户名、接口编码、外部系统、应用编码、应用组");
+            return returnMap;
+        }
+
+        String url = serverUrlApi + writeBillStatusApi;
+        String timestamp = String.valueOf(System.currentTimeMillis());
+
+        JSONObject headerObj = new JSONObject();
+        headerObj.put("applicationCode", applicationCode);
+        headerObj.put("applicationGroupCode", applicationGroupCode);
+        headerObj.put("batchNum", timestamp);
+        headerObj.put("externalSystemCode", externalSysCode);
+        headerObj.put("interfaceCode", interfaceCode);
+        headerObj.put("userName", userName);
+
+        JSONArray bodyArr = new JSONArray();
+        JSONObject bodyObj = new JSONObject();
+
+        bodyObj.put("settleNum", srmBillNo);//SRM单据编号
+        bodyObj.put("settleStatus", "APPROVED");//APPROVED 已审批 / REJECTED 已拒绝
+        bodyObj.put("documentType", documentType);//PAYMENT 付款   PREPAYMENT 预付款
+        bodyObj.put("approvedRemark", "通过");//审批意见
+
+        JSONArray lineNumArr = new JSONArray();
+        JSONObject lineNumObj = new JSONObject();
+        lineNumObj.put("lineNum", 1);
+        lineNumArr.add(lineNumObj);
+
+        bodyObj.put("settleReversalLines", lineNumArr);//结算单行
+
+
+        bodyArr.add(bodyObj);
+
+        JSONObject body=new JSONObject();
+        body.put("header", headerObj);
+        body.put("body", bodyArr);
+
+        Map<String, String> headerMap = new HashMap<>();
+        headerMap.put("Content-Type", "application/json");
+        headerMap.put("User-Agent", "apifox/1.0.0 (https://www.apifox.cn)");
+        headerMap.put("Authorization", "Bearer " + token);
+
+        logger.info("SRMHelperUtils writeApproveStatus:body " + body.toJSONString());
+        logger.info("SRMHelperUtils writeApproveStatus:header " + headerMap.toString());
+
+        try {
+//            String response = doHttpClientPost(url,  body.toJSONString(), token);
+            String response = KHttpClientUtils.postjson(url, headerMap, body.toJSONString());
+
+            if(StringUtils.isEmpty(response)){
+                returnMap.put("code", "1");
+                returnMap.put("msg", "回写审批结果失败, 返回为空");
+
+                return returnMap;
+            }
+
+            JSONObject resultJSON = JSONObject.parseObject(response);
+
+            if (resultJSON !=null && "SUCCESS".equals(resultJSON.get("responseStatus").toString())
+                    &&"SUCCESS".equals(resultJSON.get("executeResult").toString())) {
+                returnMap.put("code","回写审批结果成功");
+            } else{
+                returnMap.put("code","1");
+                returnMap.put("msg", "回写审批结果失败" + response);
+            }
+
+            return returnMap;
+        } catch(IOException e){
+            returnMap.put("code", "1");
+            returnMap.put("msg", "获取token失败, " + e.getMessage());
+
+            return returnMap;
+        } catch(Exception e){
+            returnMap.put("code", "1");
+            returnMap.put("msg", "获取token失败, " + e.getMessage());
+
+            return returnMap;
+        }
+    }
+
     /**
      * 同步付款信息至SRM
      * @param srmBillNo
@@ -303,8 +421,8 @@ public class SRMHelperUtils {
         headerMap.put("User-Agent", "apifox/1.0.0 (https://www.apifox.cn)");
         headerMap.put("Authorization", "Bearer " + token);
 
-        logger.info("SRMHelperUtils:body " + body.toJSONString());
-        logger.info("SRMHelperUtils:header " + headerMap.toString());
+        logger.info("SRMHelperUtils writeBackPayResulst:body " + body.toJSONString());
+        logger.info("SRMHelperUtils writeBackPayResulst:header " + headerMap.toString());
 
         try {
             String response = KHttpClientUtils.postjson(url, headerMap, body.toJSONString());

+ 71 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/operate/validator/ReimBurseBillReceiveTicketValidator.java

@@ -0,0 +1,71 @@
+package nckd.jimin.jyyy.fi.plugin.operate.validator;
+
+import kd.bos.context.RequestContext;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.dataentity.resource.ResManager;
+import kd.bos.entity.ExtendedDataEntity;
+import kd.bos.entity.validate.AbstractValidator;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.QueryServiceHelper;
+import kd.bos.util.StringUtils;
+import nckd.jimin.jyyy.fi.common.constant.ErPrintUserConstant;
+import nckd.jimin.jyyy.fi.common.constant.ErReimBurseBillConstant;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class ReimBurseBillReceiveTicketValidator extends AbstractValidator {
+    @Override
+    public void validate() {
+        ExtendedDataEntity[] dataEntities = getDataEntities();
+        String operateKey = getOperateKey();
+        switch (operateKey){
+            case ErReimBurseBillConstant.OPERATE.HANDIN_TICKET:
+                Arrays.stream(dataEntities).forEach(r -> checkHandinTicket(r));
+                break;
+            case ErReimBurseBillConstant.OPERATE.RECEIVE_TICKET:
+                Arrays.stream(dataEntities).forEach(r -> checkReceiptTicket(r));
+                break;
+        }
+
+    }
+
+    protected void checkHandinTicket(ExtendedDataEntity dataEntity){
+        // 单据状态为已审核
+        DynamicObject billInfo = dataEntity.getDataEntity();
+        List<String> status = Arrays.asList("E", "F", "G");
+        if(!status.contains(billInfo.getString(ErReimBurseBillConstant.KEY_BILLSTATUS))){
+            this.addErrorMessage(dataEntity, String.format("单据%s交票失败:只有审核通过、等待付款、已付款状态的单据允许交票。",billInfo.getString(ErReimBurseBillConstant.KEY_BILLNO)));
+            return;
+        }
+
+        //收票人为空
+        if(StringUtils.isNotEmpty(billInfo.getString(ErReimBurseBillConstant.KEY_NCKD_HANDIN_PERSON))){
+            this.addErrorMessage(dataEntity, String.format("单据%s交票失败:不允许重复交票。",billInfo.getString(ErReimBurseBillConstant.KEY_BILLNO)));
+            return;
+        }
+    }
+    protected void checkReceiptTicket(ExtendedDataEntity dataEntity){
+        DynamicObject billInfo = dataEntity.getDataEntity();
+
+        // 收票人不能为空
+        if(StringUtils.isEmpty(billInfo.getString(ErReimBurseBillConstant.KEY_NCKD_HANDIN_PERSON))){
+            this.addErrorMessage(dataEntity, String.format("单据%s收票失败:请先完成交票功能",billInfo.getString(ErReimBurseBillConstant.KEY_BILLNO)));
+            return;
+        }
+
+        if(StringUtils.isNotEmpty(billInfo.getString(ErReimBurseBillConstant.KEY_NCKD_RECEIPT_PERSON))){
+            this.addErrorMessage(dataEntity, String.format("单据%s收票失败:单据不允许重复收票。",billInfo.getString(ErReimBurseBillConstant.KEY_BILLNO)));
+            return;
+        }
+
+        List<String> status = Arrays.asList("E", "F", "G");
+        if(!status.contains(billInfo.getString(ErReimBurseBillConstant.KEY_BILLSTATUS))){
+            this.addErrorMessage(dataEntity, String.format("单据%s收票失败:只有审核通过、等待付款、已付款状态的单据允许收票。",billInfo.getString(ErReimBurseBillConstant.KEY_BILLNO)));
+            return;
+        }
+
+    }
+}

+ 56 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/plugin/workflow/TaskApproverWorkflowPlugin.java

@@ -0,0 +1,56 @@
+package nckd.jimin.jyyy.fi.plugin.workflow;
+
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.metadata.dynamicobject.DynamicObjectType;
+import kd.bos.dataentity.resource.ResManager;
+import kd.bos.entity.EntityMetadataCache;
+import kd.bos.logging.BizLog;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import kd.bos.workflow.api.AgentExecution;
+import kd.bos.workflow.engine.extitf.IWorkflowPlugin;
+import nckd.jimin.jyyy.fi.common.constant.ErReimBurseBillConstant;
+
+import java.util.List;
+
+/**
+ * 共享审核节点设置审核人
+ */
+public class TaskApproverWorkflowPlugin implements IWorkflowPlugin {
+
+    @Override
+    public void notify(AgentExecution e) {
+        IWorkflowPlugin.super.notify(e);
+        String businessKey = e.getBusinessKey();
+        String entityNumber = e.getEntityNumber();
+        updateBillTaskApprover(businessKey,entityNumber);
+    }
+
+    /**
+     * 更新共享审核人
+     * @param billId
+     * @param formId
+     */
+    protected void updateBillTaskApprover(Object billId,String formId){
+        DynamicObjectType entityType = EntityMetadataCache.getDataEntityType(formId);
+        if(!entityType.getProperties().containsKey(ErReimBurseBillConstant.KEY_NCKD_TASKAPPROVER)){
+            BizLog.log(String.format("单据类型【%1&s】没有共享审核人字段,无需更新",formId));
+            return;
+        }
+
+        DynamicObject billInfo = BusinessDataServiceHelper.loadSingle(billId, formId, String.join(",",ErReimBurseBillConstant.KEY_NCKD_TASKAPPROVER,"billno"));
+
+        // 按完成时间倒叙,取最晚的一条 如果共享被驳回,再次审核通过时反写
+        DynamicObject[] taskTaskhistories = BusinessDataServiceHelper.load("task_taskhistory", "billnumber,id,apprevalmessage,personid,tasktypeid,state", new QFilter[]{
+                new QFilter("billnumber", QCP.equals,billInfo.getString("billno"))
+        },"completetime desc");
+
+        if(taskTaskhistories.length > 0){
+            billInfo.set(ErReimBurseBillConstant.KEY_NCKD_TASKAPPROVER,taskTaskhistories[0].getDynamicObject("personid"));
+            SaveServiceHelper.save(new DynamicObject[]{ billInfo });
+        }
+    }
+}

+ 45 - 2
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/task/WriteBackPayResult2SRMTask.java

@@ -48,7 +48,7 @@ public class WriteBackPayResult2SRMTask extends AbstractTask implements StopTask
         filter.and(new QFilter("nckd_srmbillno", QCP.is_notnull, null));
         filter.and(new QFilter("nckd_srmbillno", QCP.not_equals2, " "));
         filter.and(new QFilter("nckd_srmbillno", QCP.not_equals2, ""));
-//        filter.and(new QFilter("billno", QCP.equals, "DGBX-250411-0021"));
+//        filter.and(new QFilter("billno", QCP.equals, "BX2010202505-0130"));
 
         DynamicObjectType type = EntityMetadataCache.getDataEntityType(entityName);
         //先找到批量的pkid
@@ -81,7 +81,26 @@ public class WriteBackPayResult2SRMTask extends AbstractTask implements StopTask
                 }
             }
 
+
+            boolean isSave = false;
             StringBuffer errMessage = new StringBuffer();
+            Map<String, String> returnMapApprove = SRMHelperUtils.writeApproveStatus(srmBillNo, "PAYMENT");
+            logger.info("付款单审批状态回写结果:" + returnMapApprove.toString());
+
+            if(returnMapApprove != null){
+                if("1".equals(returnMapApprove.get("code"))){
+                    if(errMessage.length() > 0){
+                        errMessage.append(",");
+                    }
+                    logger.info("预付单(" + billno + ", " + srmBillNo + ")审批状态回写失败," + returnMapApprove.get("msg"));
+
+                    payBillEntity.set("nckd_srmstatus", "4");
+                } else {
+                    payBillEntity.set("nckd_srmstatus", "3");
+                }
+                isSave = true;
+            }
+
             Map<String, String> returnMap = SRMHelperUtils.writeBackPayResulst(srmBillNo, paymentDate, paymentAmount);
 
             logger.info("付款单支付状态回写结果:" + returnMap.toString());
@@ -96,7 +115,9 @@ public class WriteBackPayResult2SRMTask extends AbstractTask implements StopTask
                 } else {
                     payBillEntity.set("nckd_srmstatus", "3");
                 }
+            }
 
+            if(isSave){
                 listObj.add(payBillEntity);
                 if(listObj.size() == 500) {
                     SaveServiceHelper.update(listObj.toArray(new DynamicObject[]{}));
@@ -154,7 +175,25 @@ public class WriteBackPayResult2SRMTask extends AbstractTask implements StopTask
                 }
             }
 
+            boolean isSave = false;
             StringBuffer errMessage = new StringBuffer();
+            Map<String, String> returnMapApprove = SRMHelperUtils.writeApproveStatus(srmBillNo, "PREPAYMENT");
+            logger.info("预付单审批状态回写结果:" + returnMapApprove.toString());
+
+            if(returnMapApprove != null){
+                if("1".equals(returnMapApprove.get("code"))){
+                    if(errMessage.length() > 0){
+                        errMessage.append(",");
+                    }
+                    logger.info("预付单(" + billno + ", " + srmBillNo + ")审批状态回写失败," + returnMapApprove.get("msg"));
+
+                    payBillEntity.set("nckd_srmstatus", "4");
+                } else {
+                    payBillEntity.set("nckd_srmstatus", "3");
+                }
+                isSave = true;
+            }
+
             Map<String, String> returnMap = SRMHelperUtils.writeBackPayResulst(srmBillNo, paymentDate, paymentAmount);
 
             logger.info("预付单支付状态回写结果:" + returnMap.toString());
@@ -171,8 +210,12 @@ public class WriteBackPayResult2SRMTask extends AbstractTask implements StopTask
                     payBillEntity.set("nckd_srmstatus", "3");
                 }
 
+                isSave = true;
+            }
+
+            if(isSave) {
                 listObj.add(payBillEntity);
-                if(listObj.size() == 500) {
+                if (listObj.size() == 500) {
                     SaveServiceHelper.update(listObj.toArray(new DynamicObject[]{}));
                     listObj.clear();
                 }

+ 115 - 12
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/webapi/SRMSynPayApiPlugin.java

@@ -272,6 +272,13 @@ public class SRMSynPayApiPlugin implements Serializable {
             return buildReturnData(code, srmBillNo, returnMessage, null, null, null);
         }
 
+        //合同台账
+        DynamicObject contractInfo = null;
+        if(!StringUtils.isEmpty(contract)) {
+            qFilter = new QFilter("contractcode", QCP.equals, contract);
+            contractInfo = BusinessDataServiceHelper.loadSingle("er_contractbill", qFilter.toArray());
+        }
+
         DynamicObject bizAcctOutBill = BusinessDataServiceHelper.newDynamicObject(ENTITY_PUBLICPAY);
         Date bizDate = new Date();
         try {
@@ -307,6 +314,10 @@ public class SRMSynPayApiPlugin implements Serializable {
         bizAcctOutBill.set("ispush", "false");//合同下推生成
         bizAcctOutBill.set("nckd_srmstatus", "1");//srm状态,1:SRM已推送;2:已退回SRM;3:已反写SRM;4:反写SRM失败
         bizAcctOutBill.set("nckd_duigong", "01");//是否对公业务
+        setDefaultMultViewType(bizAcctOutBill);//多选页面类型
+        bizAcctOutBill.set("isbeforeshare", "0");//费用分摊
+        bizAcctOutBill.set("sharerule", "orgrule");//
+        bizAcctOutBill.set("sharemethod", "rate");//
 
 //        String[] typeStrings = new String[]{"1008", "1009"};
 //        QFilter qFilter111 = new QFilter("number", QCP.in, typeStrings);
@@ -358,7 +369,17 @@ public class SRMSynPayApiPlugin implements Serializable {
                     return buildReturnData(code, srmBillNo, returnMessage, null, null, null);
                 }
 
-                DynamicObject projectInfo = CommonHelperUtils.queryBaseDynamicObject("bd_project", "number", xsproject);
+                //替换连接符
+                xsproject = xsproject.replace("-", ".");
+
+                QFilter projectFilter = new QFilter("status", QCP.equals, "C");
+                projectFilter.and(new QFilter("enable", QCP.equals, "1"));
+                projectFilter.and(new QFilter("number", QCP.equals, xsproject));
+                projectFilter.and(new QFilter("createorg.id", QCP.equals, costCompany.getLong("id")));
+
+                DynamicObject projectInfo = BusinessDataServiceHelper.loadSingle("bd_project", projectFilter.toArray());
+
+//                DynamicObject projectInfo = CommonHelperUtils.queryBaseDynamicObject("bd_project", "number", xsproject);
                 if(projectInfo == null){
                     returnMessage = "项目(" + xsproject + ")在星瀚系统中未匹配到数据!";
                     return buildReturnData(code, srmBillNo, returnMessage, null, null, null);
@@ -383,7 +404,7 @@ public class SRMSynPayApiPlugin implements Serializable {
             if(currency.getLong("id") != 1L){
                 exchangeRate = CommonHelperUtils.getExchangeRate(exchangeTableId, currency.getLong("id"), 1L, bizDate);
             }
-
+            entry.set("exchangerate", exchangeRate);//汇率
             entry.set("expquotetype", "0");//换算方式
             entry.set("currexpenseamount", amountOri.multiply(exchangeRate).setScale(2, BigDecimal.ROUND_HALF_UP));//报销金额本位币
             entry.set("expeapprovecurramount", amountOri.multiply(exchangeRate).setScale(2, BigDecimal.ROUND_HALF_UP));//核定金额本位币
@@ -406,6 +427,8 @@ public class SRMSynPayApiPlugin implements Serializable {
         qFilter = new QFilter("number", QCP.equals, "BANK");
 
         DynamicObject settleType = BusinessDataServiceHelper.loadSingle("bd_settlementtype", qFilter.toArray());
+        DynamicObject supplier = null;
+
         DynamicObjectCollection accountEntry  = bizAcctOutBill.getDynamicObjectCollection("accountentry");
         type = accountEntry.getDynamicObjectType();
         JSONArray bizAccountOutBillAccountEntry = inputData.getJSONArray("bizAccountOutBillAccountEntry");
@@ -427,7 +450,7 @@ public class SRMSynPayApiPlugin implements Serializable {
                 return buildReturnData(code, srmBillNo, returnMessage, null, null, null);
             }
 
-            DynamicObject supplier = CommonHelperUtils.queryBaseDynamicObject("bd_supplier", "societycreditcode", payerName);
+            supplier = CommonHelperUtils.queryBaseDynamicObject("bd_supplier", "societycreditcode", payerName);
             if(supplier == null){
                 returnMessage = "供应商(" + payerName + ")在星瀚系统中未匹配到数据!";
                 return buildReturnData(code, srmBillNo, returnMessage, null, null, null);
@@ -468,6 +491,7 @@ public class SRMSynPayApiPlugin implements Serializable {
             }
 
             entry.set("accountcurrency", currency);//币别
+            entry.set("accexchangerate", exchangeRate);//汇率
             entry.set("orireceiveamount", amountOri);//收款金额
             entry.set("receiveamount", amountOriLocal);//收款金额本位币
             entry.set("oriaccnotpayamount", amountOri);//未付金额
@@ -723,6 +747,80 @@ public class SRMSynPayApiPlugin implements Serializable {
         }
         bizAcctOutBill.set("invoiceentry", invoiceEntry);
 
+
+
+        //合同信息
+        if(contractInfo != null){
+            DynamicObjectCollection contractEntry  = bizAcctOutBill.getDynamicObjectCollection("contractentry");
+            type = contractEntry.getDynamicObjectType();
+
+            DynamicObject currency = contractInfo.getDynamicObject("contractcurrency");
+            currency = CommonHelperUtils.queryBaseDynamicObject("bd_currency", "number", currency.getString("number"));
+
+            if(currency == null){
+                returnMessage = "币别(" + orgUnit + ")在星瀚系统中未匹配到数据!";
+                return buildReturnData(code, srmBillNo, returnMessage, null, null, null);
+            }
+
+            BigDecimal exchangeRate = BigDecimal.ONE;
+            if(currency.getLong("id") != 1L){
+                exchangeRate = CommonHelperUtils.getExchangeRate(exchangeTableId, currency.getLong("id"), 1L, bizDate);
+            }
+
+            BigDecimal contractAmount = contractInfo.getBigDecimal("contractamount");//合同总额(初始)
+            BigDecimal oriapplyAmount = contractInfo.getBigDecimal("oriapplyamount");//合同总额(变更后)
+
+            DynamicObjectCollection contractPartyEntry = contractInfo.getDynamicObjectCollection("contractpartyentry"); //
+            if(contractPartyEntry.size() > 0){
+                for(DynamicObject partyEntry : contractPartyEntry){
+                    DynamicObject entry = new DynamicObject(type);
+
+                    DynamicObject contractparty = partyEntry.getDynamicObject("contractparty");
+                    if(contractparty.getLong("id") != supplier.getLong("id")){
+                        continue;
+                    }
+
+                    entry.set("seq", 1);
+                    entry.set("contractcode", contract);//合同号
+                    entry.set("contractname", contractInfo.getString("contractname"));//合同名称
+                    entry.set("signdate", contractInfo.getDate("signdate"));//签订日期
+                    entry.set("contractdescription", contractInfo.getString("description"));//合同说明
+                    entry.set("contractapplier", contractInfo.getDynamicObject("applier"));//经办人
+                    entry.set("contractcostorg", contractInfo.getDynamicObject("costcompany"));//核算组织
+                    entry.set("contractparta", contractInfo.getDynamicObject("parta"));//甲方old
+                    entry.set("contractpartbtype", "bd_supplier");//乙方类型
+                    entry.set("contractpartb", contractparty);//乙方
+
+                    DynamicObjectCollection payplanEntrys = contractInfo.getDynamicObjectCollection("expenseentryentity");
+                    if(payplanEntrys.size() > 0){
+                        DynamicObject planEntry = payplanEntrys.get(0);
+
+                        entry.set("contractexppaytypeid", planEntry.getDynamicObject("paymenttypeid"));//付款类型
+                        entry.set("contractexphappendate", planEntry.getDate("happendate"));//预计付款日期
+                        entry.set("contractexpproject", planEntry.getDynamicObject("std_project"));//项目
+                        entry.set("contractexpenseitem", planEntry.getDynamicObject("expenseitem"));//费用项目
+                        entry.set("contractexpcurrency", planEntry.getDynamicObject("entrycurrency"));//币种
+                        entry.set("contractexpchangerate", planEntry.getBigDecimal("exchangerate"));//汇率
+                        entry.set("contractexpquotetype", "0");//换算方式
+                        entry.set("contractnotpayamount", planEntry.getBigDecimal("expnotpayamount"));//未付金额本位币
+                        entry.set("contractcanloanamount", planEntry.getBigDecimal("canloanamount"));//可预付金额
+                        entry.set("concurrcanloanamount", planEntry.getBigDecimal("canloancurramount"));//可预付金额本位币
+                    }
+
+                    entry.set("contractpartatypenew", "bos_org");//甲方类型
+                    entry.set("contractpartanew", costCompany);//甲方
+                    entry.set("nckd_contractamt", contractAmount);//合同总额(初始)
+                    entry.set("nckd_oriapplyamt", oriapplyAmount);//合同总额(变更后)
+
+                    contractEntry.add(entry);
+
+                    break;
+                }
+            }
+
+            bizAcctOutBill.set("contractentry", contractEntry);
+        }
+
         try {
             //新增保存供应商对象
             OperationResult resultSave = SaveServiceHelper.saveOperate(ENTITY_PUBLICPAY, new DynamicObject[]{bizAcctOutBill}, OperateOption.create());
@@ -896,7 +994,8 @@ public class SRMSynPayApiPlugin implements Serializable {
         dailyLoanBill.set("nckd_srmstatus", "1");//srm状态,1:SRM已推送;2:已退回SRM;3:已反写SRM;4:反写SRM失败
 //        dailyLoanBill.set("repaymentdate", repaymentDate);//预计冲销日期
         dailyLoanBill.set("nckd_duigong", "01");//是否对公业务
-//        dailyLoanBill.set("nckd_payviewtypemul", getDefaultMultViewType());//多选页面类型
+
+        setDefaultMultViewType(dailyLoanBill);//多选页面类型
 
         BigDecimal totalReimburseAmount = BigDecimal.ZERO;//报销金额合计
 
@@ -931,6 +1030,7 @@ public class SRMSynPayApiPlugin implements Serializable {
             entry.set("entrycostdept", dept);//费用承担部门
             entry.set("entrycostcompany", costCompany);//费用承担公司
             entry.set("entrycurrency", currency);//币别
+            entry.set("exchangerate", exchangeRate);//预付汇率
             entry.set("expenseamount", amountOri);//申请金额
             entry.set("expeapproveamount", amountOri);//核定金额
             entry.set("orgiexpebalanceamount", amountOri);//未核销金额
@@ -1201,19 +1301,22 @@ public class SRMSynPayApiPlugin implements Serializable {
      * 默认多选页面类型
      * @return
      */
-    private Object[] getDefaultMultViewType(){
+    private void setDefaultMultViewType(DynamicObject objectInfo){
         String[] typeStrings = new String[]{"1008", "1009"};
 
         QFilter qFilter = new QFilter("number", QCP.in, typeStrings);
         DynamicObject[] viewTypeCols = BusinessDataServiceHelper.load("nckd_payviewtype", "id, number, name", qFilter.toArray());
         if(viewTypeCols != null && viewTypeCols.length > 0){
-            List<Long> idList = Arrays.stream(viewTypeCols)
-                    .map(type ->  type.getLong("id"))
-                    .collect(Collectors.toList());
-            Object[] basedataIds = idList.toArray();
-            return basedataIds;
-        }
+            DynamicObjectCollection veiwTypeMulColl = objectInfo.getDynamicObjectCollection("nckd_payviewtypemul");
+
+            for (DynamicObject viewType : viewTypeCols) {
+                DynamicObject newViewTypeMul = new DynamicObject(veiwTypeMulColl.getDynamicObjectType());
+                newViewTypeMul.set("fbasedataId", viewType);
 
-        return null;
+                veiwTypeMulColl.add(newViewTypeMul);
+            }
+
+            objectInfo.set("nckd_payviewtypemul", veiwTypeMulColl);
+        }
     }
 }