修改医疗模块
diff --git a/backend/build.gradle b/backend/build.gradle
index 468595c..30774d0 100644
--- a/backend/build.gradle
+++ b/backend/build.gradle
@@ -74,7 +74,7 @@
     compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.9.1'
     compile group: 'log4j', name: 'log4j', version: '1.2.17'
 
-    compile group: 'com.supwisdom', name: 'payapi-sdk', version: '1.0.28'
+    compile group: 'com.supwisdom', name: 'payapi-sdk', version: '1.0.28-10-g10b32b4'
     
     implementation 'org.hamcrest:hamcrest:2.1'
 }
diff --git a/backend/src/main/java/com/supwisdom/dlpay/medical/domain/TBMedicalDtl.java b/backend/src/main/java/com/supwisdom/dlpay/medical/domain/TBMedicalDtl.java
index 386cc9e..98d6b25 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/medical/domain/TBMedicalDtl.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/medical/domain/TBMedicalDtl.java
@@ -3,7 +3,11 @@
 import javax.persistence.*;
 
 @Entity
-@Table(name = "tb_medicaldtl",indexes = {@Index(name = "medicaldtl_idx",columnList = "admnumber,feeno,organizationid")})
+@Table(name = "th_medicaldtl", indexes = {
+    @Index(name = "medicaldtl_idx", columnList = "uid,emergency,feeno,organizationid"),
+    @Index(name = "medicaldtl_idx2", columnList = "uid,accdate,organizationid"),
+    @Index(name = "medicaldtl_idx3", columnList = "paystatus,resultid,organizationid"),
+    @Index(name = "medicaldtl_idx4", columnList = "patientid")})
 public class TBMedicalDtl {
   @Id
   @Column(name = "billno", length = 32)
@@ -13,16 +17,16 @@
   @Column(name = "uid", length = 32)
   private String uid;
   /**
-   * 付款金额;付款金额 = 总金额 + 加收费用
-   */
-  @Column(name = "payamount", precision = 10, scale = 3)
-  private Double payamount;
-  /**
    * 总金额
    */
   @Column(name = "totalfee", precision = 10, scale = 3)
   private Double totalfee;
   /**
+   * 归并费用名称
+   */
+  @Column(name = "mergingname",length = 32)
+  private String mergingname;
+  /**
    * 加收费用描述
    */
   @Column(name = "extrafeedesc", length = 200)
@@ -33,10 +37,20 @@
   @Column(name = "feeno", length = 32)
   private String feeno;
   /**
+   * 收费类型代码
+   */
+  @Column(name = "feetypecode", length = 32)
+  private String feetypecode;
+  /**
    * 患者就诊序号
    */
-  @Column(name = "admnumber", length = 64)
-  private String admnumber;
+  @Column(name = "emergency", length = 64)
+  private String emergency;
+  /**
+   * 就诊日期
+   */
+  @Column(name = "medicaldate", length = 8)
+  private String medicaldate;
   /**
    * 医院code
    */
@@ -49,6 +63,11 @@
   private String invoiceno;
   @Column(name = "paystatus", length = 15)
   private String paystatus;
+  /**
+   * 入账日期
+   */
+  @Column(name = "accdate", length = 8)
+  private String accdate;
   @Column(name = "transdate", length = 14)
   private String transdate;
   @Column(name = "transtime", length = 6)
@@ -56,10 +75,20 @@
   @Column(name = "citizencardno", length = 32)
   private String citizencardno;
   /**
+   * 患者id
+   */
+  @Column(name = "patientid", length = 64)
+  private String patientid;
+  /**
    * HIS结算标识
    */
   @Column(name = "resultid", length = 64)
   private String resultid;
+  /**
+   * HIS结算日期
+   */
+  @Column(name = "resultdate", length = 8)
+  private String resultdate;
 
   public String getBillno() {
     return billno;
@@ -85,14 +114,6 @@
     this.uid = uid;
   }
 
-  public Double getPayamount() {
-    return payamount;
-  }
-
-  public void setPayamount(Double payamount) {
-    this.payamount = payamount;
-  }
-
   public Double getTotalfee() {
     return totalfee;
   }
@@ -125,12 +146,12 @@
     this.feeno = feeno;
   }
 
-  public String getAdmnumber() {
-    return admnumber;
+  public String getEmergency() {
+    return emergency;
   }
 
-  public void setAdmnumber(String admnumber) {
-    this.admnumber = admnumber;
+  public void setEmergency(String emergency) {
+    this.emergency = emergency;
   }
 
   public String getInvoiceno() {
@@ -180,4 +201,44 @@
   public void setResultid(String resultid) {
     this.resultid = resultid;
   }
+
+  public String getAccdate() {
+    return accdate;
+  }
+
+  public void setAccdate(String accdate) {
+    this.accdate = accdate;
+  }
+
+  public String getPatientid() {
+    return patientid;
+  }
+
+  public void setPatientid(String patientid) {
+    this.patientid = patientid;
+  }
+
+  public String getFeetypecode() {
+    return feetypecode;
+  }
+
+  public void setFeetypecode(String feetypecode) {
+    this.feetypecode = feetypecode;
+  }
+
+  public String getResultdate() {
+    return resultdate;
+  }
+
+  public void setResultdate(String resultdate) {
+    this.resultdate = resultdate;
+  }
+
+  public String getMergingname() {
+    return mergingname;
+  }
+
+  public void setMergingname(String mergingname) {
+    this.mergingname = mergingname;
+  }
 }
diff --git a/backend/src/main/java/com/supwisdom/dlpay/medical/util/MedicalClient.java b/backend/src/main/java/com/supwisdom/dlpay/medical/util/MedicalClient.java
index f3e7533..03b2825 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/medical/util/MedicalClient.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/medical/util/MedicalClient.java
@@ -12,6 +12,7 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.*;
 import org.springframework.stereotype.Component;
+import org.springframework.web.client.HttpServerErrorException;
 import org.springframework.web.client.RestTemplate;
 
 import java.util.HashMap;
@@ -51,7 +52,7 @@
       logger.error("调用医疗接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
       throw new MedicineException("请求医疗系统异常");
     }
-    List<PatientInfoResponse> list = result.getData();
+    List<PatientInfoResponse> list = result.getData().get(0);
     if (list != null && list.size() > 0) {
       return list.get(0);
     }
@@ -70,7 +71,7 @@
       logger.error("调用医疗接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
       throw new MedicineException("请求医疗系统异常");
     }
-    return result.getData();
+    return result.getData().get(0);
   }
 
   public List<ArrangeInfoResponse> getArrangeInfo(String organizationId, String date) {
@@ -84,7 +85,7 @@
       logger.error("调用医疗接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
       throw new MedicineException("请求医疗系统异常");
     }
-    return result.getData();
+    return result.getData().get(0);
   }
 
   public AppointmentResponse confirmAppointment(ConfirmRequestBean bean) {
@@ -104,7 +105,7 @@
       logger.error("调用医疗接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
       throw new MedicineException("请求医疗系统异常");
     }
-    return result.getData();
+    return result.getData().get(0);
   }
 
   public UnPayedResponse getUnPayedList(UnPayedRequest bean) {
@@ -112,15 +113,22 @@
     Map<String, Object> param = new HashMap<>(4);
     param.put("organizationId", bean.getOrganizationId());
     param.put("queryType", bean.getQueryType());
-    param.put("patientIdList", bean.getPatientIdList());
-    String response = httpPost(url + "getUnpayedList", JSON.toJSONString(param));
+    param.put("patientIdentityCardList", bean.getPatientIdentityCardList());
+    String response;
+    try {
+      response = httpPost(url + "getUnpayedList", JSON.toJSONString(param));
+    } catch (HttpServerErrorException e) {
+      //  当前用户在HIS中没有档案时,会返回500 异常
+      logger.error("调用HIS异常",e);
+      return new UnPayedResponse();
+    }
     MedicalResponse<UnPayedResponse> result = JSON.parseObject(response, new TypeReference<MedicalResponse<UnPayedResponse>>() {
     });
     if (result.getCode() != MedicalConstant.MEDICAL_RESPONSE_SUCCESS) {
-      logger.error("调用医疗接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
+      logger.error("调用医疗待支付列表接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
       throw new MedicineException("请求医疗系统异常");
     }
-    return result.getData();
+    return result.getData().get(0);
   }
 
   public PayedResponse getPayedList(PayedRequest bean) {
@@ -135,10 +143,10 @@
     MedicalResponse<PayedResponse> result = JSON.parseObject(response, new TypeReference<MedicalResponse<PayedResponse>>() {
     });
     if (result.getCode() != MedicalConstant.MEDICAL_RESPONSE_SUCCESS) {
-      logger.error("调用医疗接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
+      logger.error("调用医疗获取支付列表接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
       throw new MedicineException("请求医疗系统异常");
     }
-    return result.getData();
+    return result.getData().get(0);
   }
 
   public PreFeeResponse getPreCalculatedFee(PreFeeRequest bean) {
@@ -147,16 +155,20 @@
     param.put("organizationId", bean.getOrganizationId());
     param.put("boilSign", bean.getBoilSign());
     param.put("feeRecords", bean.getFeeRecords());
+    param.put("patientId", bean.getPatientId());
     String response = httpPost(url + "getPrecalculatedFee", JSON.toJSONString(param));
     MedicalResponse<PreFeeResponse> result = JSON.parseObject(response, new TypeReference<MedicalResponse<PreFeeResponse>>() {
     });
     if (result.getCode() != MedicalConstant.MEDICAL_RESPONSE_SUCCESS) {
-      logger.error("调用医疗接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
+      logger.error("调用医疗预结算接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
       throw new MedicineException("请求医疗系统异常");
     }
-    return result.getData();
+    return result.getData().get(0);
   }
 
+  /**
+   * 费用结算处理确认
+   */
   public NotifyPayedResponse notifyPayed(NotifyPayedRequest bean) {
     String url = getMedicalUrl();
     Map<String, Object> param = new HashMap<>(8);
@@ -172,14 +184,14 @@
     param.put("totalFee ", bean.getTotalFee());
     param.put("brid ", bean.getBrid());
     param.put("feeRecords ", bean.getFeeRecords());
-    String response = httpPost(url + "getPrecalculatedFee", JSON.toJSONString(param));
+    String response = httpPost(url + "notifyPayed", JSON.toJSONString(param));
     MedicalResponse<NotifyPayedResponse> result = JSON.parseObject(response, new TypeReference<MedicalResponse<NotifyPayedResponse>>() {
     });
     if (result.getCode() != MedicalConstant.MEDICAL_RESPONSE_SUCCESS) {
-      logger.error("调用医疗接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
+      logger.error("调用医疗结算确认接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
       throw new MedicineException("请求医疗系统异常");
     }
-    return result.getData();
+    return result.getData().get(0);
   }
 
   private String getMedicalUrl() {
diff --git a/backend/src/main/java/com/supwisdom/dlpay/medical/util/MedicalConstant.java b/backend/src/main/java/com/supwisdom/dlpay/medical/util/MedicalConstant.java
index a24cb3b..541ba26 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/medical/util/MedicalConstant.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/medical/util/MedicalConstant.java
@@ -14,8 +14,17 @@
    * 订单查询模式
    */
   public final static int ORDER_QUERYTYPE_PATIENTID = 1;//按患者id查询
+  public final static int ORDER_QUERYTYPE_IDENTITYCARD = 2;//按证件查询
   public final static int ORDER_QUERYTYPE_MEDICALCARD = 3;//按诊疗卡类型查询
   /**
+   * 支付状态
+   */
+  public final static String PAY_STATE_PAYED = "1";
+  /**
+   * 支付方式
+   */
+  public final static String PAY_MODE_DLSMK = "6";
+  /**
    * 支付列表执行标志
    */
   public final static int PAYED_EXECUTEFLAG_INVALID = 0;//本参数无效
@@ -27,6 +36,9 @@
    * 医疗系统响应状态码
    */
   public final static int MEDICAL_RESPONSE_SUCCESS = 200;//成功
+
+
+
   /**
    * 本地流水状态
    */
@@ -42,5 +54,8 @@
    * payapi响应代码
    */
   public final static Integer PAYAPI_SUCCESS_RETCODE = 0;
+  public final static Integer PAYAPI_WAIT_QUERY = 55555;
+  public final static Integer PAYAPI_DEAL_ERROR = 30000;
+  public final static Integer PAYAPI_NOT_EXISTS = 10004;
 
 }
diff --git a/backend/src/main/java/com/supwisdom/dlpay/medical/util/MedicalResponse.java b/backend/src/main/java/com/supwisdom/dlpay/medical/util/MedicalResponse.java
index bf4db4b..efef416 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/medical/util/MedicalResponse.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/medical/util/MedicalResponse.java
@@ -1,9 +1,11 @@
 package com.supwisdom.dlpay.medical.util;
 
+import java.util.ArrayList;
+
 public class MedicalResponse<T> {
   private int code;
   private String message;
-  private T data;
+  private ArrayList<T> data;
 
   public int getCode() {
     return code;
@@ -21,11 +23,11 @@
     this.message = message;
   }
 
-  public T getData() {
+  public ArrayList<T> getData() {
     return data;
   }
 
-  public void setData(T data) {
+  public void setData(ArrayList<T> data) {
     this.data = data;
   }
 }
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/api/async_tasks.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/api/async_tasks.kt
index 63591dc..39b93a8 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/api/async_tasks.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/api/async_tasks.kt
@@ -23,6 +23,15 @@
         }
     }
 
+    @Bean(value = ["notifyHIS"])
+    fun threadPoolExecutor(): Executor {
+        return ThreadPoolTaskExecutor().apply {
+            corePoolSize = 5
+            maxPoolSize = 10
+            setWaitForTasksToCompleteOnShutdown(true)
+        }
+    }
+
     override fun getAsyncUncaughtExceptionHandler(): AsyncUncaughtExceptionHandler? {
         return MyAsyncUncaughtExceptionHandler()
     }
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/api/scheduler_task.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/api/scheduler_task.kt
index ee5c14c..8592797 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/api/scheduler_task.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/api/scheduler_task.kt
@@ -1,10 +1,14 @@
 package com.supwisdom.dlpay.api
 
+import com.supwisdom.dlpay.medical.dao.MedicalDtlDao
+import com.supwisdom.dlpay.medical.task.NotifyHISAsyncTask
+import com.supwisdom.dlpay.medical.util.MedicalConstant
 import com.supwisdom.dlpay.paysdk.ApiLoginHelper
 import com.supwisdom.dlpay.paysdk.proxy.ApiLoginProxy
 import mu.KotlinLogging
 import net.javacrumbs.shedlock.core.SchedulerLock
 import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.data.domain.PageRequest
 import org.springframework.scheduling.annotation.Scheduled
 import org.springframework.stereotype.Component
 
@@ -22,4 +26,24 @@
         val loginHelper = ApiLoginHelper(apiLoginProxy)
         loginHelper.refresh()
     }
+}
+
+@Component
+class NotifyHISPayedSchedulerTask {
+    @Autowired
+    private lateinit var medicalDtlDao: MedicalDtlDao
+    @Autowired
+    private lateinit var notifyHISAsyncTask: NotifyHISAsyncTask
+
+//    @Scheduled(cron = "0 */1 * * * ?")
+//    @SchedulerLock(name = "dealNotifyHISPayed", lockAtMostForString = "PT10M")
+//    fun notifyHISPayed() {
+//        val medicalDtlList = medicalDtlDao.findByPaystatusAndResultidIsNull(MedicalConstant.DTL_STATUS_SUCCESS, PageRequest.of(0, 10))
+//        if (medicalDtlList.isNullOrEmpty()) {
+//            return
+//        }
+//        medicalDtlList.forEach {
+//            notifyHISAsyncTask.notifyHIS(it.billno)
+//        }
+//    }
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/MedicalApi.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/MedicalApi.kt
index 09338d3..ee3e35e 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/MedicalApi.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/MedicalApi.kt
@@ -8,7 +8,9 @@
 import com.supwisdom.dlpay.medical.bean.ConfirmRequestBean
 import com.supwisdom.dlpay.medical.bean.PaymentRequestBean
 import com.supwisdom.dlpay.medical.exception.MedicineException
-import com.supwisdom.dlpay.medical.service.MedicineService
+import com.supwisdom.dlpay.medical.service.MedicalService
+import com.supwisdom.dlpay.medical.task.NotifyHISAsyncTask
+import com.supwisdom.dlpay.medical.util.MedicalConstant
 import com.supwisdom.dlpay.mobile.domain.TBMobileUser
 import com.supwisdom.dlpay.mobile.service.MobileApiService
 import com.supwisdom.dlpay.paysdk.proxy.UserProxy
@@ -19,14 +21,16 @@
 import org.springframework.web.bind.annotation.*
 
 @RestController
-@RequestMapping("/mobileapi/medicineapi")
+@RequestMapping("/mobileapi/medicalapi")
 class MedicalApi {
     @Autowired
-    lateinit var medicineService: MedicineService
+    lateinit var medicalService: MedicalService
     @Autowired
     lateinit var mobileApiService: MobileApiService
     @Autowired
     lateinit var userProxy: UserProxy
+    @Autowired
+    lateinit var notifyHISAsyncTask: NotifyHISAsyncTask
 
     val logger = KotlinLogging.logger { }
 
@@ -38,9 +42,9 @@
     /**
      * 查询医院列表
      */
-    @GetMapping("/hospital/list")
+    /*@GetMapping("/hospital/list")
     fun getHospitalList(pageno: Int, pagesize: Int, name: String?): JsonResult? {
-        val data = medicineService.getHospitalList(pageno, pagesize, name)
+        val data = medicalService.getHospitalList(pageno, pagesize, name)
         return JsonResult.ok().put("data", data)
     }
 
@@ -52,7 +56,7 @@
         val p = SecurityContextHolder.getContext().authentication
         val user = mobileApiService.findUserById(p.name)
                 ?: return JsonResult.error("用户不存在,请注册")
-        val data = medicineService.getMedicalCardList(user.uid, hospitalcode)
+        val data = medicalService.getMedicalCardList(user.uid, hospitalcode)
         return JsonResult.ok().put("data", data)
     }
 
@@ -65,7 +69,7 @@
             val p = SecurityContextHolder.getContext().authentication
             val user = mobileApiService.findUserById(p.name)
                     ?: return JsonResult.error("用户不存在,请注册")
-            medicineService.deleteMedicalCard(user.uid, cardid)
+            medicalService.deleteMedicalCard(user.uid, cardid)
             return JsonResult.ok()
         } catch (e: MedicineException) {
             logger.error(e.message)
@@ -84,10 +88,10 @@
                     ?: return JsonResult.error("用户不存在,请注册")
             bean.checkParam()
             bean.uid = user.uid
-            medicineService.addPatient(bean)
+            medicalService.addPatient(bean)
             return JsonResult.ok()
         } catch (e: Exception) {
-            logger.error("系统异常",e)
+            logger.error("系统异常", e)
             return JsonResult.error("系统异常,请稍后重试")
         }
     }
@@ -98,10 +102,10 @@
     @GetMapping("/arrange/info/{hospitalcode}")
     fun addPatient(date: String, @PathVariable hospitalcode: String): JsonResult? {
         return try {
-            val data = medicineService.getArrangeInfo(hospitalcode, date)
+            val data = medicalService.getArrangeInfo(hospitalcode, date)
             JsonResult.ok().put("data", data)
         } catch (e: Exception) {
-            logger.error("系统异常",e)
+            logger.error("系统异常", e)
             JsonResult.error("系统异常,请稍后重试")
         }
     }
@@ -116,10 +120,10 @@
             val user = mobileApiService.findUserById(p.name)
                     ?: return JsonResult.error("用户不存在,请注册")
             bean.uid = user.uid
-            medicineService.confirmAppointment(bean)
+            medicalService.confirmAppointment(bean)
             return JsonResult.ok()
         } catch (e: Exception) {
-            logger.error("系统异常",e)
+            logger.error("系统异常", e)
             return JsonResult.error("系统异常,请稍后重试")
         }
     }
@@ -132,7 +136,7 @@
         val p = SecurityContextHolder.getContext().authentication
         val user = mobileApiService.findUserById(p.name)
                 ?: return JsonResult.error("用户不存在,请注册")
-        val data = medicineService.getAppointmentList(pageno, pagesize, user.uid)
+        val data = medicalService.getAppointmentList(pageno, pagesize, user.uid)
         return JsonResult.ok().put("data", data)
     }
 
@@ -145,7 +149,7 @@
             val p = SecurityContextHolder.getContext().authentication
             val user = mobileApiService.findUserById(p.name)
                     ?: return JsonResult.error("用户不存在,请注册")
-            val data = medicineService.deleteAppointment(appointmentid, user.uid)
+            val data = medicalService.deleteAppointment(appointmentid, user.uid)
             return JsonResult.ok().put("data", data)
         } catch (e: MedicineException) {
             logger.error(e.message)
@@ -156,16 +160,29 @@
     /**
      * 获取待支付列表
      */
-    @GetMapping("/unpayed/list")
-    fun getUnPayedList(hospitalcode: String, cardid: String): JsonResult? {
+    @PostMapping("/unpayed/list")
+    fun getUnPayedList(hospitalcode: String): JsonResult? {
         try {
             val p = SecurityContextHolder.getContext().authentication
             val user = mobileApiService.findUserById(p.name)
                     ?: return JsonResult.error("用户不存在,请注册")
-            val data = medicineService.getUnPayedList(user.uid, hospitalcode, cardid)
+            if (user.userid.isNullOrEmpty()) {
+                return JsonResult.error("请绑定银行卡")
+            }
+            val userInfo = userProxy.querybycardno(QueryUserParam().apply {
+                this.userid = user.userid
+            })
+            if (userInfo.retcode != 0) {
+                logger.error { "获取userid为${user.userid}的用户信息失败,错误信息:${userInfo.retmsg}" }
+                return JsonResult.error("获取用户信息失败")
+            }
+            val data = medicalService.getUnPayedList(user.uid, userInfo.idno, hospitalcode)
             return JsonResult.ok().put("data", data)
         } catch (e: Exception) {
-            logger.error("系统异常",e)
+            logger.error("系统异常", e)
+            if (e is MedicineException) {
+                return JsonResult.error(e.message)
+            }
             return JsonResult.error("系统异常,请稍后重试")
         }
     }
@@ -173,16 +190,19 @@
     /**
      * 获取已支付列表
      */
-    @GetMapping("/payed/list")
+    @PostMapping("/payed/list")
     fun getPayedList(hospitalcode: String, cardid: String): JsonResult? {
         try {
             val p = SecurityContextHolder.getContext().authentication
             val user = mobileApiService.findUserById(p.name)
                     ?: return JsonResult.error("用户不存在,请注册")
-            val data = medicineService.getPayedList(user.uid, hospitalcode, cardid)
+            val data = medicalService.getPayedList(user.uid, hospitalcode, cardid)
             return JsonResult.ok().put("data", data)
         } catch (e: Exception) {
-            logger.error("系统异常",e)
+            logger.error("系统异常", e)
+            if (e is MedicineException) {
+                return JsonResult.error(e.message)
+            }
             return JsonResult.error("系统异常,请稍后重试")
         }
     }
@@ -190,23 +210,70 @@
     /**
      * 支付接口
      */
-    @PostMapping("/pay")
-    fun medicalPayment(@RequestBody bean: PaymentRequestBean): JsonResult? {
-        val p = SecurityContextHolder.getContext().authentication
-        val user = mobileApiService.findUserById(p.name)
-                ?: return JsonResult.error("用户不存在,请注册")
-        val checkResult = checkUserConsume(user)
-        if (checkResult?.get("code") != 200) {
-            return checkResult
+    @PostMapping("/pay/{billno}")
+    fun medicalPayment(@PathVariable billno: String): JsonResult? {
+        try {
+            val p = SecurityContextHolder.getContext().authentication
+            val user = mobileApiService.findUserById(p.name)
+                    ?: return JsonResult.error("用户不存在,请注册")
+            val bean = PaymentRequestBean()
+            bean.billno = billno
+            val checkResult = checkUserConsume(user, bean)
+            if (checkResult?.get("code") != 200) {
+                return checkResult
+            }
+            medicalService.medicalPayPreInit(user.uid, bean)
+            medicalService.medicalPayInit(billno)
+            val confirmResult = medicalService.medicalPayConfirm(billno)
+            return if (confirmResult!!["code"] == MedicalConstant.MEDICAL_RESPONSE_SUCCESS) {
+                if (confirmResult["msg"] == MedicalConstant.DTL_STATUS_SUCCESS) {
+                    notifyHISAsyncTask.notifyHIS(billno)
+                    JsonResult.ok().put("status", MedicalConstant.DTL_STATUS_SUCCESS)
+                } else {
+                    JsonResult.ok().put("status", MedicalConstant.DTL_STATUS_WIP)
+                }
+            } else {
+                confirmResult
+            }
+        } catch (e: Exception) {
+            logger.error("系统异常", e)
+            if (e is MedicineException) {
+                return JsonResult.error(e.message)
+            }
+            return JsonResult.error("系统异常,请稍后重试")
         }
-        val cardNo = checkResult["data"] as String
-        medicineService.medicalPayPreInit(user.uid, bean, cardNo)
-//        medicineService.medicalPayInit()
-//        medicineService.medicalPayConfirm()
-        return JsonResult.ok()
     }
 
-    fun checkUserConsume(user: TBMobileUser): JsonResult? {
+    /**
+     * 查询订单支付是否成功
+     */
+    @PostMapping("/pay/query/{billno}")
+    fun queryPayStatus(@PathVariable billno: String): JsonResult? {
+        try {
+            val p = SecurityContextHolder.getContext().authentication
+            val user = mobileApiService.findUserById(p.name)
+                    ?: return JsonResult.error("用户不存在,请注册")
+            val result = medicalService.queryMedicalPayResult(billno, user.uid)
+            return if (result!!["code"] == MedicalConstant.MEDICAL_RESPONSE_SUCCESS) {
+                if (result["msg"] == MedicalConstant.DTL_STATUS_SUCCESS) {
+                    notifyHISAsyncTask.notifyHIS(billno)
+                    JsonResult.ok().put("status", MedicalConstant.DTL_STATUS_SUCCESS)
+                } else {
+                    JsonResult.ok().put("status", MedicalConstant.DTL_STATUS_WIP)
+                }
+            } else {
+                result
+            }
+        } catch (e: Exception) {
+            logger.error("系统异常", e)
+            if (e is MedicineException) {
+                return JsonResult.error(e.message)
+            }
+            return JsonResult.error("系统异常,请稍后重试")
+        }
+    }
+
+    fun checkUserConsume(user: TBMobileUser, bean: PaymentRequestBean): JsonResult? {
         if (TradeDict.STATUS_NORMAL != user.status) {
             return JsonResult.error("用户状态异常")
         }
@@ -234,6 +301,8 @@
         if (!cardResponse.card.signed) {
             return JsonResult.error("请签约银行卡")
         }
-        return JsonResult.ok().put("data", userInfo.cardno)
-    }
+        bean.cardNo = userInfo.cardno
+        bean.idno = userInfo.idno
+        return JsonResult.ok()
+    }*/
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/NotifyPayedBean.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/NotifyPayedBean.kt
index da8b4a3..ec69a8e 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/NotifyPayedBean.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/NotifyPayedBean.kt
@@ -10,15 +10,15 @@
     var payAmount = 0.0
     var outOrderNumber = ""
     var payer = ""
-    var totalFee  = 0.0
-    var brid  = ""
-    var feeRecords  = ArrayList<FeeRecordItem>()
+    var totalFee = 0.0
+    var brid = ""
+    var feeRecords = ArrayList<FeeRecordItem>()
 }
 
 class NotifyPayedResponse {
-    var agtOrderNumber = ""
-    var resultId = ""
-    var invoiceNumber = ""
-    var paymentBudgetNumber = ""
+    var agtOrderNumber: String? = ""
+    var resultId: String? = ""
+    var invoiceNumber: String? = ""
+    var paymentBudgetNumber: String? = ""
     var feeRecords = ArrayList<FeeRecordItem>()
 }
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/PayedBean.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/PayedBean.kt
index 3ec31f7..446980f 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/PayedBean.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/PayedBean.kt
@@ -9,34 +9,34 @@
 }
 
 class PayedResponse {
-    var patientId = ""
-    var patientMedicalCardType = 0
-    var patientMedicalCardNumber = ""
+    var patientId: String? = ""
+    var patientMedicalCardType: Int? = 0
+    var patientMedicalCardNumber: String? = ""
     var invoiceList = ArrayList<InvoiceItem>()
 }
 
 class InvoiceItem {
-    var invoiceNumber = ""
-    var medicalDate = ""
-    var admNumber = ""
+    var invoiceNumber: String? = ""
+    var medicalDate: String? = ""
+    var admNumber: String? = ""
     var costList = ArrayList<costItem>()
 }
 
 class costItem {
-    var mergingCode = 0
-    var mergingName = ""
-    var executionStatus = 0 //执行判别: 0、已付款/未执行/待执行,1、表示已取药2、表示已执行3、标志已退费
-    var execute = ""    //执行科室
-    var feeNo = ""
-    var feeTypeCode = ""
-    var totalFee = 0.0
+    var mergingCode: Int? = 0
+    var mergingName: String? = ""
+    var executionStatus: Int? = 0 //执行判别: 0、已付款/未执行/待执行,1、表示已取药2、表示已执行3、标志已退费
+    var execute: String? = ""    //执行科室
+    var feeNo: String? = ""
+    var feeTypeCode: String? = ""
+    var totalFee: Double? = 0.0
 }
 
 class PayedDTO {
-    var medicalDate = ""
-    var mergingName = ""
-    var executionStatus = 0
-    var execute = ""
-    var totalFee = 0.0
-    var admNumber = ""
+    var medicalDate: String? = ""
+    var mergingName: String? = ""
+    var executionStatus: Int? = 0
+    var execute: String? = ""
+    var totalFee: Double? = 0.0
+    var admNumber: String? = ""
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/PaymentRequestBean.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/PaymentRequestBean.kt
index 05b16e9..5131801 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/PaymentRequestBean.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/PaymentRequestBean.kt
@@ -1,8 +1,7 @@
 package com.supwisdom.dlpay.medical.bean
 
 class PaymentRequestBean {
-    var hospitalcode = ""
-    var cardid = ""
-    var feeno = ""
-    var admnumber = ""
+    var billno = ""
+    var cardNo = ""
+    var idno = ""
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/PrecalculatedFeeBean.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/PrecalculatedFeeBean.kt
index b3238fb..4dfce60 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/PrecalculatedFeeBean.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/PrecalculatedFeeBean.kt
@@ -4,19 +4,20 @@
     var organizationId = ""
     var boilSign = 0
     var feeRecords = ArrayList<FeeRecordItem>()
+    var patientId = ""
 }
 
 class FeeRecordItem {
-    var feeNo = ""
-    var feeTypeCode = ""
-    var feeTypeName = ""
-    var totalFee = 0.0
+    var feeNo: String? = ""
+    var feeTypeCode: String? = ""
+    var feeTypeName: String? = ""
+    var totalFee: Double? = 0.0
 }
 
 class PreFeeResponse {
-    var payAmount = 0.0
-    var invoiceNumber = ""
-    var totalFee = 0.0
-    var paymentBudgetNumber = ""    //预结算标识
-    var extraFeeDesc = ""   //加收费费用描述
+    var payAmount: Double? = 0.0
+    var invoiceNumber: String? = ""
+    var totalFee: Double? = 0.0
+    var paymentBudgetNumber: String? = ""    //预结算标识
+    var extraFeeDesc: String? = ""   //加收费费用描述
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/UnPayedBean.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/UnPayedBean.kt
index 27a2bcf..1b0bd14 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/UnPayedBean.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/bean/UnPayedBean.kt
@@ -5,48 +5,55 @@
 class UnPayedRequest {
     var organizationId = ""
     var queryType = 0
-    var patientIdList = ArrayList<String>()
+    var patientIdentityCardList = ArrayList<IdentityCardBean>()
+}
+
+class IdentityCardBean {
+    var cardType: String? = ""
+    var cardNumber: String? = ""
 }
 
 class UnPayedResponse {
-    var patientId = ""
-    var patientMedicalCardType = 0
-    var patientMedicalCardNumber = ""
-    var patientName = ""
-    var patientSex = ""
-    var patientAge = ""
+    var patientId: String? = ""
+    var patientMedicalCardType: Int? = 0
+    var patientMedicalCardNumber: String? = ""
+    var patientName: String? = ""
+    var patientSex: String? = ""
+    var patientAge: String? = ""
     var medicalInformation = ArrayList<MedicalInformation>()
 }
 
 class MedicalInformation {
-    var medicalDate = ""
-    var doctorName = ""
-    var doctorCode = ""
-    var departmentName = ""
-    var departmentCode = ""
-    var totalFee = 0.0
-    var admNumber = ""  //就诊序号
+    var medicalDate: String? = ""
+    var doctorName: String? = ""
+    var doctorCode: String? = ""
+    var departmentName: String? = ""
+    var departmentCode: String? = ""
+    var totalFee: Double? = 0.0
+    var emergencyNumber: String? = ""  //就诊序号
     var mergingItems = ArrayList<MergingItems>()
 }
 
 class MergingItems {
-    var mergingCode = 0
-    var mergingName = ""
-    var mergingSubtotal = 0.0
-    var feeNo = ""
-    var feeTypeCode = ""
-    var feeTypeName = ""
-    var feeDate = ""
-    var boilSign = 0    //代煎标志,0-不代煎,1-代煎
+    var mergingCode: Int? = 0
+    var mergingName: String? = ""
+    var mergingSubtotal: Double? = 0.0
+    var feeNo: String? = ""
+    var feeTypeCode: String? = ""
+    var feeTypeName: String? = ""
+    var feeDate: String? = ""
+    var boilSign: Int? = 0    //代煎标志,0-不代煎,1-代煎
 }
 
 class UnPayedDTO {
-    var billno = ""
-    var medicalDate = ""
-    var doctorName = ""
-    var subjectName = ""
-    var admNumber = ""
-    var mergingSubtotal = 0.0
-    var feeNo = ""
+    var billNo: String? = ""
+    var medicalDate: String? = ""
+    var doctorName: String? = ""
+    var subjectName: String? = ""
+    var emergencyNumber: String? = ""
+    var mergingSubtotal: Double? = 0.0
+    var feeNo: String? = ""
+    var status: String? = ""
+    var mergingName: String? = ""
 }
 
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/dao/MedicalDtlDao.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/dao/MedicalDtlDao.kt
index 0b8081f..f535820 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/dao/MedicalDtlDao.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/dao/MedicalDtlDao.kt
@@ -1,6 +1,7 @@
 package com.supwisdom.dlpay.medical.dao
 
 import com.supwisdom.dlpay.medical.domain.TBMedicalDtl
+import org.springframework.data.domain.Pageable
 import org.springframework.data.jpa.repository.JpaRepository
 import org.springframework.data.jpa.repository.Lock
 import org.springframework.data.jpa.repository.Query
@@ -14,7 +15,11 @@
     @Lock(LockModeType.PESSIMISTIC_WRITE)
     @Query("select t from TBMedicalDtl t where t.billno=?1")
     @QueryHints(QueryHint(name = "javax.persistence.lock.timeout", value = "0"))
-    fun findByBillnoForUpdate(billno: String?): TBMedicalDtl
+    fun findByBillnoForUpdate(billno: String?): TBMedicalDtl?
 
-    fun findByAdmnumberAndFeenoAndOrganizationidAndPaystatusNot(admNumber: String, organizationId: String, feeNo: String, payStatus: String): TBMedicalDtl?
+    fun findByPaystatusAndResultidIsNull(status: String, pageable: Pageable): List<TBMedicalDtl>?
+
+    fun findByUidAndEmergencyAndFeenoAndOrganizationidAndPaystatusNot(uid: String, emergency: String, feeNo: String, organizationId: String, payStatus: String): TBMedicalDtl?
+
+    fun findByUidAndOrganizationidAndPaystatus(uid: String, organizationId: String, payStatus: String, pageable: Pageable): List<TBMedicalDtl>?
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/service/MedicineService.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/service/MedicalService.kt
similarity index 72%
rename from backend/src/main/kotlin/com/supwisdom/dlpay/medical/service/MedicineService.kt
rename to backend/src/main/kotlin/com/supwisdom/dlpay/medical/service/MedicalService.kt
index 5cd2410..1e5683c 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/service/MedicineService.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/service/MedicalService.kt
@@ -6,7 +6,7 @@
 import com.supwisdom.dlpay.medical.domain.TBMedicalCard
 import org.springframework.transaction.annotation.Transactional
 
-interface MedicineService {
+interface MedicalService {
     @Transactional(readOnly = true)
     fun getHospitalList(pageno: Int, pageSize: Int, name: String?): Pagination
 
@@ -32,20 +32,29 @@
     fun deleteAppointment(appointmentId: String, uid: String)
 
     @Transactional
-    fun getUnPayedList(uid: String, organizationId: String, cardId: String): List<UnPayedDTO>
+    fun getUnPayedList(uid: String, idno: String, organizationId: String): List<UnPayedDTO>
 
+    /**
+     * 从HIS查询已支付列表
+     */
     @Transactional
     fun getPayedList(uid: String, organizationId: String, cardId: String): ArrayList<PayedDTO>
 
+    /**
+     * 从本地数据查询已支付列表
+     */
     @Transactional
-    fun medicalPayPreInit(uid: String, bean: PaymentRequestBean, cardNo: String): JsonResult?
+    fun getPayedList(uid: String, organizationId: String): ArrayList<PayedDTO>
 
     @Transactional
-    fun medicalPayInit(billNo: String): JsonResult?
+    fun medicalPayPreInit(uid: String, bean: PaymentRequestBean)
+
+    @Transactional
+    fun medicalPayInit(billNo: String)
 
     @Transactional
     fun medicalPayConfirm(billNo: String): JsonResult?
 
     @Transactional
-    fun notifyHISPayed()
+    fun queryMedicalPayResult(billNo: String, uid: String): JsonResult?
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/service/impl/MedicalServiceImpl.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/service/impl/MedicalServiceImpl.kt
new file mode 100644
index 0000000..f2e38ec
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/service/impl/MedicalServiceImpl.kt
@@ -0,0 +1,468 @@
+package com.supwisdom.dlpay.medical.service.impl
+
+import com.supwisdom.dlpay.api.bean.CitizenCardPayfinishParam
+import com.supwisdom.dlpay.api.bean.CitizenCardPayinitParam
+import com.supwisdom.dlpay.api.bean.JsonResult
+import com.supwisdom.dlpay.api.bean.QueryDtlResultParam
+import com.supwisdom.dlpay.framework.jpa.page.Pagination
+import com.supwisdom.dlpay.framework.service.SystemUtilService
+import com.supwisdom.dlpay.framework.util.MoneyUtil
+import com.supwisdom.dlpay.framework.util.StringUtil
+import com.supwisdom.dlpay.medical.bean.*
+import com.supwisdom.dlpay.medical.dao.AppointmentDtlDao
+import com.supwisdom.dlpay.medical.dao.HospitalDao
+import com.supwisdom.dlpay.medical.dao.MedicalCardDao
+import com.supwisdom.dlpay.medical.dao.MedicalDtlDao
+import com.supwisdom.dlpay.medical.domain.TBAppointmentDtl
+import com.supwisdom.dlpay.medical.domain.TBMedicalCard
+import com.supwisdom.dlpay.medical.domain.TBMedicalDtl
+import com.supwisdom.dlpay.medical.exception.MedicineException
+import com.supwisdom.dlpay.medical.service.MedicalService
+import com.supwisdom.dlpay.medical.util.MedicalClient
+import com.supwisdom.dlpay.medical.util.MedicalConstant
+import com.supwisdom.dlpay.paysdk.proxy.CitizenCardPayProxy
+import com.supwisdom.dlpay.paysdk.proxy.TransactionProxy
+import com.supwisdom.dlpay.portal.util.PortalConstant
+import mu.KotlinLogging
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.data.domain.PageRequest
+import org.springframework.stereotype.Service
+
+@Service
+class MedicalServiceImpl : MedicalService {
+    @Autowired
+    lateinit var hospitalDao: HospitalDao
+    @Autowired
+    lateinit var medicalCardDao: MedicalCardDao
+    @Autowired
+    lateinit var systemUtilService: SystemUtilService
+    @Autowired
+    lateinit var appointmentDtlDao: AppointmentDtlDao
+    @Autowired
+    lateinit var medicalClient: MedicalClient
+    @Autowired
+    lateinit var medicalDtlDao: MedicalDtlDao
+    @Autowired
+    lateinit var citizenCardPayProxy: CitizenCardPayProxy
+    @Autowired
+    lateinit var transactionProxy: TransactionProxy
+    val logger = KotlinLogging.logger { }
+
+    override fun getHospitalList(pageno: Int, pageSize: Int, name: String?): Pagination {
+        return hospitalDao.getHospitalList(pageno, pageSize, name)
+    }
+
+    override fun getMedicalCardList(uid: String, hospitalcode: String): List<TBMedicalCard>? {
+        return medicalCardDao.findByUidAndOrganizationid(uid, hospitalcode)
+    }
+
+    override fun deleteMedicalCard(uid: String, cardid: String) {
+        val medicalCard = medicalCardDao.findByCardidAndUid(cardid, uid)
+                ?: throw MedicineException("未找到该就诊卡")
+        medicalCardDao.delete(medicalCard)
+    }
+
+    override fun addPatient(bean: AddPatientBean) {
+        //  查询当前就诊人在该医院的就诊卡列表
+        val response = medicalClient.getPatientMedicalCardList(bean)
+        if (null != response && !response.listMedicalCard.isNullOrEmpty()) {
+            //  已有就诊卡:查询详情后本地保存
+            //  删除本地该患者原有就诊卡
+            val list = response.listMedicalCard
+            val localCard = medicalCardDao.findByUidAndOrganizationidAndCardnumberAndCardtype(
+                    bean.uid, bean.hospitalcode, bean.cardno, MedicalConstant.CARD_TYPE_IDCAED)
+            if (!localCard.isNullOrEmpty()) {
+                medicalCardDao.deleteAll(localCard)
+            }
+            list.forEach {
+                val detailResponse = medicalClient.getMedicalCardDetail(bean.hospitalcode, it.patientId)
+                val medicalCard = TBMedicalCard().apply {
+                    this.cardnumber = bean.cardno
+                    this.cardtype = MedicalConstant.CARD_TYPE_IDCAED
+                    this.medicalcardnumber = detailResponse.patientMedicalCardNumber
+                    this.medicalcardtype = detailResponse.patientMedicalCardType
+                    this.organizationid = bean.hospitalcode
+                    this.patientbirthday = detailResponse.patientBirthday
+                    this.patientid = detailResponse.patientId
+                    this.patientname = detailResponse.patientName
+                    this.patientsex = detailResponse.patientSex
+                    this.uid = bean.uid
+                    if (!StringUtil.isEmpty(detailResponse.patientMobile)) {
+                        this.patientmobile = detailResponse.patientMobile
+                    } else {
+                        this.patientmobile = response.patientMobile
+                    }
+                }
+                medicalCardDao.save(medicalCard)
+            }
+        } else {
+            //  无就诊卡,在HIS中新建,成功后本地保存
+            val addResponse = medicalClient.registerPatientInfo(bean)
+            if (null != addResponse && !addResponse.listMedicalCard.isNullOrEmpty()) {
+                //  删除本地该患者原有就诊卡
+                val addList = addResponse.listMedicalCard
+                val localCard = medicalCardDao.findByUidAndOrganizationidAndCardnumberAndCardtype(
+                        bean.uid, bean.hospitalcode, bean.cardno, MedicalConstant.CARD_TYPE_IDCAED)
+                if (!localCard.isNullOrEmpty()) {
+                    medicalCardDao.deleteAll(localCard)
+                }
+                addList.forEach {
+                    val medicalCard = TBMedicalCard().apply {
+                        this.cardnumber = bean.cardno
+                        this.cardtype = MedicalConstant.CARD_TYPE_IDCAED
+                        this.medicalcardnumber = it.patientMedicalCardNumber
+                        this.medicalcardtype = it.patientMedicalCardType
+                        this.organizationid = bean.hospitalcode
+                        this.patientid = it.patientId
+                        this.patientname = bean.name
+                        this.patientsex = bean.sex
+                        this.uid = bean.uid
+                        this.patientmobile = addResponse.patientMobile
+                    }
+                    medicalCardDao.save(medicalCard)
+                }
+            } else {
+                throw MedicineException("新增就诊卡失败")
+            }
+        }
+    }
+
+    override fun getArrangeInfo(organizationid: String, date: String): List<ArrangeInfoResponse> {
+        return medicalClient.getArrangeInfo(organizationid, date)
+    }
+
+    override fun confirmAppointment(bean: ConfirmRequestBean) {
+        val medicalCard = medicalCardDao.findByCardidAndUid(bean.cardid, bean.uid)
+                ?: throw MedicineException("未找到该就诊卡")
+        bean.apply {
+            this.patientid = medicalCard.patientid
+            this.patientname = medicalCard.patientname
+            this.patientmobile = medicalCard.patientmobile
+        }
+        val appointmentResponse = medicalClient.confirmAppointment(bean)
+        val appointmentDtl = TBAppointmentDtl()
+        appointmentDtl.uid = bean.uid
+        appointmentDtl.organizationid = appointmentResponse.organizationId
+        appointmentDtl.departmentid = bean.departmentid
+        appointmentDtl.departmentname = bean.departmentname
+        appointmentDtl.ghrq = bean.ghrq
+        appointmentDtl.zblb = bean.zblb
+        appointmentDtl.patientid = bean.patientid
+        appointmentDtl.patientname = bean.patientname
+        appointmentDtl.patientmobile = bean.patientmobile
+        appointmentDtl.serialnumber = appointmentResponse.serialNumber
+        appointmentDtl.createdate = systemUtilService.sysdatetime.hostdatetime
+        appointmentDtl.delete = false
+        appointmentDtlDao.save(appointmentDtl)
+    }
+
+    override fun getAppointmentList(pageno: Int, pagesize: Int, uid: String): Pagination {
+        return appointmentDtlDao.getAppointmentList(pageno, pagesize, uid)
+    }
+
+    override fun deleteAppointment(appointmentId: String, uid: String) {
+        val appointmentDtl = appointmentDtlDao.findByIdAndUidAndDelete(appointmentId, uid, false)
+                ?: throw MedicineException("未找到该条就诊记录")
+        appointmentDtl.delete = true
+        appointmentDtlDao.save(appointmentDtl)
+    }
+
+    fun getUnPayedResponse(organizationId: String, idno: String): UnPayedResponse {
+        val unPayedIdentityCardList = ArrayList<IdentityCardBean>()
+        unPayedIdentityCardList.add(IdentityCardBean().apply {
+            this.cardType = MedicalConstant.CARD_TYPE_IDCAED
+            this.cardNumber = idno
+        })
+        val upPayedRequest = UnPayedRequest().apply {
+            this.organizationId = organizationId
+            this.queryType = MedicalConstant.ORDER_QUERYTYPE_IDENTITYCARD
+            this.patientIdentityCardList = unPayedIdentityCardList
+        }
+        //根据患者id查询未支付账单
+        return medicalClient.getUnPayedList(upPayedRequest)
+    }
+
+    override fun getUnPayedList(uid: String, idno: String, organizationId: String): List<UnPayedDTO> {
+        //根据患者id查询未支付账单
+        val unPayedResponse = getUnPayedResponse(organizationId, idno)
+        val unPayedDTOList = ArrayList<UnPayedDTO>()
+        //拆分每次就诊下的每个项目为一条展示数据
+        unPayedResponse.medicalInformation.forEach { medicalInformation ->
+            for (mergingItems in medicalInformation.mergingItems) {
+                // 因为异步通知HIS,HIS中数据延迟,所以本地扣费成功后的流水仍有可能拉到
+                val localDtl = medicalDtlDao.findByUidAndEmergencyAndFeenoAndOrganizationidAndPaystatusNot(
+                        uid, medicalInformation.emergencyNumber!!, mergingItems.feeNo!!, organizationId, MedicalConstant.DTL_STATUS_FAIL)
+                var skip = false
+                if (localDtl != null) {
+                    if (localDtl.paystatus == MedicalConstant.DTL_STATUS_SUCCESS) {
+                        //  已扣费成功,等待通知HIS成功,此处无须额外处理
+                        continue
+                    } else {
+                        //  当流水为init或wip时都跳过生成本地流水
+                        skip = true
+                    }
+                }
+                var medicalDtl: TBMedicalDtl
+                if (!skip) {
+                    medicalDtl = TBMedicalDtl().apply {
+                        this.billno = systemUtilService.refno
+                        this.emergency = medicalInformation.emergencyNumber
+                        this.feeno = mergingItems.feeNo
+                        this.feetypecode = mergingItems.feeTypeCode
+                        this.uid = uid
+                        this.mergingname = mergingItems.mergingName
+                        this.paystatus = MedicalConstant.DTL_STATUS_INIT
+                        this.organizationid = organizationId
+                        this.patientid = unPayedResponse.patientId
+                        this.totalfee = mergingItems.mergingSubtotal
+                    }
+                    medicalDtlDao.save(medicalDtl)
+                } else {
+                    medicalDtl = localDtl!!
+                }
+                val unPayedDTO = UnPayedDTO().apply {
+                    this.billNo = medicalDtl.billno
+                    this.medicalDate = medicalInformation.medicalDate
+                    this.subjectName = medicalInformation.departmentName
+                    this.doctorName = medicalInformation.doctorName
+                    this.emergencyNumber = medicalInformation.emergencyNumber
+                    this.feeNo = mergingItems.feeNo
+                    this.mergingSubtotal = mergingItems.mergingSubtotal
+                    this.status = medicalDtl.paystatus
+                    this.mergingName = mergingItems.mergingName
+                }
+                unPayedDTOList.add(unPayedDTO)
+            }
+        }
+        return unPayedDTOList
+    }
+
+    override fun getPayedList(uid: String, organizationId: String, cardId: String): ArrayList<PayedDTO> {
+        val medicalCard = medicalCardDao.findByCardidAndUid(cardId, uid)
+                ?: throw MedicineException("未找到该就诊卡")
+        val payedPatientIdList = ArrayList<String>()
+        payedPatientIdList.add(medicalCard.patientid)
+        val payedRequest = PayedRequest()
+        payedRequest.organizationId = organizationId
+        payedRequest.queryType = MedicalConstant.ORDER_QUERYTYPE_PATIENTID
+        payedRequest.patientIdList = payedPatientIdList
+        payedRequest.executeFlag = MedicalConstant.PAYED_EXECUTEFLAG_INVALID
+        payedRequest.outpatientType = MedicalConstant.PAYED_OUTPATIENTTYPE_NORMAL
+        val payedResponse = medicalClient.getPayedList(payedRequest)
+        val payedDTOList = ArrayList<PayedDTO>()
+        //拆分每次就诊下的每个项目为一条展示数据
+        payedResponse.invoiceList.forEach { invoiceItem ->
+            invoiceItem.costList.forEach { costItem ->
+                val payedDTO = PayedDTO().apply {
+                    this.totalFee = costItem.totalFee
+                    this.medicalDate = invoiceItem.medicalDate
+                    this.executionStatus = costItem.executionStatus
+                    this.execute = costItem.execute
+                    this.mergingName = costItem.mergingName
+                    this.admNumber = invoiceItem.admNumber
+                }
+                payedDTOList.add(payedDTO)
+            }
+        }
+        return payedDTOList
+    }
+
+
+    override fun getPayedList(uid: String, organizationId: String): ArrayList<PayedDTO> {
+        val medicalDtlList = medicalDtlDao.findByUidAndOrganizationidAndPaystatus(uid, organizationId, MedicalConstant.DTL_STATUS_SUCCESS, PageRequest.of(0, 10))
+        val payedDTOList = ArrayList<PayedDTO>()
+        if (!medicalDtlList.isNullOrEmpty()) {
+            medicalDtlList.forEach {
+
+            }
+        }
+        return payedDTOList
+    }
+
+    override fun medicalPayPreInit(uid: String, bean: PaymentRequestBean) {
+        val medicalDtl = medicalDtlDao.findByBillnoForUpdate(bean.billno)
+                ?: throw MedicineException("未找到流水为[${bean.billno}]的流水")
+        if (medicalDtl.paystatus != null && medicalDtl.paystatus != MedicalConstant.DTL_STATUS_INIT) {
+            throw MedicineException("该流水状态异常,请查询后再试")
+        }
+        //1.从HIS中找到待支付流水
+        //1.1 根据患者id查询未支付账单
+        val unPayedResponse = getUnPayedResponse(medicalDtl.organizationid, bean.idno)
+        var mergingItems: MergingItems? = null
+        unPayedResponse.medicalInformation.forEach { medicalInformation ->
+            if (medicalInformation.emergencyNumber == medicalDtl.emergency) {
+                medicalInformation.mergingItems.forEach { queryMergingItems ->
+                    if (queryMergingItems.feeNo == medicalDtl.feeno) {
+                        mergingItems = queryMergingItems
+                    }
+                }
+            }
+        }
+        if (mergingItems == null) {
+            throw MedicineException("未找到该条待缴费记录")
+        }
+        //2.向HIS预结算
+        val feeRecords = ArrayList<FeeRecordItem>()
+        feeRecords.add(FeeRecordItem().apply {
+            this.feeNo = mergingItems!!.feeNo
+            this.feeTypeCode = mergingItems!!.feeTypeCode
+            this.feeTypeName = mergingItems!!.feeTypeName
+        })
+
+        val preFeeRequest = PreFeeRequest().apply {
+            this.boilSign = mergingItems!!.boilSign!!
+            this.organizationId = medicalDtl.organizationid
+            this.feeRecords = feeRecords
+            this.patientId = unPayedResponse.patientId!!
+        }
+        val preFeeResponse = medicalClient.getPreCalculatedFee(preFeeRequest)
+        medicalDtl.apply {
+            this.citizencardno = bean.cardNo
+            this.extrafeedesc = preFeeResponse.extraFeeDesc
+            this.invoiceno = preFeeResponse.invoiceNumber
+            this.transdate = systemUtilService.sysdatetime.hostdate
+            this.transtime = systemUtilService.sysdatetime.hosttime
+        }
+        medicalDtlDao.save(medicalDtl)
+    }
+
+    override fun medicalPayInit(billNo: String) {
+        //4.本地向payapi扣费
+        //4.1 payapi扣费初始化
+        val medicalDtl = medicalDtlDao.findByBillnoForUpdate(billNo)
+                ?: throw MedicineException("未找到流水为[${billNo}]的流水")
+        if (medicalDtl.paystatus != null && medicalDtl.paystatus != MedicalConstant.DTL_STATUS_INIT) {
+            throw MedicineException("该流水状态异常,请查询后再试")
+        }
+        // 查询是否已初始化
+        val queryResult = transactionProxy.queryDtlResult(QueryDtlResultParam().apply {
+            this.billno = medicalDtl.billno
+            this.shopaccno = systemUtilService.getBusinessValue(PortalConstant.SYSPARA_MEDICAL_SHOPACCNO)
+        })
+        if (MedicalConstant.PAYAPI_SUCCESS_RETCODE == queryResult.retcode) {
+            //  查询到该流水说明已初始化,可直接确认
+            medicalDtl.refno = queryResult.refno
+        } else if (MedicalConstant.PAYAPI_NOT_EXISTS == queryResult.retcode) {
+            //  未查到该流水,继续初始化步骤
+            val initParam = CitizenCardPayinitParam().apply {
+                this.billno = medicalDtl.billno
+                this.cardNo = medicalDtl.citizencardno
+                this.amount = MoneyUtil.YuanToFen(medicalDtl.totalfee)
+                this.dtltype = MedicalConstant.DTLTYPE_MEDICAL
+                this.transdate = medicalDtl.transdate
+                this.transtime = medicalDtl.transtime
+                this.shopaccno = systemUtilService.getBusinessValue(PortalConstant.SYSPARA_MEDICAL_SHOPACCNO)
+            }
+            val payInit = citizenCardPayProxy.citizencardPayinit(initParam)
+            if (payInit.retcode != MedicalConstant.PAYAPI_SUCCESS_RETCODE) {
+                throw MedicineException(payInit.retmsg)
+            }
+            medicalDtl.refno = payInit.refno
+        }
+        medicalDtl.paystatus = MedicalConstant.DTL_STATUS_WIP
+        medicalDtlDao.save(medicalDtl)
+    }
+
+    override fun medicalPayConfirm(billNo: String): JsonResult? {
+        //4.2 paypai扣费确认
+        val medicalDtl = medicalDtlDao.findByBillnoForUpdate(billNo)
+                ?: throw MedicineException("未找到流水为[${billNo}]的流水")
+        val confirmParam = CitizenCardPayfinishParam().apply {
+            this.refno = medicalDtl.refno
+        }
+        val payConfirm = citizenCardPayProxy.citizencardPayFinish(confirmParam)
+        when (payConfirm.retcode) {
+            MedicalConstant.PAYAPI_SUCCESS_RETCODE -> {
+                medicalDtl.paystatus = MedicalConstant.DTL_STATUS_SUCCESS
+                medicalDtl.accdate = systemUtilService.sysdatetime.hostdate
+                medicalDtlDao.save(medicalDtl)
+                return JsonResult.ok(MedicalConstant.DTL_STATUS_SUCCESS)
+            }
+            //  确认返回结果为待查询
+            MedicalConstant.PAYAPI_WAIT_QUERY -> {
+                //  查询确认结果
+                val queryResult = transactionProxy.queryDtlResult(QueryDtlResultParam().apply {
+                    this.refno = medicalDtl.refno
+                    this.shopaccno = systemUtilService.getBusinessValue(PortalConstant.SYSPARA_MEDICAL_SHOPACCNO)
+                })
+                if (queryResult.retcode == MedicalConstant.PAYAPI_SUCCESS_RETCODE) {
+                    when (queryResult.status) {
+                        MedicalConstant.DTL_STATUS_SUCCESS -> {
+                            medicalDtl.paystatus = MedicalConstant.DTL_STATUS_SUCCESS
+                            medicalDtl.accdate = systemUtilService.sysdatetime.hostdate
+                            medicalDtlDao.save(medicalDtl)
+                            return JsonResult.ok(MedicalConstant.DTL_STATUS_SUCCESS)
+                        }
+                        MedicalConstant.DTL_STATUS_FAIL -> {
+                            medicalDtl.paystatus = MedicalConstant.DTL_STATUS_FAIL
+                            medicalDtlDao.save(medicalDtl)
+                            logger.error("向payapi扣费确认失败:[${queryResult.retmsg}]")
+                            return JsonResult.error(queryResult.retmsg)
+                        }
+                        MedicalConstant.DTL_STATUS_INIT -> {
+                            medicalDtl.paystatus = MedicalConstant.DTL_STATUS_WIP
+                            medicalDtlDao.save(medicalDtl)
+                            return JsonResult.ok(MedicalConstant.DTL_STATUS_WIP)
+                        }
+                    }
+                }
+                medicalDtl.paystatus = MedicalConstant.DTL_STATUS_WIP
+                medicalDtlDao.save(medicalDtl)
+                logger.error("查询确认结果失败:${queryResult.retcode},${queryResult.retmsg}")
+                return JsonResult.ok(MedicalConstant.DTL_STATUS_WIP)
+            }
+            MedicalConstant.PAYAPI_DEAL_ERROR -> {
+                medicalDtl.paystatus = MedicalConstant.DTL_STATUS_FAIL
+                medicalDtlDao.save(medicalDtl)
+                return JsonResult.error(payConfirm.retmsg)
+            }
+            else -> {
+                logger.error("未知的确认状态码:${payConfirm.retcode},${payConfirm.retmsg}")
+                medicalDtl.paystatus = MedicalConstant.DTL_STATUS_FAIL
+                medicalDtlDao.save(medicalDtl)
+                return JsonResult.error(payConfirm.retmsg)
+            }
+        }
+    }
+
+    override fun queryMedicalPayResult(billNo: String, uid: String): JsonResult? {
+        val medicalDtl = medicalDtlDao.findByBillnoForUpdate(billNo)
+                ?: throw MedicineException("未找到流水为[${billNo}]的流水")
+        if (uid != medicalDtl.uid) {
+            throw MedicineException("未在当前用户的账户下查询到该条流水")
+        }
+        if (medicalDtl.paystatus != MedicalConstant.DTL_STATUS_WIP) {
+            throw MedicineException("该流水状态异常,请查询后再试")
+        }
+        val queryResult = transactionProxy.queryDtlResult(QueryDtlResultParam().apply {
+            this.refno = medicalDtl.refno
+            this.shopaccno = systemUtilService.getBusinessValue(PortalConstant.SYSPARA_MEDICAL_SHOPACCNO)
+        })
+        if (queryResult.retcode == MedicalConstant.PAYAPI_SUCCESS_RETCODE) {
+            when (queryResult.status) {
+                MedicalConstant.DTL_STATUS_SUCCESS -> {
+                    medicalDtl.paystatus = MedicalConstant.DTL_STATUS_SUCCESS
+                    medicalDtl.accdate = systemUtilService.sysdatetime.hostdate
+                    medicalDtlDao.save(medicalDtl)
+                    return JsonResult.ok(MedicalConstant.DTL_STATUS_SUCCESS)
+                }
+                MedicalConstant.DTL_STATUS_FAIL -> {
+                    medicalDtl.paystatus = MedicalConstant.DTL_STATUS_FAIL
+                    medicalDtlDao.save(medicalDtl)
+                    return JsonResult.error(queryResult.retmsg)
+                }
+                MedicalConstant.DTL_STATUS_INIT -> {
+                    medicalDtl.paystatus = MedicalConstant.DTL_STATUS_WIP
+                    medicalDtlDao.save(medicalDtl)
+                    return JsonResult.ok(MedicalConstant.DTL_STATUS_WIP)
+                }
+            }
+            logger.error("未知的查询状态码:${queryResult.status},${queryResult.retmsg}")
+        } else {
+            logger.error("查询支付结果失败:${queryResult.retcode},${queryResult.retmsg}")
+        }
+        medicalDtl.paystatus = MedicalConstant.DTL_STATUS_WIP
+        medicalDtlDao.save(medicalDtl)
+        return JsonResult.ok(MedicalConstant.DTL_STATUS_WIP)
+    }
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/service/impl/MedicineServiceImpl.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/service/impl/MedicineServiceImpl.kt
deleted file mode 100644
index d5cba58..0000000
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/service/impl/MedicineServiceImpl.kt
+++ /dev/null
@@ -1,367 +0,0 @@
-package com.supwisdom.dlpay.medical.service.impl
-
-import com.supwisdom.dlpay.api.bean.CitizenCardPayfinishParam
-import com.supwisdom.dlpay.api.bean.CitizenCardPayinitParam
-import com.supwisdom.dlpay.api.bean.JsonResult
-import com.supwisdom.dlpay.framework.jpa.page.Pagination
-import com.supwisdom.dlpay.framework.service.SystemUtilService
-import com.supwisdom.dlpay.framework.util.MoneyUtil
-import com.supwisdom.dlpay.framework.util.StringUtil
-import com.supwisdom.dlpay.medical.bean.*
-import com.supwisdom.dlpay.medical.dao.AppointmentDtlDao
-import com.supwisdom.dlpay.medical.dao.HospitalDao
-import com.supwisdom.dlpay.medical.dao.MedicalCardDao
-import com.supwisdom.dlpay.medical.dao.MedicalDtlDao
-import com.supwisdom.dlpay.medical.domain.TBAppointmentDtl
-import com.supwisdom.dlpay.medical.domain.TBMedicalCard
-import com.supwisdom.dlpay.medical.domain.TBMedicalDtl
-import com.supwisdom.dlpay.medical.exception.MedicineException
-import com.supwisdom.dlpay.medical.service.MedicineService
-import com.supwisdom.dlpay.medical.util.MedicalClient
-import com.supwisdom.dlpay.medical.util.MedicalConstant
-import com.supwisdom.dlpay.paysdk.proxy.CitizenCardPayProxy
-import com.supwisdom.dlpay.portal.util.PortalConstant
-import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.stereotype.Service
-
-@Service
-class MedicineServiceImpl : MedicineService {
-    @Autowired
-    lateinit var hospitalDao: HospitalDao
-    @Autowired
-    lateinit var medicalCardDao: MedicalCardDao
-    @Autowired
-    lateinit var systemUtilService: SystemUtilService
-    @Autowired
-    lateinit var appointmentDtlDao: AppointmentDtlDao
-    @Autowired
-    lateinit var medicalClient: MedicalClient
-    @Autowired
-    lateinit var medicalDtlDao: MedicalDtlDao
-    @Autowired
-    lateinit var citizenCardPayProxy: CitizenCardPayProxy
-
-    override fun getHospitalList(pageno: Int, pageSize: Int, name: String?): Pagination {
-        return hospitalDao.getHospitalList(pageno, pageSize, name)
-    }
-
-    override fun getMedicalCardList(uid: String, hospitalcode: String): List<TBMedicalCard>? {
-        return medicalCardDao.findByUidAndOrganizationid(uid, hospitalcode)
-    }
-
-    override fun deleteMedicalCard(uid: String, cardid: String) {
-        val medicalCard = medicalCardDao.findByCardidAndUid(cardid, uid)
-                ?: throw MedicineException("未找到该就诊卡")
-        medicalCardDao.delete(medicalCard)
-    }
-
-    override fun addPatient(bean: AddPatientBean) {
-        //  查询当前就诊人在该医院的就诊卡列表
-        val response = medicalClient.getPatientMedicalCardList(bean)
-        if (null != response && !response.listMedicalCard.isNullOrEmpty()) {
-            //  已有就诊卡:查询详情后本地保存
-            //  删除本地该患者原有就诊卡
-            val list = response.listMedicalCard
-            val localCard = medicalCardDao.findByUidAndOrganizationidAndCardnumberAndCardtype(
-                    bean.uid, bean.hospitalcode, bean.cardno, MedicalConstant.CARD_TYPE_IDCAED)
-            if (!localCard.isNullOrEmpty()) {
-                medicalCardDao.deleteAll(localCard)
-            }
-            list.forEach {
-                val detailResponse = medicalClient.getMedicalCardDetail(bean.hospitalcode, it.patientId)
-                val medicalCard = TBMedicalCard().apply {
-                    this.cardnumber = bean.cardno
-                    this.cardtype = MedicalConstant.CARD_TYPE_IDCAED
-                    this.medicalcardnumber = detailResponse.patientMedicalCardNumber
-                    this.medicalcardtype = detailResponse.patientMedicalCardType
-                    this.organizationid = bean.hospitalcode
-                    this.patientbirthday = detailResponse.patientBirthday
-                    this.patientid = detailResponse.patientId
-                    this.patientname = detailResponse.patientName
-                    this.patientsex = detailResponse.patientSex
-                    this.uid = bean.uid
-                    if (!StringUtil.isEmpty(detailResponse.patientMobile)) {
-                        this.patientmobile = detailResponse.patientMobile
-                    } else {
-                        this.patientmobile = response.patientMobile
-                    }
-                }
-                medicalCardDao.save(medicalCard)
-            }
-        } else {
-            //  无就诊卡,在HIS中新建,成功后本地保存
-            val addResponse = medicalClient.registerPatientInfo(bean)
-            if (null != addResponse && !addResponse.listMedicalCard.isNullOrEmpty()) {
-                //  删除本地该患者原有就诊卡
-                val addList = addResponse.listMedicalCard
-                val localCard = medicalCardDao.findByUidAndOrganizationidAndCardnumberAndCardtype(
-                        bean.uid, bean.hospitalcode, bean.cardno, MedicalConstant.CARD_TYPE_IDCAED)
-                if (!localCard.isNullOrEmpty()) {
-                    medicalCardDao.deleteAll(localCard)
-                }
-                addList.forEach {
-                    val medicalCard = TBMedicalCard().apply {
-                        this.cardnumber = bean.cardno
-                        this.cardtype = MedicalConstant.CARD_TYPE_IDCAED
-                        this.medicalcardnumber = it.patientMedicalCardNumber
-                        this.medicalcardtype = it.patientMedicalCardType
-                        this.organizationid = bean.hospitalcode
-                        this.patientid = it.patientId
-                        this.patientname = bean.name
-                        this.patientsex = bean.sex
-                        this.uid = bean.uid
-                        this.patientmobile = addResponse.patientMobile
-                    }
-                    medicalCardDao.save(medicalCard)
-                }
-            } else {
-                throw MedicineException("新增就诊卡失败")
-            }
-        }
-    }
-
-    override fun getArrangeInfo(organizationid: String, date: String): List<ArrangeInfoResponse> {
-        return medicalClient.getArrangeInfo(organizationid, date)
-    }
-
-    override fun confirmAppointment(bean: ConfirmRequestBean) {
-        val medicalCard = medicalCardDao.findByCardidAndUid(bean.cardid, bean.uid)
-                ?: throw MedicineException("未找到该就诊卡")
-        bean.apply {
-            this.patientid = medicalCard.patientid
-            this.patientname = medicalCard.patientname
-            this.patientmobile = medicalCard.patientmobile
-        }
-        val appointmentResponse = medicalClient.confirmAppointment(bean)
-        val appointmentDtl = TBAppointmentDtl()
-        appointmentDtl.uid = bean.uid
-        appointmentDtl.organizationid = appointmentResponse.organizationId
-        appointmentDtl.departmentid = bean.departmentid
-        appointmentDtl.departmentname = bean.departmentname
-        appointmentDtl.ghrq = bean.ghrq
-        appointmentDtl.zblb = bean.zblb
-        appointmentDtl.patientid = bean.patientid
-        appointmentDtl.patientname = bean.patientname
-        appointmentDtl.patientmobile = bean.patientmobile
-        appointmentDtl.serialnumber = appointmentResponse.serialNumber
-        appointmentDtl.createdate = systemUtilService.sysdatetime.hostdatetime
-        appointmentDtl.delete = false
-        appointmentDtlDao.save(appointmentDtl)
-    }
-
-    override fun getAppointmentList(pageno: Int, pagesize: Int, uid: String): Pagination {
-        return appointmentDtlDao.getAppointmentList(pageno, pagesize, uid)
-    }
-
-    override fun deleteAppointment(appointmentId: String, uid: String) {
-        val appointmentDtl = appointmentDtlDao.findByIdAndUidAndDelete(appointmentId, uid, false)
-                ?: throw MedicineException("未找到该条就诊记录")
-        appointmentDtl.delete = true
-        appointmentDtlDao.save(appointmentDtl)
-    }
-
-    fun getUnPayedResponse(organizationId: String, petientId: String): UnPayedResponse {
-        val unPayedPatientIdList = ArrayList<String>()
-        unPayedPatientIdList.add(petientId)
-        val upPayedRequest = UnPayedRequest()
-        upPayedRequest.organizationId = organizationId
-        upPayedRequest.queryType = MedicalConstant.ORDER_QUERYTYPE_PATIENTID
-        upPayedRequest.patientIdList = unPayedPatientIdList
-        //根据患者id查询未支付账单
-        return medicalClient.getUnPayedList(upPayedRequest)
-    }
-
-    override fun getUnPayedList(uid: String, organizationId: String, cardId: String): List<UnPayedDTO> {
-        val medicalCard = medicalCardDao.findByCardidAndUid(cardId, uid)
-                ?: throw MedicineException("未找到该就诊卡")
-        //根据患者id查询未支付账单
-        val unPayedResponse = getUnPayedResponse(organizationId, medicalCard.patientid)
-        val unPayedDTOList = ArrayList<UnPayedDTO>()
-        //拆分每次就诊下的每个项目为一条展示数据
-        unPayedResponse.medicalInformation.forEach { medicalInformation ->
-            for (mergingItems in medicalInformation.mergingItems) {
-                // 因为异步通知HIS,HIS中数据延迟,所以本地扣费成功后的流水任有可能拉到
-                val localDtl = medicalDtlDao.findByAdmnumberAndFeenoAndOrganizationidAndPaystatusNot(
-                        medicalInformation.admNumber, organizationId, mergingItems.feeNo, MedicalConstant.DTL_STATUS_FAIL)
-                if (localDtl != null) {
-                    //TODO:其余状态处理
-                    if (localDtl.paystatus == MedicalConstant.DTL_STATUS_SUCCESS) {
-                        continue
-                    }
-                }
-                val medicalDtl = TBMedicalDtl().apply {
-                    this.billno = systemUtilService.refno
-                    this.admnumber = medicalInformation.admNumber
-                    this.feeno = mergingItems.feeNo
-                    this.uid = uid
-                    this.paystatus = MedicalConstant.DTL_STATUS_INIT
-                    this.transdate = systemUtilService.sysdatetime.hostdate
-                    this.transtime = systemUtilService.sysdatetime.hosttime
-                    this.organizationid = organizationId
-                }
-                medicalDtlDao.save(medicalDtl)
-
-                val unPayedDTO = UnPayedDTO().apply {
-                    this.billno = medicalDtl.billno
-                    this.medicalDate = medicalInformation.medicalDate
-                    this.subjectName = medicalInformation.departmentName
-                    this.doctorName = medicalInformation.doctorName
-                    this.admNumber = medicalInformation.admNumber
-                    this.feeNo = mergingItems.feeNo
-                    this.mergingSubtotal = mergingItems.mergingSubtotal
-                }
-                unPayedDTOList.add(unPayedDTO)
-            }
-        }
-        return unPayedDTOList
-    }
-
-    override fun getPayedList(uid: String, organizationId: String, cardId: String): ArrayList<PayedDTO> {
-        val medicalCard = medicalCardDao.findByCardidAndUid(cardId, uid)
-                ?: throw MedicineException("未找到该就诊卡")
-        val payedPatientIdList = ArrayList<String>()
-        payedPatientIdList.add(medicalCard.patientid)
-        val payedRequest = PayedRequest()
-        payedRequest.organizationId = organizationId
-        payedRequest.queryType = MedicalConstant.ORDER_QUERYTYPE_PATIENTID
-        payedRequest.patientIdList = payedPatientIdList
-        payedRequest.executeFlag = MedicalConstant.PAYED_EXECUTEFLAG_INVALID
-        payedRequest.outpatientType = MedicalConstant.PAYED_OUTPATIENTTYPE_NORMAL
-        val payedResponse = medicalClient.getPayedList(payedRequest)
-        val payedDTOList = ArrayList<PayedDTO>()
-        //拆分每次就诊下的每个项目为一条展示数据
-        payedResponse.invoiceList.forEach { invoiceItem ->
-            invoiceItem.costList.forEach { costItem ->
-                val payedDTO = PayedDTO().apply {
-                    this.totalFee = costItem.totalFee
-                    this.medicalDate = invoiceItem.medicalDate
-                    this.executionStatus = costItem.executionStatus
-                    this.execute = costItem.execute
-                    this.mergingName = costItem.mergingName
-                    this.admNumber = invoiceItem.admNumber
-                }
-                payedDTOList.add(payedDTO)
-            }
-        }
-        return payedDTOList
-    }
-
-    override fun medicalPayPreInit(uid: String, bean: PaymentRequestBean, cardNo: String): JsonResult? {
-        val medicalCard = medicalCardDao.findByCardidAndUid(bean.cardid, uid)
-                ?: throw MedicineException("未找到该就诊卡")
-        //1.从HIS中找到待支付流水
-        //1.1 根据患者id查询未支付账单
-        val unPayedResponse = getUnPayedResponse(bean.hospitalcode, medicalCard.patientid)
-        var mergingItems: MergingItems? = null
-        unPayedResponse.medicalInformation.forEach { medicalInformation ->
-            if (medicalInformation.admNumber == bean.admnumber) {
-                medicalInformation.mergingItems.forEach { queryMergingItems ->
-                    if (queryMergingItems.feeNo == bean.feeno) {
-                        mergingItems = queryMergingItems
-                    }
-                }
-            }
-        }
-        if (mergingItems == null) {
-            throw MedicineException("未找到该条待缴费记录")
-        }
-        //2.向HIS预结算
-        val feeRecords = ArrayList<FeeRecordItem>()
-        feeRecords.add(FeeRecordItem().apply {
-            this.feeNo = mergingItems!!.feeNo
-            this.feeTypeCode = mergingItems!!.feeTypeCode
-            this.feeTypeName = mergingItems!!.mergingName
-        })
-
-        val preFeeRequest = PreFeeRequest().apply {
-            this.boilSign = mergingItems!!.boilSign
-            this.organizationId = bean.hospitalcode
-            this.feeRecords = feeRecords
-        }
-        val preFeeResponse = medicalClient.getPreCalculatedFee(preFeeRequest)
-        //查看本地是否有该条流水记录
-        val localMedicalDtl = medicalDtlDao.findByAdmnumberAndFeenoAndOrganizationidAndPaystatusNot(
-                bean.admnumber, bean.hospitalcode, mergingItems!!.feeNo, MedicalConstant.DTL_STATUS_FAIL)
-        if (localMedicalDtl != null) {
-            //锁住该条流水
-            medicalDtlDao.findByBillnoForUpdate(localMedicalDtl.billno)
-            when (localMedicalDtl.paystatus) {
-                MedicalConstant.DTL_STATUS_SUCCESS -> {
-                    return JsonResult.ok("该缴费已成功支付")
-                }
-                MedicalConstant.DTL_STATUS_WIP -> {
-                    return JsonResult.ok("请求正在处理中,请稍后查询处理结果")
-                }
-                MedicalConstant.DTL_STATUS_INIT -> {
-                    //流水已生成,跳过生成本地流水步骤
-                    return JsonResult.ok("continue")
-                }
-            }
-        }
-        //3.本地新建一条支付流水
-        val medicalDtl = TBMedicalDtl().apply {
-            this.billno = systemUtilService.refno
-            this.admnumber = bean.admnumber
-            this.feeno = mergingItems!!.feeNo
-            this.uid = uid
-            this.paystatus = MedicalConstant.DTL_STATUS_INIT
-            this.transdate = systemUtilService.sysdatetime.hostdate
-            this.transtime = systemUtilService.sysdatetime.hosttime
-            this.citizencardno = cardNo
-            this.payamount = preFeeResponse.payAmount
-            this.totalfee = preFeeResponse.totalFee
-            this.extrafeedesc = preFeeResponse.extraFeeDesc
-            this.invoiceno = preFeeResponse.invoiceNumber
-        }
-        medicalDtlDao.save(medicalDtl)
-        return JsonResult.ok()
-    }
-
-    override fun medicalPayInit(billNo: String): JsonResult? {
-        //4.本地向payapi扣费
-        //4.1 payapi扣费初始化
-        val medicalDtl = medicalDtlDao.findByBillnoForUpdate(billNo)
-        val initParam = CitizenCardPayinitParam().apply {
-            this.billno = medicalDtl.billno
-            this.cardNo = medicalDtl.citizencardno
-            this.amount = MoneyUtil.YuanToFen(medicalDtl.payamount)
-            this.dtltype = MedicalConstant.DTLTYPE_MEDICAL
-            this.transdate = medicalDtl.transdate
-            this.transtime = medicalDtl.transtime
-            this.shopaccno = systemUtilService.getBusinessValue(PortalConstant.SYSPARA_MEDICAL_SHOPACCNO)
-        }
-        val payInit = citizenCardPayProxy.citizencardPayinit(initParam)
-        if (payInit.retcode == 0) {
-            throw MedicineException("向payapi请求异常:${payInit.retcode}-${payInit.retmsg}")
-        }
-        medicalDtl.refno = payInit.refno
-        medicalDtl.paystatus = MedicalConstant.DTL_STATUS_WIP
-        medicalDtlDao.save(medicalDtl)
-        return JsonResult.ok()
-    }
-
-    override fun medicalPayConfirm(billNo: String): JsonResult? {
-        //4.2 paypai扣费确认
-        val medicalDtl = medicalDtlDao.findByBillnoForUpdate(billNo)
-        val confirmParam = CitizenCardPayfinishParam().apply {
-            this.refno = medicalDtl.refno
-        }
-        val payConfirm = citizenCardPayProxy.citizencardPayFinish(confirmParam)
-        if (payConfirm.retcode != MedicalConstant.PAYAPI_SUCCESS_RETCODE) {
-            throw MedicineException("向payapi请求异常:${payConfirm.retcode}-${payConfirm.retmsg}")
-        }
-
-        //6.修改本地流水状态
-        medicalDtl.paystatus = MedicalConstant.DTL_STATUS_SUCCESS
-        medicalDtlDao.save(medicalDtl)
-        return JsonResult.ok()
-}
-
-    override fun notifyHISPayed() {
-        //5.向HIS支付确认
-        val notifyPayedRequest = NotifyPayedRequest().apply {
-
-        }
-        val notifyPayedResponse = medicalClient.notifyPayed(notifyPayedRequest)
-    }
-}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medical/task/NotifyHISAsyncTask.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/task/NotifyHISAsyncTask.kt
new file mode 100644
index 0000000..abfafa2
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medical/task/NotifyHISAsyncTask.kt
@@ -0,0 +1,80 @@
+package com.supwisdom.dlpay.medical.task
+
+import com.supwisdom.dlpay.framework.service.SystemUtilService
+import com.supwisdom.dlpay.medical.bean.FeeRecordItem
+import com.supwisdom.dlpay.medical.bean.NotifyPayedRequest
+import com.supwisdom.dlpay.medical.dao.MedicalDtlDao
+import com.supwisdom.dlpay.medical.exception.MedicineException
+import com.supwisdom.dlpay.medical.util.MedicalClient
+import com.supwisdom.dlpay.medical.util.MedicalConstant
+import com.supwisdom.dlpay.mobile.service.MobileApiService
+import com.supwisdom.dlpay.paysdk.proxy.UserProxy
+import mu.KotlinLogging
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.scheduling.annotation.Async
+import org.springframework.stereotype.Component
+import org.springframework.transaction.annotation.Transactional
+
+@Component
+class NotifyHISAsyncTask {
+    @Autowired
+    private lateinit var medicalDtlDao: MedicalDtlDao
+    @Autowired
+    private lateinit var mobileApiService: MobileApiService
+    @Autowired
+    private lateinit var userProxy: UserProxy
+    @Autowired
+    private lateinit var medicalClient: MedicalClient
+    @Autowired
+    private lateinit var systemUtilService: SystemUtilService
+
+    private val logger = KotlinLogging.logger { }
+
+    @Async("notifyHIS")
+    @Transactional
+    fun notifyHIS(billNo: String) {
+        val medicalDtl = medicalDtlDao.findByBillnoForUpdate(billNo)
+                ?: throw MedicineException("未找到流水为[${billNo}]的流水")
+        if (medicalDtl.resultid != null || medicalDtl.paystatus != MedicalConstant.DTL_STATUS_SUCCESS) {
+            logger.error("待通知HIS流水billno[${billNo}]状态异常")
+            return
+        }
+        val mobileUser = mobileApiService.findUserById(medicalDtl.uid)
+        if (mobileUser == null) {
+            logger.error("未找到该uid为[${medicalDtl.uid}]的用户")
+            return
+        }
+        val personResponse = userProxy.queryPerson(mobileUser.userid)
+        if (personResponse.retcode != 0) {
+            logger.error { "查询用户[${mobileUser.userid}]信息失败:${personResponse.retmsg}" }
+            return
+        }
+        val notifyPayedRequest = NotifyPayedRequest().apply {
+            this.organizationId = medicalDtl.organizationid
+            this.patientId = medicalDtl.patientid
+            this.invoiceNumber = medicalDtl.invoiceno
+            this.payMode = MedicalConstant.PAY_MODE_DLSMK
+            this.payState = MedicalConstant.PAY_STATE_PAYED
+            this.agtOrderNumber = medicalDtl.refno
+            this.payAmount = medicalDtl.totalfee
+            this.outOrderNumber = medicalDtl.billno
+            this.payer = personResponse.person.name
+            this.totalFee = medicalDtl.totalfee
+            this.brid = medicalDtl.patientid
+            val feeRecords = ArrayList<FeeRecordItem>()
+            feeRecords.add(FeeRecordItem().apply {
+                this.feeNo = medicalDtl.feeno
+                this.feeTypeCode = medicalDtl.feetypecode
+            })
+            this.feeRecords = feeRecords
+        }
+        val notifyPayedResponse = medicalClient.notifyPayed(notifyPayedRequest)
+        if (notifyPayedResponse != null && !notifyPayedResponse.feeRecords.isNullOrEmpty()) {
+            medicalDtl.resultid = notifyPayedResponse.resultId
+            medicalDtl.resultdate = systemUtilService.sysdatetime.hostdate
+            medicalDtlDao.save(medicalDtl)
+        } else {
+            logger.error("向HIS结算确认失败")
+        }
+    }
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
index cb6a4fe..e13bbc9 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
@@ -557,6 +557,10 @@
             this.idtype = idtype
             this.idno = idno
             this.phone = user.phone
+            this.uid = user.uid
+            this.rsaprivate = user.rsaprivate
+            this.rsapublic = user.rsapublic
+            this.secertkey = user.secertkey
         })
         if (bindCardResult["retcode"] != 0) {
             logger.error { "绑卡失败,${bindCardResult["retmsg"]}" }
@@ -722,7 +726,15 @@
             return JsonResult.error("用户不存在,请注册")
         }
         if (!user.userid.isNullOrEmpty()) {
-            val response = userProxy.signbxy(user.userid, agree, user.phone)
+            val response = userProxy.signbxy(SignBxyParam().apply {
+                this.userid = user.userid
+                this.code = agree
+                this.phone = user.phone
+                this.uid = user.uid
+                this.rsaprivate = user.rsaprivate
+                this.rsapublic = user.rsapublic
+                this.secertkey = user.secertkey
+            })
             if (response.retcode != 0) {
                 logger.error { "用户签约失败:${response.retmsg}" }
                 return JsonResult.error("签约失败,${response.retmsg}")
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/domain/TBMobileUser.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/domain/TBMobileUser.kt
index 7ec41ec..31d16e6 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/domain/TBMobileUser.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/domain/TBMobileUser.kt
@@ -9,7 +9,9 @@
 import javax.validation.constraints.NotNull
 
 @Entity
-@Table(name = "TB_MOBILE_USER", indexes = [Index(name = "mobile_user_loginid_idx", columnList = "loginid", unique = true)])
+@Table(name = "TB_MOBILE_USER", indexes = [
+    Index(name = "mobile_user_loginid_idx", columnList = "loginid", unique = true),
+    Index(name = "mobile_user_phone_idx", columnList = "phone")])
 class TBMobileUser : UserDetails {
     override fun getAuthorities(): Collection<GrantedAuthority>? {
         return this.auths
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/security.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/security.kt
index cc591c3..f5c7c4b 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/security.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/security.kt
@@ -159,7 +159,7 @@
         }
         logger.info(url)
         val authHeader:String? = request.getHeader(jwtConfig.header)
-        if (url.startsWith("/mobileapi/v1")||url.startsWith("/mobileapi/medicineapi")) {
+        if (url.startsWith("/mobileapi/v1")||url.startsWith("/mobileapi/medicalapi")) {
             if (!authHeader.isNullOrEmpty()) {
                 try {
                     val jwt = if (authHeader.startsWith(jwtConfig.tokenHeader)) {
diff --git a/backend/src/test/java/test.java b/backend/src/test/java/test.java
deleted file mode 100644
index e7b34d4..0000000
--- a/backend/src/test/java/test.java
+++ /dev/null
@@ -1,39 +0,0 @@
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class test {
-  public static void main(String[] args) {
-    String sqlFragment = "您的验证码为:${code},订单号:${billno},本次消费:${money}元,请勿泄漏于他人。";
-    Map<String, String> map = new HashMap<>();
-    map.put("code", "23423");
-    map.put("billno", "6116c8e6e0c0464995f4e480473b6a1e");
-    map.put("money", "12.34");
-     Pattern pattern = Pattern.compile("\\$\\{[\\w]*}");
-    Matcher matcher = pattern.matcher(sqlFragment);
-    //循环,字符串中有多少个符合的,就循环多少次
-    while(matcher.find()){
-      //每一个符合正则的字符串
-      String e = matcher.group();
-      //截取出括号中的内容
-      String substring = e.substring(2, e.length()-1);
-      //字符串截取
-      //进行替换
-      String value = "init";
-      if (map.containsKey(substring)) {
-        value = map.get(substring);
-      }
-			sqlFragment = sqlFragment.replace(e, value);
-
-    }
-    System.out.println(sqlFragment);
-  }
-
-  @Test
-  public void test() {
-    System.out.println(String.format("%08d",2));
-  }
-}
diff --git a/config/application-devel-pg.properties b/config/application-devel-pg.properties
index 67f03e9..2237bf3 100644
--- a/config/application-devel-pg.properties
+++ b/config/application-devel-pg.properties
@@ -5,8 +5,8 @@
 spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
 # Postgresql settings
 spring.datasource.platform=postgresql
-#spring.datasource.url=jdbc:postgresql://172.28.201.70:15432/portal
-spring.datasource.url=jdbc:postgresql://localhost:5432/portal
+spring.datasource.url=jdbc:postgresql://172.28.201.70:15432/portal
+#spring.datasource.url=jdbc:postgresql://localhost:5432/portal
 spring.datasource.username=payapi
 spring.datasource.password=123456
 spring.datasource.continue-on-error=true