浏览代码

fix taihe-rpcå重构到rpc项目,并处理其中的mq

daiyihua 1 年之前
父节点
当前提交
b840c23030
共有 52 个文件被更改,包括 8381 次插入250 次删除
  1. 1 1
      ywt-platform-outpatient-common/src/main/java/com/ywt/outpatient/core/utils/BizUtil.java
  2. 71 0
      ywt-platform-outpatient-common/src/main/java/com/ywt/outpatient/core/utils/IdCardUtil.java
  3. 18 0
      ywt-platform-outpatient-common/src/main/java/com/ywt/outpatient/core/utils/JsonUtil.java
  4. 49 0
      ywt-platform-outpatient-rpc/src/main/java/com/ywt/outpatient/rpc/mq/KafkaMsgListener.java
  5. 389 0
      ywt-platform-outpatient-rpc/src/main/java/com/ywt/outpatient/rpc/provider/MriProvider.java
  6. 738 0
      ywt-platform-outpatient-rpc/src/main/java/com/ywt/outpatient/rpc/provider/TaiheOutpatientProvider.java
  7. 2744 0
      ywt-platform-outpatient-rpc/src/main/java/com/ywt/outpatient/rpc/provider/TaiheRegisterProvider.java
  8. 4 0
      ywt-platform-outpatient-sdk/pom.xml
  9. 4 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/DoctorHisCodeRepository.java
  10. 18 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/MedicalCardRepository.java
  11. 347 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/MriScreening.java
  12. 238 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/MriScreeningQuestionOptions.java
  13. 10 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/MriScreeningQuestionOptionsRepository.java
  14. 8 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/MriScreeningRepository.java
  15. 225 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/MriSubscribe.java
  16. 21 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/MriSubscribeRepository.java
  17. 7 6
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/OfflineConsultation.java
  18. 11 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/OrderPaymentRepository.java
  19. 424 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/Orders.java
  20. 13 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/OrdersRepository.java
  21. 238 172
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/OutpatientOrder.java
  22. 265 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/OutpatientOrderDetail.java
  23. 15 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/OutpatientOrderDetailRepository.java
  24. 29 1
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/OutpatientOrderRepository.java
  25. 397 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/RegisterRecord.java
  26. 13 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/RegisterRecordRepository.java
  27. 107 70
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/RegisteredOrder.java
  28. 24 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/RegisteredOrderRepository.java
  29. 3 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/UserRepository.java
  30. 26 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/HisMedCardConfig.java
  31. 35 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/MriBookConfig.java
  32. 53 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/OutpatientConfig.java
  33. 53 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/PatientInfo.java
  34. 37 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/Question.java
  35. 73 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/QuestionOption.java
  36. 46 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/ScreeningTable.java
  37. 3 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/enums/ConfigTypeEnum.java
  38. 57 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/enums/Gender.java
  39. 9 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/enums/RegisteredTypeEnum.java
  40. 140 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/Constants.java
  41. 5 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/IdGenerator.java
  42. 63 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/VerifyCreateRegisteredResult.java
  43. 60 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/VerifyRegisterWithoutMedicalCardResult.java
  44. 187 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/common/ConfigProvider.java
  45. 116 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/common/MessageModel.java
  46. 182 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/common/NfYwtWeChatMsgService.java
  47. 4 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/common/ServiceResult.java
  48. 347 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/common/TaiheWeChatMsgService.java
  49. 72 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/common/WeChatMsgProvider.java
  50. 113 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/handler/RestCallerApiProvider.java
  51. 35 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/handler/RestTemplateConfig.java
  52. 234 0
      ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/handler/RestTemplateHandler.java

+ 1 - 1
ywt-platform-outpatient-common/src/main/java/com/ywt/outpatient/core/utils/BizUtil.java

@@ -26,7 +26,7 @@ import java.util.regex.Pattern;
 @Component
 public final class BizUtil {
 
-    private static String payCode4NfyybyfyTest;
+    public static String payCode4NfyybyfyTest;
 
     @Value("${test.paycode4nfyybyfy:}")
     public void setPayCode4NfyybyfyTest(String pc) {

+ 71 - 0
ywt-platform-outpatient-common/src/main/java/com/ywt/outpatient/core/utils/IdCardUtil.java

@@ -1,5 +1,7 @@
 package com.ywt.outpatient.core.utils;
 
+import com.ywt.biz.common.constant.YwtCommonRespCode;
+import com.ywt.biz.common.exception.YwtCommonException;
 import com.ywt.biz.common.util.Checker;
 import com.ywt.biz.common.util.DateUtil;
 import com.ywt.biz.common.util.StringHelper;
@@ -511,4 +513,73 @@ public final class IdCardUtil {
 
         return digit % 2 == 0 ? 2 : 1;
     }
+
+    /**
+     * 港澳台身份证,通过身份证获取性别
+     *
+     * @param idCardNo 港澳台身份证号
+     * @return 1-男,2-女,0-未知
+     */
+    public static int getSexIntWithGAT(String idCardNo) {
+        if (!Checker.isNone(idCardNo) && idCardNo.trim().length() > 2) {
+            int len = idCardNo.length();
+            char ch = idCardNo.charAt(len - 2);
+            int digit = Integer.parseInt(String.valueOf(ch));
+
+            return digit % 2 == 0 ? 2 : 1;
+        }
+        return 0;
+    }
+
+    /**
+     * 校验是否为合法的大陆身份证号码
+     *
+     * @param idCardNo 身份证
+     * @return 是否合法
+     */
+    public static boolean verifyMainlandIdCard(String idCardNo) {
+        if (StringHelper.isNullOrWhiteSpace(idCardNo)) {
+            return false;
+        }
+
+        int len = idCardNo.length();
+
+        if (len != 15 && len != 18) {
+            return false;
+        }
+
+        if (!isIdCardNoFormat(idCardNo)) {
+            return false;
+        }
+
+        if (len == 18) {
+            String checkCode = String.valueOf(calculateCheckCode(idCardNo.substring(0, len - 1)));
+            String c = String.valueOf(idCardNo.charAt(len - 1));
+
+            if (!checkCode.toUpperCase().equals(c.toUpperCase())) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+    /**
+     * 根据身份证和出生日期计算年龄,支持大陆身份证和港澳台身份证。
+     * 优先判断是否大陆身份证,如果是,则从身份证里获取出生日期再计算年龄;如果无身份证或港澳台身份证,则从传入的出生日期计算年龄
+     * @param idNo 身份证号码
+     * @param birthday 出生日期
+     * @return 年龄
+     * @throws YwtCommonException 非合法大陆身份证,或港澳台身份证但无出生日期,则抛出异常
+     */
+    public static int calcAgeByIdNoAndBirthday(String idNo, String birthday) throws YwtCommonException {
+        if (!Checker.isNone(idNo) && IdCardUtil.verifyMainlandIdCard(idNo)) {
+            return IdCardUtil.getCurrentAge(idNo);
+        } else {
+            // 如果身份证号为空或者非大陆身份证,则根据his系统录入的出生年月日
+            int curAge = IdCardUtil.getCurrentAgeByBirthday(birthday);
+            if (curAge < 0) throw new YwtCommonException(YwtCommonRespCode.P_ERR, "当前诊疗卡未绑定出生日期信息,请完善");
+            return curAge;
+        }
+    }
+
 }

+ 18 - 0
ywt-platform-outpatient-common/src/main/java/com/ywt/outpatient/core/utils/JsonUtil.java

@@ -0,0 +1,18 @@
+package com.ywt.outpatient.core.utils;
+
+import com.google.gson.Gson;
+
+public final class JsonUtil {
+    private JsonUtil() {
+    }
+
+    private static Gson gson = new Gson();
+
+    public static String toJson(Object obj){
+        return gson.toJson(obj);
+    }
+
+    public static  <T> T fromJson(String json, Class<T> clazz){
+        return gson.fromJson(json, clazz);
+    }
+}

+ 49 - 0
ywt-platform-outpatient-rpc/src/main/java/com/ywt/outpatient/rpc/mq/KafkaMsgListener.java

@@ -5,9 +5,11 @@ import com.alibaba.fastjson2.JSONObject;
 import com.ywt.biz.common.util.Checker;
 import com.ywt.gapi.nat.PayCallbackRequest;
 import com.ywt.gapi.nat.RefundNatOrderCallbackRequest;
+import com.ywt.gapi.taihe.register.RefundCallbackRequest;
 import com.ywt.gapi.third.cloudfilm.RefundCheckResultOrderCallbackRequest;
 import com.ywt.outpatient.rpc.provider.CloudfilmProvider;
 import com.ywt.outpatient.rpc.provider.NatProvider;
+import com.ywt.outpatient.rpc.provider.TaiheRegisterProvider;
 import org.apache.kafka.clients.consumer.ConsumerRecord;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -34,6 +36,8 @@ public class KafkaMsgListener {
 
     @Autowired
     private CloudfilmProvider cloudfilmProvider;
+    @Autowired
+    private TaiheRegisterProvider taiheRegisterProvider;
 
     @KafkaListener(topics = "_com.ywt.gapi.nat.NatService_refundNatOrderCallback", groupId = GROUP_NAME)
     public void refundNatOrderCallback(ConsumerRecord<String, String> record, Acknowledgment ack) {
@@ -114,4 +118,49 @@ public class KafkaMsgListener {
         }
         ack.acknowledge();
     }
+
+    @KafkaListener(topics = "_com.ywt.gapi.taihe.register.TaiheRegisterService_refundCallback", groupId = GROUP_NAME)
+    public void refundCallback(ConsumerRecord<String, String> record, Acknowledgment ack) {
+        logger.info("KafkaMsgListener#refundCallback(topic={}, partition={}, value={}): 开始消费", record.topic(), record.partition(), record.value());
+        try {
+            boolean isValid = JSON.isValid(record.value());
+            if (isValid) {
+                JSONObject jsonObject = JSONObject.parseObject(record.value());
+                taiheRegisterProvider.refundCallback(RefundCallbackRequest.newBuilder()
+                        .setRefundStatus(Checker.getIntegerValue(jsonObject.getIntValue("refundStatus")))
+                        .setRefundNo(Checker.getStringValue(jsonObject.getString("refundNo")))
+                        .build());
+                logger.info("KafkaMsgListener#refundCallback(topic={}, partition={}, value={}): 消费完成", record.topic(), record.partition(), record.value());
+            }
+        } catch (Exception e) {
+            logger.error("KafkaMsgListener#refundCallback(topic={}, partition={}, value={}):\n {}", record.topic(), record.partition(), record.value(), e.getMessage(), e);
+        }
+        ack.acknowledge();
+    }
+
+
+    @KafkaListener(topics = "_com.ywt.gapi.taihe.register.TaiheRegisterService_payCallback", groupId = GROUP_NAME)
+    public void taiheRegisterServicePayCallback(ConsumerRecord<String, String> record, Acknowledgment ack) {
+        logger.info("KafkaMsgListener#TaiheRegisterService#payCallback(topic={}, partition={}, value={}): 开始消费", record.topic(), record.partition(), record.value());
+        try {
+            boolean isValid = JSON.isValid(record.value());
+            if (isValid) {
+                JSONObject jsonObject = JSONObject.parseObject(record.value());
+                taiheRegisterProvider.payCallback(com.ywt.gapi.taihe.register.PayCallbackRequest.newBuilder()
+                        .setPaymentNo(Checker.getStringValue(jsonObject.getString("paymentNo")))
+                        .setPaymentChannel(Checker.getIntegerValue(jsonObject.getIntValue("paymentChannel")))
+                        .setBizId(Checker.getIntegerValue(jsonObject.getIntValue("bizId")))
+                        .setOrderId(Checker.getIntegerValue(jsonObject.getIntValue("orderId")))
+                        .setTerminal(Checker.getIntegerValue(jsonObject.getIntValue("terminal")))
+                        .setOrderNo(Checker.getStringValue(jsonObject.getString("orderNo")))
+                        .setWxTransactionId(Checker.getStringValue(jsonObject.getString("wxTransactionId")))
+                        .setPayFinishDate(Checker.getLongValue(jsonObject.getLongValue("payFinishDate")))
+                        .build());
+                logger.info("KafkaMsgListener#TaiheRegisterService#payCallback(topic={}, partition={}, value={}): 消费完成", record.topic(), record.partition(), record.value());
+            }
+        } catch (Exception e) {
+            logger.error("KafkaMsgListener#TaiheRegisterService#payCallback(topic={}, partition={}, value={}):\n {}", record.topic(), record.partition(), record.value(), e.getMessage(), e);
+        }
+        ack.acknowledge();
+    }
 }

+ 389 - 0
ywt-platform-outpatient-rpc/src/main/java/com/ywt/outpatient/rpc/provider/MriProvider.java

@@ -0,0 +1,389 @@
+package com.ywt.outpatient.rpc.provider;
+
+
+import com.ywt.biz.common.constant.YwtCommonRespCode;
+import com.ywt.biz.common.exception.YwtCommonException;
+import com.ywt.biz.common.util.Checker;
+import com.ywt.biz.common.util.DateUtil;
+import com.ywt.biz.common.util.serializers.JsonSerializer;
+import com.ywt.gapi.ResultCode;
+import com.ywt.gapi.taihe.biz.*;
+import com.ywt.outpatient.domain.entity.center.*;
+import com.ywt.outpatient.service.rpc.common.ConfigProvider;
+import com.ywt.outpatient.service.rpc.common.TaiheWeChatMsgService;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.time.LocalDate;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * @author Walker
+ * Created on 2020/7/13
+ */
+@DubboService
+public class MriProvider extends DubboTaiheBizServiceTriple.TaiheBizServiceImplBase {
+    private final Logger logger = LoggerFactory.getLogger(MriProvider.class);
+
+    @Autowired
+    private MriSubscribeRepository mriSubscribeRepository;
+
+    @Autowired
+    private MriScreeningRepository mriScreeningRepository;
+
+    @Autowired
+    private MriScreeningQuestionOptionsRepository mriScreeningQuestionOptionsRepository;
+
+    @Autowired
+    private ConfigProvider configProvider;
+
+    @Autowired
+    private TaiheWeChatMsgService taiheWeChatMsgService;
+
+    public static final int LEVEL_0 = 0;
+    public static final int LEVEL_1 = 1;
+    public static final int LEVEL_2 = 2;
+    public static final String BIRTHDAY_FORMAT = "yyyy-MM-dd";
+    public static final String REPLACEMENT_INPUT = "${input}";
+
+    @Override
+    public MriBaseResponse mriBooking(MriBookingRequest request) {
+        int userId = request.getUserId();
+        String name = request.getName();
+        int sex = request.getSex();
+        String mobile = request.getMobile();
+        String date = request.getDate();
+        MriBaseResponse.Builder builder = MriBaseResponse.newBuilder();
+        try {
+            Date bookDate = validateBookDate(date);
+            if (userId <= 0) throw new YwtCommonException(YwtCommonRespCode.P_ERR, "用户 id 不正确");
+            // 一名患者,一个日期,只能预约一个号,以“手机号”来判断是一个患者。当患者重复预约时,点击提交,提示“患者已预约,请勿重复预约”
+            if (checkHasBooked(mobile, bookDate)) throw new YwtCommonException(YwtCommonRespCode.P_ERR, "患者已预约,请勿重复预约");
+            // 当患者被后台标志 N 次以上(包含 N 次)预约不就诊的,拉入黑名单,患者点击提交时,提示“用户过去 N 次预约未就诊,已被拉入黑名单”。
+            if (checkIfInBlackList(mobile)) throw new YwtCommonException(YwtCommonRespCode.P_ERR, String.format("用户过去 %d 次预约未就诊,已被拉入黑名单",
+                    configProvider.getMriBlackListLimitation()));
+            // 每天最多只有 N 个号源
+            // TODO: 并发控制
+            if (checkIfFullyBooked(bookDate)) throw new YwtCommonException(YwtCommonRespCode.P_ERR, "当前选择的时间已约满,请更换时间重试");
+            // 可以预约,插入数据
+            MriSubscribe subscribe = new MriSubscribe();
+            subscribe.setCreateTime(new Date());
+            subscribe.setUpdateTime(new Date());
+            subscribe.setDeleted(0);
+            subscribe.setPatientMobile(mobile);
+            subscribe.setPatientName(name);
+            subscribe.setSex(sex);
+            subscribe.setUserId(userId);
+            subscribe.setSubscribeTime(bookDate);
+            subscribe.setStatus(0);
+            mriSubscribeRepository.save(subscribe);
+            // 预约成功的患者,对应的号源减1,并推送太和分院公众号微信模板消息提醒
+            taiheWeChatMsgService.sendMsgForMriBooking(userId, name, mobile, date);
+            builder.setCode(ResultCode.SUCCEED_VALUE).setInfo("操作成功");
+            return builder.build();
+        } catch (YwtCommonException e) {
+            builder.setCode(ResultCode.PARAMETER_ERROR_VALUE).setInfo(e.getMessage());
+            return builder.build();
+        } catch (Exception e) {
+            logger.error("MriService#mriBooking(request={}):\n {}", request, e.getMessage(), e);
+            return builder.setCode(ResultCode.PARAMETER_ERROR_VALUE).setInfo(e.getMessage()).build();
+        }
+    }
+
+    private Date validateBookDate(String date) throws YwtCommonException {
+        Date bookDate = DateUtil.stringToDate(date, BIRTHDAY_FORMAT);
+        if (bookDate == null) throw new YwtCommonException(YwtCommonRespCode.P_ERR, "日期格式不正确");
+        // 只能预约未来 N 天的号(当天不能预约)
+        LocalDate bookLocalDate = DateUtil.convertToLocalDate(bookDate);
+        LocalDate today = LocalDate.now();
+        LocalDate maxDate = today.plusDays(configProvider.getMriMaxBookDay());
+        if (!bookLocalDate.isAfter(today) || bookLocalDate.isAfter(maxDate))
+            throw new YwtCommonException(YwtCommonRespCode.P_ERR, String.format("只能预约未来 %d 天的号", configProvider.getMriMaxBookDay()));
+        return bookDate;
+    }
+
+    private boolean checkHasBooked(String mobile, Date date) {
+        return mriSubscribeRepository.findFirstByPatientMobileAndSubscribeTime(mobile, date) != null;
+    }
+
+    private boolean checkIfInBlackList(String mobile) {
+        return mriSubscribeRepository.findByPatientMobileForBreakPromise(mobile).size() >= configProvider.getMriBlackListLimitation();
+    }
+
+    private boolean checkIfFullyBooked(Date date) {
+        return mriSubscribeRepository.findBySubscribeTime(date).size() >= configProvider.getMriMaxBookNum();
+    }
+
+    @Override
+    public GetScreeningTableResponse getScreeningTable(GetScreeningTableRequest request) {
+        int userId = request.getUserId();
+        GetScreeningTableResponse.Builder builder = GetScreeningTableResponse.newBuilder();
+        try {
+            ScreeningTable table = getScreeningTableByUserId(userId);
+            builder.setCode(ResultCode.SUCCEED_VALUE)
+                    .setMsg("操作成功")
+                    .setScreeningTable(table);
+            return builder.build();
+        } catch (Exception e) {
+            logger.error("MriService#getScreeningTable(request={}):\n {}", request, e.getMessage(), e);
+            return builder.setCode(ResultCode.APP_ERROR_VALUE)
+                    .setMsg(e.getMessage())
+                    .build();
+        }
+    }
+
+    private String getCheckedSummaryByCategory(List<Question> list, String category) {
+        List<Question> filteredQuestions = list.stream()
+                .filter(question -> category.equals(question.getCategory()))
+                .collect(Collectors.toList());
+        StringBuilder sb = new StringBuilder();
+        for (Question filteredQuestion : filteredQuestions) {
+            List<QuestionOption> checkedOptions = filteredQuestion.getOptionsList()
+                    .stream()
+                    .filter(QuestionOption::getValue1)
+                    .collect(Collectors.toList());
+            if (!checkedOptions.isEmpty()) {
+                sb.append(filteredQuestion.getQuestionId())
+                        .append("、")
+                        .append(getCheckedString(checkedOptions))
+                        .append("\n");
+            }
+        }
+        return sb.toString();
+    }
+
+    private String getCheckedString(List<QuestionOption> list) {
+        StringBuilder sb = new StringBuilder();
+        for (QuestionOption option : list) {
+            if (option.getValue1()) {
+                String optName = option.getName();
+                optName = optName.replaceFirst(Pattern.quote(REPLACEMENT_INPUT), Checker.getStringValue(option.getValue2()));
+                optName = optName.replaceFirst(Pattern.quote(REPLACEMENT_INPUT), Checker.getStringValue(option.getValue3()));
+                sb.append(optName).append(" ");
+                List<QuestionOption> childrenList = option.getChildrenList();
+                if (childrenList != null && !childrenList.isEmpty()) {
+                    String childrenString = getCheckedString(childrenList);
+                    sb.append(childrenString).append(" ");
+                }
+            }
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public SubmitScreeningTableResponse submitScreeningTable(SubmitScreeningTableRequest request) {
+        int userId = request.getUserId();
+        ScreeningTable table = request.getTable();
+        String submitContent = request.getSubmitContent();
+        PatientInfo patientInfo = table.getPatientInfo();
+        SubmitScreeningTableResponse.Builder builder = SubmitScreeningTableResponse.newBuilder();
+        try {
+            int tableId = table.getTableId();
+            MriScreening mriScreening;
+            if (tableId > 0) {
+                // 更新筛查表
+                mriScreening = mriScreeningRepository.findById(tableId).orElse(null);
+                if (mriScreening == null) throw new YwtCommonException(YwtCommonRespCode.P_ERR, String.format("记录 id 不存在:%d", tableId));
+            } else {
+                // 插入新的记录
+                mriScreening = new MriScreening();
+                mriScreening.setDeleted(0);
+                mriScreening.setCreateTime(new Date());
+            }
+            if (patientInfo != null) {
+                mriScreening.setPatientName(patientInfo.getPatientName());
+                mriScreening.setSex(patientInfo.getSex());
+                Date d = DateUtil.stringToDate(patientInfo.getBirthday(), BIRTHDAY_FORMAT);
+                if (d == null) throw new YwtCommonException(YwtCommonRespCode.P_ERR, "出生年月格式不正确!");
+                mriScreening.setBirthday(d);
+                mriScreening.setPatientMobile(patientInfo.getPatientMobile());
+                mriScreening.setAddress(patientInfo.getAddress());
+            }
+            List<Question> questions = table.getQuestionsList();
+            String baseDiseaseHistoryMg = getCheckedSummaryByCategory(questions, "基础病史");
+            mriScreening.setBaseDiseaseHistoryMg(baseDiseaseHistoryMg);
+            String geneticDiseaseHistoryMg = getCheckedSummaryByCategory(questions, "遗传病史");
+            mriScreening.setGeneticDiseaseHistoryMg(geneticDiseaseHistoryMg);
+            String livingHabitsMg = getCheckedSummaryByCategory(questions, "生活习惯");
+            mriScreening.setLivingHabitsMg(livingHabitsMg);
+            String clinicalSymptomsMg = getCheckedSummaryByCategory(questions, "临床症状");
+            mriScreening.setClinicalSymptomsMg(clinicalSymptomsMg);
+            String rmiResult = getCheckedSummaryByCategory(questions, "磁共振检查结果");
+            mriScreening.setRmiResult(rmiResult);
+
+            mriScreening.setUpdateTime(new Date());
+            mriScreening.setUserId(userId);
+            mriScreening.setSubmitContent(submitContent);
+            mriScreening.setCompleted(request.getCompleted());
+            MriScreening result = mriScreeningRepository.save(mriScreening);
+            builder.setCode(ResultCode.SUCCEED_VALUE).setMsg("操作成功").setTableId(result.getId());
+            return builder.build();
+        } catch (YwtCommonException e) {
+            builder.setCode(ResultCode.PARAMETER_ERROR_VALUE).setMsg(e.getMessage());
+            return builder.build();
+        } catch (Exception e) {
+            logger.error("MriService#submitScreeningTable(request={}):\n {}", request, e.getMessage(), e);
+            return builder.setCode(ResultCode.APP_ERROR_VALUE)
+                    .setMsg(e.getMessage())
+                    .build();
+        }
+    }
+
+    /**
+     * 返回所有问题选项,空值
+     *
+     * @return question list
+     */
+    private List<Question> getAllQuestions() {
+        List<MriScreeningQuestionOptions> optionList = mriScreeningQuestionOptionsRepository.findAllByDeletedOrderByWeightAsc(0);
+        Map<Integer, List<MriScreeningQuestionOptions>> questionsMap = optionList.stream()
+                .collect(Collectors.groupingBy(MriScreeningQuestionOptions::getQuestionId));
+        List<Question> questions = new LinkedList<>();
+        for (Map.Entry<Integer, List<MriScreeningQuestionOptions>> qIdListEntry : questionsMap.entrySet()) {
+            int questionId = qIdListEntry.getKey();
+            List<MriScreeningQuestionOptions> options = qIdListEntry.getValue();
+            String category = options.isEmpty() ? "" : options.get(0).getCategoryName();
+            List<com.ywt.outpatient.domain.models.QuestionOption> questionOptions = getNestedOptionList(options);
+            Question question = Question.newBuilder()
+                    .setQuestionId(questionId)
+                    .setCategory(category)
+                    .addAllOptions(convertModel2GrpcDefObj(questionOptions))
+                    .build();
+            questions.add(question);
+        }
+        return questions;
+    }
+
+    private List<QuestionOption> convertModel2GrpcDefObj(List<com.ywt.outpatient.domain.models.QuestionOption> list) {
+        return list.stream()
+                .map(questionOption -> {
+                    List<QuestionOption> options = new LinkedList<>();
+                    List<com.ywt.outpatient.domain.models.QuestionOption> children = questionOption.getChildren();
+                    if (children != null && !children.isEmpty()) {
+                        options = convertModel2GrpcDefObj(children);
+                    }
+                    return QuestionOption.newBuilder()
+                            .setId(Checker.getIntegerValue(questionOption.getId()))
+                            .setName(Checker.getStringValue(questionOption.getName()))
+                            .setValue1(Checker.getBooleanValue(questionOption.getValue1()))
+                            .setValue2(Checker.getStringValue(questionOption.getValue2()))
+                            .setValue3(Checker.getStringValue(questionOption.getValue3()))
+                            .addAllChildren(options)
+                            .build();
+                })
+                .collect(Collectors.toList());
+    }
+
+    private List<com.ywt.outpatient.domain.models.QuestionOption> getNestedOptionList(List<MriScreeningQuestionOptions> list) {
+        List<com.ywt.outpatient.domain.models.QuestionOption> lv0 = getQuestionOptionsByLevel(list, LEVEL_0);
+        List<com.ywt.outpatient.domain.models.QuestionOption> lv1 = getQuestionOptionsByLevel(list, LEVEL_1);
+        List<com.ywt.outpatient.domain.models.QuestionOption> lv2 = getQuestionOptionsByLevel(list, LEVEL_2);
+        List<com.ywt.outpatient.domain.models.QuestionOption> lst1 = mergeChildrenOptions(lv1, lv2);
+        return mergeChildrenOptions(lv0, lst1);
+    }
+
+    private List<com.ywt.outpatient.domain.models.QuestionOption> mergeChildrenOptions(List<com.ywt.outpatient.domain.models.QuestionOption> parentList, List<com.ywt.outpatient.domain.models.QuestionOption> childrenList) {
+        if (!childrenList.isEmpty()) {
+            for (com.ywt.outpatient.domain.models.QuestionOption opParent : parentList) {
+                List<com.ywt.outpatient.domain.models.QuestionOption> children = new LinkedList<>();
+                for (com.ywt.outpatient.domain.models.QuestionOption opChild : childrenList) {
+                    if (opParent.getId() == opChild.getParentId()) {
+                        children.add(opChild);
+                    }
+                }
+                opParent.setChildren(children);
+            }
+        }
+        return parentList;
+    }
+
+    private List<com.ywt.outpatient.domain.models.QuestionOption> getQuestionOptionsByLevel(List<MriScreeningQuestionOptions> list, int level) {
+        return list.stream()
+                .filter(mriScreeningQuestionOptions -> mriScreeningQuestionOptions.getLevel() == level)
+                .map(mriScreeningQuestionOptions -> {
+                    com.ywt.outpatient.domain.models.QuestionOption qo = new com.ywt.outpatient.domain.models.QuestionOption();
+                    qo.setId(mriScreeningQuestionOptions.getId());
+                    qo.setName(mriScreeningQuestionOptions.getName());
+                    qo.setParentId(mriScreeningQuestionOptions.getParentId());
+                    return qo;
+                })
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * 根据用户 id 获取筛查表内容返回
+     *
+     * @param userId 用户 id
+     * @return table
+     */
+    private ScreeningTable getScreeningTableByUserId(int userId) {
+        // 获取当前用户最后一次提交的答案
+        MriScreening mriScreening = mriScreeningRepository.findFirstByUserIdOrderByUpdateTimeDesc(userId);
+        List<Question> questions = new LinkedList<>();
+        PatientInfo.Builder patientInfoBuilder = PatientInfo.newBuilder();
+        int tableId = 0;
+        if (mriScreening == null) {
+            // 没有提交过答案,返回空白问题列表
+            questions = getAllQuestions();
+        } else {
+            // 已提交答案,检查是否完成所有问题
+            boolean completed = Checker.getBooleanValue(mriScreening.getCompleted());
+            if (completed) {
+                // 返回新的问题列表
+                questions = getAllQuestions();
+            } else {
+                // 返回上次提交的内容
+                String submitContent = mriScreening.getSubmitContent();
+                com.ywt.outpatient.domain.models.ScreeningTable table = JsonSerializer.from(submitContent, com.ywt.outpatient.domain.models.ScreeningTable.class);
+                if (table != null && table.getQuestions() != null) {
+                    questions = table.getQuestions().stream()
+                            .map(question -> Question.newBuilder()
+                                    .setQuestionId(question.getQuestionId())
+                                    .setCategory(question.getCategory())
+                                    .addAllOptions(convertModel2GrpcDefObj(question.getOptions()))
+                                    .build())
+                            .collect(Collectors.toList());
+                }
+                patientInfoBuilder.setPatientName(mriScreening.getPatientName());
+                patientInfoBuilder.setSex(mriScreening.getSex());
+                patientInfoBuilder.setBirthday(DateUtil.convertToString(mriScreening.getBirthday(), BIRTHDAY_FORMAT));
+                patientInfoBuilder.setPatientMobile(mriScreening.getPatientMobile());
+                patientInfoBuilder.setAddress(mriScreening.getAddress());
+                tableId = mriScreening.getId();
+            }
+        }
+        return ScreeningTable.newBuilder()
+                .setPatientInfo(patientInfoBuilder.build())
+                .addAllQuestions(questions)
+                .setTableId(tableId)
+                .build();
+    }
+
+    @Override
+    public GetAvailableBookNumResponse getAvailableBookNum(GetAvailableBookNumRequest request) {
+        String date = request.getDate();
+        GetAvailableBookNumResponse.Builder builder = GetAvailableBookNumResponse.newBuilder();
+        try {
+            Date bookDate = validateBookDate(date);
+            int leftBookNum = configProvider.getMriMaxBookNum() - mriSubscribeRepository.findBySubscribeTime(bookDate).size();
+            if (leftBookNum < 0) leftBookNum = 0;
+            builder.setCode(ResultCode.SUCCEED_VALUE).setMsg("OK").setCount(leftBookNum);
+            return builder.build();
+        } catch (YwtCommonException e) {
+            builder.setCode(ResultCode.PARAMETER_ERROR_VALUE).setMsg(e.getMessage());
+            return builder.build();
+        } catch (Exception e) {
+            logger.error("MriService#getAvailableBookNum(request={}):\n {}", request, e.getMessage(), e);
+            return builder.setCode(ResultCode.APP_ERROR_VALUE)
+                    .setMsg(e.getMessage())
+                    .build();
+        }
+    }
+}

+ 738 - 0
ywt-platform-outpatient-rpc/src/main/java/com/ywt/outpatient/rpc/provider/TaiheOutpatientProvider.java

@@ -0,0 +1,738 @@
+package com.ywt.outpatient.rpc.provider;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.ywt.biz.common.enums.PaymentStatusEnum;
+import com.ywt.biz.common.enums.RefundStatusEnum;
+import com.ywt.biz.common.util.Checker;
+import com.ywt.biz.common.util.DateUtil;
+import com.ywt.biz.common.util.StringHelper;
+import com.ywt.biz.common.util.serializers.JsonSerializer;
+import com.ywt.gapi.ResultCode;
+import com.ywt.gapi.doctor.DoctorHisCode;
+import com.ywt.gapi.doctor.DoctorService;
+import com.ywt.gapi.doctor.GetDoctorHisCodeRequest;
+import com.ywt.gapi.doctor.GetDoctorHisCodeResponse;
+import com.ywt.gapi.taihe.outpaitent.*;
+import com.ywt.gapi.third.taihe.PaymentItem;
+import com.ywt.gapi.third.taihe.TaiheService;
+import com.ywt.outpatient.core.PagedList;
+import com.ywt.outpatient.core.SqlHelper;
+import com.ywt.outpatient.core.utils.MoneyUtil;
+import com.ywt.outpatient.domain.entity.center.MedicalCardRepository;
+import com.ywt.outpatient.domain.entity.center.OutpatientOrderDetailRepository;
+import com.ywt.outpatient.domain.entity.center.OutpatientOrderRepository;
+import com.ywt.outpatient.domain.models.OutpatientConfig;
+import com.ywt.outpatient.domain.models.enums.OutpatientStatusEnum;
+import com.ywt.outpatient.service.rpc.Constants;
+import com.ywt.outpatient.service.rpc.IdGenerator;
+import com.ywt.outpatient.service.rpc.common.ConfigProvider;
+import com.ywt.outpatient.domain.entity.center.MedicalCard;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+
+/**
+ * 太和医院门诊缴费业务类
+ *
+ * @author johnson lin
+ * @date 2019-05-29 3:31 PM
+ */
+@DubboService
+public class TaiheOutpatientProvider extends DubboTaiheOutpatientServiceTriple.TaiheOutpatientServiceImplBase{
+    private static Logger logger = LoggerFactory.getLogger(TaiheOutpatientProvider.class);
+
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
+
+    @Autowired
+    private SqlHelper sqlHelper;
+
+    @Autowired
+    private IdGenerator idGenerator;
+
+    @Autowired
+    private OutpatientOrderRepository outpatientOrderRepository;
+
+    @Autowired
+    private OutpatientOrderDetailRepository outpatientOrderDetailRepository;
+
+    @DubboReference
+    private DoctorService doctorServiceBlockingStub;
+
+    @DubboReference
+    private TaiheService taiheServiceBlockingStub;
+
+    @Autowired
+    private MedicalCardRepository medicalCardRepository;
+
+    @Autowired
+    private ConfigProvider configProvider;
+
+
+    /**
+     * 获取门诊缴费单详情
+     * 对于未缴费的门诊缴费单,会同步线下缴费状态和最新的处方费用
+     *
+     * @param request          {@link GetOutpatientDetailRequest}
+     */
+    @Override
+    public GetOutpatientDetailResponse getOutpatientDetail(GetOutpatientDetailRequest request) {
+        GetOutpatientDetailResponse.Builder builder = GetOutpatientDetailResponse.newBuilder();
+        try {
+            com.ywt.outpatient.domain.entity.center.OutpatientOrder outpatientOrder = outpatientOrderRepository.getFirstByOrderIdAndDeletedFalse(request.getOrderId());
+            if (outpatientOrder == null) {
+                builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("门诊缴费单不存在");
+                return builder.build();
+            }
+
+            //同步缴费状态、缴费金额
+            syncOutpatientOrderInfo(outpatientOrder);
+
+            OutpatientOrder gOutpatientOrder = OutpatientOrder.newBuilder()
+                    .setOrderId(Checker.getIntegerValue(outpatientOrder.getOrderId()))
+                    .setOrderNo(Checker.getStringValue(outpatientOrder.getOrderNo()))
+                    .setCreateTime(DateUtil.convertToTimestamp(outpatientOrder.getCreateTime()))
+                    .setHospitalId(outpatientOrder.getHospitalId())
+                    .setHospitalName(outpatientOrder.getHospitalName())
+                    .setDeptCode(Checker.getStringValue(outpatientOrder.getDeptCode()))
+                    .setDeptName(Checker.getStringValue(outpatientOrder.getDeptName()))
+                    .setDoctorCode(Checker.getStringValue(outpatientOrder.getDoctorCode()))
+                    .setDoctorName(Checker.getStringValue(outpatientOrder.getDoctorName()))
+                    .setTotal(outpatientOrder.getTotal())
+                    .setReimbursement(outpatientOrder.getReimbursement())
+                    .setIndividual(outpatientOrder.getIndividual())
+                    .setPaymentStatus(outpatientOrder.getPaymentStatus())
+                    .setOutpatientStatus(outpatientOrder.getOutpatientStatus())
+                    .setUserId(outpatientOrder.getUserId())
+                    .setHisPatientId(outpatientOrder.getHisPatientId())
+                    .setPayName(Checker.getStringValue(outpatientOrder.getPayName()))
+                    .setPatientAge(Checker.getIntegerValue(outpatientOrder.getPatientAge()))
+                    .setPatientName(Checker.getStringValue(outpatientOrder.getPatientName()))
+                    .setPatientSex(Checker.getIntegerValue(outpatientOrder.getPatientSex()))
+                    .setPrescriptionDate(DateUtil.convertToTimestamp(outpatientOrder.getPrescriptionDate()))
+                    .setHisOrderNo(outpatientOrder.getHisOrderNo())
+                    .build();
+            builder.setCode(ResultCode.SUCCEED_VALUE).setOrder(gOutpatientOrder).build();
+        } catch (Exception e) {
+            logger.error("getOutpatientDetail({}): {}", request, e.getMessage(), e);
+            builder.setCode(ResultCode.APP_EXCEPTION_VALUE).setMsg(Constants.ERROR_INFO).build();
+        } finally {
+            return builder.build();
+        }
+    }
+
+    /**
+     * 获取门诊缴费单列表
+     *
+     * @param request          {@link GetOutpatientListRequest}
+     */
+    @Override
+    public GetOutpatientListResponse getOutpatientList(GetOutpatientListRequest request) {
+        GetOutpatientListResponse.Builder builder = GetOutpatientListResponse.newBuilder();
+
+        try {
+            if (request.getUserId() <= 0) {
+                builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("invalid userId");
+                return builder.build();
+            }
+
+            final String fields = "*";
+            final String orderBy = "create_time desc";
+            String whereSql = "user_id = ? and payment_status = ? and deleted = 0";
+            Object[] args = new Object[]{request.getUserId(), PaymentStatusEnum.Success.getValue()};
+            int[] argTypes = new int[]{Types.INTEGER, Types.INTEGER};
+
+            List<OutpatientOrder> lst = new LinkedList<>();
+            PagedList<com.ywt.outpatient.domain.entity.center.OutpatientOrder> pagedList = sqlHelper.getPagedList(
+                    request.getPageIndex(), request.getPageSize(), fields, whereSql, orderBy, com.ywt.outpatient.domain.entity.center.OutpatientOrder.class, args, argTypes);
+
+            if (pagedList.getItems() != null) {
+                String selfPay = "0.00元";
+                String insuranceFee = "0.00元";
+                String insuranceFundfee = "0.00元";
+                String insuranceSelfFee = "0.00元";
+                String insuranceOtherFee = "0.00元";
+
+                for (com.ywt.outpatient.domain.entity.center.OutpatientOrder item : pagedList.getItems()) {
+                    String statusName = "已支付";
+                    if (item.getRefundStatus() != null && item.getRefundStatus() == RefundStatusEnum.SUCCESS.getValue()) {
+                        statusName = "已退款";
+                    }
+                    if (!Checker.isNone(item.getInsTxReturnStr())) {
+
+                        JsonNode node = JsonSerializer.readToNode(item.getInsTxReturnStr());
+                        if (node != null) {
+                            String selfPayStr = extracted(node, "cash_fee");
+                            selfPay = MoneyUtil.cent2Yuan(Integer.parseInt(selfPayStr)) + "元";
+                            String insFeeStr = extracted(node, "insurance_fee");
+                            insuranceFee = MoneyUtil.cent2Yuan(Integer.parseInt(insFeeStr)) + "元";
+                            String insuranceFundfeeStr = extracted(node, "insurance_fund_fee");
+                            insuranceFundfee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceFundfeeStr)) + "元";
+                            String insuranceSelfFeeStr = extracted(node, "insurance_self_fee");
+                            insuranceSelfFee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceSelfFeeStr)) + "元";
+                            String insuranceOtherFeeStr = extracted(node, "insurance_other_fee");
+                            insuranceOtherFee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceOtherFeeStr)) + "元";
+                        }
+                    }
+                    String insDetail = "(微信支付:" + insuranceOtherFee + "; 医保个账扣款:" + insuranceSelfFee + "; 医保统筹扣款:" + insuranceFundfee + ")";
+
+                    OutpatientOrder order = OutpatientOrder.newBuilder()
+                            .setOrderId(Checker.getIntegerValue(item.getOrderId()))
+                            .setOrderNo(Checker.getStringValue(item.getOrderNo()))
+                            .setHisOrderNo(Checker.getStringValue(item.getHisOrderNo()))
+                            .setCreateTime(DateUtil.convertToTimestamp(item.getCreateTime()))
+                            .setHospitalId(item.getHospitalId())
+                            .setHospitalName(item.getHospitalName())
+                            .setDeptCode(Checker.getStringValue(item.getDeptCode()))
+                            .setDeptName(Checker.getStringValue(item.getDeptName()))
+                            .setDoctorCode(Checker.getStringValue(item.getDoctorCode()))
+                            .setDoctorName(Checker.getStringValue(item.getDoctorName()))
+                            .setTotal(item.getTotal())
+                            .setReimbursement(item.getReimbursement())
+                            .setIndividual(item.getIndividual())
+                            .setPaymentStatus(item.getPaymentStatus())
+                            .setOutpatientStatus(item.getOutpatientStatus())
+                            .setUserId(item.getUserId())
+                            .setHisPatientId(item.getHisPatientId())
+                            .setPayName(Checker.getStringValue(item.getPayName()))
+                            .setStatusName(statusName)
+                            .setPatientName(Checker.getStringValue(item.getPatientName()))
+                            .setPatientSex(Checker.getIntegerValue(item.getPatientSex()))
+                            .setInvoiceNo(Checker.getStringValue(item.getInvoiceNo()))
+                            .setSelfPay(selfPay)
+                            .setInsurance(insuranceFee)
+                            .setInsDetail(insDetail)
+                            .build();
+                    lst.add(order);
+                }
+            }
+
+            builder.setCode(ResultCode.SUCCEED_VALUE)
+                    .setCount(pagedList.getTotal())
+                    .setTotalPage(pagedList.getTotalPage())
+                    .addAllOrder(lst)
+                    .build();
+        } catch (Exception e) {
+            logger.error("getOutpatientList({}): {}", request, e.getMessage(), e);
+            builder.setCode(ResultCode.APP_EXCEPTION_VALUE).setMsg(Constants.ERROR_INFO);
+        } finally {
+            return builder.build();
+        }
+    }
+
+    private String extracted(JsonNode node, String key) {
+        if (Checker.isNone(node)) {
+            return "0";
+        }
+        JsonNode jn = node.get(key);
+        if (jn != null) {
+            String value = jn.asText();
+            return value;
+        } else {
+            return "0";
+        }
+    }
+
+    /**
+     * 当缴费单未支付成功时,同步缴费单信息(支付状态、缴费金额)
+     *
+     * @param outpatientOrder {@link OutpatientOrder}
+     */
+    private void syncOutpatientOrderInfo(com.ywt.outpatient.domain.entity.center.OutpatientOrder outpatientOrder) {
+        //判断是否已线下缴费
+        if (outpatientOrder.getPaymentStatus() != PaymentStatusEnum.Success.getValue() &&
+                outpatientOrder.getPaymentStatus() != PaymentStatusEnum.Processing.getValue()) {
+            com.ywt.gapi.third.taihe.GetOutpatientListRequest req = com.ywt.gapi.third.taihe.GetOutpatientListRequest.newBuilder()
+                    .setPatientId(outpatientOrder.getHisPatientId())
+                    //类型:1-门诊待缴费记录 2-门诊已缴费记录 3-门诊已退费记录
+                    .setType(1)
+                    .setHospitalId(Checker.getIntegerValue(outpatientOrder.getHospitalId()))
+                    .build();
+            com.ywt.gapi.third.taihe.GetOutpatientListResponse res = taiheServiceBlockingStub.getOutpatientList(req);
+            if (res.getCode() != ResultCode.SUCCEED_VALUE) {
+                throw new RuntimeException("同步缴费状态失败," + res.getMsg());
+            }
+
+            String sql;
+            Object[] args;
+            int[] argTypes;
+
+            List<PaymentItem> items = res.getPaymentList();
+            if (items != null && items.size() > 0 &&
+                    items.stream().anyMatch(p -> p.getHisOrdNum().equals(outpatientOrder.getHisOrderNo()))) {
+                //线下未缴费,同步最新的处方费用
+                PaymentItem paymentItem = items.stream().filter(
+                        p -> p.getHisOrdNum().equals(outpatientOrder.getHisOrderNo()))
+                        .collect(Collectors.toList()).get(0);
+                outpatientOrder.setTotal(paymentItem.getTotalFee());
+                outpatientOrder.setReimbursement(paymentItem.getMedInsFee());
+                outpatientOrder.setIndividual(paymentItem.getSelfFee());
+                outpatientOrderRepository.save(outpatientOrder);
+
+                sql = "update orders set order_amount = ? where id = ?";
+                args = new Object[]{outpatientOrder.getTotal() / 100.0, outpatientOrder.getOrderId()};
+                argTypes = new int[]{Types.DECIMAL, Types.INTEGER};
+                jdbcTemplate.update(sql, args, argTypes);
+            } else {
+                //线下已缴费,更新状态
+                outpatientOrder.setPaymentStatus(PaymentStatusEnum.Success.getValue());
+                outpatientOrder.setOutpatientStatus(OutpatientStatusEnum.PAID.getValue());
+                outpatientOrderRepository.save(outpatientOrder);
+
+                sql = "update orders set payment_status = ? where id = ?";
+                args = new Object[]{PaymentStatusEnum.Success.getValue(), outpatientOrder.getOrderId()};
+                argTypes = new int[]{Types.INTEGER, Types.INTEGER};
+                jdbcTemplate.update(sql, args, argTypes);
+            }
+        }
+    }
+
+    @Override
+    public GetMedicalCardInfoByPatientIdResponse getMedicalCardInfoByPatientId(GetMedicalCardInfoByPatientIdRequest request) {
+        GetMedicalCardInfoByPatientIdResponse.Builder builder = GetMedicalCardInfoByPatientIdResponse.newBuilder();
+        try {
+            String hisPatientId = request.getHisPatientId();
+            int hospitalId = request.getHospitalId() > 0 ? request.getHospitalId() : Constants.TAIHE_HOSPITAL_ID;
+            int userId = request.getUserId();
+            MedicalCard medicalCard = null;
+            StringBuilder where = new StringBuilder("status = 1");
+            if (userId > 0) {
+                where.append(" and user_id = ").append(userId);
+            }
+            if (!StringHelper.isNullOrEmpty(hisPatientId)) {
+                where.append(" and his_patient_id = ").append(hisPatientId);
+            }
+            where.append(" and hospital_id = ").append(hospitalId);
+            String sql = String.format("select * from ywt_center.medical_card where %s limit 1;", where.toString());
+//            System.out.println(sql);
+            try {
+                medicalCard = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(MedicalCard.class));
+            } catch (DataAccessException e) {
+                logger.error("TaiheOutpatientService#getMedicalCardInfoByPatientId(sql = {}):\n {}", sql, e.getMessage(), e);
+            }
+            if (medicalCard == null) {
+                builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("找不到就诊卡信息");
+            } else {
+
+                builder.setCode(ResultCode.SUCCEED_VALUE)
+                        .setMsg("")
+                        .setUserId(Checker.getIntegerValue(medicalCard.getUserId()))
+                        .setHospitalId(Checker.getIntegerValue(medicalCard.getHospitalId()))
+                        .setCardNo(Checker.getStringValue(medicalCard.getCardNo()))
+                        .setCardType(Checker.getStringValue(medicalCard.getCardType()))
+                        .setPatientName(Checker.getStringValue(medicalCard.getPatientName()))
+                        .setMobile(Checker.getStringValue(medicalCard.getMobile()))
+                        .setSex(Checker.getIntegerValue(medicalCard.getSex()))
+                        .setBirthday(Checker.getStringValue(medicalCard.getBirthday()))
+                        .setAddress(Checker.getStringValue(medicalCard.getAddress()))
+                        .setTelephoneNo(Checker.getStringValue(medicalCard.getTelephoneNo()))
+                        .setDocumentId(Checker.getStringValue(medicalCard.getDocumentId()))
+                        .setBalance(Checker.getIntegerValue(medicalCard.getBalance()))
+                        .setIdTypeCode(Checker.getStringValue(medicalCard.getIdTypeCode()))
+                        .setIdTypeDesc(Checker.getStringValue(medicalCard.getIdTypeDesc()))
+                        .setIdNo(Checker.getStringValue(medicalCard.getIdNo()))
+                        .setInsureCardNo(Checker.getStringValue(medicalCard.getInsureCardNo()))
+                        .setAccInfo(Checker.getStringValue(medicalCard.getAccInfo()))
+                        .setPatientType(Checker.getStringValue(medicalCard.getPatientType()))
+                        .setStatus(Checker.getIntegerValue(medicalCard.getStatus()))
+                        .setHisPatientId(Checker.getStringValue(medicalCard.getHisPatientId()))
+                        .setCardId(medicalCard.getId())
+                        .setGuardian(Checker.getStringValue(medicalCard.getGuardian()));
+            }
+        } catch (Exception e) {
+            logger.error("TaiheOutpatientService#getMedicalCardInfoByPatientId(request={}):\n {}", request, e.getMessage(), e);
+        } finally {
+            return builder.build();
+        }
+    }
+
+    @Override
+    public GetOutpatientOrderByHisOrderNoResponse getOutpatientOrderByHisOrderNo(GetOutpatientOrderByHisOrderNoRequest request) {
+        GetOutpatientOrderByHisOrderNoResponse.Builder builder = GetOutpatientOrderByHisOrderNoResponse.newBuilder();
+        try {
+            String hisOrderNo = request.getHisOrderNo();
+            String invoiceNo = request.getInvoiceNo();
+            com.ywt.outpatient.domain.entity.center.OutpatientOrder outpatientOrder = outpatientOrderRepository.getByHisOrderNo(hisOrderNo);
+            if (outpatientOrder == null) {
+                // 找不到订单返回空单号
+                builder.setCode(ResultCode.SUCCEED_VALUE).setMsg("找不到订单信息").setOrderNo("");
+            } else {
+                // 如果发票号已经修改,需要更新数据库
+                String ivcNo = Checker.getStringValue(outpatientOrder.getInvoiceNo());
+                if (!Checker.isNone(invoiceNo) && !ivcNo.equals(invoiceNo)) {
+                    outpatientOrder.setInvoiceNo(invoiceNo);
+                    outpatientOrderRepository.save(outpatientOrder);
+                }
+                builder.setCode(ResultCode.SUCCEED_VALUE)
+                        .setMsg("")
+                        .setHospitalId(Checker.getIntegerValue(outpatientOrder.getHospitalId()))
+                        .setHospitalName(Checker.getStringValue(outpatientOrder.getHospitalName()))
+                        .setDeptName(Checker.getStringValue(outpatientOrder.getDeptName()))
+                        .setDoctorName(Checker.getStringValue(outpatientOrder.getDoctorName()))
+                        .setTotal(Checker.getIntegerValue(outpatientOrder.getTotal()))
+                        .setReimbursement(Checker.getIntegerValue(outpatientOrder.getReimbursement()))
+                        .setIndividual(Checker.getIntegerValue(outpatientOrder.getIndividual()))
+                        .setPaymentStatus(Checker.getIntegerValue(outpatientOrder.getPaymentStatus()))
+                        .setOutpatientStatus(Checker.getIntegerValue(outpatientOrder.getOutpatientStatus()))
+                        .setUserId(Checker.getIntegerValue(outpatientOrder.getUserId()))
+                        .setOrderId(Checker.getIntegerValue(outpatientOrder.getOrderId()))
+                        .setOrderNo(Checker.getStringValue(outpatientOrder.getOrderNo()))
+                        .setHisPatientId(Checker.getStringValue(outpatientOrder.getHisPatientId()))
+                        .setHisClinicCode(Checker.getStringValue(outpatientOrder.getHisClinicCode()))
+                        .setHisOrderNo(Checker.getStringValue(outpatientOrder.getHisOrderNo()))
+                        .setPayUrl(Checker.getStringValue(outpatientOrder.getMedPayUrl()))
+                        .setMedTransId(Checker.getStringValue(outpatientOrder.getMedTransId()))
+                        .setPayAppId(Checker.getStringValue(outpatientOrder.getMedPayAppId()));
+            }
+        } catch (Exception e) {
+            logger.error("TaiheOutpatientService#getOutpatientOrderByHisOrderNo(request={}):\n {}", request, e.getMessage(), e);
+        } finally {
+            return builder.build();
+        }
+    }
+
+    @Override
+    public BaseResult saveOutpatientOrderDetails(SaveOutpatientOrderDetailsRequest request) {
+        BaseResult.Builder builder = BaseResult.newBuilder();
+        try {
+            String hisOrderNo = request.getHisOrderNo();
+            List<OutpatientOrderDetail> details = request.getDetailList();
+            if (!Checker.isNone(details)) {
+                details.forEach(d -> {
+                    // 根据 hisOrderNo & code 判断是否已有记录,没有才插入
+                    int count = outpatientOrderDetailRepository.countByHisOrderNoAndCode(hisOrderNo, Checker.getStringValue(d.getItemCode()));
+                    if (count <= 0) {
+                        com.ywt.outpatient.domain.entity.center.OutpatientOrderDetail detail = new com.ywt.outpatient.domain.entity.center.OutpatientOrderDetail();
+                        detail.setHisOrderNo(Checker.getStringValue(hisOrderNo));
+                        detail.setCreateTime(new Date());
+                        detail.setUpdateTime(new Date());
+                        detail.setDeleted(0);
+                        detail.setId(0);
+                        detail.setName(Checker.getStringValue(d.getItemName()));
+                        detail.setPrice(Checker.getIntegerValue(d.getItemPrice()));
+                        detail.setCode(Checker.getStringValue(d.getItemCode()));
+                        detail.setNumber(Checker.getStringValue(d.getItemNumber()));
+                        detail.setSpec(Checker.getStringValue(d.getItemSpec()));
+                        detail.setUnit(Checker.getStringValue(d.getItemUnit()));
+                        detail.setTotalFee(Checker.getIntegerValue(d.getItemTotalFee()));
+                        outpatientOrderDetailRepository.save(detail);
+                    }
+                });
+            }
+            return builder.build();
+        } catch (Exception e) {
+            logger.error("TaiheOutpatientService#saveOutpatientOrderDetails(request={}):\n {}", request, e.getMessage(), e);
+            return builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg(e.getMessage()).build();
+        }
+    }
+
+    @Override
+    public GetOutpatientOrderDetailResponse getOutpatientOrderDetail(GetOutpatientOrderDetailRequest request) {
+        GetOutpatientOrderDetailResponse.Builder builder = GetOutpatientOrderDetailResponse.newBuilder();
+        try {
+            String hisOrderNo = request.getHisOrderNo();
+            List<com.ywt.outpatient.domain.entity.center.OutpatientOrderDetail> list = outpatientOrderDetailRepository.getByHisOrderNo(hisOrderNo);
+            List<OutpatientOrderDetail> results = new LinkedList<>();
+            com.ywt.outpatient.domain.entity.center.OutpatientOrder outpatientOrder = outpatientOrderRepository.getByHisOrderNo(hisOrderNo);
+            list.forEach(i -> {
+                OutpatientOrderDetail d = OutpatientOrderDetail.newBuilder()
+                        .setItemName(i.getName())
+                        .setItemPrice(i.getPrice())
+                        .setItemCode(i.getCode())
+                        .setItemNumber(i.getNumber())
+                        .setItemSpec(i.getSpec())
+                        .setItemUnit(i.getUnit())
+                        .setItemTotalFee(i.getTotalFee())
+                        .build();
+                results.add(d);
+            });
+            String patientName = "";
+            int patientAge = 0;
+            int patientSex = 0;
+            String invoiceNo = "";
+            String selfPay = "0.00元";
+            String insuranceFee = "0.00元";
+            String insuranceFundfee = "0.00元";
+            String insuranceSelfFee = "0.00元";
+            String insuranceOtherFee = "0.00元";
+            //判断是否使用医保, 0使用了医保, 1纯自费
+            int type = 0;
+            if (outpatientOrder != null) {
+                patientName = Checker.getStringValue(outpatientOrder.getPatientName());
+                patientAge = Checker.getIntegerValue(outpatientOrder.getPatientAge());
+                patientSex = Checker.getIntegerValue(outpatientOrder.getPatientSex());
+                invoiceNo = Checker.getStringValue(outpatientOrder.getInvoiceNo());
+                if (!Checker.isNone(outpatientOrder.getInsTxReturnStr())) {
+
+                    JsonNode node = JsonSerializer.readToNode(outpatientOrder.getInsTxReturnStr());
+                    if (node != null) {
+                        String selfPayStr = extracted(node, "cash_fee");
+                        selfPay = MoneyUtil.cent2Yuan(Integer.parseInt(selfPayStr)) + "元";
+                        String insFeeStr = extracted(node, "insurance_fee");
+                        insuranceFee = MoneyUtil.cent2Yuan(Integer.parseInt(insFeeStr)) + "元";
+                        String insuranceFundfeeStr = extracted(node, "insurance_fund_fee");
+                        insuranceFundfee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceFundfeeStr)) + "元";
+                        String insuranceSelfFeeStr = extracted(node, "insurance_self_fee");
+                        insuranceSelfFee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceSelfFeeStr)) + "元";
+                        String insuranceOtherFeeStr = extracted(node, "insurance_other_fee");
+                        insuranceOtherFee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceOtherFeeStr)) + "元";
+                    }
+                } else {
+                    type = 1;
+                }
+            } else {
+                type = 1;
+            }
+            String insDetail = "(微信支付:" + insuranceOtherFee + "; 医保个账扣款:" + insuranceSelfFee + "; 医保统筹扣款:" + insuranceFundfee + ")";
+            builder.setCode(ResultCode.SUCCEED_VALUE)
+                    .setMsg("操作成功")
+                    .setPatientAge(patientAge)
+                    .setPatientSex(patientSex)
+                    .setPatientName(patientName)
+                    .setInvoiceNo(invoiceNo)
+                    .setSelfPay(selfPay)
+                    .setInsurance(insuranceFee)
+                    .setInsDetail(insDetail)
+                    .setType(type)
+                    .addAllDetail(results);
+            return builder.build();
+        } catch (Exception e) {
+            logger.error("TaiheOutpatientService#getOutpatientOrderDetail(request={}):\n {}", request, e.getMessage(), e);
+            return builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg(e.getMessage()).build();
+        }
+    }
+
+    @Override
+    public GetMedicalCardInfoByPatientIdResponse getMedicalCardInfoById(GetMedicalCardInfoByIdRequest request) {
+        GetMedicalCardInfoByPatientIdResponse.Builder builder = GetMedicalCardInfoByPatientIdResponse.newBuilder();
+        try {
+            int cardId = request.getId();
+            MedicalCard medicalCard;
+            medicalCard = medicalCardRepository.getById(cardId);
+            if (medicalCard == null) {
+                builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("找不到就诊卡信息");
+            } else {
+                builder.setCode(ResultCode.SUCCEED_VALUE)
+                        .setMsg("")
+                        .setUserId(Checker.getIntegerValue(medicalCard.getUserId()))
+                        .setHospitalId(Checker.getIntegerValue(medicalCard.getHospitalId()))
+                        .setCardNo(Checker.getStringValue(medicalCard.getCardNo()))
+                        .setCardType(Checker.getStringValue(medicalCard.getCardType()))
+                        .setPatientName(Checker.getStringValue(medicalCard.getPatientName()))
+                        .setMobile(Checker.getStringValue(medicalCard.getMobile()))
+                        .setSex(Checker.getIntegerValue(medicalCard.getSex()))
+                        .setBirthday(Checker.getStringValue(medicalCard.getBirthday()))
+                        .setAddress(Checker.getStringValue(medicalCard.getAddress()))
+                        .setTelephoneNo(Checker.getStringValue(medicalCard.getTelephoneNo()))
+                        .setDocumentId(Checker.getStringValue(medicalCard.getDocumentId()))
+                        .setBalance(Checker.getIntegerValue(medicalCard.getBalance()))
+                        .setIdTypeCode(Checker.getStringValue(medicalCard.getIdTypeCode()))
+                        .setIdTypeDesc(Checker.getStringValue(medicalCard.getIdTypeDesc()))
+                        .setIdNo(Checker.getStringValue(medicalCard.getIdNo()))
+                        .setInsureCardNo(Checker.getStringValue(medicalCard.getInsureCardNo()))
+                        .setAccInfo(Checker.getStringValue(medicalCard.getAccInfo()))
+                        .setPatientType(Checker.getStringValue(medicalCard.getPatientType()))
+                        .setStatus(Checker.getIntegerValue(medicalCard.getStatus()))
+                        .setHisPatientId(Checker.getStringValue(medicalCard.getHisPatientId()))
+                        .setCardId(medicalCard.getId())
+                        .setGuardian(Checker.getStringValue(medicalCard.getGuardian()));
+            }
+        } catch (Exception e) {
+            logger.error("TaiheOutpatientService#getMedicalCardInfoById(request={}):\n {}", request, e.getMessage(), e);
+            builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg(e.getMessage());
+        } finally {
+            return builder.build();
+        }
+    }
+
+    @Override
+    public UpdateOutpatientOrderResponse updateOutpatientOrder(UpdateOutpatientOrderRequest request) {
+        UpdateOutpatientOrderResponse.Builder builder = UpdateOutpatientOrderResponse.newBuilder();
+        try {
+            String hisOrderNo = request.getHisOrderNo();
+            String invoiceNo = request.getInvoiceNo();
+            if (!Checker.isNone(hisOrderNo) && !Checker.isNone(invoiceNo)) {
+                com.ywt.outpatient.domain.entity.center.OutpatientOrder outpatientOrder = outpatientOrderRepository.getByHisOrderNo(hisOrderNo);
+                if (outpatientOrder != null) {
+                    outpatientOrder.setInvoiceNo(invoiceNo);
+                    outpatientOrderRepository.save(outpatientOrder);
+                    builder.setCode(ResultCode.SUCCEED_VALUE).setMsg("操作成功");
+                } else {
+                    builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("找不到门诊缴费单记录");
+                }
+            } else {
+                builder.setCode(ResultCode.PARAMETER_ERROR_VALUE).setMsg("订单号或发票号不能为空");
+            }
+            logger.info("updateOutpatientOrder():\n {} \nhisOrderNo: {}, invoiceNo: {}", builder.getMsg(), hisOrderNo,
+                    invoiceNo);
+            return builder.build();
+        } catch (Exception e) {
+            logger.error("TaiheOutpatientService#updateOutpatientOrder(request={}):\n {}", request, e.getMessage(), e);
+            return builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg(e.getMessage()).build();
+
+        }
+    }
+
+    @Override
+    public GetLatestOutpatientOrderResponse getLatestOutpatientOrder(GetLatestOutpatientOrderRequest request) {
+        GetLatestOutpatientOrderResponse.Builder builder = GetLatestOutpatientOrderResponse.newBuilder();
+        int doctorId = request.getDoctorId();
+        int userId = request.getUserId();
+        int hospitalId = request.getHospitalId();
+        try {
+            // 根据 doctorId 获取 doctorCode
+            GetDoctorHisCodeRequest getDoctorHisCodeRequest = GetDoctorHisCodeRequest.newBuilder()
+                    .setDoctorId(doctorId)
+                    .setHospitalId(hospitalId)
+                    .build();
+            GetDoctorHisCodeResponse response = doctorServiceBlockingStub.getDoctorHisCode(getDoctorHisCodeRequest);
+            if (response.getResult().getCode() == ResultCode.SUCCEED) {
+                DoctorHisCode doctorHisCode = response.getDoctorHisCode();
+                String doctorCode = Checker.getStringValue(doctorHisCode.getDoctorCode());
+                com.ywt.outpatient.domain.entity.center.OutpatientOrder order =
+                        outpatientOrderRepository.getLatestOutpatientOrder(doctorCode, userId, hospitalId);
+                if (order != null) {
+                    builder.setCreateTime(DateUtil.convertToTimestamp(order.getCreateTime()));
+                    builder.setCode(ResultCode.SUCCEED_VALUE);
+                    builder.setInfo("操作成功");
+                } else {
+                    builder.setCode(ResultCode.APP_ERROR_VALUE);
+                    builder.setInfo("找不到记录");
+                }
+            } else {
+                builder.setCode(ResultCode.APP_ERROR_VALUE);
+                builder.setInfo("找不到医生信息");
+            }
+            return builder.build();
+        } catch (Exception e) {
+            logger.error("TaiheOutpatientService#getLatestOutpatientOrder(request={}):\n {}", request, e.getMessage(), e);
+            return builder.setCode(ResultCode.APP_ERROR_VALUE).setInfo(e.getMessage()).build();
+        }
+    }
+
+    @Override
+    public GetOutPatientConfigResponse getOutpatientConfigs(GetOutPatientConfigRequest request) {
+        int hospitalId = request.getHospitalId();
+        GetOutPatientConfigResponse.Builder builder = GetOutPatientConfigResponse.newBuilder();
+        try {
+            OutpatientConfig config = configProvider.getOutpatientConfig(hospitalId);
+            if (config != null) {
+                builder.setNotifyUrl(Checker.getStringValue(config.getNotifyUrl()));
+                builder.setReturnUrl(Checker.getStringValue(config.getReturnUrl()));
+                builder.setOpenId(Checker.getStringValue(config.getOpenId()));
+                builder.setHospitalId(Checker.getIntegerValue(config.getHospitalId()));
+                builder.setInsuSupportCardType(Checker.getStringValue(config.getInsuSupportCardType()));
+            }
+            return builder.build();
+        } catch (Exception e) {
+            logger.error("TaiheOutpatientService#getOutpatientConfigs(request={}):\n {}", request, e.getMessage(), e);
+            return builder.build();
+        }
+    }
+
+    /**
+     * 判断是否有未支付的门诊缴费订单
+     */
+    @Override
+    public CheckHasOutstandingOutpatientOrderResponse checkHasOutstandingOutpatientOrder(CheckHasOutstandingOutpatientOrderRequest request) {
+        int userId = request.getUserId();
+        int hospitalId = Checker.getIntegerValue(request.getHospitalId());
+        int type = Checker.getIntegerValue(request.getType());
+        logger.info("-----checkHasOutstandingOutpatientOrder-----");
+        logger.info("payment_status:" + PaymentStatusEnum.Pending.getValue() + "\tuserId:" + userId + "\thospitalId:" + hospitalId);
+        CheckHasOutstandingOutpatientOrderResponse.Builder builder = CheckHasOutstandingOutpatientOrderResponse.newBuilder();
+        try {
+            boolean hasOutstandingOutpatientOrder = false;
+            if (userId > 0 && type == 1) {
+                // 查找当天未支付的门诊缴费订单
+                String startPattern = "yyyy-MM-dd 00:00:00";
+                String createTimeStart = DateUtil.formatDate(new Date(), startPattern);
+                Date createTimeStartDate = DateUtil.parseDate(createTimeStart, "");
+
+                String endPattern = "yyyy-MM-dd 23:59:59";
+                String createTimeEnd = DateUtil.formatDate(new Date(), endPattern);
+                Date createTimeEndDate = DateUtil.parseDate(createTimeEnd, "");
+                ArrayList<Object> paramList = new ArrayList<>();
+                String sql = "select count(1) from outpatient_order where payment_status = ? and user_id = ? and create_time >= ? and create_time <= ?";
+                paramList.add(PaymentStatusEnum.Pending.getValue());
+                paramList.add(userId);
+                paramList.add(createTimeStartDate);
+                paramList.add(createTimeEndDate);
+                if (hospitalId > 0) {
+                    sql += " and hospital_id = ? ";
+                    paramList.add(hospitalId);
+                }
+                int count = jdbcTemplate.queryForObject(sql, paramList.toArray(), Integer.class);
+                logger.info("createTimeStart:" + createTimeStart + "\tcreateTimeEnd:" + createTimeEnd + "\tcreateTimeStartDate:" + createTimeStartDate + "\tcreateTimeEndDate:" + createTimeEndDate + "\tcount:" + count);
+                hasOutstandingOutpatientOrder = count > 0 ? true : false;
+            }
+            builder.setCode(ResultCode.SUCCEED_VALUE);
+            builder.setMsg("操作成功");
+            builder.setHasOutstandingOutpatientOrder(hasOutstandingOutpatientOrder);
+            return builder.build();
+        } catch (Exception e) {
+            logger.error("TaiheOutpatientService#getOutpatientConfigs(request={}):\n {}", request, e.getMessage(), e);
+            return builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg(e.getMessage()).build();
+        }
+    }
+
+    @Override
+    public GetOutpatientOrderDetailByInvoiceResponse getOutpatientOrderByInvoiceNo(GetOutpatientOrderDetailByInvoiceRequest request) {
+        GetOutpatientOrderDetailByInvoiceResponse.Builder builder = GetOutpatientOrderDetailByInvoiceResponse.newBuilder();
+        try {
+            String invoiceNo = request.getInvoiceNo();
+            com.ywt.outpatient.domain.entity.center.OutpatientOrder outpatientOrder = outpatientOrderRepository.getByInvoiceNo(invoiceNo);
+            String selfPay = "0.00元";
+            String insuranceFee = "0.00元";
+            String insuranceFundfee = "0.00元";
+            String insuranceSelfFee = "0.00元";
+            String insuranceOtherFee = "0.00元";
+            //判断是否使用医保, 0使用了医保, 1纯自费
+            int type = 0;
+
+            if (!Checker.isNone(outpatientOrder) && !Checker.isNone(outpatientOrder.getInsTxReturnStr())) {
+
+                JsonNode node = JsonSerializer.readToNode(outpatientOrder.getInsTxReturnStr());
+                if (node != null) {
+                    String selfPayStr = extracted(node, "cash_fee");
+                    selfPay = MoneyUtil.cent2Yuan(Integer.parseInt(selfPayStr)) + "元";
+                    String insFeeStr = extracted(node, "insurance_fee");
+                    insuranceFee = MoneyUtil.cent2Yuan(Integer.parseInt(insFeeStr)) + "元";
+                    String insuranceFundfeeStr = extracted(node, "insurance_fund_fee");
+                    insuranceFundfee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceFundfeeStr)) + "元";
+                    String insuranceSelfFeeStr = extracted(node, "insurance_self_fee");
+                    insuranceSelfFee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceSelfFeeStr)) + "元";
+                    String insuranceOtherFeeStr = extracted(node, "insurance_other_fee");
+                    insuranceOtherFee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceOtherFeeStr)) + "元";
+                }
+            } else{
+                type = 1;
+            }
+            String insDetail = "(微信支付:" + insuranceOtherFee + "; 医保个账扣款:" + insuranceSelfFee + "; 医保统筹扣款:" + insuranceFundfee + ")";
+            builder.setCode(ResultCode.SUCCEED_VALUE)
+                    .setSelfPay(selfPay)
+                    .setInsurance(insuranceFee)
+                    .setInsDetail(insDetail)
+                    .setType(type);
+
+        } catch (Exception e) {
+            logger.error("TaiheOutpatientService# getOutpatientOrderByInvoiceNo(request={}):\n {}", request, e.getMessage(), e);
+            builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg(e.getMessage());
+        } finally {
+            return builder.build();
+        }
+    }
+}

+ 2744 - 0
ywt-platform-outpatient-rpc/src/main/java/com/ywt/outpatient/rpc/provider/TaiheRegisterProvider.java

@@ -0,0 +1,2744 @@
+package com.ywt.outpatient.rpc.provider;
+
+import com.google.protobuf.TextFormat;
+import com.ywt.biz.common.constant.GlobalConstants;
+import com.ywt.biz.common.constant.YwtCommonRespCode;
+import com.ywt.biz.common.enums.*;
+import com.ywt.biz.common.exception.YwtCommonException;
+import com.ywt.biz.common.util.Checker;
+import com.ywt.biz.common.util.DateUtil;
+import com.ywt.biz.common.util.HttpUtil;
+import com.ywt.biz.common.util.StringHelper;
+import com.ywt.gapi.Result;
+import com.ywt.gapi.ResultCode;
+import com.ywt.gapi.base.idCard.IdCardService;
+import com.ywt.gapi.base.idCard.ValidateIdCardRequest;
+import com.ywt.gapi.base.idCard.ValidateIdCardResponse;
+import com.ywt.gapi.doctor.DoctorInfoResponse;
+import com.ywt.gapi.doctor.DoctorRequest;
+import com.ywt.gapi.doctor.DoctorService;
+import com.ywt.gapi.ordercenter.OrderCenterService;
+import com.ywt.gapi.ordercenter.RefundRequest;
+import com.ywt.gapi.ordercenter.RefundResponse;
+import com.ywt.gapi.system.*;
+import com.ywt.gapi.taihe.register.RegisterResponse;
+import com.ywt.gapi.taihe.register.*;
+import com.ywt.gapi.taihe.register.RegisteredOrder;
+import com.ywt.gapi.third.taihe.*;
+import com.ywt.gapi.user.*;
+import com.ywt.gapi.user.User;
+import com.ywt.outpatient.core.PagedList;
+import com.ywt.outpatient.core.SqlHelper;
+import com.ywt.outpatient.core.utils.BizUtil;
+import com.ywt.outpatient.core.utils.CheckUtil;
+import com.ywt.outpatient.core.utils.IdCardUtil;
+import com.ywt.outpatient.domain.entity.center.*;
+import com.ywt.outpatient.domain.entity.center.MedicalCard;
+import com.ywt.outpatient.domain.models.HisMedCardConfig;
+import com.ywt.outpatient.domain.models.enums.*;
+import com.ywt.outpatient.service.rpc.Constants;
+import com.ywt.outpatient.service.rpc.IdGenerator;
+import com.ywt.outpatient.service.rpc.VerifyCreateRegisteredResult;
+import com.ywt.outpatient.service.rpc.VerifyRegisterWithoutMedicalCardResult;
+import com.ywt.outpatient.service.rpc.common.*;
+import com.ywt.outpatient.service.rpc.handler.RestCallerApiProvider;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import java.math.BigDecimal;
+import java.sql.Types;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static com.ywt.biz.common.util.DateUtil.convertToLocalDate;
+
+
+/**
+ * 太和医院预约挂号业务类
+ *
+ * @author johnson lin
+ * @date 2019-04-30 2:55 PM
+ */
+@DubboService
+public class TaiheRegisterProvider extends DubboTaiheRegisterServiceTriple.TaiheRegisterServiceImplBase {
+    private static Logger logger = LoggerFactory.getLogger(TaiheRegisterProvider.class);
+
+    @DubboReference(url = GlobalConstants.CENTRAL_CONTROL_SERVICE_NFYY_SERVICE_DUBBO_REFERENCE_URL, protocol = GlobalConstants.DUBBO_REFERENCE_PROTOCOL)
+    private TaiheService taiheServiceBlockingStub;
+
+    @DubboReference
+    private OrderCenterService orderCenterServiceBlockingStub;
+
+    @DubboReference
+    private SystemService systemServiceBlockingStub;
+
+    @Autowired
+    private MedicalCardRepository medicalCardRepository;
+
+    @Autowired
+    private IdGenerator idGenerator;
+
+    @Autowired
+    private RegisteredOrderRepository registeredOrderRepository;
+
+    @Autowired
+    private DoctorHisCodeRepository doctorHisCodeRepository;
+
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
+
+    @Autowired
+    private TaiheWeChatMsgService taiheWeChatMsgService;
+
+    @Autowired
+    private UserUnionsRepository userUnionsRepository;
+
+    @Autowired
+    private OrderPaymentRepository orderPaymentRepository;
+
+    @Autowired
+    private OfflineConsultationRepository offlineConsultationRepository;
+
+    @Autowired
+    private SqlHelper sqlHelper;
+
+    @Autowired
+    private RegisterRecordRepository registerRecordRepository;
+
+    @Autowired
+    private NfYwtWeChatMsgService nfYwtWeChatMsgService;
+
+    @DubboReference
+    private DoctorService doctorServiceBlockingStub;
+
+    @DubboReference
+    private UserService userServiceBlockingStub;
+
+    @Autowired
+    private UserRepository userRepository;
+
+    @Autowired
+    private ConfigProvider configProvider;
+
+    @Autowired
+    private OrderRepository orderRepository;
+
+    @Autowired
+    private PatientRepository patientRepository;
+
+    @DubboReference
+    IdCardService idCardServiceBlockingStub;
+
+    @Autowired
+    RefundLogRepository refundLogRepository;
+
+    @Autowired
+    private RestCallerApiProvider restCallerApiProvider ;
+
+    @Autowired
+    private WeChatMsgProvider weChatMsgProvider;
+
+    private static int OFFICAIL = 21;
+    private static int MIN = 20;
+
+    /**
+     * 挂号
+     * Update: 接入东华 HIS 后业务流程变更:锁号 --> 支付 --> HIS 挂号
+     *
+     * @param request {@link CreateRegisteredRequest}
+     */
+    @Override
+    public CreateRegisteredResponse createRegistered(CreateRegisteredRequest request) {
+        CreateRegisteredResponse.Builder builder = CreateRegisteredResponse.newBuilder();
+        try {
+            VerifyCreateRegisteredResult verifyCreateRegisteredResult = verifyCreateRegisteredRequest(request);
+            if (!verifyCreateRegisteredResult.isSuccess()) {
+                throw new YwtCommonException(YwtCommonRespCode.P_ERR, String.format("校验未通过:%s", verifyCreateRegisteredResult.getMsg()));
+            }
+            com.ywt.outpatient.domain.entity.center.MedicalCard medicalCard = verifyCreateRegisteredResult.getMedicalCard();
+            String doctorTitle = verifyCreateRegisteredResult.getDoctorTitle();
+            String doctorSessTypeCode = request.getDoctorSessTypeCode(); // 出诊级别code
+            String doctorSessTypeName = request.getDoctorSessTypeName(); // 出诊级别name
+            int paymentChannel = Checker.getIntegerValue(request.getPaymentChannel(), PaymentChannelEnum.WeChat.getValue());
+            int paymentStatus = PaymentStatusEnum.Pending.getValue();
+
+            if (request.getTotal() == 0) {
+                paymentChannel = PaymentChannelEnum.FREE.getValue();
+                paymentStatus = PaymentStatusEnum.Success.getValue();
+            }
+            // 默认太和,兼容
+            int hospitalId = request.getHospitalId() > 0 ? request.getHospitalId() : Constants.TAIHE_HOSPITAL_ID;
+            //获取医生ID
+            int doctorId = 0;
+            DoctorHisCode doctorHisCode = doctorHisCodeRepository.getDoctorByHisCode(hospitalId, request.getDoctorCode());
+            if (doctorHisCode != null && doctorHisCode.getDoctorId() > 0) {
+                doctorId = doctorHisCode.getDoctorId();
+            }
+            // 需求变动:白云医院的夜诊或午间诊,无论是公医还是 6 岁以下,都统一按照诊查费收费(即全收费)
+            // 判断是否全收费(统一按照诊查费收费)
+            // 2023年7月6日,需求变动:太和也使用这个规则
+            boolean isFullChargeReg = checkIsFullChargeReg(hospitalId, request.getPeriod(), doctorSessTypeName);
+
+            // 判断是否是公医,公医挂号费 0 元
+            boolean isFreeMedicalTreat = false;
+            com.ywt.outpatient.domain.entity.center.MedicalCard mc = medicalCardRepository.getById(request.getMedicalCardId());
+            if (!isFullChargeReg) {
+                if (mc != null) {
+                    isFreeMedicalTreat = configProvider.getFmtFlagList(Checker.getIntegerValue(request.getHospitalId())).contains(Checker.getStringValue(mc.getPatientType()));
+                }
+                if (isFreeMedicalTreat) {
+                    paymentChannel = PaymentChannelEnum.FREE.getValue();
+                    paymentStatus = PaymentStatusEnum.Success.getValue();
+                }
+            } else {
+                logger.info("TaiheRegisterService#createRegistered(): 白云夜诊");
+            }
+            com.ywt.outpatient.domain.entity.center.RegisteredOrder registeredOrder = new com.ywt.outpatient.domain.entity.center.RegisteredOrder();
+            registeredOrder.setUserId(request.getUserId());
+            registeredOrder.setDoctorId(doctorId);
+            registeredOrder.setDoctorTitle(doctorTitle);
+            registeredOrder.setRegisteredDate(DateUtil.convertTimestampToDate(request.getRegisteredDate()));
+            registeredOrder.setRegisteredPeriod(request.getPeriod());
+            registeredOrder.setStartTime(request.getStartTime());
+            registeredOrder.setEndTime(request.getEndTime());
+            registeredOrder.setHisPatientId(medicalCard.getHisPatientId());
+            registeredOrder.setMedicalCardId(request.getMedicalCardId());
+            registeredOrder.setPatientSex(medicalCard.getSex());
+            registeredOrder.setPatientName(medicalCard.getPatientName());
+            registeredOrder.setPaymentChannel(paymentChannel);
+            registeredOrder.setScheduleItemCode(request.getScheduleItemCode());
+            registeredOrder.setDoctorCode(request.getDoctorCode());
+            registeredOrder.setDoctorName(request.getDoctorName());
+            registeredOrder.setDeptId(request.getDeptId());
+            registeredOrder.setDeptCode(request.getDeptCode());
+            registeredOrder.setDeptName(request.getDeptName());
+            int medicalFee = Checker.getIntegerValue(request.getMedicalFee());
+            registeredOrder.setSubHospitalId(request.getSubHospitalId());
+
+            // 6 岁以下加收 30% 的挂号费
+            if (!isFullChargeReg) {
+                int curAge = IdCardUtil.calcAgeByIdNoAndBirthday(medicalCard.getIdNo(), medicalCard.getBirthday());
+                if (curAge < 6) {
+                    medicalFee = (new BigDecimal("1.3")).multiply((new BigDecimal(String.valueOf(medicalFee)))).intValue();
+                    logger.info("TaiheRegisterService#createRegistered : 6 岁以下加收 30% 的挂号费,原挂号费:{},重新计算得挂号费:{}",
+                            request.getMedicalFee(), medicalFee);
+                }
+                if (isFreeMedicalTreat) {
+                    logger.info("TaiheRegisterService#createRegistered(): 公医,cardId: {}", request.getMedicalCardId());
+                    medicalFee = 0;
+                }
+            }
+            int regFee = request.getRegisteredFee();
+            registeredOrder.setRegisteredFee(regFee);
+            registeredOrder.setTotal(medicalFee + regFee);
+            registeredOrder.setMedicalFee(medicalFee);
+            registeredOrder.setPaymentStatus(paymentStatus);
+            registeredOrder.setSource(request.getSource());
+            registeredOrder.setMedicalCardNo(medicalCard.getCardNo());
+            registeredOrder.setRegisteredType(RegisteredTypeEnum.GENERAL.getValue());
+
+            // 锁号
+            // 需求改动:
+            // 2020年8月12日:锁号使用病人 ID, 不再使用卡号
+            LockOrderRequest lockOrderRequest = LockOrderRequest.newBuilder()
+//                    .setCardNo(medicalCard.getCardNo())
+                    .setPatID(medicalCard.getHisPatientId())
+                    .setEndTime(Checker.getStringValue(request.getEndTime()))
+                    .setStartTime(Checker.getStringValue(request.getStartTime()))
+                    .setScheduleItemCode(Checker.getStringValue(request.getScheduleItemCode()))
+                    .setAvailableNumStr(Checker.getStringValue(request.getAvailableNumStr()))
+                    .setLockQueueNo(Checker.getStringValue(request.getLockQueueNo()))
+                    .setHospitalId(hospitalId)
+                    .build();
+            LockOrderResponse lockOrderResponse = taiheServiceBlockingStub.lockOrder(lockOrderRequest);
+            if (lockOrderResponse.getCode() != ResultCode.SUCCEED_VALUE) {
+                String errMsg = StringHelper.isNullOrEmpty(lockOrderResponse.getMsg()) ? "号源不足,请选择其他医生!" : lockOrderResponse.getMsg();
+                throw new YwtCommonException(YwtCommonRespCode.P_ERR, errMsg);
+            }
+            // 存入 orderCode
+            registeredOrder.setHisOrderCode(Checker.getStringValue(lockOrderResponse.getOrderCode()));
+            registeredOrder.setHospitalId(hospitalId);
+            registeredOrder.setHospitalName(BizUtil.getHospitalNameByIdSimply(hospitalId));
+            registeredOrder.setRemark(BizUtil.getHospitalNameByIdSimply(hospitalId));
+            //创建订单中心订单
+            ServiceResult serviceResult = createOrder(registeredOrder);
+            if (!serviceResult.isSuccessful()) {
+                throw new YwtCommonException(YwtCommonRespCode.P_ERR, String.format("创建订单出错:%s", serviceResult.getMsg()));
+            }
+
+            // 非名医挂号,如果挂号费是 0 元的订单或公医订单,不用支付,直接去 HIS 挂号然后修改订单状态
+            // 名医挂号还是要等线下就诊订单支付成功后再去 HIS 挂号
+            if (!checkIsNetDept(request.getDeptCode(), hospitalId) && (isFreeMedicalTreat || request.getTotal() == 0)) {
+                payFreeReg(registeredOrder.getId(), paymentChannel);
+            }
+
+            builder.setCode(ResultCode.SUCCEED_VALUE)
+                    .setOrderId(registeredOrder.getOrderId())
+                    .setOrderType(OrderTypeEnum.REGISTERED.getValue())
+                    .setHisClinicCode(0)
+                    .setIdNo(Checker.getStringValue(medicalCard.getIdNo()))
+                    .setName(Checker.getStringValue(medicalCard.getPatientName()))
+                    .setMobile(Checker.getStringValue(medicalCard.getMobile()))
+                    .setDoctorId(registeredOrder.getDoctorId())
+                    .setOrderNo(registeredOrder.getOrderNo())
+                    .setRegId(registeredOrder.getId())
+                    .build();
+            logger.info("createRegistered(): \nrequest - {}\nresponse - {}", TextFormat.printToUnicodeString(request),
+                    TextFormat.printToUnicodeString(builder.build()));
+            return builder.build();
+
+        } catch (YwtCommonException ame) {
+            builder.setCode(ResultCode.PARAMETER_ERROR_VALUE).setMsg(ame.getMessage());
+            return builder.build();
+        } catch (Exception e) {
+            logger.error("createRegistered({}): {}", TextFormat.printToUnicodeString(request), e.getMessage(), e);
+            builder.setCode(ResultCode.APP_EXCEPTION_VALUE).setMsg(Constants.ERROR_INFO);
+            return builder.build();
+        }
+    }
+
+    /**
+     * 免费挂号,0 元挂号费的订单(如公医)调用 HIS 挂号并修改订单状态
+     */
+    private void payFreeReg(int regId, int paymentChannel) throws YwtCommonException {
+        com.ywt.outpatient.domain.entity.center.RegisteredOrder registeredOrder = registeredOrderRepository.getById(regId);
+        if (registeredOrder == null) {
+            throw new YwtCommonException(YwtCommonRespCode.P_ERR, "0 元挂号:挂号订单不存在");
+        }
+        int orderId = Checker.getIntegerValue(registeredOrder.getOrderId());
+        String payMode = Constants.PAY_MODE_WECHAT;
+        if (paymentChannel == PaymentChannelEnum.AliPay.getValue()) {
+            payMode = Constants.PAY_MODE_ALI;
+        }
+        // 调用HIS接口,进行挂号同时把支付状态回写到HIS系统
+        String hisOrderCode = Checker.getStringValue(registeredOrder.getHisOrderCode());
+        PayRequest payReq = PayRequest.newBuilder()
+                .setOrderCode(hisOrderCode)
+                .setTransactionId("")// 不支付没有流水
+                .setPatientId(Checker.getStringValue(registeredOrder.getHisPatientId()))
+                .setCardNo(Checker.getStringValue(registeredOrder.getMedicalCardNo()))
+                .setPayAmount(0)
+                .setPayMode(payMode)
+                .setPayTime(DateUtil.convertToString(new Date()))
+                .setHospitalId(Checker.getIntegerValue(registeredOrder.getHospitalId()))
+                .build();
+        PayResponse payRes = taiheServiceBlockingStub.pay(payReq);
+        //若挂号不成功,记录失败原因,进行退费处理,资金原路退回
+        if (payRes.getCode() != ResultCode.SUCCEED_VALUE) {
+            logger.info("payFreeReg({}):支付状态回写到HIS系统失败:{}", regId, payRes.getMsg());
+            registeredOrder.setRemark(payRes.getMsg());
+            // 挂号失败,修改挂号订单状态为初始状态
+            registeredOrder.setRegisteredStatus(0);
+            registeredOrderRepository.save(registeredOrder);
+            throw new YwtCommonException(YwtCommonRespCode.P_ERR, String.format("call HIS pay:%s", payRes.getMsg()));
+        } else {
+            //挂号成功,更新挂号订单信息
+            registeredOrderRepository.updateRegisterInfoById(payRes.getSeqCode(), String.valueOf(payRes.getRegFee())
+                    , payRes.getAdmitRange(), payRes.getAdmitAddress(), "", payRes.getTransactionId()
+                    , hisOrderCode, RegisteredStatusEnum.Booked.getValue(), registeredOrder.getId(), payRes.getAdmNo());
+            // 更新订单信息,暂不需要
+//            Order order = orderRepository.getOrderById(orderId);
+//            order.setPaymentStatus(PaymentStatusEnum.Success.getValue());
+//            order.setPaymentNo(request.getOutTradeNo());
+//            order.setPayTime(new Date());
+//            orderRepository.save(order);
+
+            // 发送消息
+            registeredOrder.setHisAdmitAddress(Checker.getStringValue(payRes.getAdmitAddress()));
+            registeredOrder.setHisSeqCode(payRes.getSeqCode());
+            registeredOrder.setHisAdmitRange(payRes.getAdmitRange());
+            // 根据订单下单来源判断是哪个终端的订单
+            int source = Checker.getIntegerValue(registeredOrder.getSource());
+            if (!BizUtil.isAlipayMp(source)) {
+                // 微信体系才发送微信消息
+                nfYwtWeChatMsgService.sendMsgForRegister(registeredOrder);
+                taiheWeChatMsgService.sendMsgForRegister(registeredOrder);
+            }
+        }
+    }
+
+    /**
+     * 校验 CreateRegisteredRequest 参数是否合法
+     *
+     * @param request {@link CreateRegisteredRequest}
+     */
+    private VerifyCreateRegisteredResult verifyCreateRegisteredRequest(CreateRegisteredRequest request) throws YwtCommonException {
+        VerifyCreateRegisteredResult result = new VerifyCreateRegisteredResult();
+        long minTimestamp = DateUtil.convertToTimestamp(LocalDate.now());
+        long maxTimestamp = DateUtil.convertToTimestamp(LocalDate.now().plusDays(8));
+        if (request.getRegisteredDate() < minTimestamp || request.getRegisteredDate() > maxTimestamp) {
+            //只能预约8天内的号源
+            return result.failed("预约日期格式不正确");
+        }
+        if (StringHelper.isNullOrWhiteSpace(request.getDeptCode()) || StringHelper.isNullOrWhiteSpace(request.getDeptName())) {
+            return result.failed("科室不存在");
+        }
+        if (StringHelper.isNullOrWhiteSpace(request.getDoctorCode()) || StringHelper.isNullOrWhiteSpace(request.getDoctorName())) {
+            return result.failed("医生不存在");
+        }
+        if (StringHelper.isNullOrWhiteSpace(request.getStartTime())) {
+            return result.failed("预约开始时间不存在");
+        }
+        if (StringHelper.isNullOrWhiteSpace(request.getEndTime())) {
+            return result.failed("预约结束时间不存在");
+        }
+        if (request.getMedicalCardId() < 1) {
+            return result.failed("请选择就诊人");
+        }
+        if (StringHelper.isNullOrWhiteSpace(request.getScheduleItemCode())) {
+            return result.failed("门诊排班项记录标识不能为空");
+        }
+        if (RegisteredDatePeriod.valueOf(request.getPeriod()) == null) {
+            return result.failed("所选择的预约时段不存在!");
+        }
+        //判断门诊排班项记录标识是否合法
+        String serviceDate = DateUtil.convertTimestampToDateString(request.getRegisteredDate(), "yyyy-MM-dd");
+//        GetScheduleTimeInfoRequest req = GetScheduleTimeInfoRequest.newBuilder()
+//                .setDeptCode(request.getDeptCode())
+//                .setDoctorCode(request.getDoctorCode())
+//                .setServiceDate(serviceDate)
+//                .setDatePeriod(request.getPeriod())
+//                .build();
+//        GetScheduleTimeInfoResponse res = taiheServiceBlockingStub.getScheduleTimeInfo(req);
+//        if (res.getCode() != ResultCode.SUCCEED_VALUE) {
+//            return result.failed(res.getMsg());
+//        }
+//        if (res.getScheduleTimeInfosList().stream().noneMatch(p -> request.getScheduleItemCode().equals(p.getScheduleItemCode()))) {
+//            return result.failed("门诊排班项记录标识不存在");
+//        }
+        //判断医生编码是否合法
+        GetScheduleListRequest getScheduleListRequest = GetScheduleListRequest.newBuilder()
+                .setDeptCode(request.getDeptCode())
+                .setDoctorCode(request.getDoctorCode())
+                .setServiceDate(serviceDate)
+                .setHospitalId(request.getHospitalId())
+                .build();
+        GetScheduleListResponse getScheduleListResponse = taiheServiceBlockingStub.getScheduleList(getScheduleListRequest);
+        if (getScheduleListResponse.getCode() != ResultCode.SUCCEED_VALUE || getScheduleListResponse.getSchedulesList().size() == 0) {
+            return result.failed("医生不存在");
+        }
+        Schedule schedule = getScheduleListResponse.getSchedulesList().stream()
+                .filter(s -> s.getDatePeriod() == Checker.getIntegerValue(request.getPeriod()))
+                .findFirst()
+                .orElse(null);
+        if (schedule == null) {
+            return result.failed("当前时间段没有匹配的排班数据!");
+        }
+        //校验传入的价格
+        if (checkIsNetDept(request.getDeptCode(), request.getHospitalId())) {
+            if (request.getMedicalFee() != 0 || request.getRegisteredFee() != 0 || request.getTotal() != 0) {
+                //名医门诊科室的挂号费为 0
+                return result.failed("挂号费不正确");
+            }
+        } else {
+            if (request.getMedicalFee() != schedule.getCheckupFee() || request.getRegisteredFee() != schedule.getRegFee()) {
+                return result.failed("诊查费不正确");
+            }
+            if (request.getTotal() != request.getMedicalFee() + request.getRegisteredFee()) {
+                return result.failed("费用不正确");
+            }
+        }
+        //诊疗卡是否合法
+        // 2020年5月21日20点44分:暂时移除 userId 的限制
+//        MedicalCard medicalCard = medicalCardRepository.getByIdAndStatusAndUserId(request.getMedicalCardId(),
+//                MedicalCardStatus.NORMAL.getValue(), request.getUserId());
+        com.ywt.outpatient.domain.entity.center.MedicalCard medicalCard = medicalCardRepository.getByIdAndStatus(request.getMedicalCardId(),
+                MedicalCardStatusEnum.NORMAL.getValue());
+        if (medicalCard == null) {
+            logger.info(String.format("诊疗卡不存在!cardId: %d, userId: %d", request.getMedicalCardId(),
+                    request.getUserId()));
+            return result.failed("诊疗卡不存在!");
+        }
+        // 小于 14 岁挂内科的号,需要提示去儿科挂号
+        if (checkIsInternalMedicineDept(request.getDeptCode(), request.getHospitalId())) {
+            boolean isAgeLt14 = IdCardUtil.calcAgeByIdNoAndBirthday(medicalCard.getIdNo(), medicalCard.getBirthday()) < 14;
+            int hospitalId = request.getHospitalId() > 0 ? request.getHospitalId() : Constants.TAIHE_HOSPITAL_ID;
+            if (isAgeLt14) {
+                // 呼吸内科改造
+                if (Constants.NFYYBYFY_INTERNAL_BREATHE_MEDICINE_DEPT_CODE.equals(request.getDeptCode()) && hospitalId == Constants.NFYYBYFY_HOSPITAL_ID) {
+                    return result.failed("该患者挂号年龄不在挂号范围:≤14岁患者请挂儿科号就诊");
+                } else {
+                    return result.failed("就诊人少于14岁,请预约儿科医生就诊!");
+                }
+            }
+        }
+        result.setSuccess(true);
+        result.setDoctorTitle(schedule.getDoctorTitle());
+        result.setMedicalCard(medicalCard);
+        return result;
+    }
+
+    /**
+     * 创建预约挂号订单
+     *
+     * @param registeredOrder {@link RegisteredOrder}
+     * @return {@link ServiceResult}
+     */
+    private ServiceResult createOrder(com.ywt.outpatient.domain.entity.center.RegisteredOrder registeredOrder) {
+        ServiceResult serviceResult = new ServiceResult();
+        Date now = new Date();
+        int id = idGenerator.genRegisteredOrderId();
+        registeredOrder.setId(id);
+        registeredOrder.setDeleted(false);
+        registeredOrder.setUpdateTime(now);
+        registeredOrder.setCreateTime(now);
+        registeredOrder.setRegisteredStatus(0);
+        registeredOrderRepository.save(registeredOrder);
+
+        //创建订单中心订单
+        int orderType = OrderTypeEnum.REGISTERED.getValue();
+        com.ywt.gapi.ordercenter.CreateOrderRequest req = com.ywt.gapi.ordercenter.CreateOrderRequest.newBuilder()
+                .setOrderType(orderType)
+                .setBizId(registeredOrder.getId())
+                .setPaymentCallbackMethod("/com.ywt.gapi.taihe.register.TaiheRegisterService/payCallback")
+                .setPayCode(getHospPayCodeByHospId(registeredOrder.getHospitalId(), Checker.getIntegerValue(registeredOrder.getSource())))
+                .setAmount(registeredOrder.getTotal())
+                .setPayBody(OrderTypeEnum.REGISTERED.getDisplayName())
+                .setUserId(registeredOrder.getUserId())
+                .setPatientMobile("")
+                .setDoctorId(registeredOrder.getDoctorId())
+                .build();
+        com.ywt.gapi.ordercenter.CreateOrderResponse res = orderCenterServiceBlockingStub.createOrder(req);
+
+        if (res.getCode() != ResultCode.SUCCEED_VALUE) {
+            return serviceResult.failed("创建订单不成功,原因:" + res.getInfo());
+        }
+
+        //更新订单ID、订单编码
+        registeredOrderRepository.updateOrderIdAndOrderNoById(res.getOrderId(), res.getOrderNo(), registeredOrder.getId());
+
+        registeredOrder.setOrderId(res.getOrderId());
+        registeredOrder.setOrderNo(res.getOrderNo());
+        return serviceResult.succeed();
+    }
+
+    /**
+     * 根据医院 id 获取对应医院的支付代码,目前只支持太和和白云分院
+     * v1.6.5_nfby 开始,白云小程序支持太和医院的挂号,订单的支付代码根据创建订单的客户端来源判断
+     * @param hospitalId 医院 id
+     * @return 支付代码
+     */
+    public static String getHospPayCodeByHospId(int hospitalId, int source) {
+        switch (hospitalId) {
+            case com.ywt.outpatient.core.Constants.TAIHE_HOSPITAL_ID:
+                if (BizUtil.isAlipayMp(source)) return com.ywt.outpatient.core.Constants.TH_PAY_CODE_ALIPAY;
+                String nfyybyfyTaihePayCode = StringHelper.isNullOrEmpty(BizUtil.payCode4NfyybyfyTest) ? Constants.NFYYBYFY_TAIHE_REG_PAY_CODE : BizUtil.payCode4NfyybyfyTest;
+                return source == OfflineConsultationSourceEnum.NFYYBYFY_WXAPP.getValue() ? nfyybyfyTaihePayCode : Constants.TAIHE_PAY_CODE;
+            case com.ywt.outpatient.core.Constants.NFYYBYFY_HOSPITAL_ID:
+                if (BizUtil.isAlipayMp(source)) return com.ywt.outpatient.core.Constants.NFYYBYFY_PAY_CODE_ALIPAY;
+                if (!StringHelper.isNullOrEmpty(BizUtil.payCode4NfyybyfyTest)) return BizUtil.payCode4NfyybyfyTest;
+                return com.ywt.outpatient.core.Constants.NFYYBYFY_PAY_CODE;
+            default:
+                return "";
+        }
+    }
+    /**
+     * 取消预约,若用户已支付挂号费,则挂号费原路退还给用户
+     *
+     * @param request          {@link CancelRegisteredRequest}
+     */
+    @Override
+    public CancelRegisteredResponse cancelRegistered(CancelRegisteredRequest request) {
+        CancelRegisteredResponse.Builder builder = CancelRegisteredResponse.newBuilder();
+
+        try {
+            // 默认太和,兼容旧接口
+            int hospitalId = request.getHospitalId() > 0 ? request.getHospitalId() : Constants.TAIHE_HOSPITAL_ID;
+            com.ywt.outpatient.domain.entity.center.RegisteredOrder registeredOrder = registeredOrderRepository.getFirstByOrderIdAndHospitalIdAndDeletedFalse(
+                    request.getOrderId(), hospitalId);
+            if (registeredOrder == null) {
+                builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("订单不存在");
+                return builder.build();
+            }
+            if (registeredOrder.getUserId() != request.getUserId()) {
+                builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("您没有权限取消该预约");
+                return builder.build();
+            }
+            if (StringHelper.isNullOrWhiteSpace(registeredOrder.getHisOrderCode())) {
+                builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("订单未预约成功,无法取消");
+                return builder.build();
+            }
+            // 从 v2.1.9_nfby 开始,白云分院的取消预约按钮显示规则修改:(太和等医院逻辑不变)
+            // ①就诊当天00:00后,“取消预约”按钮不显示。
+            // ②预约挂号订单有诊断的(通过his接口判断),“取消预约”按钮不显示。
+            // 点击“取消预约”按钮,提示:
+            //    a、若出现①的情况,提示“就诊当天00:00后不可线上取消!”,然后“取消预约”按钮不显示;
+            //    b、若出现②的情况,提示“已就诊,不可线上取消!”,然后“取消预约”按钮不显示;
+            if (hospitalId == Constants.NFYYBYFY_HOSPITAL_ID) {
+                if (!canTodayCancelReg(hospitalId, registeredOrder.getRegisteredDate())) {
+                    builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("就诊当天00:00后不可线上取消!");
+                    return builder.build();
+                }
+                boolean hasDiagnose = hasDiagnose(Checker.getStringValue(registeredOrder.getHisClinicCode()),
+                        Checker.getIntegerValue(registeredOrder.getHospitalId()));
+                if (hasDiagnose) {
+                    builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("已就诊,不可线上取消!");
+                    return builder.build();
+                }
+            }
+            String payMode = Constants.PAY_MODE_WECHAT;
+            boolean isAlipay = Checker.getIntegerValue(registeredOrder.getPaymentChannel()) == PaymentChannelEnum.AliPay.getValue();
+            boolean isWechatPay = Checker.getIntegerValue(registeredOrder.getPaymentChannel()) == PaymentChannelEnum.WeChat.getValue();
+            if (isAlipay) {
+                payMode = Constants.PAY_MODE_ALI;
+            }
+            String transactionId = Checker.getStringValue(registeredOrder.getWxTransactionId());
+            CancelRequest cancelReq = CancelRequest.newBuilder()
+                    .setOrderCode(registeredOrder.getHisOrderCode())
+                    .setCardNo(Checker.getStringValue(registeredOrder.getMedicalCardNo()))
+                    .setPatId(Checker.getStringValue(registeredOrder.getHisPatientId()))
+                    .setClinicCode(Checker.getStringValue(registeredOrder.getHisClinicCode()))
+                    .setHospitalId(hospitalId)
+                    .setTransactionId(transactionId)
+                    .setPayMode(payMode)
+                    .build();
+            CancelResponse cancelRes = taiheServiceBlockingStub.cancel(cancelReq);
+
+            if (cancelRes.getCode() != ResultCode.SUCCEED_VALUE) {
+                logger.error("TaiheRegisterService#cancelRegistered(): {}", cancelRes.getMsg());
+                builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("该预约挂号不能取消!");
+                return builder.build();
+            }
+
+            //取消成功,更新挂号订单状态
+            registeredOrderRepository.updateRegisteredStatus(RegisteredStatusEnum.Back.getValue(), registeredOrder.getId());
+
+            //若用户已支付挂号费,则挂号费原路退还给用户
+            if (registeredOrder.getTotal() > 0 && registeredOrder.getPaymentStatus() == PaymentStatusEnum.Success.getValue()) {
+                refund(registeredOrder.getOrderId(), registeredOrder.getOrderNo(), registeredOrder.getId());
+            }
+
+            //发送模板消息
+            switch (hospitalId) {
+                case Constants.TAIHE_HOSPITAL_ID:
+                    if (isWechatPay) {
+                        //《南方医务通》公众号
+                        nfYwtWeChatMsgService.sendMsgForCancel(registeredOrder);
+                        //《南方医院太和分院》公众号
+                        taiheWeChatMsgService.sendMsgForCancel(registeredOrder);
+                    }
+                    if (isAlipay) {
+                        String orderNo = Checker.getStringValue(registeredOrder.getOrderNo());
+                        String createTime = DateUtil.convertToString(registeredOrder.getCreateTime());
+                        String paymentNo = Checker.getStringValue(registeredOrder.getPaymentNo());
+                        String regTime = DateUtil.convertToString(registeredOrder.getRegisteredDate(), "yyyy-MM-dd") +
+                                " " + Checker.getStringValue(registeredOrder.getStartTime()) + ":00";
+                        String admAddr = registeredOrder.getHisAdmitAddress();
+                        OrderPayment payment = orderPaymentRepository.getOrderPaymentByOrderNo(orderNo);
+                        String alipayUid = "";
+                        if (payment != null) {
+                            alipayUid = Checker.getStringValue(payment.getAlipayUid());
+                        }
+                        sendAlipayMpMsgForReg(Checker.getIntegerValue(registeredOrder.getOrderId()), orderNo, createTime,
+                                String.format("%.2f", Checker.getIntegerValue(registeredOrder.getTotal()) / 100d),
+                                paymentNo, Checker.getStringValue(registeredOrder.getHospitalName()),
+                                Checker.getStringValue(registeredOrder.getDeptName()), Checker.getStringValue(registeredOrder.getDoctorName()),
+                                String.valueOf(Checker.getIntegerValue(registeredOrder.getDoctorId())), Checker.getStringValue(registeredOrder.getPatientName()),
+                                regTime, (StringHelper.isNullOrEmpty(admAddr) ? "-" : admAddr), alipayUid,
+                                Checker.getIntegerValue(registeredOrder.getHospitalId()), "MERCHANT_CLOSED");
+                    }
+                    break;
+                case Constants.NFYYBYFY_HOSPITAL_ID:
+                    if (isWechatPay) {
+                        taiheWeChatMsgService.notifyCancel4NFYYBYFY(Checker.getIntegerValue(registeredOrder.getUserId()),
+                                BizUtil.getHospitalNameByIdSimply(hospitalId), Checker.getStringValue(registeredOrder.getPatientName()),
+                                Checker.getStringValue(registeredOrder.getDoctorName()),
+                                String.format("%s %s-%s", DateUtil.convertToString(registeredOrder.getRegisteredDate(), "MM月dd日"),
+                                        Checker.getStringValue(registeredOrder.getStartTime()),
+                                        Checker.getStringValue(registeredOrder.getEndTime())));
+                    }
+                    if (isAlipay) {
+                        String orderNo = Checker.getStringValue(registeredOrder.getOrderNo());
+                        String createTime = DateUtil.convertToString(registeredOrder.getCreateTime());
+                        String paymentNo = Checker.getStringValue(registeredOrder.getPaymentNo());
+                        String regTime = DateUtil.convertToString(registeredOrder.getRegisteredDate(), "yyyy-MM-dd") +
+                                " " + Checker.getStringValue(registeredOrder.getStartTime()) + ":00";
+                        String admAddr = registeredOrder.getHisAdmitAddress();
+                        OrderPayment payment = orderPaymentRepository.getOrderPaymentByOrderNo(orderNo);
+                        String alipayUid = "";
+                        if (payment != null) {
+                            alipayUid = Checker.getStringValue(payment.getAlipayUid());
+                        }
+                        sendAlipayMpMsgForReg(Checker.getIntegerValue(registeredOrder.getOrderId()), orderNo, createTime,
+                                String.format("%.2f", Checker.getIntegerValue(registeredOrder.getTotal()) / 100d),
+                                paymentNo, Checker.getStringValue(registeredOrder.getHospitalName()),
+                                Checker.getStringValue(registeredOrder.getDeptName()), Checker.getStringValue(registeredOrder.getDoctorName()),
+                                String.valueOf(Checker.getIntegerValue(registeredOrder.getDoctorId())), Checker.getStringValue(registeredOrder.getPatientName()),
+                                regTime, (StringHelper.isNullOrEmpty(admAddr) ? "-" : admAddr), alipayUid,
+                                Checker.getIntegerValue(registeredOrder.getHospitalId()), "MERCHANT_CLOSED");
+                    }
+                    break;
+                default:
+                    break;
+            }
+
+            builder.setCode(ResultCode.SUCCEED_VALUE)
+                    .setMsg("取消成功")
+                    //预约挂号单支付状态:1-订单未支付 2-订单已支付
+                    .setStatus(2);
+        } catch (Exception e) {
+            logger.error("cancelRegistered({}): {}", request, e.getMessage(), e);
+            builder.setCode(ResultCode.APP_EXCEPTION_VALUE).setMsg(Constants.ERROR_INFO);
+        } finally {
+            return builder.build();
+        }
+    }
+
+    /**
+     * 订单支付成功通知
+     *
+     * @param request {@link PayCallbackRequest}
+     */
+    @Override
+    public PayCallbackResponse payCallback(PayCallbackRequest request) {
+        PayCallbackResponse.Builder builder = PayCallbackResponse.newBuilder();
+        com.ywt.outpatient.domain.entity.center.RegisteredOrder registeredOrder = null;
+        try {
+            logger.info("TaiheRegisterService#payCallback(): bizId={}, orderId={}, orderNo={}, terminal={}",
+                    request.getBizId(), request.getOrderId(), request.getOrderNo(), request.getTerminal());
+            int paymentChannel = Checker.getIntegerValue(request.getPaymentChannel());
+            String paymentNo = request.getPaymentNo(); // 支付宝支付时,等于 tradeNo
+            // 支付流水号,支付方式是微信,表示 wxTrarsactionId,支付方式是支付宝,表示 tradeNo
+            String wxTransactionId = request.getWxTransactionId();
+            OrderPayment payment = null;
+            if (paymentChannel == PaymentChannelEnum.WeChat.getValue() && StringHelper.isNullOrEmpty(wxTransactionId)) {
+                //订单中心未返回 TransactionId(微信交易流水号),则从表 OrderPayment 读取。 2019-04-28 20:43:58
+                payment = orderPaymentRepository.getFirstByOrderIdAndPaymentStatusAndDeletedFalseOrderByCreateTimeDesc(
+                        request.getBizId(), PaymentStatusEnum.Success.getValue());
+                if (payment != null) {
+                    wxTransactionId = payment.getTransactionId();
+                    logger.info("TaiheRegisterService#payCallback(): orderPayment terminal = {}", payment.getTerminal());
+                }
+            }
+            String sql = "", payMode = "";
+            Object[] args = null;
+            int[] argTypes = null;
+            switch (paymentChannel) {
+                // 支付宝
+                case 2:
+                    sql = "update registered_order " +
+                            "set payment_status = ?" +
+                            ", payment_no = ?" +
+                            ", payment_time = ?" +
+                            ", update_time = now() " +
+                            "where id = ? and payment_status != ?";
+                    args = new Object[]{
+                            PaymentStatusEnum.Success.getValue(),
+                            paymentNo,
+                            //request.getPayFinishDate()单位:秒,转成Date格式需要转换为毫秒。
+                            new Date(request.getPayFinishDate() * 1000),
+                            request.getBizId(),
+                            PaymentStatusEnum.Success.getValue()
+                    };
+                    argTypes = new int[]{Types.INTEGER, Types.VARCHAR, Types.TIMESTAMP, Types.INTEGER, Types.INTEGER};
+                    payMode = Constants.PAY_MODE_ALI;
+                    break;
+                // 默认微信
+                default:
+                    sql = "update registered_order " +
+                            "set payment_status = ?" +
+                            ", payment_no = ?" +
+                            ", wx_transaction_id = ?" +
+                            ", payment_time = ?" +
+                            ", update_time = now() " +
+                            "where id = ? and payment_status != ?";
+                    args = new Object[]{
+                            PaymentStatusEnum.Success.getValue(),
+                            paymentNo,
+                            wxTransactionId,
+                            //request.getPayFinishDate()单位:秒,转成Date格式需要转换为毫秒。
+                            new Date(request.getPayFinishDate() * 1000),
+                            request.getBizId(),
+                            PaymentStatusEnum.Success.getValue()
+                    };
+                    argTypes = new int[]{Types.INTEGER, Types.VARCHAR, Types.VARCHAR, Types.TIMESTAMP, Types.INTEGER, Types.INTEGER};
+                    payMode = Constants.PAY_MODE_WECHAT;
+                    break;
+            }
+
+            int count = jdbcTemplate.update(sql, args, argTypes);
+            if (count < 1) {
+                builder.setCode(ResultCode.APP_ERROR_VALUE).setInfo("订单不存在或重复回调");
+                return builder.build();
+            }
+            registeredOrder = registeredOrderRepository.getById(request.getBizId());
+            String orderNo = Checker.getStringValue(registeredOrder.getOrderNo());
+            if (paymentChannel == PaymentChannelEnum.AliPay.getValue()) {
+                wxTransactionId = paymentNo;
+            }
+            int payAmount = Checker.getIntegerValue(registeredOrder.getTotal());
+            // 调用HIS接口,进行挂号同时把支付状态回写到HIS系统
+            String hisOrderCode = Checker.getStringValue(registeredOrder.getHisOrderCode());
+            PayRequest payReq = PayRequest.newBuilder()
+                    .setOrderCode(hisOrderCode)
+                    .setTransactionId(wxTransactionId)
+                    .setPatientId(registeredOrder.getHisPatientId())
+                    .setCardNo(registeredOrder.getMedicalCardNo())
+                    .setPayAmount(payAmount)
+                    //支付方式
+                    .setPayMode(payMode)
+                    .setPayTime(DateUtil.formatDate(registeredOrder.getPaymentTime(), "yyyy-MM-dd HH:mm:ss"))
+                    .setHospitalId(Checker.getIntegerValue(registeredOrder.getHospitalId()))
+                    .build();
+            PayResponse payRes = taiheServiceBlockingStub.pay(payReq);
+            //若挂号不成功,记录失败原因,进行退费处理,资金原路退回
+            if (payRes.getCode() != ResultCode.SUCCEED_VALUE) {
+                logger.info("payCallback({}):支付状态回写到HIS系统失败:{}", request, payRes.getMsg());
+                registeredOrder.setRemark(payRes.getMsg());
+                // 挂号失败,修改挂号订单状态为初始状态
+                registeredOrder.setRegisteredStatus(0);
+                registeredOrderRepository.save(registeredOrder);
+                refund(registeredOrder.getOrderId(), registeredOrder.getOrderNo(), registeredOrder.getId());
+            } else {
+                // 东华 HIS 流程是 pay 方法包括了原来的挂号和支付状态回写,下面是处理挂号成功之后的逻辑
+
+                //挂号成功,更新挂号信息
+                registeredOrderRepository.updateRegisterInfoById(payRes.getSeqCode(), String.valueOf(payRes.getRegFee())
+                        , payRes.getAdmitRange(), payRes.getAdmitAddress(), "", payRes.getTransactionId()
+                        , hisOrderCode, RegisteredStatusEnum.Booked.getValue(), registeredOrder.getId(), payRes.getAdmNo());
+
+                //发送挂号成功模板消息
+                //《南方医务通》公众号
+                // 先赋值一下就诊地址
+                registeredOrder.setHisAdmitAddress(Checker.getStringValue(payRes.getAdmitAddress()));
+                registeredOrder.setHisSeqCode(payRes.getSeqCode());
+                registeredOrder.setHisAdmitRange(payRes.getAdmitRange());
+                if (paymentChannel == PaymentChannelEnum.WeChat.getValue()) {
+
+
+                    nfYwtWeChatMsgService.sendMsgForRegister(registeredOrder);
+                    //《南方医院太和分院》公众号
+                    taiheWeChatMsgService.sendMsgForRegister(registeredOrder);
+                }
+                if (paymentChannel == PaymentChannelEnum.AliPay.getValue()) {
+                    String createTime = DateUtil.convertToString(registeredOrder.getCreateTime());
+                    String regTime = DateUtil.convertToString(registeredOrder.getRegisteredDate(), "yyyy-MM-dd") +
+                            " " + Checker.getStringValue(registeredOrder.getStartTime()) + ":00";
+                    String admAddr = registeredOrder.getHisAdmitAddress();
+                    payment = orderPaymentRepository.getOrderPaymentByOrderNo(orderNo);
+                    String alipayUid = "";
+                    if (payment != null) {
+                        alipayUid = Checker.getStringValue(payment.getAlipayUid());
+                    }
+                    sendAlipayMpMsgForReg(Checker.getIntegerValue(registeredOrder.getOrderId()), orderNo, createTime,
+                            String.format("%.2f", Checker.getIntegerValue(registeredOrder.getTotal()) / 100d),
+                            paymentNo, Checker.getStringValue(registeredOrder.getHospitalName()),
+                            Checker.getStringValue(registeredOrder.getDeptName()), Checker.getStringValue(registeredOrder.getDoctorName()),
+                            String.valueOf(Checker.getIntegerValue(registeredOrder.getDoctorId())), Checker.getStringValue(registeredOrder.getPatientName()),
+                            regTime, (StringHelper.isNullOrEmpty(admAddr) ? "-" : admAddr), alipayUid,
+                            Checker.getIntegerValue(registeredOrder.getHospitalId()), "MERCHANT_PREORDER_SUCCESS");
+                }
+
+                // 挂号成功后,更新线下就诊订单的 his_clinic_code 和 patient mobile
+                OfflineConsultation offlineConsultation = offlineConsultationRepository.getByRegId(registeredOrder.getId());
+                if (offlineConsultation != null) {
+                    try {
+                        offlineConsultation.setHisClinicCode(Integer.valueOf(payRes.getAdmNo()));
+                        String mobile = offlineConsultation.getMobile();
+                        if (Checker.isNone(mobile)) {
+                            // 如果医院登记的手机号没有,尝试用患者授权的手机号
+                            int userId = offlineConsultation.getUserId();
+                            UserRequest req = UserRequest.newBuilder().setUserid(userId).build();
+                            UserResponse resp = userServiceBlockingStub.findByUserId(req);
+                            Result result = resp.getResult();
+                            if (result.getCode() == ResultCode.SUCCEED) {
+                                User user = resp.getUser();
+                                if (Checker.isNone(user.getMobile())) {
+                                    offlineConsultation.setMobile(user.getMobile());
+                                }
+                            }
+                        }
+                        offlineConsultationRepository.save(offlineConsultation);
+                    } catch (NumberFormatException e) {
+                        logger.error("TaiheRegisterService#payCallback(request={} ) Failed to convert number:\n {}", request,  e.getMessage(), e);
+                    }
+                }
+
+                if (registeredOrder.getDoctorId() > 0) {
+                    //关注医生
+                    followDoctor(registeredOrder.getUserId(), registeredOrder.getDoctorId());
+                }
+            }
+
+            builder.setCode(ResultCode.SUCCEED_VALUE);
+        } catch (Exception e) {
+            logger.error("payCallback():{}, {}", request, e.getMessage(), e);
+            // 挂号失败,需要做退费处理
+            if (registeredOrder != null) {
+                logger.error("TaiheRegisterService#payCallback(): 挂号失败,退费处理");
+                String errMsg = Checker.getStringValue(e.getMessage(), "挂号失败,未知异常");
+                int maxMsgLength = 100;
+                registeredOrder.setRemark(errMsg.length() > maxMsgLength ? errMsg.substring(0, maxMsgLength) : errMsg);
+                // 挂号失败,修改挂号订单状态为初始状态
+                registeredOrder.setRegisteredStatus(0);
+                registeredOrderRepository.save(registeredOrder);
+                refund(registeredOrder.getOrderId(), registeredOrder.getOrderNo(), registeredOrder.getId());
+            }
+            builder.setCode(ResultCode.APP_EXCEPTION_VALUE).setInfo(Constants.ERROR_INFO);
+        } finally {
+            return builder.build();
+        }
+    }
+
+    /**
+     * 预约挂号业务,系统发起退款成功后自动向 HIS 发起退号申请,目的是尽可能保证双方的状态一致
+     */
+    private void cancelRegAfterRefunded(String refundNo) {
+        try {
+            com.ywt.outpatient.domain.entity.center.RegisteredOrder registeredOrder = registeredOrderRepository.getFirstByRefundNoAndDeletedFalse(refundNo);
+            if (registeredOrder == null) {
+                logger.warn("TaiheRegisterService#cancelRegAfterRefunded(refundNo = {}): 找不到订单信息", refundNo);
+                return ;
+            }
+            String hisOrderCode = Checker.getStringValue(registeredOrder.getHisOrderCode());
+            String medCardNo = Checker.getStringValue(registeredOrder.getMedicalCardNo());
+            String hisPatientId = Checker.getStringValue(registeredOrder.getHisPatientId());
+            String hisClinicCode = Checker.getStringValue(registeredOrder.getHisClinicCode());
+            String payMode = Constants.PAY_MODE_WECHAT;
+            boolean isAlipay = Checker.getIntegerValue(registeredOrder.getPaymentChannel()) == PaymentChannelEnum.AliPay.getValue();
+            if (isAlipay) {
+                payMode = Constants.PAY_MODE_ALI;
+            }
+            String transactionId = Checker.getStringValue(registeredOrder.getWxTransactionId());
+            int hospitalId = Checker.getIntegerValue(registeredOrder.getHospitalId());
+
+            CancelRequest cancelReq = CancelRequest.newBuilder()
+                    .setOrderCode(hisOrderCode)
+                    .setCardNo(Checker.getStringValue(medCardNo))
+                    .setPatId(Checker.getStringValue(hisPatientId))
+                    .setClinicCode(Checker.getStringValue(hisClinicCode))
+                    .setHospitalId(hospitalId)
+                    .setTransactionId(transactionId)
+                    .setPayMode(payMode)
+                    .build();
+            CancelResponse cancelRes = taiheServiceBlockingStub.cancel(cancelReq);
+
+            if (cancelRes.getCode() != ResultCode.SUCCEED_VALUE) {
+                logger.error("TaiheRegisterService#cancelRegAfterRefunded(hisOrderCode={} , medCardNo={} , hisPatientId={} , " +
+                                "hisClinicCode={} , hospitalId={} , transactionId={} , payMode={} ):退号失败:{}",
+                        hisOrderCode, medCardNo, hisPatientId, hisClinicCode, hospitalId, transactionId, payMode, cancelRes.getMsg());
+            } else {
+                logger.info("TaiheRegisterService#cancelRegAfterRefunded(hisOrderCode={} , medCardNo={} , hisPatientId={} , " +
+                                "hisClinicCode={} , hospitalId={} , transactionId={} , payMode={} ):退号成功",
+                        hisOrderCode, medCardNo, hisPatientId, hisClinicCode, hospitalId, transactionId, payMode);
+            }
+        } catch (Exception e) {
+            logger.error("TaiheRegisterService#cancelRegAfterRefunded(refundNo={}):\n {}", refundNo, e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 支付宝挂号单状态消息
+     * <a href="https://gw.alipayobjects.com/os/bmw-prod/05064ae2-e3c7-4e6c-93ed-ad4740b66000.pdf">merchantOrderStatus 状态文档</a>
+     */
+    private void sendAlipayMpMsgForReg(int orderId, String orderNo, String orderCreateTime, String orderAmountStr,
+                                       String tradeNo, String hospitalName, String deptName, String doctorName,
+                                       String doctorId, String patientName, String regDate, String deptLoc,
+                                       String alipayUid, int hospitalId, String merchantOrderStatus) {
+        String path = "/msg/sendRegMsg";
+        Map<String, Object> params = new HashMap<>();
+        params.put("orderId", orderId);
+        params.put("orderNo", orderNo);
+        params.put("orderCreateTime", orderCreateTime);
+        params.put("orderAmountStr", orderAmountStr);
+        params.put("tradeNo", tradeNo);
+        params.put("hospitalName", hospitalName);
+        params.put("deptName", deptName);
+        params.put("doctorName", doctorName);
+        params.put("doctorId", doctorId);
+        params.put("patientName", patientName);
+        params.put("regDate", regDate);
+        params.put("deptLoc", deptLoc);
+        params.put("alipayUid", alipayUid);
+        params.put("hospitalId", hospitalId);
+        params.put("merchantOrderStatus", merchantOrderStatus);
+        try {
+            HttpUtil.Resp resp = restCallerApiProvider.postAlipayMpRestApi(path, params);
+        } catch (Exception e) {
+            logger.error("TaiheRegisterService#sendAlipayMpMsgForReg(orderId={} , orderNo={} , orderCreateTime={} , " +
+                            "orderAmountStr={} , tradeNo={} , hospitalName={} , deptName={} , doctorName={} , doctorId={} , " +
+                            "patientName={} , regDate={} , deptLoc={} , alipayUid={} , hospitalId={}, merchantOrderStatus={} ):\n {}",
+                    orderId, orderNo, orderCreateTime, orderAmountStr, tradeNo, hospitalName, deptName, doctorName,
+                    doctorId, patientName, regDate, deptLoc, alipayUid, hospitalId, merchantOrderStatus, e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 退款回调
+     *
+     * @param request {@link RefundCallbackRequest}
+     */
+    @Override
+    public RefundCallbackResponse refundCallback(RefundCallbackRequest request) {
+        RefundCallbackResponse.Builder builder = RefundCallbackResponse.newBuilder();
+        try {
+            String sql =
+                    "update registered_order " +
+                            "set refund_status = ?, refund_callback_time = now() " +
+                            "where refund_no = ? and refund_status = ?;";
+            Object[] args = new Object[]{
+                    request.getRefundStatus(),
+                    request.getRefundNo(),
+                    RefundStatusEnum.PENDING.getValue()
+            };
+            int[] types = new int[]{
+                    Types.INTEGER,
+                    Types.VARCHAR,
+                    Types.INTEGER
+            };
+            int count = jdbcTemplate.update(sql, args, types);
+
+            if (count > 0) {
+                builder.setCode(ResultCode.SUCCEED_VALUE);
+                cancelRegAfterRefunded(request.getRefundNo());
+            } else {
+                builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("流水号不存在或重复回调");
+            }
+        } catch (Exception e) {
+            logger.error("refundCallback({}): {}", request, e.getMessage(), e);
+            builder.setCode(ResultCode.APP_EXCEPTION_VALUE).setMsg(Constants.ERROR_INFO);
+        } finally {
+            return builder.build();
+        }
+    }
+
+    /**
+     * 挂号(线下就诊挂号,挂号信息已先保存至数据表中)
+     *
+     * @param request {@link com.ywt.gapi.taihe.register.RegisterRequest}
+     * @deprecated 接入东华 HIS 不再调用这个方法
+     */
+    @Deprecated
+    @Override
+    public RegisterResponse register(com.ywt.gapi.taihe.register.RegisterRequest request) {
+        RegisterResponse.Builder builder =
+                RegisterResponse.newBuilder();
+        try {
+            com.ywt.outpatient.domain.entity.center.RegisteredOrder registeredOrder = registeredOrderRepository.getById(request.getRegId());
+            if (registeredOrder == null) {
+                builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("regId not exist");
+                return builder.build();
+            }
+
+            com.ywt.gapi.third.taihe.RegisterResponse registerResponse = register(registeredOrder);
+            if (registerResponse.getCode() != ResultCode.SUCCEED_VALUE) {
+                builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg(registerResponse.getMsg());
+                return builder.build();
+            }
+
+            //0元号的支付状态回写到HIS系统
+            payFree(registerResponse.getOrderCode(), registeredOrder.getHisPatientId(), Checker.getIntegerValue(registeredOrder.getHospitalId()));
+
+            builder.setCode(ResultCode.SUCCEED_VALUE);
+        } catch (Exception e) {
+            logger.error("register({}): {}", request, e.getMessage(), e);
+            builder.setCode(ResultCode.APP_EXCEPTION_VALUE).setMsg(Constants.ERROR_INFO);
+        } finally {
+            return builder.build();
+        }
+    }
+
+
+    /**
+     * 取号
+     *
+     * @param request          {@link com.ywt.gapi.taihe.register.TakeRequest}
+     */
+    @Override
+    public com.ywt.gapi.taihe.register.TakeResponse take(com.ywt.gapi.taihe.register.TakeRequest request) {
+        com.ywt.gapi.taihe.register.TakeResponse.Builder builder = com.ywt.gapi.taihe.register.TakeResponse.newBuilder();
+        try {
+            // 默认太和,兼容
+            int hospitalId = request.getHospitalId() > 0 ? request.getHospitalId() : Constants.TAIHE_HOSPITAL_ID;
+            com.ywt.outpatient.domain.entity.center.RegisteredOrder registeredOrder = registeredOrderRepository.getFirstByOrderIdAndHospitalIdAndDeletedFalse(
+                    request.getOrderId(), hospitalId);
+
+            if (registeredOrder == null) {
+                builder.setCode(ResultCode.PARAMETER_ERROR_VALUE).setMsg("挂号订单不存在");
+                return builder.build();
+            }
+            if (registeredOrder.getUserId() != request.getUserId()) {
+                builder.setCode(ResultCode.PARAMETER_ERROR_VALUE).setMsg("非法请求");
+                return builder.build();
+            }
+            if (StringHelper.isNullOrWhiteSpace(registeredOrder.getHisOrderCode())) {
+                builder.setCode(ResultCode.PARAMETER_ERROR_VALUE).setMsg("订单未预约成功");
+                return builder.build();
+            }
+
+            //进行取号处理
+            com.ywt.gapi.third.taihe.TakeRequest req = com.ywt.gapi.third.taihe.TakeRequest.newBuilder()
+                    .setOrderCode(registeredOrder.getHisOrderCode())
+                    .setPatientId(registeredOrder.getHisPatientId())
+                    .setHospitalId(hospitalId)
+                    .build();
+            com.ywt.gapi.third.taihe.TakeResponse res = taiheServiceBlockingStub.take(req);
+
+            if (res.getCode() != ResultCode.SUCCEED_VALUE) {
+                builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg(res.getMsg());
+                return builder.build();
+            }
+
+            registeredOrder.setRegisteredStatus(registeredOrder.getRegisteredStatus() | RegisteredStatusEnum.Took.getValue());
+            registeredOrder.setHisClinicCode(res.getRegistrationId());
+            registeredOrderRepository.save(registeredOrder);
+
+            //发送模板消息
+            taiheWeChatMsgService.sendMsgForTook(registeredOrder);
+
+            builder.setCode(ResultCode.SUCCEED_VALUE).setHisClinicCode(Checker.getStringValue(registeredOrder.getHisClinicCode()));
+        } catch (Exception e) {
+            logger.error("take({}): {}", request, e.getMessage(), e);
+            builder.setCode(ResultCode.APP_EXCEPTION_VALUE).setMsg(Constants.ERROR_INFO);
+        } finally {
+            return builder.build();
+        }
+    }
+
+    /**
+     * 获取候诊订单列表
+     *
+     * @param request          {@link GetQueueListRequest}
+     */
+    @Override
+    public GetQueueListResponse getQueueList(GetQueueListRequest request) {
+        GetQueueListResponse.Builder builder = GetQueueListResponse.newBuilder();
+
+        try {
+            if (request.getUserId() < 1) {
+                builder.setCode(ResultCode.PARAMETER_ERROR_VALUE).setMsg("用户不存在");
+                return builder.build();
+            }
+            int hospitalId = request.getHospitalId() > 0 ? request.getHospitalId() : Constants.TAIHE_HOSPITAL_ID;
+            List<RegisteredOrder> lst = new LinkedList<>();
+            String currentDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-M-d"));
+            List<com.ywt.outpatient.domain.entity.center.RegisteredOrder> orderList = registeredOrderRepository.listQueueOrders(request.getUserId(), currentDate,
+                    hospitalId);
+
+            if (orderList != null) {
+                for (com.ywt.outpatient.domain.entity.center.RegisteredOrder order : orderList) {
+                    Date paymentDate;
+                    if (order.getPaymentTime() != null) {
+                        paymentDate = order.getPaymentTime();
+                    } else {
+                        paymentDate = order.getCreateTime();
+                    }
+
+                    int status = -1;
+                    String statusStr = "";
+                    Map<String, Integer> map = getRegisteredStatusName(order);
+                    for (Map.Entry<String, Integer> me : map.entrySet()) {
+                        //根据键值对对象获得键和值
+                        status = me.getValue();
+                        statusStr = me.getKey();
+                    }
+
+                    RegisteredOrder item = RegisteredOrder.newBuilder()
+                            .setOrderId(order.getOrderId())
+                            .setOrderNo(order.getOrderNo())
+                            .setRegisteredId(order.getId())
+                            .setUserId(order.getUserId())
+                            .setHospitalId(order.getHospitalId())
+                            .setHospitalName(BizUtil.getHospitalNameByIdSimply(order.getHospitalId()))
+                            .setRegisteredDate(DateUtil.convertToTimestamp(order.getRegisteredDate()))
+                            .setRegisteredPeriod(order.getRegisteredPeriod())
+                            .setStartTime(Checker.getStringValue(order.getStartTime()))
+                            .setEndTime(Checker.getStringValue(order.getEndTime()))
+                            .setMedicalCardId(order.getMedicalCardId())
+                            .setPatientName(order.getPatientName())
+                            .setPaymentChannel(order.getPaymentChannel())
+                            .setCreateTime(DateUtil.convertToTimestamp(order.getCreateTime()))
+                            .setDoctorCode(Checker.getStringValue(order.getDoctorCode()))
+                            .setDeptCode(Checker.getStringValue(order.getDeptCode()))
+                            .setDeptName(Checker.getStringValue(order.getDeptName()))
+                            .setRegisteredFee(order.getRegisteredFee())
+                            .setMedicalFee(order.getMedicalFee())
+                            .setPaymentStatus(order.getPaymentStatus())
+                            .setRegisteredStatus(order.getRegisteredStatus())
+                            .setTotal(order.getTotal())
+                            .setDoctorName(Checker.getStringValue(order.getDoctorName()))
+                            .setSex(Checker.getIntegerValue(order.getPatientSex()))
+                            .setHisClinicCode(Checker.getStringValue(order.getHisClinicCode()))
+                            .setAddress(Checker.getStringValue(order.getHisAdmitAddress()))
+                            .setPaymentDate(DateUtil.convertToTimestamp(paymentDate))
+                            .setStatusName(statusStr)
+                            .setStatus(status)
+                            .setHisSeqCode(Checker.getStringValue(order.getHisSeqCode()))
+                            .build();
+                    lst.add(item);
+                }
+            }
+
+            builder.setCode(ResultCode.SUCCEED_VALUE).addAllOrder(lst);
+        } catch (Exception e) {
+            logger.error("getQueueList({}): {}", request, e.getMessage(), e);
+            builder.setCode(ResultCode.APP_EXCEPTION_VALUE).setMsg(Constants.ERROR_INFO);
+        } finally {
+            return builder.build();
+        }
+    }
+
+    /**
+     * 获取太和门诊记录
+     *
+     * @param request          {@link GetCommonOrderListRequest}
+     */
+    @Override
+    public GetCommonOrderListResponse getCommonOrderList(GetCommonOrderListRequest request) {
+        GetCommonOrderListResponse.Builder builder = GetCommonOrderListResponse.newBuilder();
+        try {
+            List<Object> paramList = new LinkedList<>();
+            List<Integer> typeList = new LinkedList<>();
+            StringBuilder whereSql = new StringBuilder("user_id = ? and (order_type = ? or order_type = 13) and deleted = 0");
+            //v2.2.2版本,白云不展示线下就诊
+            if (request.getTerminal() == TerminalEnum.NFYYBYFY_WXAPP.getValue()) {
+                whereSql = new StringBuilder("user_id = ? and (order_type = ?) and deleted = 0");
+            }
+
+            paramList.add(request.getUserId());
+            paramList.add(OrderTypeEnum.REGISTERED.getValue());
+//            paramList.add(OrderType.OFFLINE_CONSULT.getValue());
+//            paramList.add(request.getTerminal());
+//            typeList.add(Types.INTEGER);
+            typeList.add(Types.INTEGER);
+            typeList.add(Types.INTEGER);
+
+            if (request.getStartDate() > 0L && request.getEndDate() > 0L && request.getStartDate() < request.getEndDate()) {
+                whereSql.append(" and create_time >= ? and create_time < ?");
+                paramList.add(new Date(request.getStartDate()));
+                paramList.add(new Date(request.getEndDate()));
+                typeList.add(Types.TIMESTAMP);
+                typeList.add(Types.TIMESTAMP);
+            }
+
+            Object[] args = paramList.toArray();
+            int[] argTypes = typeList.stream().mapToInt(i -> i).toArray();
+            String orderBy = "id desc";
+            String fields = "*";
+            PagedList<Orders> pagedList = sqlHelper.getPagedList(
+                    request.getPageIndex(), request.getPageSize(), fields, whereSql.toString(), orderBy, Orders.class, args, argTypes);
+            CommonOrder commonOrder;
+            List<CommonOrder> lst = new LinkedList<>();
+            if (pagedList.getItems() != null && pagedList.getItems().size() > 0) {
+                for (Orders item : pagedList.getItems()) {
+                    int hospitalId = 0;
+                    String hospitalName = "";
+                    String deptName = "";
+                    String doctorName = "";
+                    String doctorTitle = "";
+                    String patientName = "";
+                    int amount = 0;
+                    String statusName = "";
+                    String patientSex = "";
+                    String registeredDate = "";
+                    String startTime = "";
+                    String endTime = "";
+                    //订单是否可以取消,1-是,0-否
+                    int cancel = 0;
+                    String deptCode = "";
+                    int registeredType = 0;
+                    String hisAdmAddr = "";// HIS 就诊地点
+                    String hisPatientId = "";
+                    int subHospitalId = 0;
+                    String seqCode = "";
+                    String addr = "";
+
+                    if (item.getOrderType() == OrderTypeEnum.REGISTERED.getValue()) {
+                        com.ywt.outpatient.domain.entity.center.RegisteredOrder registeredOrder = registeredOrderRepository.getById(item.getBusinessId());
+                        if (registeredOrder == null || registeredOrder.getDeleted() || registeredOrder.getRegisteredStatus() <= 0
+                                || checkIsNetDept(registeredOrder.getDeptCode(), registeredOrder.getHospitalId())) {
+                            continue;
+                        }
+
+                        hospitalId = registeredOrder.getHospitalId();
+                        hospitalName = registeredOrder.getHospitalName();
+                        deptName = registeredOrder.getDeptName();
+                        doctorName = registeredOrder.getDoctorName();
+                        doctorTitle = registeredOrder.getDoctorTitle();
+                        patientName = registeredOrder.getPatientName();
+                        patientSex = Gender.getDisplayName(registeredOrder.getPatientSex());
+                        amount = registeredOrder.getTotal();
+                        deptCode = registeredOrder.getDeptCode();
+                        hisPatientId = registeredOrder.getHisPatientId();
+                        registeredType = Checker.getIntegerValue(registeredOrder.getRegisteredType(), RegisteredTypeEnum.GENERAL.getValue());
+                        startTime = registeredOrder.getStartTime();
+                        endTime = registeredOrder.getEndTime();
+                        seqCode = Checker.getStringValue(registeredOrder.getHisSeqCode());
+                        registeredDate = String.format("%s %s~%s"
+                                , DateUtil.formatDate(registeredOrder.getRegisteredDate() ,"yyyy-MM-dd")
+                                , registeredOrder.getStartTime()
+                                , registeredOrder.getEndTime());
+                        hisAdmAddr = Checker.getStringValue(registeredOrder.getHisAdmitAddress());
+                        if (hospitalId == Constants.NFYY_HOSPITAL_ID) {
+                            if (!StringHelper.isNullOrWhiteSpace(registeredOrder.getHisRegFee())) {
+                                //南方医院诊查费以挂号接口返回的价格为主,若HIS系统返回的 HisRegFee 字段不为空,则以该价格为主
+                                amount = (int) (Checker.parseDouble(registeredOrder.getHisRegFee()) * 100d);
+                            }
+                            statusName = getNfyyRegisteredStatusName(registeredOrder);
+                        } else if (hospitalId == Constants.TAIHE_HOSPITAL_ID || hospitalId == Constants.NFYYBYFY_HOSPITAL_ID) {
+                            statusName = getTaiheRegisteredStatusName(registeredOrder);
+                        }
+
+                        if (registeredOrder.getRegisteredStatus() == 1 || registeredOrder.getRegisteredStatus() == 5) {
+                            // 已预约或已取号状态
+                            // 从 v2.1.9_nfby 开始,白云分院的取消预约按钮显示规则修改:(太和等医院逻辑不变)
+                            // ①就诊当天00:00后,“取消预约”按钮不显示。
+                            // ②预约挂号订单有诊断的(通过his接口判断),“取消预约”按钮不显示。
+                            boolean hasDiagnose = hasDiagnose(Checker.getStringValue(registeredOrder.getHisClinicCode()),
+                                    Checker.getIntegerValue(registeredOrder.getHospitalId()));
+                            // 是否超过退号时间,规则:白云-预约日期及之后不可退号;太和等其他医院-预约日期后不可退号;
+                            boolean canTodayCancelReg = canTodayCancelReg(hospitalId, registeredOrder.getRegisteredDate());
+                            if (canTodayCancelReg && !hasDiagnose) {
+                                cancel = 1;
+                            }
+                        }
+                        subHospitalId = Checker.getIntegerValue(registeredOrder.getSubHospitalId());
+                        addr = Checker.getStringValue(registeredOrder.getHisAdmitAddress());
+                    } else if (item.getOrderType() == OrderTypeEnum.OFFLINE_CONSULT.getValue()) {
+                        OfflineConsultation consultation = offlineConsultationRepository.getById(item.getBusinessId());
+                        if (consultation == null || consultation.getDeleted()
+                                || consultation.getPaymentStatus() != PaymentStatusEnum.Success.getValue()) {
+                            continue;
+                        }
+                        if (consultation.getRefundStatus() != null &&
+                                consultation.getRefundStatus() == RefundStatusEnum.SUCCESS.getValue()) {
+                            statusName = "已退款";
+                        } else {
+                            statusName = "已支付";
+                            // 从 v2.1.9_nfby 开始,白云分院的取消预约按钮显示规则修改:(太和等医院逻辑不变)
+                            // ①就诊当天00:00后,“取消预约”按钮不显示。
+                            // ②预约挂号订单有诊断的(通过his接口判断),“取消预约”按钮不显示。
+                            int regId = Checker.getIntegerValue(consultation.getRegId());
+                            if (regId > 0) {
+                                com.ywt.outpatient.domain.entity.center.RegisteredOrder registeredOrder = registeredOrderRepository.getById(regId);
+                                boolean hasDiagnose = hasDiagnose(Checker.getStringValue(registeredOrder.getHisClinicCode()),
+                                        Checker.getIntegerValue(registeredOrder.getHospitalId()));
+                                // 是否超过退号时间,规则:白云-预约日期及之后不可退号;太和等其他医院-预约日期后不可退号;
+                                boolean canTodayCancelReg = canTodayCancelReg(hospitalId, registeredOrder.getRegisteredDate());
+                                if (canTodayCancelReg && !hasDiagnose) {
+                                    cancel = 1;
+                                }
+                            } else {
+                                logger.info("TaiheRegisterService#getCommonOrderList(bizId={}): regId 有误", item.getBusinessId());
+                            }
+                        }
+
+                        hospitalId = Checker.getIntegerValue(consultation.getHospitalId());
+                        hospitalName = Checker.getStringValue(consultation.getHospitalName());
+                        doctorName = consultation.getDoctorName();
+                        patientName = consultation.getRealName();
+                        patientSex = Gender.getDisplayName(consultation.getSex());
+                        amount = consultation.getTotal();
+
+                        deptName = "名医门诊";
+                        registeredDate = consultation.getRegisteredTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
+                        if (consultation.getRegId() != null && consultation.getRegId() > 0) {
+                            com.ywt.outpatient.domain.entity.center.RegisteredOrder registeredOrder = registeredOrderRepository.getById(consultation.getRegId());
+                            if (registeredOrder != null && !registeredOrder.getDeleted()) {
+                                if (registeredOrder.getDeptId() > 0) {
+                                    GetDeptRequest req = GetDeptRequest.newBuilder().setDeptId(registeredOrder.getDeptId()).build();
+                                    GetDeptResponse res = systemServiceBlockingStub.getDept(req);
+                                    if (res.getCode() == ResultCode.SUCCEED_VALUE) {
+                                        deptName = res.getDept().getDeptName() + "(名医门诊)";
+                                    }
+                                }
+                                registeredDate = String.format("%s %s~%s"
+                                        , DateUtil.formatDate(registeredOrder.getRegisteredDate(), "yyyy-MM-dd")
+                                        , registeredOrder.getStartTime()
+                                        , registeredOrder.getEndTime());
+                            }
+                        }
+                    }
+
+                    commonOrder = CommonOrder.newBuilder()
+                            .setOrderId(item.getId())
+                            .setOrderNo(item.getOrderNo())
+                            .setOrderType(item.getOrderType())
+                            //统一显示为 预约挂号
+                            .setOrderTitle(OrderTypeEnum.REGISTERED.getDisplayName())
+                            .setHospitalId(hospitalId)
+                            .setHospitalName(Checker.getStringValue(hospitalName))
+                            .setDeptName(Checker.getStringValue(deptName))
+                            .setDoctorName(Checker.getStringValue(doctorName))
+                            .setDoctorTitle(Checker.getStringValue(doctorTitle))
+                            .setDeptCode(deptCode)
+                            .setPatientName(patientName)
+                            .setPatientSex(patientSex)
+                            .setAmount(amount)
+                            .setRegisteredType(registeredType)
+                            .setRegisteredDate(registeredDate)
+                            .setStartTime(startTime)
+                            .setEndTime(endTime)
+                            .setStatusName(statusName)
+                            .setCancel(cancel)
+                            .setHisAdmAddr(hisAdmAddr)
+                            .setHisPatientId(hisPatientId)
+                            .setSubHospitalId(subHospitalId)
+                            .setSeqCode(seqCode)
+                            .setHisAdmAddr(addr)
+                            .build();
+                    lst.add(commonOrder);
+                }
+            }
+            builder.setCode(ResultCode.SUCCEED_VALUE)
+                    .addAllOrder(lst)
+                    .setTotalPage(pagedList.getTotalPage())
+                    .setCount(pagedList.getTotal());
+        } catch (Exception e) {
+            logger.error("getCommonOrderList({}): {}", request, e.getMessage(), e);
+            builder.setCode(ResultCode.APP_EXCEPTION_VALUE).setMsg(Constants.ERROR_INFO);
+        } finally {
+            return builder.build();
+        }
+    }
+
+    /**
+     * 判断 HIS 是否已有诊断
+     */
+    private boolean hasDiagnose(String hisClinicCode, int hospitalId) {
+        GetDiagnoseRecordRequest getDiagnoseRecordRequest = GetDiagnoseRecordRequest.newBuilder()
+                .setClinicCode(hisClinicCode)
+                .setHospitalId(hospitalId)
+                .build();
+        GetDiagnoseRecordResponse getDiagnoseRecordResponse = taiheServiceBlockingStub.getDiagnoseRecord(getDiagnoseRecordRequest);
+        if (getDiagnoseRecordResponse.getCode() == ResultCode.SUCCEED_VALUE) {
+            // 请求成功,视为已出诊断
+            return true;
+        } else {
+            logger.info("TaiheRegisterService#hasDiagnose(hisClinicCode={} , hospitalId={} ): 获取诊断失败:{}", hisClinicCode, hospitalId, getDiagnoseRecordResponse.getInfo());
+            return false;
+        }
+    }
+
+    /**
+     * 判断当前日期是否超过可退号日期
+     * <p>
+     * 规则:白云-预约日期及之后不可退号;太和等其他医院-预约日期后不可退号;
+     *
+     * @param hospitalId     医院 id
+     * @param registeredDate 挂号日期
+     * @return 是否超过可退号日期
+     */
+    private boolean canTodayCancelReg(int hospitalId, Date registeredDate) {
+        Date currentDate = new Date();
+        return hospitalId == Constants.NFYYBYFY_HOSPITAL_ID ? currentDate.before(registeredDate) : !currentDate.after(registeredDate);
+    }
+
+
+    /**
+     * 获取挂号订单列表
+     *
+     * @param request          {@link GetRegisteredListRequest}
+     */
+    @Override
+    public GetRegisteredListResponse getRegisteredList(GetRegisteredListRequest request) {
+        GetRegisteredListResponse.Builder builder = GetRegisteredListResponse.newBuilder();
+        try {
+            List<RegisteredOrder> lst = new LinkedList<>();
+            PagedList<com.ywt.outpatient.domain.entity.center.RegisteredOrder> pagedList = listRegisteredOrder(
+                    request.getPageIndex(), request.getPageSize(), request.getUserId(), 0L, 0L,
+                    request.getHospitalId(), request.getRegisteredType());
+
+            if (pagedList.getItems() != null && pagedList.getItems().size() > 0) {
+                for (com.ywt.outpatient.domain.entity.center.RegisteredOrder item : pagedList.getItems()) {
+                    int total = item.getTotal();
+                    String statusName = "";
+                    String deptName = item.getDeptName();
+
+                    if (item.getHospitalId() == Constants.TAIHE_HOSPITAL_ID || item.getHospitalId() == Constants.NFYYBYFY_HOSPITAL_ID) {
+                        statusName = getTaiheRegisteredStatusName(item);
+
+                        if (checkIsNetDept(item.getDeptCode(), item.getHospitalId())) {
+                            deptName = "名医门诊";
+                            if (item.getDeptId() > 0) {
+                                GetDeptRequest req = GetDeptRequest.newBuilder().setDeptId(item.getDeptId()).build();
+                                GetDeptResponse res = systemServiceBlockingStub.getDept(req);
+                                if (res.getCode() == ResultCode.SUCCEED_VALUE) {
+                                    deptName = res.getDept().getDeptName() + "(名医门诊)";
+                                }
+                            }
+                        }
+                    } else {
+                        statusName = getNfyyRegisteredStatusName(item);
+                        if (!StringHelper.isNullOrWhiteSpace(item.getHisRegFee())) {
+                            //南方医院诊查费以挂号接口返回的价格为主,若HIS系统返回的 HisRegFee 字段不为空,则以该价格为主
+                            total = (int) (Checker.parseDouble(item.getHisRegFee()) * 100d);
+                        }
+                    }
+                    RegisteredOrder registeredOrder = RegisteredOrder.newBuilder()
+                            .setOrderId(item.getOrderId())
+                            .setOrderNo(item.getOrderNo())
+                            .setHospitalName(Checker.getStringValue(item.getHospitalName()))
+                            .setHospitalId(Checker.getIntegerValue(item.getHospitalId()))
+                            .setRegisteredId(item.getId())
+                            .setUserId(item.getUserId())
+                            .setRegisteredDate(DateUtil.convertToTimestamp(item.getRegisteredDate()))
+                            .setRegisteredPeriod(item.getRegisteredPeriod())
+                            .setStartTime(Checker.getStringValue(item.getStartTime()))
+                            .setEndTime(Checker.getStringValue(item.getEndTime()))
+                            .setMedicalCardId(item.getMedicalCardId())
+                            .setPaymentChannel(item.getPaymentChannel())
+                            .setCreateTime(DateUtil.convertToTimestamp(item.getCreateTime()))
+                            .setDoctorCode(Checker.getStringValue(item.getDoctorCode()))
+                            .setDoctorName(item.getDoctorName())
+                            .setDeptCode(item.getDeptCode())
+                            .setDeptName(deptName)
+                            .setRegisteredFee(item.getRegisteredFee())
+                            .setRegisteredType(item.getRegisteredType())
+                            .setMedicalFee(item.getMedicalFee())
+                            .setPaymentStatus(item.getPaymentStatus())
+                            .setRegisteredStatus(item.getRegisteredStatus())
+                            .setTotal(total)
+                            .setDoctorName(item.getDoctorName())
+                            .setSex(item.getPatientSex())
+                            .setPatientName(item.getPatientName())
+                            .setStatusName(statusName)
+                            .build();
+                    lst.add(registeredOrder);
+                }
+            }
+            builder.setCode(ResultCode.SUCCEED_VALUE)
+                    .addAllOrder(lst)
+                    .setTotalPage(pagedList.getTotalPage())
+                    .setCount(pagedList.getTotal());
+        } catch (Exception e) {
+            logger.error("getRegisteredList({}): {}", request, e.getMessage(), e);
+            builder.setCode(ResultCode.APP_EXCEPTION_VALUE).setMsg(Constants.ERROR_INFO);
+        } finally {
+            return builder.build();
+        }
+    }
+
+    /**
+     * 南方医院预约挂号订单状态
+     *
+     * @param registeredOrder
+     * @return
+     */
+    private String getNfyyRegisteredStatusName(com.ywt.outpatient.domain.entity.center.RegisteredOrder registeredOrder) {
+        if ((registeredOrder.getRegisteredStatus() & RegisteredStatusEnum.Cancel.getValue()) == RegisteredStatusEnum.Cancel.getValue() ||
+                (registeredOrder.getRegisteredStatus() & RegisteredStatusEnum.Back.getValue()) == RegisteredStatusEnum.Back.getValue()) {
+            return "已取消";
+        }
+        if (registeredOrder.getPaymentStatus() == PaymentStatusEnum.Pending.getValue()) {
+            return "待支付";
+        }
+        if (registeredOrder.getPaymentStatus() == PaymentStatusEnum.Success.getValue()) {
+            String regDateStr = DateUtil.formatDate(registeredOrder.getRegisteredDate(), "yyyy-MM-dd");
+            if (registeredOrder.getEndTime() != null) {
+                regDateStr = regDateStr + " " + registeredOrder.getEndTime() + ":00";
+            } else {
+                regDateStr = regDateStr + " " + "00:00:00";
+            }
+            if (DateUtil.hourBetween(regDateStr) <= 0) {
+                return "已完成";
+            }
+            return "待就诊";
+        }
+        return "";
+    }
+
+    /**
+     * 太和分院预约挂号订单状态
+     *
+     * @param registeredOrder
+     * @return
+     */
+    private String getTaiheRegisteredStatusName(com.ywt.outpatient.domain.entity.center.RegisteredOrder registeredOrder) {
+        String statusName = "";
+        if (registeredOrder.getRefundStatus() != null && registeredOrder.getRefundStatus() == RefundStatusEnum.SUCCESS.getValue()) {
+            statusName = "已退款";
+        } else if ((registeredOrder.getRegisteredStatus() & RegisteredStatusEnum.Cancel.getValue()) == RegisteredStatusEnum.Cancel.getValue() ||
+                (registeredOrder.getRegisteredStatus() & RegisteredStatusEnum.Back.getValue()) == RegisteredStatusEnum.Back.getValue()) {
+            statusName = "已取消";
+        } else if (registeredOrder.getPaymentStatus() == PaymentStatusEnum.Pending.getValue()) {
+            statusName = "待支付";
+        } else if (registeredOrder.getPaymentStatus() == PaymentStatusEnum.Success.getValue()) {
+            statusName = "待就诊";
+
+            String regDateStr = DateUtil.formatDate(registeredOrder.getRegisteredDate(), "yyyy-MM-dd");
+            if (registeredOrder.getEndTime() != null) {
+                regDateStr = regDateStr + " " + registeredOrder.getEndTime() + ":00";
+            } else {
+                regDateStr = regDateStr + " " + "00:00:00";
+            }
+
+            LocalDateTime now = LocalDateTime.now();
+            LocalDateTime registeredTime = LocalDateTime.parse(regDateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+
+            if (now.isAfter(registeredTime)) {
+                statusName = "已完成";
+            }
+        }
+        return statusName;
+    }
+
+    /**
+     * 获取预约挂号订单状态
+     *
+     * @param registeredOrder
+     * @return
+     */
+    public Map<String, Integer> getRegisteredStatusName(com.ywt.outpatient.domain.entity.center.RegisteredOrder registeredOrder) {
+        Map<String, Integer> map = new HashMap<>(1);
+        int registeredStatus = registeredOrder.getRegisteredStatus();
+        if ((registeredStatus & RegisteredStatusEnum.Back.getValue()) == RegisteredStatusEnum.Back.getValue()) {
+            map.put("已退号", 5);
+            return map;
+        }
+        if ((registeredStatus & RegisteredStatusEnum.Expired.getValue()) == RegisteredStatusEnum.Expired.getValue()) {
+            map.put("已过期", 4);
+            return map;
+        }
+        if ((registeredStatus & RegisteredStatusEnum.Cancel.getValue()) == RegisteredStatusEnum.Cancel.getValue()) {
+            map.put("已取消", 2);
+            return map;
+        }
+        if ((registeredStatus & RegisteredStatusEnum.Took.getValue()) == RegisteredStatusEnum.Took.getValue()) {
+            map.put("已取号", 3);
+            return map;
+        }
+        if ((registeredStatus & RegisteredStatusEnum.Booked.getValue()) == RegisteredStatusEnum.Booked.getValue()) {
+            map.put("已预约", 1);
+            return map;
+        }
+
+        return map;
+    }
+
+
+    /**
+     * 发起退款
+     *
+     * @param orderId    订单Id
+     * @param orderNo    订单编号
+     * @param registerId 预约挂号表主键
+     */
+    private void refund(int orderId, String orderNo, int registerId) {
+        String sql =
+                "update registered_order " +
+                        "set refund_status = ?, refund_time = now() " +
+                        "where id = ? and (refund_status is null or refund_status = ? or refund_status = ?);";
+        Object[] args = new Object[]
+                {
+                        RefundStatusEnum.PENDING.getValue(),
+                        registerId,
+                        RefundStatusEnum.EXCEPTION.getValue(),
+                        RefundStatusEnum.CLOSED.getValue()
+                };
+        int[] types = new int[]
+                {
+                        Types.INTEGER,
+                        Types.INTEGER,
+                        Types.INTEGER,
+                        Types.INTEGER
+                };
+        int count = jdbcTemplate.update(sql, args, types);
+
+        if (count < 1) {
+            logger.info("refund({}, {}, {}): registered order not exist or refund repeatedly.", orderId, orderNo, registerId);
+            return ;
+        }
+
+        RefundRequest req = RefundRequest.newBuilder()
+                //退款金额(单位:分), 当为0时,默认该订单总金额
+                .setAmount(0)
+                .setOrderId(orderId)
+                .setOrderNo(orderNo)
+                //退款方式,1: 人工, 2: 系统
+                .setRefundType(2)
+                .setRefundNotifyMethod("/com.ywt.gapi.taihe.register.TaiheRegisterService/refundCallback")
+                .build();
+        RefundResponse res = orderCenterServiceBlockingStub.refund(req);
+
+        if (res.getCode() == ResultCode.SUCCEED_VALUE) {
+            sql = "update registered_order set refund_no = ? where id = ?;";
+            args = new Object[]{res.getRefundNo(), registerId};
+            types = new int[]{Types.VARCHAR, Types.INTEGER};
+            count = jdbcTemplate.update(sql, args, types);
+
+            if (count < 1) {
+                logger.info("refund({}, {}, {}): 退款成功,更新状态失败", orderId, orderNo, registerId);
+            }
+            return ;
+        }
+
+        //发起退款失败,还原状态
+        sql = "update registered_order set refund_status = null, refund_time = null where id = ?;";
+        args = new Object[]{registerId};
+        types = new int[]{Types.INTEGER};
+        count = jdbcTemplate.update(sql, args, types);
+
+        if (count < 1) {
+            logger.info("refund({}, {}, {}): 还原状态失败", orderId, orderNo, registerId);
+        }
+        logger.info("refund({}, {}, {}): refund failed. req: {}; res: {}", orderId, orderNo, registerId, req, res);
+    }
+
+    /**
+     * 调用HIS接口,进行挂号
+     * 若挂号成功,更新挂号信息,并且如果系统存在该挂号医生的信息,则患者会自动关注该医生
+     *
+     * @param registeredOrder 挂号订单
+     * @return {@link RegisterResponse}
+     * @deprecated 接入东华 HIS 不再调用这个方法
+     */
+    @Deprecated
+    private com.ywt.gapi.third.taihe.RegisterResponse register(com.ywt.outpatient.domain.entity.center.RegisteredOrder registeredOrder) {
+        com.ywt.gapi.third.taihe.RegisterRequest req = com.ywt.gapi.third.taihe.RegisterRequest.newBuilder()
+                .setScheduleItemCode(registeredOrder.getScheduleItemCode())
+                .setPatientId(registeredOrder.getHisPatientId())
+                .setCardNo(registeredOrder.getMedicalCardNo())
+                .setStartTime(registeredOrder.getStartTime())
+                .setEndTime(registeredOrder.getEndTime())
+                .build();
+        com.ywt.gapi.third.taihe.RegisterResponse res = taiheServiceBlockingStub.register(req);
+
+        if (res.getCode() == ResultCode.SUCCEED_VALUE) {
+            //挂号成功,更新挂号信息
+//            registeredOrderRepository.updateRegisterInfoById(res.getSeqCode(), String.valueOf(res.getRegFee())
+//                    , res.getAdmitRange(), res.getAdmitAddress(), res.getOrderContent(), ""
+//                    , res.getOrderCode(), RegisteredStatusEnum.Booked.getValue(), registeredOrder.getId());
+
+            if (registeredOrder.getDoctorId() > 0) {
+                //关注医生
+                followDoctor(registeredOrder.getUserId(), registeredOrder.getDoctorId());
+            }
+        }
+        return res;
+    }
+
+    /**
+     * 0元号的支付状态回写到HIS系统
+     *
+     * @param hisOrderCode HIS系统订单编码
+     * @param hisPatientId HIS系统患者ID(门诊ID)
+     */
+    private void payFree(String hisOrderCode, String hisPatientId, int hospitalId) {
+        PayFreeRequest req = PayFreeRequest.newBuilder()
+                .setOrderCode(hisOrderCode)
+                .setPatientId(hisPatientId)
+                .setHospitalId(hospitalId)
+                .build();
+        PayFreeResponse res = taiheServiceBlockingStub.payFree(req);
+        if (res.getCode() != ResultCode.SUCCEED_VALUE) {
+            logger.info("payFree({}, {}):0元号的支付状态回写到HIS系统失败:{}", hisOrderCode, hisPatientId, res.getMsg());
+        }
+    }
+
+    /**
+     * 关注医生(临时方法,后续该方法需迁至 UserService RPC)
+     *
+     * @param userId   用户ID
+     * @param doctorId 医生ID
+     */
+    private void followDoctor(int userId, int doctorId) {
+        UserUnions unions = userUnionsRepository.getFirstByUserIdAndUnionUserIdAndTypeAndDeletedFalse(userId, doctorId, 4);
+
+        if (unions != null) {
+            if (unions.getStatus() != 0) {
+                unions.setStatus(0);
+                unions.setUpdateTime(new Date());
+            }
+        } else {
+            unions = new UserUnions();
+            int unionsId = idGenerator.genUserUnionsId();
+            unions.setCreateTime(new Date());
+            unions.setUpdateTime(new Date());
+            unions.setDeleted(false);
+            unions.setId(unionsId);
+            // 0-启用,1-禁用(此时表示0-关注,1-不关注)
+            unions.setStatus(0);
+            unions.setType(4);
+            unions.setUserId(userId);
+            unions.setUnionUserId(doctorId);
+            unions.setHasPresc(0);
+        }
+        userUnionsRepository.save(unions);
+    }
+
+    /**
+     * 预约挂号订单列表
+     *
+     * @param pageIndex
+     * @param pageSize
+     * @param userId
+     * @param startDate
+     * @param endDate
+     * @param registeredType
+     * @param hospitalId
+     * @return
+     */
+    private PagedList<com.ywt.outpatient.domain.entity.center.RegisteredOrder> listRegisteredOrder(
+            int pageIndex, int pageSize, int userId, long startDate, long endDate, int hospitalId, int registeredType) {
+        List<Object> paramList = new LinkedList<>();
+        List<Integer> typeList = new LinkedList<>();
+        StringBuilder whereSql = new StringBuilder("user_id = ? and registered_status > 0 and deleted = 0");
+        paramList.add(userId);
+        typeList.add(Types.INTEGER);
+
+        if (hospitalId > 0) {
+            whereSql.append(" and hospital_id = ?");
+            paramList.add(hospitalId);
+            typeList.add(Types.INTEGER);
+        }
+        if (RegisteredTypeEnum.isDefined(registeredType)) {
+            whereSql.append(" and registered_type = ?");
+            paramList.add(registeredType);
+            typeList.add(Types.INTEGER);
+        }
+        if (startDate > 0L && endDate > 0L && startDate < endDate) {
+            whereSql.append(" and create_time >= ? and create_time < ?");
+            paramList.add(new Date(startDate));
+            paramList.add(new Date(endDate));
+            typeList.add(Types.TIMESTAMP);
+            typeList.add(Types.TIMESTAMP);
+        }
+
+        Object[] args = paramList.toArray();
+        int[] argTypes = typeList.stream().mapToInt(i -> i).toArray();
+        String orderBy = "id desc";
+        String fields = "*";
+        return sqlHelper.getPagedList(pageIndex, pageSize, fields, whereSql.toString(), orderBy, com.ywt.outpatient.domain.entity.center.RegisteredOrder.class, args, argTypes);
+    }
+
+    /**
+     * 无诊疗卡预约挂号
+     *
+     * @param request          {@link RegisterWithoutMedicalCardRequest}
+     */
+    @Override
+    public RegisterWithoutMedicalCardResponse registerWithoutMedicalCard(RegisterWithoutMedicalCardRequest request) {
+        RegisterWithoutMedicalCardResponse.Builder builder = RegisterWithoutMedicalCardResponse.newBuilder();
+
+        try {
+            // 默认太和,兼容
+            int hospitalId = request.getHospitalId() > 0 ? request.getHospitalId() : Constants.TAIHE_HOSPITAL_ID;
+            VerifyRegisterWithoutMedicalCardResult result = verifyCreateRegisteredRequest(request);
+            if (!result.isSuccess()) {
+                builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg(result.getMsg());
+                return builder.build();
+            }
+            RegisterRecord record = new RegisterRecord();
+            record.setHospitalId(hospitalId);
+            record.setHospitalName(BizUtil.getHospitalNameByIdSimply(hospitalId));
+            record.setDeptId(0);
+            record.setDeptCode(request.getDeptCode());
+            record.setDeptName(request.getDeptName());
+            record.setDoctorId(0);
+            record.setDoctorCode(request.getDoctorCode());
+            record.setDoctorName(request.getDoctorName());
+            record.setDoctorTitle(result.getDoctorTitle());
+            record.setMedicalFee(request.getMedicalFee());
+            record.setRegisteredFee(request.getRegisteredFee());
+            record.setTotal(request.getMedicalFee() + request.getRegisteredFee());
+            record.setRegisteredDate(DateUtil.convertToLocalDate(request.getRegisteredDate()));
+            record.setRegisteredPeriod(request.getPeriod());
+            record.setStartTime(request.getStartTime());
+            record.setEndTime(request.getEndTime());
+            record.setIdType(request.getIdType());
+            record.setIdNo(request.getIdNo());
+            record.setPatientName(request.getPatientName());
+            record.setBirthday(DateUtil.convertToLocalDate(request.getBirthday()));
+            record.setPatientSex(request.getPatientSex());
+            record.setPatientMobile(request.getPatientMobile());
+            record.setUserId(request.getUserId());
+            record.setScheduleItemCode(request.getScheduleItemCode());
+            record.setDeleted(false);
+            record.setCreateTime(LocalDateTime.now());
+            registerRecordRepository.save(record);
+            builder.setCode(ResultCode.SUCCEED_VALUE);
+
+            //发送模板消息
+            taiheWeChatMsgService.sendMsgForRegisterWithoutMedicalCard(record);
+        } catch (Exception e) {
+            logger.error("registerWithoutMedicalCard({}): {}", request, e.getMessage(), e);
+            builder.setCode(ResultCode.APP_EXCEPTION_VALUE).setMsg(Constants.ERROR_INFO);
+        } finally {
+            return builder.build();
+        }
+    }
+
+    /**
+     * 校验 RegisterWithoutMedicalCardRequest 参数是否合法
+     *
+     * @param request {@link RegisterWithoutMedicalCardRequest}
+     */
+    private VerifyRegisterWithoutMedicalCardResult verifyCreateRegisteredRequest(RegisterWithoutMedicalCardRequest request) {
+        VerifyRegisterWithoutMedicalCardResult result = new VerifyRegisterWithoutMedicalCardResult();
+        long minTimestamp = DateUtil.convertToTimestamp(LocalDate.now());
+        long maxTimestamp = DateUtil.convertToTimestamp(LocalDate.now().plusDays(8));
+        if (request.getRegisteredDate() < minTimestamp || request.getRegisteredDate() > maxTimestamp) {
+            //只能预约8天内的号源
+            return result.failed("预约日期格式不正确");
+        }
+        if (StringHelper.isNullOrWhiteSpace(request.getDeptCode()) || StringHelper.isNullOrWhiteSpace(request.getDeptName())) {
+            return result.failed("科室不存在");
+        }
+        if (StringHelper.isNullOrWhiteSpace(request.getDoctorCode()) || StringHelper.isNullOrWhiteSpace(request.getDoctorName())) {
+            return result.failed("医生不存在");
+        }
+        if (StringHelper.isNullOrWhiteSpace(request.getStartTime())) {
+            return result.failed("预约开始时间不存在");
+        }
+        if (StringHelper.isNullOrWhiteSpace(request.getEndTime())) {
+            return result.failed("预约结束时间不存在");
+        }
+        if (StringHelper.isNullOrWhiteSpace(request.getScheduleItemCode())) {
+            return result.failed("门诊排班项记录标识不能为空");
+        }
+        if (StringHelper.isNullOrWhiteSpace(request.getIdType())) {
+            return result.failed("请选择证件类型");
+        }
+        if (StringHelper.isNullOrWhiteSpace(request.getIdNo())) {
+            return result.failed("请输入证件号码");
+        }
+        if (StringHelper.isNullOrWhiteSpace(request.getPatientName())) {
+            return result.failed("姓名不能为空");
+        }
+        if (StringHelper.isNullOrWhiteSpace(request.getPatientMobile())) {
+            return result.failed("手机号不能为空");
+        }
+        if (request.getPatientSex() != Gender.FEMALE.getValue() && request.getPatientSex() != Gender.MALE.getValue()) {
+            return result.failed("请选择性别");
+        }
+        if (request.getPeriod() != RegisteredDatePeriod.MORNING.getValue() &&
+                request.getPeriod() != RegisteredDatePeriod.AFTERNOON.getValue() &&
+                request.getPeriod() != RegisteredDatePeriod.NIGHT.getValue()) {
+            return result.failed("所选择的预约时段不存在!");
+        }
+        //判断门诊排班项记录标识是否合法
+        String serviceDate = DateUtil.convertTimestampToDateString(request.getRegisteredDate(), "yyyy-MM-dd");
+//        GetScheduleTimeInfoRequest req = GetScheduleTimeInfoRequest.newBuilder()
+//                .setDeptCode(request.getDeptCode())
+//                .setDoctorCode(request.getDoctorCode())
+//                .setServiceDate(serviceDate)
+//                .setDatePeriod(request.getPeriod())
+//                .build();
+//        GetScheduleTimeInfoResponse res = taiheServiceBlockingStub.getScheduleTimeInfo(req);
+//        if (res.getCode() != ResultCode.SUCCEED_VALUE) {
+//            return result.failed(res.getMsg());
+//        }
+//        if (res.getScheduleTimeInfosList().stream().noneMatch(p -> request.getScheduleItemCode().equals(p.getScheduleItemCode()))) {
+//            return result.failed("门诊排班项记录标识不存在");
+//        }
+        //判断医生编码是否合法
+        GetScheduleListRequest getScheduleListRequest = GetScheduleListRequest.newBuilder()
+                .setDeptCode(request.getDeptCode())
+                .setDoctorCode(request.getDoctorCode())
+                .setServiceDate(serviceDate)
+                .setHospitalId(request.getHospitalId())
+                .build();
+        GetScheduleListResponse getScheduleListResponse = taiheServiceBlockingStub.getScheduleList(getScheduleListRequest);
+        if (getScheduleListResponse.getCode() != ResultCode.SUCCEED_VALUE || getScheduleListResponse.getSchedulesList().size() == 0) {
+            return result.failed("医生不存在");
+        }
+        Schedule schedule = getScheduleListResponse.getSchedulesList().stream()
+                .filter(s -> s.getDatePeriod() == Checker.getIntegerValue(request.getPeriod()))
+                .findFirst()
+                .orElse(null);
+        if (schedule == null) {
+            return result.failed("当前时间段没有匹配的排班数据!");
+        }
+        //校验传入的价格
+        if (checkIsNetDept(request.getDeptCode(), request.getHospitalId())) {
+            if (request.getMedicalFee() != 0 || request.getRegisteredFee() != 0 || request.getTotal() != 0) {
+                //名医门诊科室的挂号费为 0
+                return result.failed("问诊费不正确");
+            }
+        } else {
+            if (request.getMedicalFee() != schedule.getCheckupFee() || request.getRegisteredFee() != schedule.getRegFee()) {
+                return result.failed("诊查费不正确");
+            }
+            if (request.getTotal() != request.getMedicalFee() + request.getRegisteredFee()) {
+                return result.failed("费用不正确");
+            }
+        }
+        result.setSuccess(true);
+        result.setDoctorTitle(schedule.getDoctorTitle());
+        return result;
+    }
+
+
+    /**
+     * 判断该科室是否属于名医诊区(包括一级二级)
+     * TODO: 可以把 {@link Constants#TAIHE_NET_DEPT_CODE} 做成配置,这样以后改动可以减少代码层面的修改。
+     *
+     * @param deptCode 待判断科室
+     * @return true or false
+     */
+    public boolean checkIsNetDept(String deptCode, Integer hospitalId) {
+        // 默认太和,兼容
+        int hid = Checker.getIntegerValue(hospitalId) > 0 ? hospitalId : Constants.TAIHE_HOSPITAL_ID;
+        if (getNetDeptByHospitalId(hid).contains(deptCode)) return true;
+        HospitalDeptListRequest req = HospitalDeptListRequest.newBuilder()
+                .setHospitalId(hid)
+                .build();
+        HospitalDeptListResponse res = systemServiceBlockingStub.getHospitalDeptList(req);
+        if (res.getResult().getCode() == ResultCode.SUCCEED) {
+            List<HospitalDept> hospitalDepts = res.getHospitalDeptListList();
+            List<String> netDeptIds = new LinkedList<>();
+            if (!Checker.isNone(hospitalDepts)) {
+                List<HospitalDept> hdList = hospitalDepts.stream()
+                        .filter(hospitalDept -> getNetDeptByHospitalId(hid).contains(hospitalDept.getDeptCode())).collect(Collectors.toList());
+                for (HospitalDept hd : hdList) {
+                    netDeptIds.add(hd.getDeptCode());
+                    hd.getDeptListList().forEach(sd -> {
+                        netDeptIds.add(sd.getDeptCode());
+                    });
+                }
+                return netDeptIds.stream().anyMatch(id -> id.equals(deptCode));
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 判断该科室是否属于儿科(包括一级二级)
+     *
+     * @param deptCode 待判断科室
+     * @return true or false
+     */
+    public boolean checkIsPediatricDept(String deptCode, Integer hospitalId) {
+        // 默认太和,兼容
+        int hid = Checker.getIntegerValue(hospitalId) > 0 ? hospitalId : Constants.TAIHE_HOSPITAL_ID;
+        if (getPediatricDeptByHospitalId(hid).equals(deptCode)) return true;
+        HospitalDeptListRequest req = HospitalDeptListRequest.newBuilder()
+                .setHospitalId(hid)
+                .build();
+        HospitalDeptListResponse res = systemServiceBlockingStub.getHospitalDeptList(req);
+        if (res.getResult().getCode() == ResultCode.SUCCEED) {
+            List<HospitalDept> hospitalDepts = res.getHospitalDeptListList();
+            List<String> netDeptIds = new LinkedList<>();
+            if (!Checker.isNone(hospitalDepts)) {
+                HospitalDept hd = hospitalDepts.stream()
+                        .filter(hospitalDept -> getPediatricDeptByHospitalId(hid).equals(hospitalDept.getDeptCode())).findFirst().orElse(null);
+                if (hd != null) {
+                    netDeptIds.add(hd.getDeptCode());
+                    hd.getDeptListList().forEach(sd -> {
+                        netDeptIds.add(sd.getDeptCode());
+                    });
+                    return netDeptIds.stream().anyMatch(id -> id.equals(deptCode));
+                }
+            }
+        }
+        return false;
+    }
+
+    private String getPediatricDeptByHospitalId(int hospitalId) {
+        switch (hospitalId) {
+            case Constants.TAIHE_HOSPITAL_ID:
+                return Constants.TAIHE_PEDIATRIC_DEPT_CODE;
+            case Constants.NFYYBYFY_HOSPITAL_ID:
+                return Constants.NFYYBYFY_PEDIATRIC_DEPT_CODE;
+            default:
+                return "";
+        }
+    }
+
+    private String getInternalMedicineDeptByHospitalId(int hospitalId) {
+        switch (hospitalId) {
+            case Constants.TAIHE_HOSPITAL_ID:
+                return Constants.TAIHE_INTERNAL_MEDICINE_DEPT_CODE;
+            case Constants.NFYYBYFY_HOSPITAL_ID:
+                return Constants.NFYYBYFY_INTERNAL_MEDICINE_DEPT_CODE;
+            default:
+                return "";
+        }
+    }
+
+    private List<String> getNetDeptByHospitalId(int hospitalId) {
+        List<String> list = new ArrayList<>();
+        switch (hospitalId) {
+            case Constants.TAIHE_HOSPITAL_ID:
+                list.add(Constants.TAIHE_NET_DEPT_CODE);
+//                list.add(Constants.TAIHE_NET_DEPT_CODE_NIGHT_DIAGNOSIS);
+                break;
+            case Constants.NFYYBYFY_HOSPITAL_ID:
+                list.add(Constants.NFYYBYFY_NET_DEPT_CODE);
+                break;
+            default:
+                list.add("");
+                break;
+        }
+        return list;
+    }
+
+    /**
+     * 判断该科室是否属于内科(包括一级二级)
+     *
+     * @param deptCode 待判断科室
+     * @return true or false
+     */
+    public boolean checkIsInternalMedicineDept(String deptCode, Integer hospitalId) {
+        // 默认太和,兼容
+        int hid = Checker.getIntegerValue(hospitalId) > 0 ? hospitalId : Constants.TAIHE_HOSPITAL_ID;
+        List<String> deptCodes = Arrays.asList(getInternalMedicineDeptByHospitalId(hid).split(","));
+        if (deptCodes.contains(deptCode)) return true;
+        HospitalDeptListRequest req = HospitalDeptListRequest.newBuilder()
+                .setHospitalId(hid)
+                .build();
+        HospitalDeptListResponse res = systemServiceBlockingStub.getHospitalDeptList(req);
+        if (res.getResult().getCode() == ResultCode.SUCCEED) {
+            List<HospitalDept> hospitalDepts = res.getHospitalDeptListList();
+            List<String> netDeptIds = new LinkedList<>();
+            if (!Checker.isNone(hospitalDepts)) {
+                HospitalDept hd = hospitalDepts.stream()
+                        .filter(hospitalDept -> deptCodes.contains(hospitalDept.getDeptCode())).findFirst().orElse(null);
+                if (hd != null) {
+                    netDeptIds.add(hd.getDeptCode());
+                    hd.getDeptListList().forEach(sd -> {
+                        netDeptIds.add(sd.getDeptCode());
+                    });
+                    return netDeptIds.stream().anyMatch(id -> id.equals(deptCode));
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 根据 deptCode 获取科室信息 (二级)
+     *
+     * @param deptCode
+     * @param hospitalId
+     * @return
+     */
+    public HospitalDept getDepartmentByDeptCodeAndHospitalId(String deptCode, int hospitalId) {
+        if (Checker.isNone(deptCode)) return null;
+        HospitalDeptListRequest req = HospitalDeptListRequest.newBuilder()
+                .setHospitalId(hospitalId)
+                .build();
+        HospitalDeptListResponse res = systemServiceBlockingStub.getHospitalDeptList(req);
+        if (res.getResult().getCode() == ResultCode.SUCCEED) {
+            List<HospitalDept> hospitalDepts = res.getHospitalDeptListList();
+            if (!Checker.isNone(hospitalDepts)) {
+                // 返回的是一级嵌套二级列表,需要处理
+                return hospitalDepts.stream()
+                        .flatMap(d -> d.getDeptListList().stream())
+                        .map(d -> HospitalDept.newBuilder()
+                                .setDeptCode(d.getDeptCode())
+                                .setDeptId(d.getDeptId())
+                                .setDeptName(d.getDeptName())
+                                .build())
+                        .filter(hospitalDept -> deptCode.equals(hospitalDept.getDeptCode()))
+                        .findFirst()
+                        .orElse(null);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public GetOfflineConsultInfoByDoctorIdResponse getOfflineConsultInfoByDoctorId(GetOfflineConsultInfoByDoctorIdRequest request) {
+        GetOfflineConsultInfoByDoctorIdResponse.Builder builder = GetOfflineConsultInfoByDoctorIdResponse.newBuilder();
+        try {
+            int doctorId = request.getDoctorId();
+            // 默认太和,兼容处理
+            int hospitalId = request.getHospitalId() > 0 ? request.getHospitalId() : Constants.TAIHE_HOSPITAL_ID;
+            List<DoctorHisCode> doctorHisCodeList = doctorHisCodeRepository.getListByDoctorIdAndHospitalId(doctorId,
+                    hospitalId);
+            if (Checker.isNone(doctorHisCodeList)) {
+                throw new YwtCommonException(YwtCommonRespCode.P_ERR, "医生 id 有误");
+            }
+            DoctorHisCode netRelated = doctorHisCodeList.stream()
+                    .filter(d -> checkIsNetDept(d.getDeptCode(), hospitalId))
+                    .findFirst()
+                    .orElse(null);
+            if (netRelated == null) {
+                throw new YwtCommonException(YwtCommonRespCode.P_ERR, "找不到医生对应的科室排班信息");
+            }
+            String deptCode = netRelated.getDeptCode();
+            String doctorName = netRelated.getDoctorName();
+            String doctorHisCode = netRelated.getHisCode();
+            // 获取 deptId & deptName
+            HospitalDept hospitalDept = getDepartmentByDeptCodeAndHospitalId(deptCode, hospitalId);
+            if (hospitalDept == null) {
+                throw new YwtCommonException(YwtCommonRespCode.P_ERR, "找不到科室信息");
+            }
+            int deptId = hospitalDept.getDeptId();
+            String deptName = hospitalDept.getDeptName();
+            // 获取医生问诊费
+            DoctorRequest doctorRequest = DoctorRequest.newBuilder()
+                    .setUserid(doctorId)
+                    .build();
+            DoctorInfoResponse response = doctorServiceBlockingStub.getDoctorInfo(doctorRequest);
+            if (response.getResult().getCode() != ResultCode.SUCCEED) {
+                throw new YwtCommonException(YwtCommonRespCode.P_ERR, String.format("获取不到医生信息: %s", response.getResult().getInfo()));
+            }
+            // v3.2.0 线下就诊费用跟问诊费分开,线下就诊费用读取 offline_fee 字段
+            int consultFee = Checker.getIntegerValue(response.getInfo().getOfflineFee());
+            builder.setCode(ResultCode.SUCCEED_VALUE)
+                    .setInfo("")
+                    .setDeptCode(deptCode)
+                    .setDoctorName(doctorName)
+                    .setDoctorHisCode(doctorHisCode)
+                    .setDeptId(deptId)
+                    .setDeptName(deptName)
+                    .setConsultFee(consultFee);
+
+            return builder.build();
+        } catch (YwtCommonException e) {
+            builder.setCode(ResultCode.PARAMETER_ERROR_VALUE).setInfo(e.getMessage());
+            return builder.build();
+        } catch (Exception e) {
+            logger.error("TaiheRegisterService#getOfflineConsultInfoByDoctorId(request={}):\n {}", request, e.getMessage(), e);
+            return builder.setCode(ResultCode.APP_ERROR_VALUE).setInfo(e.getMessage()).build();
+        }
+    }
+
+    @Override
+    public GetLatestRegOrderResponse getLatestRegOrder(GetLatestRegOrderRequest request) {
+        GetLatestRegOrderResponse.Builder builder = GetLatestRegOrderResponse.newBuilder();
+        int doctorId = request.getDoctorId();
+        int userId = request.getUserId();
+        int hospitalId = request.getHospitalId();
+        try {
+            // 支付成功的都算
+            String endDate = DateUtil.convertTimestampToDateString(System.currentTimeMillis(), "yyyy-MM-dd");
+            com.ywt.outpatient.domain.entity.center.RegisteredOrder order = registeredOrderRepository.getLatestRegOrderUntilDate(doctorId, userId, endDate, hospitalId);
+            if (order != null) {
+                String regDate = DateUtil.formatDate(order.getRegisteredDate(), "yyyy-MM-dd");
+                String regDateEnd = regDate + " 18:00:00";// 挂号从就诊当天 18 点(发送消息的时间点)过后开始算
+                logger.info("regDateEnd " + regDateEnd);
+                builder.setRegisterDate(DateUtil.stringToDate(regDateEnd, "yyyy-MM-dd HH:mm:ss").getTime());
+                builder.setCode(ResultCode.SUCCEED_VALUE);
+                builder.setInfo("操作成功");
+            } else {
+                builder.setCode(ResultCode.APP_ERROR_VALUE);
+                builder.setInfo("找不到记录");
+            }
+            return builder.build();
+        } catch (Exception e) {
+            logger.error("TaiheRegisterService#getLatestRegOrder(request={}):\n {}",request, e.getMessage(), e);
+            return builder.setCode(ResultCode.APP_ERROR_VALUE).setInfo(e.getMessage()).build();
+        }
+    }
+
+    @Override
+    public CalAdditionalFeeResponse calAdditionalFee(CalAdditionalFeeRequest request) {
+        int medicalCardId = Checker.getIntegerValue(request.getMedicalCardId());
+        int medicalFee = Checker.getIntegerValue(request.getMedicalFee());
+        int registeredFee = Checker.getIntegerValue(request.getRegisteredFee());
+        int userId = Checker.getIntegerValue(request.getUserId());
+        int hospitalId = Checker.getIntegerValue(request.getHospitalId());
+        String doctorSessTypeName = Checker.getStringValue(request.getDoctorSessTypeName());
+        CalAdditionalFeeResponse.Builder builder = CalAdditionalFeeResponse.newBuilder();
+        try {
+
+            com.ywt.outpatient.domain.entity.center.MedicalCard medicalCard = medicalCardRepository.getByIdAndStatus(medicalCardId,
+                    MedicalCardStatusEnum.NORMAL.getValue());
+            logger.error("TaiheRegisterService#calAdditionalFee medicalCardId {} userId {}", medicalCardId, userId);
+            if (medicalCard == null) {
+                builder.setCode(ResultCode.PARAMETER_ERROR_VALUE).setInfo("诊疗卡不存在");
+            } else {
+                String idNo = medicalCard.getIdNo();
+                String birthday = medicalCard.getBirthday();
+                boolean isFullChargeReg = checkIsFullChargeReg(hospitalId, request.getPeriod(), doctorSessTypeName);
+                // 判断是否是公医,公医挂号费 0 元
+                boolean isFreeMedicalTreat = false;
+                if (!isFullChargeReg) {
+                    // 6 岁以下加收 30% 的挂号费
+                    int curAge = 0;
+                    try {
+                        curAge = IdCardUtil.calcAgeByIdNoAndBirthday(idNo, birthday);
+                    } catch (Exception e) {
+                        logger.error("TaiheRegisterService#calAdditionalFee(idNo={} , birthday={} ): 无法获取年龄,不加收费用,由 HIS 判断", idNo, birthday);
+                    }
+                    if (curAge < 6) {
+                        logger.info("TaiheRegisterService#calAdditionalFee : 挂号费 {} 诊查费 {}", registeredFee, medicalFee);
+                        medicalFee = (new BigDecimal("1.3")).multiply((new BigDecimal(String.valueOf(medicalFee)))).intValue();
+                    }
+                    isFreeMedicalTreat = configProvider.getFmtFlagList(hospitalId).contains(Checker.getStringValue(medicalCard.getPatientType()));
+                    if (isFreeMedicalTreat) {
+                        logger.info("TaiheRegisterService#createRegistered(): 公医,cardId: {}", request.getMedicalCardId());
+                        medicalFee = 0;
+                    }
+                } else {
+                    logger.info("TaiheRegisterService#createRegistered(): 白云夜诊");
+                }
+                int payAmount = medicalFee + registeredFee;
+                logger.info("TaiheRegisterService#calAdditionalFee :重新计算总费用:{}", payAmount);
+                builder.setCode(ResultCode.SUCCEED_VALUE).setInfo("").setPayMedicalFee(medicalFee).setPayTotal(payAmount).setIsFreeMedicalTreat(isFreeMedicalTreat);
+            }
+            return builder.build();
+        } catch (Exception e) {
+            logger.error("TaiheRegisterService#calAdditionalFee(request={}):\n {}", request, e.getMessage(), e);
+            return builder.setCode(ResultCode.APP_ERROR_VALUE).setInfo(e.getMessage()).build();
+        }
+    }
+
+    /**
+     * 根据 userId & mobile 获取 hisPatientId, 如果没有记录,会调用 HIS 接口进行建档,然后新增诊疗卡记录并返回
+     */
+    @Override
+    public GetHisPatientIdByUserIdAndMobileResponse getHisPatientIdByUserIdAndMobile(GetHisPatientIdByUserIdAndMobileRequest request) {
+        int userId = request.getUserId();
+        String mobile = request.getMobile();
+        String idCardNo = request.getCardNo();
+        String cardType = Checker.getStringValue(request.getCardType(), "1");
+        GetHisPatientIdByUserIdAndMobileResponse.Builder builder = GetHisPatientIdByUserIdAndMobileResponse.newBuilder();
+        try {
+            // 默认太和,兼容
+            int hospitalId = request.getHospitalId() > 0 ? request.getHospitalId() : Constants.TAIHE_HOSPITAL_ID;
+            String hisPatientId = "";
+            com.ywt.outpatient.domain.entity.center.MedicalCard medicalCard = medicalCardRepository.getByUserIdAndIdNoAndStatusAndHospitalIdOrderByUpdateTimeDesc(
+                    userId, idCardNo, MedicalCardStatusEnum.NORMAL.getValue(), hospitalId)
+                    .stream()
+                    .findFirst()
+                    .orElse(null);
+            if (medicalCard == null) {
+                logger.info("userId={}, idCardNo={}, mobile={}查询不到结果", userId, idCardNo, mobile);
+                com.ywt.outpatient.domain.entity.center.User user = userRepository.getByIdAndIsDeletedFalse(userId);
+                if (user == null) {
+                    throw new YwtCommonException(YwtCommonRespCode.P_ERR, String.format("用户不存在,id: %d", userId));
+                }
+                // 不能直接用 userName, 要使用 patientName, 因为用户可以添加其他患者
+                String patientName = request.getName();
+                String userName = Checker.isNone(patientName) ? Checker.getStringValue(user.getRealName()) : patientName;
+                // 查询 HIS 是否已有 姓名+身份证 绑定的卡
+                GetPatientInfoRequest getPatientInfoRequest = GetPatientInfoRequest.newBuilder()
+                        .setPatientName(userName)
+                        .setIdNo(idCardNo)
+                        .setHospitalId(hospitalId)
+                        .setCardType(cardType)
+                        .build();
+                GetPatientInfoResponse getPatientInfoResponse = taiheServiceBlockingStub.getPatientInfo(getPatientInfoRequest);
+                com.ywt.outpatient.domain.entity.center.MedicalCard mc;
+                if (getPatientInfoResponse.getCode() == ResultCode.SUCCEED_VALUE) {
+                    // 能获取到信息,插入数据
+                    PatientInfo patientInfo = getPatientInfoResponse.getPatientInfo();
+                    if (patientInfo != null) {
+                        // HIS 查询到信息,插入数据
+                        mc = addNewMedicalCard(userId, userName, mobile, Checker.getIntegerValue(user.getSex()),
+                                patientInfo.getCardNo(), patientInfo.getPatientId(),
+                                idCardNo, patientInfo.getPatientType(), request.getAddress(), hospitalId, 0, cardType);
+                    } else {
+                        if (!"1".equals(cardType)) {
+                            throw new YwtCommonException(YwtCommonRespCode.P_ERR, "港澳台患者需先到院线下建档。");
+                        }
+                        // 建档
+                        mc = createNewMedicalCard(request.getAddress(), request.getCardNo(), userId, user, userName, hospitalId, cardType);
+                    }
+                } else {
+                    if (!"1".equals(cardType)) {
+                        throw new YwtCommonException(YwtCommonRespCode.P_ERR, "港澳台患者需先到院线下建档。");
+                    }
+                    logger.error("获取就诊卡信息失败,patientName: {}, idCardNo: {}: {}", userName, idCardNo, getPatientInfoResponse.getMsg());
+                    // 建档
+                    mc = createNewMedicalCard(request.getAddress(), request.getCardNo(), userId, user, userName, hospitalId, cardType);
+                }
+                hisPatientId = mc.getHisPatientId();
+            } else {
+                hisPatientId = Checker.getStringValue(medicalCard.getHisPatientId());
+            }
+            // 更新 patient 的 idCardNo & address
+            try {
+                int patId = Integer.parseInt(request.getPatientNo());
+                Patient patient = patientRepository.getById(patId);
+                if (patient != null) {
+                    if (StringHelper.isNullOrEmpty(patient.getAddress())) {
+                        patient.setAddress(request.getAddress());
+                    }
+                    if (StringHelper.isNullOrEmpty(patient.getIdCardNo())) {
+                        patient.setIdCardNo(request.getCardNo());
+                    }
+                    patientRepository.save(patient);
+                } else {
+                    logger.warn("TaiheRegisterService#getHisPatientIdByUserIdAndMobile(): 找不到该患者 patId: {}", patId);
+                }
+            } catch (NumberFormatException e) {
+                logger.error("TaiheRegisterService#getHisPatientIdByUserIdAndMobile(): 解析 patientNo 出错 patientNo: {}", request.getPatientNo());
+            }
+            builder.setCode(ResultCode.SUCCEED_VALUE)
+                    .setHisPatientId(hisPatientId);
+            return builder.build();
+        } catch (YwtCommonException ame) {
+            builder.setCode(ResultCode.PARAMETER_ERROR_VALUE)
+                    .setInfo(Checker.getStringValue(ame.getMessage()));
+            return builder.build();
+        } catch (Exception e) {
+            logger.error("TaiheRegisterService#getHisPatientIdByUserIdAndMobile(request={}):\n {}", request, e.getMessage(), e);
+            builder.setCode(ResultCode.APP_ERROR_VALUE)
+                    .setInfo(e.getMessage());
+            return builder.build();
+        }
+    }
+
+    /**
+     * 调用 HIS 接口建档,建档成功后新建就诊卡
+     */
+    private com.ywt.outpatient.domain.entity.center.MedicalCard createNewMedicalCard4HIS(String address, String cardNo, String city, String userName, String mobile,
+                                                                                         String isInsu, int hospitalId, int userId, int sex, int relationship, String cardType) throws YwtCommonException {
+        com.ywt.outpatient.domain.entity.center.MedicalCard mc;
+        CreatePatInfoRequest createPatInfoRequest = CreatePatInfoRequest.newBuilder()
+                .setAddress(Checker.getStringValue(address))
+                .setIdNo(Checker.getStringValue(cardNo))
+                .setPatientName(userName)
+                .setCity(city)
+                .setPhoneNo(mobile)
+                .setIsInsu(isInsu)
+                .setHospitalId(hospitalId)
+                .build();
+        CreatePatInfoResponse createPatInfoResponse = taiheServiceBlockingStub.createPatInfo(createPatInfoRequest);
+        if (createPatInfoResponse.getCode() != ResultCode.SUCCEED_VALUE) {
+//            throw new AppMessageException(String.format("HIS 建档:%s", createPatInfoResponse.getInfo()));
+            throw new YwtCommonException(YwtCommonRespCode.P_ERR, createPatInfoResponse.getInfo());
+        }
+        // 建档成功,新增诊疗卡记录
+        mc = addNewMedicalCard(userId, userName, mobile, sex, createPatInfoResponse.getPatientCard(),
+                createPatInfoResponse.getPatientId(), cardNo, "", address, hospitalId, relationship, cardType);// TODO: 2020/6/18 patientType 没有返回
+        return mc;
+    }
+
+    /**
+     * 一键挂号调用的建档方法,具体实现已重写到 createNewMedicalCard4HIS
+     */
+    private com.ywt.outpatient.domain.entity.center.MedicalCard createNewMedicalCard(String address, String cardNo, int userId,
+                                                                                     com.ywt.outpatient.domain.entity.center.User user, String userName,
+                                                                                     int hospitalId, String cardType) throws YwtCommonException {
+        return createNewMedicalCard4HIS(Checker.getStringValue(address), Checker.getStringValue(cardNo),
+                Checker.getStringValue(user.getCity()), userName, Checker.getStringValue(user.getMobile()), "",
+                hospitalId, userId, Checker.getIntegerValue(user.getSex()), 0, cardType);
+    }
+
+    private com.ywt.outpatient.domain.entity.center.MedicalCard addNewMedicalCard(int userId, String patientName, String mobile, int sex, String cardNo,
+                                                                                  String hisPatientId, String idCardNo, String patientType, String address,
+                                                                                  int hospitalId, int relationship, String cardType) {
+
+        GetPatientInfoRequest getPatientInfoRequest = GetPatientInfoRequest.newBuilder()
+                .setPatientName(patientName)
+                .setIdNo(idCardNo)
+                .setHospitalId(hospitalId)
+                .setCardType(cardType)
+                .build();
+        GetPatientInfoResponse getPatientInfoResponse = taiheServiceBlockingStub.getPatientInfo(getPatientInfoRequest);
+        if (getPatientInfoResponse.getCode() == ResultCode.SUCCEED_VALUE) {
+            PatientInfo patientInfo = getPatientInfoResponse.getPatientInfo();
+            patientType = Checker.getStringValue(patientInfo.getPatientType());
+        }
+
+        com.ywt.outpatient.domain.entity.center.MedicalCard mc = new com.ywt.outpatient.domain.entity.center.MedicalCard();
+        mc.setId(idGenerator.genMedicalCardId());
+        mc.setUserId(userId);
+        mc.setHospitalId(hospitalId);
+        mc.setCardNo(cardNo);
+        mc.setIdNo(idCardNo);
+        mc.setAddress(address);
+        mc.setHisPatientId(hisPatientId);
+        mc.setCardType(cardType);
+        mc.setPatientName(patientName);
+        mc.setMobile(mobile);
+        mc.setSex(Checker.getIntegerValue(sex));
+        mc.setBalance(0);
+        mc.setStatus(MedicalCardStatusEnum.NORMAL.getValue());
+        mc.setCreateTime(new Date());
+        mc.setPatientType(patientType);
+        if (relationship > 0) {
+            mc.setRelationship(relationship);
+        }
+        medicalCardRepository.save(mc);
+        return mc;
+
+    }
+
+    /**
+     * 调用 HIS 接口建档,建档成功后新建就诊卡
+     */
+    @Override
+    public CreateMedicalCardResponse createMedicalCard(CreateMedicalCardRequest request) {
+        CreateMedicalCardResponse.Builder builder = CreateMedicalCardResponse.newBuilder();
+        String phoneNo = request.getPhoneNo();
+        String idNo = request.getIdNo();
+        String patientName = request.getPatientName();
+        String city = request.getCity();
+        String address = request.getAddress();
+        String isInsu = request.getIsInsu();
+        int relationship = request.getRelationship();
+        int userId = request.getUserId();
+        int hospitalId = request.getHospitalId();
+        int terminal = request.getTerminal();
+        String idCardNoType = "1";
+        String cardType = Checker.getStringValue(request.getCardType(), idCardNoType);
+        try {
+            logger.info("createMedicalCard:phoneNo={}, idNo={}, patientName={}, city={}, address={}, isInsu={}, relationship={}, userId={}, hospitalId={}, cardType={}",
+                    phoneNo, idNo, patientName, city, address, isInsu, relationship, userId, hospitalId, cardType);
+            // 如果不是身份证
+            if (!idCardNoType.equals(cardType)) {
+                // 港澳台身份证
+                // 如果前端传入的是大陆身份证,但提交的类型是港澳台类型,这里需要返回错误提示
+                if (IdCardUtil.verifyMainlandIdCard(idNo)) {
+                    throw new YwtCommonException(YwtCommonRespCode.P_ERR, "“身份证号”或“证件类型”有误,建档不成功,请修改!");
+                }
+                int sex = IdCardUtil.getSexIntWithGAT(idNo);
+                // 查询 HIS 是否已有 姓名+身份证 绑定的卡
+                // 先查一次数据库有没有存在建卡记录
+                com.ywt.outpatient.domain.entity.center.MedicalCard card = medicalCardRepository.getByUserIdAndPatientNameAndIdNoAndCardTypeAndHospitalIdAndStatus(userId,
+                        patientName, idNo, cardType, hospitalId, MedicalCardStatusEnum.NORMAL.getValue());
+                if (card != null) {
+                    if (relationship > 0) {
+                        card.setRelationship(relationship);
+                        medicalCardRepository.save(card);
+
+                    }
+                    builder.setCode(ResultCode.SUCCEED_VALUE)
+                            .setInfo("已有诊疗卡")
+                            .setMedicalCardId(card.getId());
+                } else {
+                    GetPatientInfoRequest getPatientInfoRequest = GetPatientInfoRequest.newBuilder()
+                            .setPatientName(patientName)
+                            .setIdNo(idNo)
+                            .setHospitalId(hospitalId)
+                            .setCardType(cardType)
+                            .build();
+                    GetPatientInfoResponse getPatientInfoResponse = taiheServiceBlockingStub.getPatientInfo(getPatientInfoRequest);
+                    if (getPatientInfoResponse.getCode() == ResultCode.SUCCEED_VALUE) {
+                        PatientInfo patientInfo = getPatientInfoResponse.getPatientInfo();
+                        String rMobile = patientInfo.getMobile();
+                        String rPatientName = patientInfo.getPatientName();
+                        String rIdNo = patientInfo.getIdNo();
+                        String patientType = Checker.getStringValue(patientInfo.getPatientType());
+                        if (phoneNo.equals(rMobile) && patientName.equals(rPatientName) && idNo.equals(rIdNo)) {
+                            // 用户提交的手机号、姓名、身份证跟 HIS 查询到的信息一致,自动创建诊疗卡
+                            com.ywt.outpatient.domain.entity.center.MedicalCard mc = addNewMedicalCard(userId, patientName, phoneNo, sex, patientInfo.getCardNo(),
+                                    patientInfo.getPatientId(), idNo, patientType, address, hospitalId, relationship, cardType);
+                            builder.setCode(ResultCode.SUCCEED_VALUE)
+                                    .setInfo("已有诊疗卡,绑定成功")
+                                    .setMedicalCardId(mc.getId());
+                            sendMsgForCreateCard(userId, hospitalId, mc, terminal);
+
+                        } else {
+                            // 信息不一致,不建卡,直接返回 HIS 的错误提示
+                            logger.error("TaiheRegisterService#createMedicalCard(): 用户信息与 HIS 信息不一致({}-{}, {}-{}, {}-{}, {})",
+                                    phoneNo, rMobile, patientName, rPatientName, idNo, rIdNo, cardType);
+                            builder.setCode(ResultCode.APP_ERROR_VALUE)
+                                    .setInfo("个人信息与预留在院系统信息不一致");
+                        }
+                    } else {
+                        logger.error("TaiheRegisterService#createMedicalCard({}, {}, {}, {}): 无法获取患者信息:{}",
+                                patientName, idNo, hospitalId, cardType, getPatientInfoResponse.getMsg());
+                        builder.setCode(ResultCode.APP_ERROR_VALUE)
+                                .setInfo("港澳台患者需先到院线下建档。");
+                    }
+                }
+            } else {
+                // 大陆身份证
+                if (!IdCardUtil.verifyMainlandIdCard(idNo)) {
+                    throw new YwtCommonException(YwtCommonRespCode.P_ERR, "“身份证号”或“证件类型”有误,建档不成功,请修改!");
+                }
+                // 根据配置做实名校验
+                HisMedCardConfig config = configProvider.getHisMedCardConfig(hospitalId);
+                if (config != null && Checker.getBooleanValue(config.getNameAuth())) {
+                    ValidateIdCardResponse validateIdCardResponse = idCardServiceBlockingStub.validateIdCard(ValidateIdCardRequest.newBuilder()
+                            .setIdCardNo(idNo)
+                            .setRealName(patientName)
+                            .build());
+                    if (validateIdCardResponse.getCode() != ResultCode.SUCCEED_VALUE)
+                        throw new YwtCommonException(YwtCommonRespCode.P_ERR, String.format("实名校验:%s", validateIdCardResponse.getInfo()));
+                    if (!validateIdCardResponse.getValid())
+                        throw new YwtCommonException(YwtCommonRespCode.P_ERR, String.format("实名校验:%s(^%s^%s^)", validateIdCardResponse.getInfo(),
+                                idNo, patientName));
+                }
+                CheckUtil.ensureNotEmpty(phoneNo, "手机号不能为空");
+                CheckUtil.ensureNotEmpty(patientName, "患者姓名不能为空");
+                CheckUtil.ensureNotEmpty(city, "在线建卡市区不能为空");
+                CheckUtil.ensureNotEmpty(address, "详细地址不能为空");
+                CheckUtil.ensureLargerThanZero(hospitalId, "请指定医院");
+                CheckUtil.ensureLargerThanZero(userId, "请登录后操作");
+                com.ywt.outpatient.domain.entity.center.User user = new com.ywt.outpatient.domain.entity.center.User();
+                user.setCity(city);
+                user.setMobile(phoneNo);
+                int sex = IdCardUtil.getSexInt(idNo);
+                user.setSex(sex);
+                try {
+                    com.ywt.outpatient.domain.entity.center.MedicalCard medicalCard = createNewMedicalCard4HIS(address, idNo, city, patientName, phoneNo, isInsu, hospitalId,
+                            userId, IdCardUtil.getSexInt(idNo), relationship, cardType);
+                    builder.setCode(ResultCode.SUCCEED_VALUE)
+                            .setMedicalCardId(medicalCard.getId())
+                            .setMedicalCardNo(medicalCard.getCardNo());
+                    sendMsgForCreateCard(userId, hospitalId, medicalCard, terminal);
+                } catch (YwtCommonException e) {
+                    // 建卡 HIS 返回失败,查询 HIS 是否已有 姓名+身份证 绑定的卡
+                    // 先查一次数据库有没有存在建卡记录
+                    com.ywt.outpatient.domain.entity.center.MedicalCard card = medicalCardRepository.getByUserIdAndPatientNameAndIdNoAndCardTypeAndHospitalIdAndStatus(userId,
+                            patientName, idNo, cardType, hospitalId, MedicalCardStatusEnum.NORMAL.getValue());
+                    if (card != null) {
+                        if (relationship > 0) {
+                            card.setRelationship(relationship);
+                            medicalCardRepository.save(card);
+                        }
+                        builder.setCode(ResultCode.SUCCEED_VALUE)
+                                .setInfo("已有诊疗卡")
+                                .setMedicalCardId(card.getId());
+                    } else {
+                        GetPatientInfoRequest getPatientInfoRequest = GetPatientInfoRequest.newBuilder()
+                                .setPatientName(patientName)
+                                .setIdNo(idNo)
+                                .setHospitalId(hospitalId)
+                                .setCardType(cardType)
+                                .build();
+                        GetPatientInfoResponse getPatientInfoResponse = taiheServiceBlockingStub.getPatientInfo(getPatientInfoRequest);
+                        if (getPatientInfoResponse.getCode() == ResultCode.SUCCEED_VALUE) {
+                            PatientInfo patientInfo = getPatientInfoResponse.getPatientInfo();
+                            String rMobile = patientInfo.getMobile();
+                            String rPatientName = patientInfo.getPatientName();
+                            String rIdNo = patientInfo.getIdNo();
+                            String patientType = Checker.getStringValue(patientInfo.getPatientType());
+                            if (phoneNo.equals(rMobile) && patientName.equals(rPatientName) && idNo.equals(rIdNo)) {
+                                // 用户提交的手机号、姓名、身份证跟 HIS 查询到的信息一致,自动创建诊疗卡
+                                MedicalCard mc = addNewMedicalCard(userId, patientName, phoneNo, sex, patientInfo.getCardNo(),
+                                        patientInfo.getPatientId(), idNo, patientType, address, hospitalId, relationship, cardType);
+                                builder.setCode(ResultCode.SUCCEED_VALUE)
+                                        .setInfo("已有诊疗卡,绑定成功")
+                                        .setMedicalCardId(mc.getId());
+                                sendMsgForCreateCard(userId, hospitalId, mc, terminal);
+                            } else {
+                                // 信息不一致,不建卡,直接返回 HIS 的错误提示
+                                logger.error("TaiheRegisterService#createMedicalCard(): 用户信息与 HIS 信息不一致({}-{}, {}-{}, {}-{}, {})",
+                                        phoneNo, rMobile, patientName, rPatientName, idNo, rIdNo, cardType);
+                                builder.setCode(ResultCode.APP_ERROR_VALUE)
+                                        .setInfo("个人信息与预留在院系统信息不一致");
+                            }
+                        } else {
+                            logger.error("TaiheRegisterService#createMedicalCard({}, {}, {}, {}): 无法获取患者信息:{}",
+                                    patientName, idNo, hospitalId, cardType, getPatientInfoResponse.getMsg());
+                            builder.setCode(ResultCode.APP_ERROR_VALUE)
+                                    .setInfo(getPatientInfoResponse.getMsg());
+                        }
+                    }
+                }
+            }
+            return builder.build();
+        } catch (YwtCommonException e) {
+            builder.setCode(ResultCode.PARAMETER_ERROR_VALUE).setInfo(e.getMessage());
+            return builder.build();
+        } catch (Exception e) {
+            logger.error("TaiheRegisterService#createMedicalCard(request={}):\n {}", request, e.getMessage(), e);
+            builder.setCode(ResultCode.APP_EXCEPTION_VALUE).setInfo(e.getMessage());
+            return builder.build();
+        }
+    }
+
+    public void sendMsgForCreateCard(int userId, int hospital, com.ywt.outpatient.domain.entity.center.MedicalCard card, int terminal) {
+
+        int age = 0;
+        String realAge = "";
+        String idNo = Checker.getStringValue(card.getIdNo());
+        String birthday = Checker.getStringValue(card.getBirthday());
+        try {
+            age = IdCardUtil.calcAgeByIdNoAndBirthday(idNo, birthday);
+            realAge = String.valueOf(age);
+        } catch (YwtCommonException e) {
+            e.printStackTrace();
+            logger.error("TaiheRegisterService#calAdditionalFee(idNo={} , birthday={} ): 无法获取身份证与生日", idNo, birthday);
+        }
+        String sexStr = "";
+        String cardNo = card.getCardNo() + "(ID号:" + card.getHisPatientId() + ")";
+        sexStr = card.getSex() == 1 ? "男" : "女";
+        taiheWeChatMsgService.sendMsgForCreateMedicalCard(userId, cardNo, card.getPatientName(), sexStr, realAge, hospital);
+        int terminalHosp = getHospByTerminal(terminal);
+        if (terminalHosp != hospital && terminalHosp > 0) {
+            taiheWeChatMsgService.sendMsgForCreateMedicalCard(userId, cardNo, card.getPatientName(), sexStr, realAge, terminalHosp);
+        }
+
+    }
+
+    public int getHospByTerminal(int terminal) {
+        int hospital = 0;
+        if (terminal == TerminalEnum.TaiheWxOfficial.getValue()) {
+            hospital = Constants.TAIHE_HOSPITAL_ID;
+        }
+        if (terminal == TerminalEnum.NFYYBYFY_WXAPP.getValue()) {
+            hospital = Constants.NFYYBYFY_HOSPITAL_ID;
+        }
+        return hospital;
+    }
+
+    @Override
+    public RegisterCheckInMessageResponse registerCheckInMessage(RegisterCheckInMessageRequest request) {
+        RegisterCheckInMessageResponse.Builder builder = RegisterCheckInMessageResponse.newBuilder();
+        int userId = request.getUserId();
+        int hospitalId = request.getHospitalId();
+        String name = request.getPatName();
+        String deptName = request.getAdmLoc();
+        String regDate = request.getAdmArriveDate();
+        String queueNo = Checker.getStringValue(request.getQueueNo());
+        String areaId = request.getAreaCode();
+        String cardNo = request.getCardNo();
+        String admBoroughDesc = Checker.getStringValue(request.getAdmBoroughDesc());
+        String rangeTime = Checker.getStringValue(request.getRangTime());
+        String doctorName = Checker.getStringValue(request.getAdmDoc());
+        try {
+//                   String doctorName = order.getDoctorName();
+//                   String regTime = regDate + "    " + order.getStartTime() + "-" + order.getEndTime();
+            String date = getCurrentDate();
+            String regTime = date + "    " + rangeTime;
+
+            logger.info("TaiheWeChatMsgService#sendMsgForRegister(): 白云小程序挂太和的号再发一条消息到白云公众号");
+
+            if (hospitalId == 41) {
+                GetSnsUserInfoResponse response = userServiceBlockingStub.getSnsUserInfo(GetSnsUserInfoRequest.newBuilder()
+                        .setUserId(userId)
+                        .setTerminal(OFFICAIL)
+                        .build());
+                String openId = "";
+                String unionId = "";
+                if (response.getCode() != 0 || (response.getCode() == 0 && Checker.isNone(response.getSnsUserInfo().getOpenId()))) {
+
+                    String templateId = "6-WClPs06KY0CJWGHoLqgkq0W7mwXsdpMJtWhCD31Qs";
+                    String page = String.format(Constants.CHECK_IN_DETAIL, areaId, cardNo, "false");
+                    Map<String, String> keywordMap = new HashMap();
+                    keywordMap.put("thing3", "南方医科大学南方医院白云分院");
+                    keywordMap.put("thing4", deptName);
+                    keywordMap.put("thing5", doctorName);
+                    String thing1 = "您已报道成功,序列号为" + queueNo + ",请在候诊区等候,,叫号后请到" + admBoroughDesc + "就诊。门诊开诊时间:周一到周五8:00-12:00,13:00-16:00,周六周日:8:00-12:00。";
+                    keywordMap.put("thing1", thing1);
+
+                    GetSnsUserInfoResponse snsResponse = userServiceBlockingStub.getSnsUserInfo(GetSnsUserInfoRequest.newBuilder()
+                            .setUserId(userId)
+                            .setTerminal(MIN)
+                            .build());
+                    if (snsResponse.getCode() == 0) {
+                        openId = snsResponse.getSnsUserInfo().getOpenId();
+                        weChatMsgProvider.sendMPSubscribeMessage(MIN, openId, templateId, page, keywordMap);
+                    }
+                }
+            }
+            nfYwtWeChatMsgService.sendMsgForCheckIn(name, queueNo, deptName, areaId, cardNo, doctorName, regTime, admBoroughDesc, userId, hospitalId);
+            builder.setCode(ResultCode.SUCCEED_VALUE);
+            builder.setInfo("操作成功");
+            return builder.build();
+        } catch (Exception e) {
+            logger.error("TaiheRegisterService#registerCheckInMessage(request={}):\n {}", request, e.getMessage(), e);
+            builder.setCode(ResultCode.APP_EXCEPTION_VALUE).setInfo(e.getMessage());
+            return builder.build();
+        }
+    }
+
+    private String getCurrentDate() {
+        try {
+            String value = DateUtil.formatDate(new Date(), DateUtil.DADE_FROMAT_YMD);
+            return value;
+        } catch (Exception e) {
+            logger.error("TaiheRegisterService#getCurrentDate({}): {}", e.getMessage(), e);
+        }
+        return "";
+    }
+
+    private boolean checkIsFullChargeReg(int hospitalId, int period, String doctorSessTypeName) {
+        boolean isFullChargeReg = (hospitalId == Constants.NFYYBYFY_HOSPITAL_ID || hospitalId == Constants.TAIHE_HOSPITAL_ID) &&
+                (RegisteredDatePeriod.NIGHT == RegisteredDatePeriod.valueOf(period)
+                        || RegisteredDatePeriod.MIDNOON == RegisteredDatePeriod.valueOf(period))
+                || (configProvider.getHisRegisteredFeeFlagList(hospitalId).contains(doctorSessTypeName));
+        return isFullChargeReg;
+    }
+
+}
+

+ 4 - 0
ywt-platform-outpatient-sdk/pom.xml

@@ -84,5 +84,9 @@
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-csv</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
     </dependencies>
 </project>

+ 4 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/DoctorHisCodeRepository.java

@@ -30,4 +30,8 @@ public interface DoctorHisCodeRepository extends JpaRepository<DoctorHisCode, In
 
     @Query(value = "select * from doctor_his_code where hospital_id = ? and his_code = ? and deleted = 0",nativeQuery = true)
     List<DoctorHisCode> getAllDoctorByHisCode(int hospitalId, String hisCode);
+
+    @Query(value = "select * from doctor_his_code where doctor_id = ? and hospital_id = ? and deleted = 0;", nativeQuery = true)
+    List<DoctorHisCode> getListByDoctorIdAndHospitalId(int doctorId, int hospitalId);
+
 }

+ 18 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/MedicalCardRepository.java

@@ -43,4 +43,22 @@ public interface MedicalCardRepository extends JpaRepository<MedicalCard, Intege
 
     @Query(value = "select * from medical_card where id = ? and status = 1 limit 1;", nativeQuery = true)
     MedicalCard getCardByCardId(int cardId);
+
+    @Query(value = "select * from ywt_center.medical_card where user_id = ? and card_no = ? and hospital_id = ? limit 1", nativeQuery = true)
+    MedicalCard getByUserIdAndCardNoAndHospitalId(int userId, String cardNo, int hospitalId);
+
+    /**
+     * 获取 MedicalCard
+     *
+     * @param id     主键
+     * @param status 状态 {@link com.ywt.outpatient.domain.models.enums.MedicalCardStatusEnum}
+     * @return {@link MedicalCard}
+     */
+    MedicalCard getByIdAndStatus(int id, int status);
+
+    List<MedicalCard> getByUserIdAndIdNoAndStatusAndHospitalIdOrderByUpdateTimeDesc(int userId, String idNo, int status, int hospitalId);
+    @Query(value = "select * from ywt_center.medical_card where user_id = ? and patient_name = ? and id_no = ? and card_type = ? and hospital_id = ? and status = ? limit 1", nativeQuery = true)
+    MedicalCard getByUserIdAndPatientNameAndIdNoAndCardTypeAndHospitalIdAndStatus(int userId, String name, String idNo, String cardType, int hospitalId, int status);
+
+
 }

+ 347 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/MriScreening.java

@@ -0,0 +1,347 @@
+package com.ywt.outpatient.domain.entity.center;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * mri筛查表
+ */
+@Table(name = "mri_screening")
+@Entity
+public class MriScreening implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * mri筛查表,主键ID
+     */
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id", insertable = false, nullable = false)
+    private Integer id;
+
+    /**
+     * 患者姓名
+     */
+    @Column(name = "patient_name")
+    private String patientName;
+
+    /**
+     * 1-男,2-女,0-未知
+     */
+    @Column(name = "sex")
+    private Integer sex = 0;
+
+    /**
+     * 出生年月日
+     */
+    @Column(name = "birthday")
+    private Date birthday;
+
+    /**
+     * 患者手机号
+     */
+    @Column(name = "patient_mobile")
+    private String patientMobile;
+
+    /**
+     * 家庭住址
+     */
+    @Column(name = "address")
+    private String address;
+
+    /**
+     * 基础病史(用于后台统计)
+     */
+    @Column(name = "base_disease_history_mg")
+    private String baseDiseaseHistoryMg;
+
+    /**
+     * 遗传病史(用于后台统计)
+     */
+    @Column(name = "genetic_disease_history_mg")
+    private String geneticDiseaseHistoryMg;
+
+    /**
+     * 生活习惯(用于后台统计)
+     */
+    @Column(name = "living_habits_mg")
+    private String livingHabitsMg;
+
+    /**
+     * 临床症状(用于后台统计)
+     */
+    @Column(name = "clinical_symptoms_mg")
+    private String clinicalSymptomsMg;
+
+    /**
+     * 磁共振检查结果
+     */
+    @Column(name = "rmi_result")
+    private String rmiResult;
+
+    /**
+     * 是否删除(标识物理删除)
+     */
+    @Column(name = "deleted", nullable = false)
+    private Integer deleted = 0;
+
+    /**
+     * 创建时间
+     */
+    @Column(name = "create_time")
+    private Date createTime;
+
+    /**
+     * 修改时间
+     */
+    @Column(name = "update_time")
+    private Date updateTime;
+
+    @Column(name = "user_id", nullable = false)
+    private Integer userId;
+
+    @Column(name = "submit_content", nullable = false)
+    private String submitContent;
+
+    @Column(name = "completed")
+    private Boolean completed;
+
+    /**
+     * mri筛查表,主键ID
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * mri筛查表,主键ID
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    /**
+     * 患者姓名
+     */
+    public String getPatientName() {
+        return patientName;
+    }
+
+    /**
+     * 患者姓名
+     */
+    public void setPatientName(String patientName) {
+        this.patientName = patientName;
+    }
+
+    /**
+     * 1-男,2-女,0-未知
+     */
+    public Integer getSex() {
+        return sex;
+    }
+
+    /**
+     * 1-男,2-女,0-未知
+     */
+    public void setSex(Integer sex) {
+        this.sex = sex;
+    }
+
+    /**
+     * 出生年月日
+     */
+    public Date getBirthday() {
+        return birthday;
+    }
+
+    /**
+     * 出生年月日
+     */
+    public void setBirthday(Date birthday) {
+        this.birthday = birthday;
+    }
+
+    /**
+     * 患者手机号
+     */
+    public String getPatientMobile() {
+        return patientMobile;
+    }
+
+    /**
+     * 患者手机号
+     */
+    public void setPatientMobile(String patientMobile) {
+        this.patientMobile = patientMobile;
+    }
+
+    /**
+     * 家庭住址
+     */
+    public String getAddress() {
+        return address;
+    }
+
+    /**
+     * 家庭住址
+     */
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    /**
+     * 基础病史(用于后台统计)
+     */
+    public String getBaseDiseaseHistoryMg() {
+        return baseDiseaseHistoryMg;
+    }
+
+    /**
+     * 基础病史(用于后台统计)
+     */
+    public void setBaseDiseaseHistoryMg(String baseDiseaseHistoryMg) {
+        this.baseDiseaseHistoryMg = baseDiseaseHistoryMg;
+    }
+
+    /**
+     * 遗传病史(用于后台统计)
+     */
+    public String getGeneticDiseaseHistoryMg() {
+        return geneticDiseaseHistoryMg;
+    }
+
+    /**
+     * 遗传病史(用于后台统计)
+     */
+    public void setGeneticDiseaseHistoryMg(String geneticDiseaseHistoryMg) {
+        this.geneticDiseaseHistoryMg = geneticDiseaseHistoryMg;
+    }
+
+    /**
+     * 生活习惯(用于后台统计)
+     */
+    public String getLivingHabitsMg() {
+        return livingHabitsMg;
+    }
+
+    /**
+     * 生活习惯(用于后台统计)
+     */
+    public void setLivingHabitsMg(String livingHabitsMg) {
+        this.livingHabitsMg = livingHabitsMg;
+    }
+
+    /**
+     * 临床症状(用于后台统计)
+     */
+    public String getClinicalSymptomsMg() {
+        return clinicalSymptomsMg;
+    }
+
+    /**
+     * 临床症状(用于后台统计)
+     */
+    public void setClinicalSymptomsMg(String clinicalSymptomsMg) {
+        this.clinicalSymptomsMg = clinicalSymptomsMg;
+    }
+
+    /**
+     * 磁共振检查结果
+     */
+    public String getRmiResult() {
+        return rmiResult;
+    }
+
+    /**
+     * 磁共振检查结果
+     */
+    public void setRmiResult(String rmiResult) {
+        this.rmiResult = rmiResult;
+    }
+
+    /**
+     * 是否删除(标识物理删除)
+     */
+    public Integer getDeleted() {
+        return deleted;
+    }
+
+    /**
+     * 是否删除(标识物理删除)
+     */
+    public void setDeleted(Integer deleted) {
+        this.deleted = deleted;
+    }
+
+    /**
+     * 创建时间
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * 创建时间
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    /**
+     * 修改时间
+     */
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    /**
+     * 修改时间
+     */
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    public String getSubmitContent() {
+        return submitContent;
+    }
+
+    public void setSubmitContent(String submitContent) {
+        this.submitContent = submitContent;
+    }
+
+    public Boolean getCompleted() {
+        return completed;
+    }
+
+    public void setCompleted(Boolean completed) {
+        this.completed = completed;
+    }
+
+    public String toString() {
+      return "MriScreening{id=" + id + 
+        ", patientName=" + patientName + 
+        ", sex=" + sex + 
+        ", birthday=" + birthday + 
+        ", patientMobile=" + patientMobile + 
+        ", address=" + address + 
+        ", baseDiseaseHistoryMg=" + baseDiseaseHistoryMg + 
+        ", geneticDiseaseHistoryMg=" + geneticDiseaseHistoryMg + 
+        ", livingHabitsMg=" + livingHabitsMg + 
+        ", clinicalSymptomsMg=" + clinicalSymptomsMg + 
+        ", rmiResult=" + rmiResult + 
+        ", deleted=" + deleted + 
+        ", createTime=" + createTime + 
+        ", updateTime=" + updateTime + 
+        "}";
+    }
+}

+ 238 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/MriScreeningQuestionOptions.java

@@ -0,0 +1,238 @@
+package com.ywt.outpatient.domain.entity.center;
+
+import javax.persistence.*;
+import java.sql.Timestamp;
+
+/**
+ * mri筛查问题选项表(存放问题)
+ */
+@Table(name = "mri_screening_question_options")
+@Entity
+public class MriScreeningQuestionOptions {
+    /**
+     * mri筛查选项表,主键ID
+     */
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id", insertable = false, nullable = false)
+    private Integer id;
+
+    /**
+     * mri分类ID
+     */
+    @Column(name = "category_id")
+    private Integer categoryId;
+
+    /**
+     * mri分类名称
+     */
+    @Column(name = "category_name")
+    private String categoryName;
+
+    /**
+     * mri问题、选项名称
+     */
+    @Column(name = "name")
+    private String name;
+
+    /**
+     * 问题ID
+     */
+    @Column(name = "question_id", nullable = false)
+    private Integer questionId;
+
+    /**
+     * 问题父类ID
+     */
+    @Column(name = "parent_id", nullable = false)
+    private Integer parentId;
+
+    /**
+     * 权重,从小到大
+     */
+    @Column(name = "weight", nullable = false)
+    private Integer weight;
+
+    /**
+     * 是否删除(标识物理删除)
+     */
+    @Column(name = "deleted", nullable = false)
+    private Integer deleted = 0;
+
+    /**
+     * 创建时间
+     */
+    @Column(name = "create_time")
+    private Timestamp createTime;
+
+    /**
+     * 修改时间
+     */
+    @Column(name = "update_time")
+    private Timestamp updateTime;
+
+    @Column(name = "level", nullable = false)
+    private Integer level;
+
+    /**
+     * mri筛查选项表,主键ID
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * mri筛查选项表,主键ID
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    /**
+     * mri分类ID
+     */
+    public Integer getCategoryId() {
+        return categoryId;
+    }
+
+    /**
+     * mri分类ID
+     */
+    public void setCategoryId(Integer categoryId) {
+        this.categoryId = categoryId;
+    }
+
+    /**
+     * mri分类名称
+     */
+    public String getCategoryName() {
+        return categoryName;
+    }
+
+    /**
+     * mri分类名称
+     */
+    public void setCategoryName(String categoryName) {
+        this.categoryName = categoryName;
+    }
+
+    /**
+     * mri问题、选项名称
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * mri问题、选项名称
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * 问题ID
+     */
+    public Integer getQuestionId() {
+        return questionId;
+    }
+
+    /**
+     * 问题ID
+     */
+    public void setQuestionId(Integer questionId) {
+        this.questionId = questionId;
+    }
+
+    /**
+     * 问题父类ID
+     */
+    public Integer getParentId() {
+        return parentId;
+    }
+
+    /**
+     * 问题父类ID
+     */
+    public void setParentId(Integer parentId) {
+        this.parentId = parentId;
+    }
+
+    /**
+     * 权重,从小到大
+     */
+    public Integer getWeight() {
+        return weight;
+    }
+
+    /**
+     * 权重,从小到大
+     */
+    public void setWeight(Integer weight) {
+        this.weight = weight;
+    }
+
+    /**
+     * 是否删除(标识物理删除)
+     */
+    public Integer getDeleted() {
+        return deleted;
+    }
+
+    /**
+     * 是否删除(标识物理删除)
+     */
+    public void setDeleted(Integer deleted) {
+        this.deleted = deleted;
+    }
+
+    /**
+     * 创建时间
+     */
+    public Timestamp getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * 创建时间
+     */
+    public void setCreateTime(Timestamp createTime) {
+        this.createTime = createTime;
+    }
+
+    /**
+     * 修改时间
+     */
+    public Timestamp getUpdateTime() {
+        return updateTime;
+    }
+
+    public Integer getLevel() {
+        return level;
+    }
+
+    public void setLevel(Integer level) {
+        this.level = level;
+    }
+
+    /**
+     * 修改时间
+     */
+    public void setUpdateTime(Timestamp updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public String toString() {
+      return "MriScreeningQuestionOptions{id=" + id + 
+        ", categoryId=" + categoryId + 
+        ", categoryName=" + categoryName + 
+        ", name=" + name + 
+        ", questionId=" + questionId + 
+        ", parentId=" + parentId + 
+        ", weight=" + weight + 
+        ", deleted=" + deleted + 
+        ", createTime=" + createTime + 
+        ", updateTime=" + updateTime + 
+        "}";
+    }
+}

+ 10 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/MriScreeningQuestionOptionsRepository.java

@@ -0,0 +1,10 @@
+package com.ywt.outpatient.domain.entity.center;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+import java.util.List;
+
+public interface MriScreeningQuestionOptionsRepository extends JpaRepository<MriScreeningQuestionOptions, Integer>, JpaSpecificationExecutor<MriScreeningQuestionOptions> {
+    List<MriScreeningQuestionOptions> findAllByDeletedOrderByWeightAsc(int deleted);
+}

+ 8 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/MriScreeningRepository.java

@@ -0,0 +1,8 @@
+package com.ywt.outpatient.domain.entity.center;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+public interface MriScreeningRepository extends JpaRepository<MriScreening, Integer>, JpaSpecificationExecutor<MriScreening> {
+    MriScreening findFirstByUserIdOrderByUpdateTimeDesc(int userId);
+}

+ 225 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/MriSubscribe.java

@@ -0,0 +1,225 @@
+package com.ywt.outpatient.domain.entity.center;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * mri预约表
+ */
+@Entity
+@Table(name = "mri_subscribe")
+public class MriSubscribe implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * mri结果表,主键ID
+     */
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id", insertable = false, nullable = false)
+    private Integer id;
+
+    /**
+     * 患者姓名
+     */
+    @Column(name = "patient_name")
+    private String patientName;
+
+    /**
+     * 1-男,2-女,0-未知
+     */
+    @Column(name = "sex")
+    private Integer sex = 0;
+
+    /**
+     * 患者手机号
+     */
+    @Column(name = "patient_mobile")
+    private String patientMobile;
+
+    /**
+     * 预约时间
+     */
+    @Column(name = "subscribe_time")
+    private Date subscribeTime;
+
+    /**
+     * 是否删除(标识物理删除)
+     */
+    @Column(name = "deleted", nullable = false)
+    private Integer deleted = 0;
+
+    /**
+     * 创建时间
+     */
+    @Column(name = "create_time")
+    private Date createTime;
+
+    /**
+     * 修改时间
+     */
+    @Column(name = "update_time")
+    private Date updateTime;
+
+    @Column(name = "user_id")
+    private Integer userId;
+
+    /**
+     *
+     * 状态,0-正常,1-取消
+     */
+    @Column(name = "status")
+    private Integer status;
+
+    @Column(name = "break_promise")
+    private Integer breakPromise;
+
+    /**
+     * mri结果表,主键ID
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * mri结果表,主键ID
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    /**
+     * 患者姓名
+     */
+    public String getPatientName() {
+        return patientName;
+    }
+
+    /**
+     * 患者姓名
+     */
+    public void setPatientName(String patientName) {
+        this.patientName = patientName;
+    }
+
+    /**
+     * 1-男,2-女,0-未知
+     */
+    public Integer getSex() {
+        return sex;
+    }
+
+    /**
+     * 1-男,2-女,0-未知
+     */
+    public void setSex(Integer sex) {
+        this.sex = sex;
+    }
+
+    /**
+     * 患者手机号
+     */
+    public String getPatientMobile() {
+        return patientMobile;
+    }
+
+    /**
+     * 患者手机号
+     */
+    public void setPatientMobile(String patientMobile) {
+        this.patientMobile = patientMobile;
+    }
+
+    /**
+     * 预约时间
+     */
+    public Date getSubscribeTime() {
+        return subscribeTime;
+    }
+
+    /**
+     * 预约时间
+     */
+    public void setSubscribeTime(Date subscribeTime) {
+        this.subscribeTime = subscribeTime;
+    }
+
+    /**
+     * 是否删除(标识物理删除)
+     */
+    public Integer getDeleted() {
+        return deleted;
+    }
+
+    /**
+     * 是否删除(标识物理删除)
+     */
+    public void setDeleted(Integer deleted) {
+        this.deleted = deleted;
+    }
+
+    /**
+     * 创建时间
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * 创建时间
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    /**
+     * 修改时间
+     */
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    /**
+     * 修改时间
+     */
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public Integer getBreakPromise() {
+        return breakPromise;
+    }
+
+    public void setBreakPromise(Integer breakPromise) {
+        this.breakPromise = breakPromise;
+    }
+
+    public String toString() {
+      return "MriSubscribe{id=" + id + 
+        ", patientName=" + patientName + 
+        ", sex=" + sex + 
+        ", patientMobile=" + patientMobile + 
+        ", subscribeTime=" + subscribeTime + 
+        ", deleted=" + deleted + 
+        ", createTime=" + createTime + 
+        ", updateTime=" + updateTime + 
+        "}";
+    }
+}

+ 21 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/MriSubscribeRepository.java

@@ -0,0 +1,21 @@
+package com.ywt.outpatient.domain.entity.center;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.Date;
+import java.util.List;
+
+public interface MriSubscribeRepository extends JpaRepository<MriSubscribe, Integer>, JpaSpecificationExecutor<MriSubscribe> {
+
+    @Query(value = "select * from mri_subscribe where patient_mobile = ? and subscribe_time = ? and (status is null or status = 0) and deleted = 0 limit 1", nativeQuery = true)
+    MriSubscribe findFirstByPatientMobileAndSubscribeTime(String patientMobile, Date subscribeTime);
+
+    // 已取消的预约也计算未就诊次数
+    @Query(value = "select * from mri_subscribe where patient_mobile = ? and deleted = 0 and break_promise = 1", nativeQuery = true)
+    List<MriSubscribe> findByPatientMobileForBreakPromise(String patientMobile);
+
+    @Query(value = "select * from mri_subscribe where subscribe_time = ? and (status is null or status = 0) and deleted = 0 ", nativeQuery = true)
+    List<MriSubscribe> findBySubscribeTime(Date subscribeTime);
+}

+ 7 - 6
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/OfflineConsultation.java

@@ -2,6 +2,7 @@ package com.ywt.outpatient.domain.entity.center;
 
 import javax.persistence.*;
 import java.io.Serializable;
+import java.time.LocalDateTime;
 import java.util.Date;
 
 /**
@@ -118,11 +119,11 @@ public class OfflineConsultation implements Serializable {
 
     //预约日期
     @Column(name = "registered_time")
-    private Date registeredTime;
+    private LocalDateTime registeredTime;
 
     //用户取消时间
     @Column(name = "cancel_time")
-    private Date cancelTime;
+    private LocalDateTime cancelTime;
 
     //预约挂号订单(registered_order)主键
     @Column(name = "reg_id")
@@ -368,19 +369,19 @@ public class OfflineConsultation implements Serializable {
         this.source = source;
     }
 
-    public Date getRegisteredTime() {
+    public LocalDateTime getRegisteredTime() {
         return registeredTime;
     }
 
-    public void setRegisteredTime(Date registeredTime) {
+    public void setRegisteredTime(LocalDateTime registeredTime) {
         this.registeredTime = registeredTime;
     }
 
-    public Date getCancelTime() {
+    public LocalDateTime getCancelTime() {
         return cancelTime;
     }
 
-    public void setCancelTime(Date cancelTime) {
+    public void setCancelTime(LocalDateTime cancelTime) {
         this.cancelTime = cancelTime;
     }
 

+ 11 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/OrderPaymentRepository.java

@@ -32,4 +32,15 @@ public interface OrderPaymentRepository extends JpaRepository<OrderPayment, Inte
      */
     OrderPayment getFirstByPaymentNo(String paymentNo);
 
+    /**
+     * 根据orderId获取订单支付信息
+     *
+     * @param orderId       订单id
+     * @param paymentStatus 支付状态 {@link com.ywt.taihe.rpc.domain.enums.PaymentStatus}
+     * @return {@link OrderPayment}
+     */
+    @Query(value = "select * from order_payment where order_id = ? and payment_status = ? and deleted = 0 order by create_time desc limit 1;", nativeQuery = true)
+    OrderPayment getFirstByOrderIdAndPaymentStatusAndDeletedFalseOrderByCreateTimeDesc(int orderId, int paymentStatus);
+
+
 }

+ 424 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/Orders.java

@@ -0,0 +1,424 @@
+package com.ywt.outpatient.domain.entity.center;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * (Orders)实体类
+ *
+ * @author johnson lin
+ * @since 2019-05-24 10:03:50
+ */
+@Entity
+@Table(name = "orders")
+public class Orders implements Serializable {
+    private static final long serialVersionUID = -86511659857167035L;
+    
+       /**
+    * 主键
+    */
+    @Id
+    @Column(name = "id")
+    private Integer id;
+    
+    /**
+     * 订单编号
+     */
+    @Column(name = "order_no")
+    private String orderNo;
+    
+    /**
+     * 订单状态 (10-待付款,20-已付款,30-已退款,40-已取消,50-已结束)
+     */
+    @Column(name = "order_status")
+    private Integer orderStatus;
+    
+    /**
+     * 用户id
+     */
+    @Column(name = "user_id")
+    private Integer userId;
+    
+    /**
+     * 患者手机号
+     */
+    @Column(name = "patient_mobile")
+    private String patientMobile;
+    
+    /**
+     * 创建时间
+     */
+    @Column(name = "create_time")
+    private LocalDateTime createTime;
+    
+    /**
+     * 订单金额
+     */
+    @Column(name = "order_amount")
+    private Double orderAmount;
+    
+    /**
+     * 支付状态(0-待支付,1-支付处理中,2-支付成功,3-支付失败)
+     */
+    @Column(name = "payment_status")
+    private Integer paymentStatus;
+    
+    /**
+     * 订单备注
+     */
+    @Column(name = "remark")
+    private String remark;
+    
+    /**
+     * 是否删除(标识物理删除)
+     */
+    @Column(name = "is_deleted")
+    private Integer isDeleted;
+    
+    /**
+     * 订单类型(1-询诊,2-转诊,3-主诊)
+     */
+    @Column(name = "order_type")
+    private Integer orderType;
+    
+    /**
+     * 业务Id
+     */
+    @Column(name = "business_id")
+    private Integer businessId;
+    
+    /**
+     * 医生id
+     */
+    @Column(name = "doctor_id")
+    private Integer doctorId;
+    
+    /**
+     * 订单标题
+     */
+    @Column(name = "title")
+    private String title;
+    
+    @Column(name = "prepay_id")
+    private String prepayId;
+    
+    @Column(name = "deleted")
+    private Integer deleted;
+    
+    /**
+     * 订单来源
+     */
+    @Column(name = "terminal")
+    private Integer terminal;
+    
+    /**
+     * 支付成功后回调grpc方法
+     */
+    @Column(name = "payment_callback_method")
+    private String paymentCallbackMethod;
+    
+    /**
+     * 支付成功后回调rest url
+     */
+    @Column(name = "payment_callback_rest_url")
+    private String paymentCallbackRestUrl;
+    
+    /**
+     * 自定义数据
+     */
+    @Column(name = "custom")
+    private String custom;
+    
+    /**
+     * 支付代码--支付中心统一编码
+     */
+    @Column(name = "pay_code")
+    private String payCode;
+    
+    /**
+     * 支付明细描述
+     */
+    @Column(name = "pay_body")
+    private String payBody;
+    
+    /**
+     * 根据终端配置不同的支付代码(JSON格式)
+     */
+    @Column(name = "pay_code_with_terminal")
+    private String payCodeWithTerminal;
+    
+    /**
+     * 支付流水号
+     */
+    @Column(name = "payment_no")
+    private String paymentNo;
+    
+    /**
+     * 已退款总金额,单位:分
+     */
+    @Column(name = "refunded_amount")
+    private Integer refundedAmount;
+    
+    /**
+     * 支付完成时间
+     */
+    @Column(name = "pay_time")
+    private LocalDateTime payTime;
+    
+    /**
+     * 补帐
+     */
+    @Column(name = "fill_account")
+    private Integer fillAccount;
+    
+    /**
+     * 补帐时间
+     */
+    @Column(name = "fill_time")
+    private LocalDateTime fillTime;
+    
+    /**
+     * 补帐操作人
+     */
+    @Column(name = "fill_op_by")
+    private String fillOpBy;
+    
+
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getOrderNo() {
+        return orderNo;
+    }
+
+    public void setOrderNo(String orderNo) {
+        this.orderNo = orderNo;
+    }
+
+    public Integer getOrderStatus() {
+        return orderStatus;
+    }
+
+    public void setOrderStatus(Integer orderStatus) {
+        this.orderStatus = orderStatus;
+    }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    public String getPatientMobile() {
+        return patientMobile;
+    }
+
+    public void setPatientMobile(String patientMobile) {
+        this.patientMobile = patientMobile;
+    }
+
+    public LocalDateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(LocalDateTime createTime) {
+        this.createTime = createTime;
+    }
+
+    public Double getOrderAmount() {
+        return orderAmount;
+    }
+
+    public void setOrderAmount(Double orderAmount) {
+        this.orderAmount = orderAmount;
+    }
+
+    public Integer getPaymentStatus() {
+        return paymentStatus;
+    }
+
+    public void setPaymentStatus(Integer paymentStatus) {
+        this.paymentStatus = paymentStatus;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public Integer getIsDeleted() {
+        return isDeleted;
+    }
+
+    public void setIsDeleted(Integer isDeleted) {
+        this.isDeleted = isDeleted;
+    }
+
+    public Integer getOrderType() {
+        return orderType;
+    }
+
+    public void setOrderType(Integer orderType) {
+        this.orderType = orderType;
+    }
+
+    public Integer getBusinessId() {
+        return businessId;
+    }
+
+    public void setBusinessId(Integer businessId) {
+        this.businessId = businessId;
+    }
+
+    public Integer getDoctorId() {
+        return doctorId;
+    }
+
+    public void setDoctorId(Integer doctorId) {
+        this.doctorId = doctorId;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getPrepayId() {
+        return prepayId;
+    }
+
+    public void setPrepayId(String prepayId) {
+        this.prepayId = prepayId;
+    }
+
+    public Integer getDeleted() {
+        return deleted;
+    }
+
+    public void setDeleted(Integer deleted) {
+        this.deleted = deleted;
+    }
+
+    public Integer getTerminal() {
+        return terminal;
+    }
+
+    public void setTerminal(Integer terminal) {
+        this.terminal = terminal;
+    }
+
+    public String getPaymentCallbackMethod() {
+        return paymentCallbackMethod;
+    }
+
+    public void setPaymentCallbackMethod(String paymentCallbackMethod) {
+        this.paymentCallbackMethod = paymentCallbackMethod;
+    }
+
+    public String getPaymentCallbackRestUrl() {
+        return paymentCallbackRestUrl;
+    }
+
+    public void setPaymentCallbackRestUrl(String paymentCallbackRestUrl) {
+        this.paymentCallbackRestUrl = paymentCallbackRestUrl;
+    }
+
+    public String getCustom() {
+        return custom;
+    }
+
+    public void setCustom(String custom) {
+        this.custom = custom;
+    }
+
+    public String getPayCode() {
+        return payCode;
+    }
+
+    public void setPayCode(String payCode) {
+        this.payCode = payCode;
+    }
+
+    public String getPayBody() {
+        return payBody;
+    }
+
+    public void setPayBody(String payBody) {
+        this.payBody = payBody;
+    }
+
+    public String getPayCodeWithTerminal() {
+        return payCodeWithTerminal;
+    }
+
+    public void setPayCodeWithTerminal(String payCodeWithTerminal) {
+        this.payCodeWithTerminal = payCodeWithTerminal;
+    }
+
+    public String getPaymentNo() {
+        return paymentNo;
+    }
+
+    public void setPaymentNo(String paymentNo) {
+        this.paymentNo = paymentNo;
+    }
+
+    public Integer getRefundedAmount() {
+        return refundedAmount;
+    }
+
+    public void setRefundedAmount(Integer refundedAmount) {
+        this.refundedAmount = refundedAmount;
+    }
+
+    public LocalDateTime getPayTime() {
+        return payTime;
+    }
+
+    public void setPayTime(LocalDateTime payTime) {
+        this.payTime = payTime;
+    }
+
+    public Integer getFillAccount() {
+        return fillAccount;
+    }
+
+    public void setFillAccount(Integer fillAccount) {
+        this.fillAccount = fillAccount;
+    }
+
+    public LocalDateTime getFillTime() {
+        return fillTime;
+    }
+
+    public void setFillTime(LocalDateTime fillTime) {
+        this.fillTime = fillTime;
+    }
+
+    public String getFillOpBy() {
+        return fillOpBy;
+    }
+
+    public void setFillOpBy(String fillOpBy) {
+        this.fillOpBy = fillOpBy;
+    }
+
+}

+ 13 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/OrdersRepository.java

@@ -0,0 +1,13 @@
+package com.ywt.outpatient.domain.entity.center;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+/**
+ * (Orders)表Repository类
+ *
+ * @author johnson lin
+ * @since 2019-05-24 10:03:50
+ */
+public interface OrdersRepository extends JpaRepository<Orders, Integer> {
+
+}

+ 238 - 172
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/OutpatientOrder.java

@@ -4,18 +4,20 @@ import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.Id;
 import javax.persistence.Table;
+import java.io.Serializable;
+import java.time.LocalDateTime;
 import java.util.Date;
 
 @Entity
 @Table(name = "outpatient_order")
-public class OutpatientOrder {
+public class OutpatientOrder implements Serializable {
+    private static final long serialVersionUID = -20150319591256672L;
+
     @Id
+    @Column(name = "id")
     private Integer id;
 
-    /**
-     * 医院Id
-     */
-    @Column(name = "hospital_id", nullable = false)
+    @Column(name = "hospital_id")
     private Integer hospitalId;
 
     @Column(name = "hospital_name")
@@ -36,25 +38,25 @@ public class OutpatientOrder {
     /**
      * 总费用
      */
-    @Column(name = "total", nullable = false)
+    @Column(name = "total")
     private Integer total;
 
     /**
      * 医保报销
      */
-    @Column(name = "reimbursement", nullable = false)
+    @Column(name = "reimbursement")
     private Integer reimbursement;
 
     /**
      * 个人金额
      */
-    @Column(name = "individual", nullable = false)
+    @Column(name = "individual")
     private Integer individual;
 
-    @Column(name = "payment_status", nullable = false)
+    @Column(name = "payment_status")
     private Integer paymentStatus;
 
-    @Column(name = "outpatient_status", nullable = false)
+    @Column(name = "outpatient_status")
     private Integer outpatientStatus;
 
     @Column(name = "user_id")
@@ -64,7 +66,7 @@ public class OutpatientOrder {
     private String hisPatientId;
 
     @Column(name = "pay_time")
-    private Date payTime;
+    private LocalDateTime payTime;
 
     /**
      * 微信商户Id
@@ -84,33 +86,27 @@ public class OutpatientOrder {
     @Column(name = "wx_transaction_id")
     private String wxTransactionId;
 
-    /**
-     * 是否删除(标识物理删除)
-     */
-    @Column(name = "deleted", nullable = false)
+    @Column(name = "deleted")
     private Boolean deleted;
 
-    /**
-     * 创建时间
-     */
-    @Column(name = "create_time", nullable = false)
-    private Date createTime;
+    @Column(name = "create_time")
+    private LocalDateTime createTime;
 
-    /**
-     * 就诊流水号
-     */
     @Column(name = "his_clinic_code")
     private String hisClinicCode;
 
-    /**
-     * HIS订单号
-     */
-    @Column(name = "his_order_no", nullable = false)
+    @Column(name = "his_order_no")
     private String hisOrderNo;
 
-    @Column(name = "pay_name", nullable = false)
+    @Column(name = "pay_name")
     private String payName;
 
+    /**
+     * 处方生成日期
+     */
+    @Column(name = "prescription_date")
+    private LocalDateTime prescriptionDate;
+
     @Column(name = "patient_name")
     private String patientName;
 
@@ -121,16 +117,10 @@ public class OutpatientOrder {
     private Integer patientSex;
 
     /**
-     * 处方单生成日期
-     */
-    @Column(name = "prescription_date")
-    private Date prescriptionDate;
-
-    /**
      * 修改时间
      */
     @Column(name = "update_time")
-    private Date updateTime;
+    private LocalDateTime updateTime;
 
     @Column(name = "insure_key")
     private String insureKey;
@@ -141,48 +131,120 @@ public class OutpatientOrder {
     @Column(name = "insure_treatment_type")
     private String insureTreatmentType;
 
-    //身份证号
-    @Column(name = "id_no")
-    private String idNo;
-
-    //支付流水号
-    @Column(name = "payment_no")
-    private String paymentNo;
-
-    //退款状态
+    /**
+     * 退款状态
+     */
     @Column(name = "refund_status")
     private Integer refundStatus;
 
-    //退款时间
+    /**
+     * 退款时间
+     */
     @Column(name = "refund_time")
-    private Date refund_time;
+    private LocalDateTime refundTime;
 
-    //退款流水号
+    /**
+     * 退款流水号
+     */
     @Column(name = "refund_no")
     private String refundNo;
 
-    //退款回调时间
+    /**
+     * 退款回调时间
+     */
     @Column(name = "refund_callback_time")
-    private Date refundCallbackTime;
+    private String refundCallbackTime;
 
-    //订单ID
+    /**
+     * 订单ID
+     */
     @Column(name = "order_id")
     private Integer orderId;
 
-    //订单号
+    /**
+     * 订单编码
+     */
     @Column(name = "order_no")
     private String orderNo;
 
-    //支付渠道
+    /**
+     * 身份证号码
+     */
+    @Column(name = "id_no")
+    private String idNo;
+
+    /**
+     * 支付流水号
+     */
+    @Column(name = "payment_no")
+    private String paymentNo;
+
+    /**
+     * 支付渠道
+     */
     @Column(name = "payment_channel")
     private Integer paymentChannel;
 
-    @Column(name = "order_ins_type")
-    private String orderInsType;
+    @Column(name = "express")
+    private Integer express;
+
+    /**
+     * 用于退款时填写的备注
+     */
+    @Column(name = "refund_remark")
+    private String refundRemark;
+
+    /**
+     * 取药方式
+     */
+    @Column(name = "delivery_method")
+    private Integer deliveryMethod;
+
+    /**
+     * 送货地址/药店地址
+     */
+    @Column(name = "address_id")
+    private Integer addressId;
+
+    /**
+     * 邮费
+     */
+    @Column(name = "postage")
+    private Integer postage;
+
+    /**
+     * 开始时间
+     */
+    @Column(name = "start_send_time")
+    private LocalDateTime startSendTime;
+
+    /**
+     * 完成时间
+     */
+    @Column(name = "finish_send_time")
+    private LocalDateTime finishSendTime;
+
+    /**
+     * 配送号
+     */
+    @Column(name = "send_no")
+    private String sendNo;
+
+    /**
+     * 时效标准(快递的预计送达时间)
+     */
+    @Column(name = "time_standard")
+    private String timeStandard;
+
+    /**
+     * 个人支付总额
+     */
+    @Column(name = "amount")
+    private Integer amount;
+
     @Column(name = "invoice_no")
     private String invoiceNo;
-    @Column(name = "resp_log")
-    private String respLog;
+
     /**
      * 医保支付类型:1-自费,2-医保
      */
@@ -195,31 +257,11 @@ public class OutpatientOrder {
     private String medRefundId;
     @Column(name = "med_pay_url")
     private String medPayUrl;
-    @Column(name = "ins_row_id")
-    private String insRowId;
-    @Column(name = "ins_upload_fee_resp")
-    private String insUploadFeeResp;
-    @Column(name = "ins_pay_callback_resp")
-    private String insPayCallbackResp;
-    @Column(name = "ins_return_str")
-    private String insReturnStr;
+    @Column(name = "med_pay_app_id")
+    private String medPayAppId;
+
     @Column(name = "ins_tx_return_str")
     private String insTxReturnStr;
-    @Column(name = "insu_div_dr")
-    private String insuDivDr;
-    @Column(name = "med_ins_type")
-    private Integer medInsType;
-
-    @Column(name = "terminal")
-    private Integer terminal;
-
-    public String getOrderInsType() {
-        return orderInsType;
-    }
-
-    public void setOrderInsType(String orderInsType) {
-        this.orderInsType = orderInsType;
-    }
 
     public Integer getId() {
         return id;
@@ -333,11 +375,11 @@ public class OutpatientOrder {
         this.hisPatientId = hisPatientId;
     }
 
-    public Date getPayTime() {
+    public LocalDateTime getPayTime() {
         return payTime;
     }
 
-    public void setPayTime(Date payTime) {
+    public void setPayTime(LocalDateTime payTime) {
         this.payTime = payTime;
     }
 
@@ -373,11 +415,11 @@ public class OutpatientOrder {
         this.deleted = deleted;
     }
 
-    public Date getCreateTime() {
+    public LocalDateTime getCreateTime() {
         return createTime;
     }
 
-    public void setCreateTime(Date createTime) {
+    public void setCreateTime(LocalDateTime createTime) {
         this.createTime = createTime;
     }
 
@@ -397,14 +439,6 @@ public class OutpatientOrder {
         this.hisOrderNo = hisOrderNo;
     }
 
-    public Date getPrescriptionDate() {
-        return prescriptionDate;
-    }
-
-    public void setPrescriptionDate(Date prescriptionDate) {
-        this.prescriptionDate = prescriptionDate;
-    }
-
     public String getPayName() {
         return payName;
     }
@@ -413,6 +447,14 @@ public class OutpatientOrder {
         this.payName = payName;
     }
 
+    public LocalDateTime getPrescriptionDate() {
+        return prescriptionDate;
+    }
+
+    public void setPrescriptionDate(LocalDateTime prescriptionDate) {
+        this.prescriptionDate = prescriptionDate;
+    }
+
     public String getPatientName() {
         return patientName;
     }
@@ -437,11 +479,11 @@ public class OutpatientOrder {
         this.patientSex = patientSex;
     }
 
-    public Date getUpdateTime() {
+    public LocalDateTime getUpdateTime() {
         return updateTime;
     }
 
-    public void setUpdateTime(Date updateTime) {
+    public void setUpdateTime(LocalDateTime updateTime) {
         this.updateTime = updateTime;
     }
 
@@ -469,22 +511,6 @@ public class OutpatientOrder {
         this.insureTreatmentType = insureTreatmentType;
     }
 
-    public String getIdNo() {
-        return idNo;
-    }
-
-    public void setIdNo(String idNo) {
-        this.idNo = idNo;
-    }
-
-    public String getPaymentNo() {
-        return paymentNo;
-    }
-
-    public void setPaymentNo(String paymentNo) {
-        this.paymentNo = paymentNo;
-    }
-
     public Integer getRefundStatus() {
         return refundStatus;
     }
@@ -493,12 +519,12 @@ public class OutpatientOrder {
         this.refundStatus = refundStatus;
     }
 
-    public Date getRefund_time() {
-        return refund_time;
+    public LocalDateTime getRefundTime() {
+        return refundTime;
     }
 
-    public void setRefund_time(Date refund_time) {
-        this.refund_time = refund_time;
+    public void setRefundTime(LocalDateTime refundTime) {
+        this.refundTime = refundTime;
     }
 
     public String getRefundNo() {
@@ -509,11 +535,11 @@ public class OutpatientOrder {
         this.refundNo = refundNo;
     }
 
-    public Date getRefundCallbackTime() {
+    public String getRefundCallbackTime() {
         return refundCallbackTime;
     }
 
-    public void setRefundCallbackTime(Date refundCallbackTime) {
+    public void setRefundCallbackTime(String refundCallbackTime) {
         this.refundCallbackTime = refundCallbackTime;
     }
 
@@ -533,6 +559,22 @@ public class OutpatientOrder {
         this.orderNo = orderNo;
     }
 
+    public String getIdNo() {
+        return idNo;
+    }
+
+    public void setIdNo(String idNo) {
+        this.idNo = idNo;
+    }
+
+    public String getPaymentNo() {
+        return paymentNo;
+    }
+
+    public void setPaymentNo(String paymentNo) {
+        this.paymentNo = paymentNo;
+    }
+
     public Integer getPaymentChannel() {
         return paymentChannel;
     }
@@ -541,115 +583,139 @@ public class OutpatientOrder {
         this.paymentChannel = paymentChannel;
     }
 
-    public String getInvoiceNo() {
-        return invoiceNo;
+    public Integer getExpress() {
+        return express;
     }
 
-    public void setInvoiceNo(String invoiceNo) {
-        this.invoiceNo = invoiceNo;
+    public void setExpress(Integer express) {
+        this.express = express;
     }
 
-    public String getRespLog() {
-        return respLog;
+    public String getRefundRemark() {
+        return refundRemark;
     }
 
-    public void setRespLog(String respLog) {
-        this.respLog = respLog;
+    public void setRefundRemark(String refundRemark) {
+        this.refundRemark = refundRemark;
     }
 
-    public Integer getPayInsType() {
-        return payInsType;
+    public Integer getDeliveryMethod() {
+        return deliveryMethod;
     }
 
-    public void setPayInsType(Integer payInsType) {
-        this.payInsType = payInsType;
+    public void setDeliveryMethod(Integer deliveryMethod) {
+        this.deliveryMethod = deliveryMethod;
     }
 
-    public String getMedTransId() {
-        return medTransId;
+    public Integer getAddressId() {
+        return addressId;
     }
 
-    public void setMedTransId(String medTransId) {
-        this.medTransId = medTransId;
+    public void setAddressId(Integer addressId) {
+        this.addressId = addressId;
     }
 
-    public String getMedRefundId() {
-        return medRefundId;
+    public Integer getPostage() {
+        return postage;
     }
 
-    public void setMedRefundId(String medRefundId) {
-        this.medRefundId = medRefundId;
+    public void setPostage(Integer postage) {
+        this.postage = postage;
     }
 
-    public String getMedPayUrl() {
-        return medPayUrl;
+    public LocalDateTime getStartSendTime() {
+        return startSendTime;
     }
 
-    public void setMedPayUrl(String medPayUrl) {
-        this.medPayUrl = medPayUrl;
+    public void setStartSendTime(LocalDateTime startSendTime) {
+        this.startSendTime = startSendTime;
     }
 
-    public String getInsRowId() {
-        return insRowId;
+    public LocalDateTime getFinishSendTime() {
+        return finishSendTime;
     }
 
-    public void setInsRowId(String insRowId) {
-        this.insRowId = insRowId;
+    public void setFinishSendTime(LocalDateTime finishSendTime) {
+        this.finishSendTime = finishSendTime;
     }
 
-    public String getInsUploadFeeResp() {
-        return insUploadFeeResp;
+    public String getSendNo() {
+        return sendNo;
     }
 
-    public void setInsUploadFeeResp(String insUploadFeeResp) {
-        this.insUploadFeeResp = insUploadFeeResp;
+    public void setSendNo(String sendNo) {
+        this.sendNo = sendNo;
     }
 
-    public String getInsPayCallbackResp() {
-        return insPayCallbackResp;
+    public String getTimeStandard() {
+        return timeStandard;
     }
 
-    public void setInsPayCallbackResp(String insPayCallbackResp) {
-        this.insPayCallbackResp = insPayCallbackResp;
+    public void setTimeStandard(String timeStandard) {
+        this.timeStandard = timeStandard;
     }
 
-    public String getInsReturnStr() {
-        return insReturnStr;
+    public Integer getAmount() {
+        return amount;
     }
 
-    public void setInsReturnStr(String insReturnStr) {
-        this.insReturnStr = insReturnStr;
+    public void setAmount(Integer amount) {
+        this.amount = amount;
     }
 
-    public String getInsTxReturnStr() {
-        return insTxReturnStr;
+    public String getInvoiceNo() {
+        return invoiceNo;
     }
 
-    public void setInsTxReturnStr(String insTxReturnStr) {
-        this.insTxReturnStr = insTxReturnStr;
+    public void setInvoiceNo(String invoiceNo) {
+        this.invoiceNo = invoiceNo;
     }
 
-    public String getInsuDivDr() {
-        return insuDivDr;
+    public Integer getPayInsType() {
+        return payInsType;
     }
 
-    public void setInsuDivDr(String insuDivDr) {
-        this.insuDivDr = insuDivDr;
+    public void setPayInsType(Integer payInsType) {
+        this.payInsType = payInsType;
     }
 
-    public Integer getMedInsType() {
-        return medInsType;
+    public String getMedTransId() {
+        return medTransId;
     }
 
-    public void setMedInsType(Integer medInsType) {
-        this.medInsType = medInsType;
+    public void setMedTransId(String medTransId) {
+        this.medTransId = medTransId;
     }
 
-    public Integer getTerminal() {
-        return terminal;
+    public String getMedRefundId() {
+        return medRefundId;
+    }
+
+    public void setMedRefundId(String medRefundId) {
+        this.medRefundId = medRefundId;
+    }
+
+    public String getMedPayUrl() {
+        return medPayUrl;
     }
 
-    public void setTerminal(Integer terminal) {
-        this.terminal = terminal;
+    public void setMedPayUrl(String medPayUrl) {
+        this.medPayUrl = medPayUrl;
+    }
+
+    public String getMedPayAppId() {
+        return medPayAppId;
+    }
+
+    public void setMedPayAppId(String medPayAppId) {
+        this.medPayAppId = medPayAppId;
+    }
+
+    public String getInsTxReturnStr() {
+        return insTxReturnStr;
+    }
+
+    public void setInsTxReturnStr(String insTxReturnStr) {
+        this.insTxReturnStr = insTxReturnStr;
     }
-}
+}

+ 265 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/OutpatientOrderDetail.java

@@ -0,0 +1,265 @@
+package com.ywt.outpatient.domain.entity.center;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 缴费明细表
+ */
+@Table(name = "outpatient_order_detail")
+@Entity
+public class OutpatientOrderDetail implements Serializable {
+  private static final long serialVersionUID = 1L;
+
+  @Id
+  @Column(name = "id")
+  private Integer id;
+
+  /**
+   * HIS 订单号
+   */
+  @Column(name = "his_order_no", nullable = false)
+  private String hisOrderNo;
+
+  /**
+   * 创建时间
+   */
+  @Column(name = "create_time", nullable = false)
+  private Date createTime;
+
+  /**
+   * 更新时间
+   */
+  @Column(name = "update_time", nullable = false)
+  private Date updateTime;
+
+  /**
+   * 删除标识:0-未删除;1-已删除
+   */
+  @Column(name = "deleted", nullable = false)
+  private Integer deleted = 0;
+
+  /**
+   * 明细项目名称
+   */
+  @Column(name = "name", nullable = false)
+  private String name;
+
+  /**
+   * 价格
+   */
+  @Column(name = "price", nullable = false)
+  private Integer price;
+
+  /**
+   * 明细代号
+   */
+  @Column(name = "code", nullable = false)
+  private String code;
+
+  /**
+   * 明细数目
+   */
+  @Column(name = "number", nullable = false)
+  private String number;
+
+  /**
+   * 明细规格
+   */
+  @Column(name = "spec", nullable = false)
+  private String spec;
+
+  /**
+   * 明细单位
+   */
+  @Column(name = "unit", nullable = false)
+  private String unit;
+
+  /**
+   * 明细数目
+   */
+  @Column(name = "totalFee", nullable = false)
+  private Integer totalFee;
+
+  public Integer getId() {
+    return id;
+  }
+
+  public void setId(Integer id) {
+    this.id = id;
+  }
+
+  /**
+   * HIS 订单号
+   */
+  public String getHisOrderNo() {
+    return hisOrderNo;
+  }
+
+  /**
+   * HIS 订单号
+   */
+  public void setHisOrderNo(String hisOrderNo) {
+    this.hisOrderNo = hisOrderNo;
+  }
+
+  /**
+   * 创建时间
+   */
+  public Date getCreateTime() {
+    return createTime;
+  }
+
+  /**
+   * 创建时间
+   */
+  public void setCreateTime(Date createTime) {
+    this.createTime = createTime;
+  }
+
+  /**
+   * 更新时间
+   */
+  public Date getUpdateTime() {
+    return updateTime;
+  }
+
+  /**
+   * 更新时间
+   */
+  public void setUpdateTime(Date updateTime) {
+    this.updateTime = updateTime;
+  }
+
+  /**
+   * 删除标识:0-未删除;1-已删除
+   */
+  public Integer getDeleted() {
+    return deleted;
+  }
+
+  /**
+   * 删除标识:0-未删除;1-已删除
+   */
+  public void setDeleted(Integer deleted) {
+    this.deleted = deleted;
+  }
+
+  /**
+   * 明细项目名称
+   */
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * 明细项目名称
+   */
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  /**
+   * 价格
+   */
+  public Integer getPrice() {
+    return price;
+  }
+
+  /**
+   * 价格
+   */
+  public void setPrice(Integer price) {
+    this.price = price;
+  }
+
+  /**
+   * 明细代号
+   */
+  public String getCode() {
+    return code;
+  }
+
+  /**
+   * 明细代号
+   */
+  public void setCode(String code) {
+    this.code = code;
+  }
+
+  /**
+   * 明细数目
+   */
+  public String getNumber() {
+    return number;
+  }
+
+  /**
+   * 明细数目
+   */
+  public void setNumber(String number) {
+    this.number = number;
+  }
+
+  /**
+   * 明细规格
+   */
+  public String getSpec() {
+    return spec;
+  }
+
+  /**
+   * 明细规格
+   */
+  public void setSpec(String spec) {
+    this.spec = spec;
+  }
+
+  /**
+   * 明细单位
+   */
+  public String getUnit() {
+    return unit;
+  }
+
+  /**
+   * 明细单位
+   */
+  public void setUnit(String unit) {
+    this.unit = unit;
+  }
+
+  /**
+   * 明细数目
+   */
+  public Integer getTotalFee() {
+    return totalFee;
+  }
+
+  /**
+   * 明细数目
+   */
+  public void setTotalFee(Integer totalFee) {
+    this.totalFee = totalFee;
+  }
+
+  public String toString() {
+    return "OutpatientOrderDetail{id=" + id + 
+      ", hisOrderNo=" + hisOrderNo + 
+      ", createTime=" + createTime + 
+      ", updateTime=" + updateTime + 
+      ", deleted=" + deleted + 
+      ", name=" + name + 
+      ", price=" + price + 
+      ", code=" + code + 
+      ", number=" + number + 
+      ", spec=" + spec + 
+      ", unit=" + unit + 
+      ", totalFee=" + totalFee + 
+      "}";
+  }
+}

+ 15 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/OutpatientOrderDetailRepository.java

@@ -0,0 +1,15 @@
+package com.ywt.outpatient.domain.entity.center;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.List;
+
+public interface OutpatientOrderDetailRepository extends JpaRepository<OutpatientOrderDetail, Integer>, JpaSpecificationExecutor<OutpatientOrderDetail> {
+    @Query(value = "select count(*) from outpatient_order_detail where his_order_no = ? and code = ? and deleted = 0", nativeQuery = true)
+    int countByHisOrderNoAndCode(String hisOrderNo, String code);
+
+    @Query(value = "select * from outpatient_order_detail where his_order_no = ? and deleted = 0", nativeQuery = true)
+    List<OutpatientOrderDetail> getByHisOrderNo(String hisOrderNo);
+}

+ 29 - 1
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/OutpatientOrderRepository.java

@@ -7,7 +7,34 @@ import org.springframework.data.jpa.repository.Query;
 import javax.transaction.Transactional;
 import java.util.List;
 
+/**
+ * (OutpatientOrder)表Repository类
+ *
+ * @author johnson lin
+ * @since 2019-05-29 15:51:59
+ */
 public interface OutpatientOrderRepository extends JpaRepository<OutpatientOrder, Integer> {
+
+    /**
+     * 根据订单ID得到门诊缴费订单
+     *
+     * @param orderId 订单ID
+     * @return
+     */
+    OutpatientOrder getFirstByOrderIdAndDeletedFalse(int orderId);
+
+    @Query(value = "select * from outpatient_order where his_order_no = ? and deleted = 0 limit 1", nativeQuery = true)
+    OutpatientOrder getByHisOrderNo(String hisOrderNo);
+
+    @Query(value = "select * from ywt_center.outpatient_order where doctor_code = ? and user_id = ? and payment_status = 2 order by create_time desc limit 1;", nativeQuery = true)
+    OutpatientOrder getLatestOutpatientOrder(String doctorCode, int userId);
+    
+    @Query(value = "select * from ywt_center.outpatient_order where doctor_code = ? and user_id = ? and hospital_id = ? and payment_status = 2 order by create_time desc limit 1;", nativeQuery = true)
+    OutpatientOrder getLatestOutpatientOrder(String doctorCode, int userId, int hospitalId);
+
+    @Query(value = "select * from outpatient_order where invoice_no = ? and deleted = 0 limit 1", nativeQuery = true)
+    OutpatientOrder getByInvoiceNo(String invoiceNo);
+
     @Query(value = "select count(0) from outpatient_order where his_order_no = ? and deleted = 0", nativeQuery = true)
     int count(String hisOrderNo);
 
@@ -35,4 +62,5 @@ public interface OutpatientOrderRepository extends JpaRepository<OutpatientOrder
     @Transactional
     @Query(value = "update outpatient_order set order_id = ?1, order_no = ?2 where id = ?3", nativeQuery = true)
     void updateOrderIdAndOrderNoById(int orderId, String orderNo, int id);
-}
+
+}

+ 397 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/RegisterRecord.java

@@ -0,0 +1,397 @@
+package com.ywt.outpatient.domain.entity.center;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * (RegisterRecord)实体类
+ *
+ * @author johnson lin
+ * @since 2019-06-11 10:40:05
+ */
+@Entity
+@Table(name = "register_record")
+public class RegisterRecord implements Serializable {
+    private static final long serialVersionUID = 300295667867400040L;
+
+    @Id
+    @Column(name = "id")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    /**
+     * 医生姓名
+     */
+    @Column(name = "doctor_name")
+    private String doctorName;
+
+    /**
+     * 医院名称
+     */
+    @Column(name = "hospital_name")
+    private String hospitalName;
+
+    /**
+     * 科室名称
+     */
+    @Column(name = "dept_name")
+    private String deptName;
+
+    /**
+     * 医生Id
+     */
+    @Column(name = "doctor_id")
+    private Integer doctorId;
+
+    /**
+     * 医院Id
+     */
+    @Column(name = "hospital_id")
+    private Integer hospitalId;
+
+    /**
+     * 科室Id
+     */
+    @Column(name = "dept_id")
+    private Integer deptId;
+
+    /**
+     * HIS系统科室编码
+     */
+    @Column(name = "dept_code")
+    private String deptCode;
+
+    /**
+     * 总费用
+     */
+    @Column(name = "total")
+    private Integer total;
+
+    /**
+     * 诊疗费
+     */
+    @Column(name = "medical_fee")
+    private Integer medicalFee;
+
+    /**
+     * 挂号费
+     */
+    @Column(name = "registered_fee")
+    private Integer registeredFee;
+
+    /**
+     * 预约日期
+     */
+    @Column(name = "registered_date")
+    private LocalDate registeredDate;
+
+    /**
+     * 预约时段
+     */
+    @Column(name = "registered_period")
+    private Integer registeredPeriod;
+
+    /**
+     * 预约起始时间
+     */
+    @Column(name = "start_time")
+    private String startTime;
+
+    /**
+     * 预约结束时间
+     */
+    @Column(name = "end_time")
+    private String endTime;
+
+    /**
+     * 证件类型
+     */
+    @Column(name = "id_type")
+    private String idType;
+
+    /**
+     * 证件号码
+     */
+    @Column(name = "id_no")
+    private String idNo;
+
+    /**
+     * 患者姓名
+     */
+    @Column(name = "patient_name")
+    private String patientName;
+
+    /**
+     * 出生日期
+     */
+    @Column(name = "birthday")
+    private LocalDate birthday;
+
+    /**
+     * 性别
+     */
+    @Column(name = "patient_sex")
+    private Integer patientSex;
+
+    /**
+     * 手机号码
+     */
+    @Column(name = "patient_mobile")
+    private String patientMobile;
+
+    /**
+     * 用户Id
+     */
+    @Column(name = "user_id")
+    private Integer userId;
+
+    /**
+     * 医生职称
+     */
+    @Column(name = "doctor_title")
+    private String doctorTitle;
+
+    /**
+     * HIS系统医生编码
+     */
+    @Column(name = "doctor_code")
+    private String doctorCode;
+
+    /**
+     * 门诊标识
+     */
+    @Column(name = "schedule_item_code")
+    private String scheduleItemCode;
+
+    /**
+     * 是否删除
+     */
+    @Column(name = "deleted")
+    private Boolean deleted;
+
+    /**
+     * 添加日期
+     */
+    @Column(name = "create_time")
+    private LocalDateTime createTime;
+
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getDoctorName() {
+        return doctorName;
+    }
+
+    public void setDoctorName(String doctorName) {
+        this.doctorName = doctorName;
+    }
+
+    public String getHospitalName() {
+        return hospitalName;
+    }
+
+    public void setHospitalName(String hospitalName) {
+        this.hospitalName = hospitalName;
+    }
+
+    public String getDeptName() {
+        return deptName;
+    }
+
+    public void setDeptName(String deptName) {
+        this.deptName = deptName;
+    }
+
+    public Integer getDoctorId() {
+        return doctorId;
+    }
+
+    public void setDoctorId(Integer doctorId) {
+        this.doctorId = doctorId;
+    }
+
+    public Integer getHospitalId() {
+        return hospitalId;
+    }
+
+    public void setHospitalId(Integer hospitalId) {
+        this.hospitalId = hospitalId;
+    }
+
+    public Integer getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(Integer deptId) {
+        this.deptId = deptId;
+    }
+
+    public String getDeptCode() {
+        return deptCode;
+    }
+
+    public void setDeptCode(String deptCode) {
+        this.deptCode = deptCode;
+    }
+
+    public Integer getTotal() {
+        return total;
+    }
+
+    public void setTotal(Integer total) {
+        this.total = total;
+    }
+
+    public Integer getMedicalFee() {
+        return medicalFee;
+    }
+
+    public void setMedicalFee(Integer medicalFee) {
+        this.medicalFee = medicalFee;
+    }
+
+    public Integer getRegisteredFee() {
+        return registeredFee;
+    }
+
+    public void setRegisteredFee(Integer registeredFee) {
+        this.registeredFee = registeredFee;
+    }
+
+    public LocalDate getRegisteredDate() {
+        return registeredDate;
+    }
+
+    public void setRegisteredDate(LocalDate registeredDate) {
+        this.registeredDate = registeredDate;
+    }
+
+    public Integer getRegisteredPeriod() {
+        return registeredPeriod;
+    }
+
+    public void setRegisteredPeriod(Integer registeredPeriod) {
+        this.registeredPeriod = registeredPeriod;
+    }
+
+    public String getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(String startTime) {
+        this.startTime = startTime;
+    }
+
+    public String getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(String endTime) {
+        this.endTime = endTime;
+    }
+
+    public String getIdType() {
+        return idType;
+    }
+
+    public void setIdType(String idType) {
+        this.idType = idType;
+    }
+
+    public String getIdNo() {
+        return idNo;
+    }
+
+    public void setIdNo(String idNo) {
+        this.idNo = idNo;
+    }
+
+    public String getPatientName() {
+        return patientName;
+    }
+
+    public void setPatientName(String patientName) {
+        this.patientName = patientName;
+    }
+
+    public LocalDate getBirthday() {
+        return birthday;
+    }
+
+    public void setBirthday(LocalDate birthday) {
+        this.birthday = birthday;
+    }
+
+    public Integer getPatientSex() {
+        return patientSex;
+    }
+
+    public void setPatientSex(Integer patientSex) {
+        this.patientSex = patientSex;
+    }
+
+    public String getPatientMobile() {
+        return patientMobile;
+    }
+
+    public void setPatientMobile(String patientMobile) {
+        this.patientMobile = patientMobile;
+    }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    public String getDoctorTitle() {
+        return doctorTitle;
+    }
+
+    public void setDoctorTitle(String doctorTitle) {
+        this.doctorTitle = doctorTitle;
+    }
+
+    public String getDoctorCode() {
+        return doctorCode;
+    }
+
+    public void setDoctorCode(String doctorCode) {
+        this.doctorCode = doctorCode;
+    }
+
+    public String getScheduleItemCode() {
+        return scheduleItemCode;
+    }
+
+    public void setScheduleItemCode(String scheduleItemCode) {
+        this.scheduleItemCode = scheduleItemCode;
+    }
+
+    public Boolean getDeleted() {
+        return deleted;
+    }
+
+    public void setDeleted(Boolean deleted) {
+        this.deleted = deleted;
+    }
+
+    public LocalDateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(LocalDateTime createTime) {
+        this.createTime = createTime;
+    }
+
+}

+ 13 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/RegisterRecordRepository.java

@@ -0,0 +1,13 @@
+package com.ywt.outpatient.domain.entity.center;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+/**
+ * (RegisterRecord)表Repository类
+ *
+ * @author johnson lin
+ * @since 2019-06-11 10:40:07
+ */
+public interface RegisterRecordRepository extends JpaRepository<RegisterRecord, Integer> {
+
+}

+ 107 - 70
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/RegisteredOrder.java

@@ -4,28 +4,30 @@ import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.Id;
 import javax.persistence.Table;
+import java.io.Serializable;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.util.Date;
 
-@Table(name = "registered_order")
 @Entity
-public class RegisteredOrder {
+@Table(name = "registered_order")
+public class RegisteredOrder implements Serializable {
+    private static final long serialVersionUID = -47149612898406801L;
 
     /**
      * 主键
      */
     @Id
+    @Column(name = "id")
     private Integer id;
 
-    /**
-     * 用户Id
-     */
-    @Column(name = "user_id", nullable = false)
+    @Column(name = "user_id")
     private Integer userId;
 
     /**
      * 医院Id
      */
-    @Column(name = "hospital_id", nullable = false)
+    @Column(name = "hospital_id")
     private Integer hospitalId;
 
     /**
@@ -37,98 +39,97 @@ public class RegisteredOrder {
     /**
      * 科室Id
      */
-    @Column(name = "dept_id", nullable = false)
+    @Column(name = "dept_id")
     private Integer deptId;
 
     /**
      * 医生Id
      */
-    @Column(name = "doctor_id", nullable = false)
+    @Column(name = "doctor_id")
     private Integer doctorId;
 
     /**
      * 医生姓名
      */
-    @Column(name = "doctor_name", nullable = false)
+    @Column(name = "doctor_name")
     private String doctorName;
 
     /**
-     * 费用(以分为单位)
+     * 费用(以分为单位)
      */
-    @Column(name = "total", nullable = false)
+    @Column(name = "total")
     private Integer total;
 
     /**
      * 预约日期
      */
-    @Column(name = "registered_date", nullable = false)
+    @Column(name = "registered_date")
     private Date registeredDate;
 
     /**
      * 预约时间段
      */
-    @Column(name = "registered_period", nullable = false)
+    @Column(name = "registered_period")
     private Integer registeredPeriod;
 
     /**
      * 分时开始时间,格式:HH:MI
      */
-    @Column(name = "start_time", nullable = false)
+    @Column(name = "start_time")
     private String startTime;
 
     /**
      * 分时结束时间,格式:HH:MI
      */
-    @Column(name = "end_time", nullable = false)
+    @Column(name = "end_time")
     private String endTime;
 
     /**
      * HIS系统就诊人Id
      */
-    @Column(name = "his_patient_id", nullable = false)
+    @Column(name = "his_patient_id")
     private String hisPatientId;
 
     /**
      * 就诊卡Id
      */
-    @Column(name = "medical_card_id", nullable = false)
+    @Column(name = "medical_card_id")
     private Integer medicalCardId;
 
     /**
      * 就诊人
      */
-    @Column(name = "patient_name", nullable = false)
+    @Column(name = "patient_name")
     private String patientName;
 
     /**
      * 支付方式
      */
-    @Column(name = "payment_channel", nullable = false)
+    @Column(name = "payment_channel")
     private Integer paymentChannel;
 
     /**
      * 是否删除(标识物理删除)
      */
-    @Column(name = "deleted", nullable = false)
+    @Column(name = "deleted")
     private Boolean deleted;
 
     /**
-     * 更新时间
+     * 修改时间
      */
-    @Column(name = "update_time", nullable = false)
+    @Column(name = "update_time")
     private Date updateTime;
 
     /**
      * 创建时间
      */
-    @Column(name = "create_time", nullable = false)
+    @Column(name = "create_time")
     private Date createTime;
 
-
     /**
      * 门诊排班项记录标识
      */
-    @Column(name = "schedule_item_code", nullable = false)
+    @Column(name = "schedule_item_code")
     private String scheduleItemCode;
 
     /**
@@ -137,7 +138,6 @@ public class RegisteredOrder {
     @Column(name = "doctor_code")
     private String doctorCode;
 
-
     /**
      * 预约科室编号
      */
@@ -153,25 +153,25 @@ public class RegisteredOrder {
     /**
      * 挂号费
      */
-    @Column(name = "registered_fee", nullable = false)
+    @Column(name = "registered_fee")
     private Integer registeredFee;
 
     /**
      * 诊疗费
      */
-    @Column(name = "medical_fee", nullable = false)
+    @Column(name = "medical_fee")
     private Integer medicalFee;
 
     /**
      * 支付状态
      */
-    @Column(name = "payment_status", nullable = false)
+    @Column(name = "payment_status")
     private Integer paymentStatus;
 
     /**
      * 挂号订单状态
      */
-    @Column(name = "registered_status", nullable = false)
+    @Column(name = "registered_status")
     private Integer registeredStatus;
 
     /**
@@ -223,21 +223,18 @@ public class RegisteredOrder {
     private String hisTransactionId;
 
     /**
-     * 订单来源
-     */
-    @Column(name = "source", nullable = false)
-    private Integer source;
-
-    /**
-     * 诊断号(当hosptialId=12时,存放太和医院返回的就诊流水号)
+     * 诊断号
      */
     @Column(name = "his_clinic_code")
     private String hisClinicCode;
 
     /**
-     * 患者性别
+     * 订单来源
      */
-    @Column(name = "patient_sex", nullable = false)
+    @Column(name = "source")
+    private Integer source;
+
+    @Column(name = "patient_sex")
     private Integer patientSex;
 
     /**
@@ -265,7 +262,7 @@ public class RegisteredOrder {
     private String wxTransactionId;
 
     /**
-     * 预约类型:2-加号预约,1-普通预约
+     * 2-加号预约 1或其他-普通预约
      */
     @Column(name = "registered_type")
     private Integer registeredType;
@@ -276,41 +273,66 @@ public class RegisteredOrder {
     @Column(name = "flag_id")
     private Integer flagId;
 
-    //支付流水号
     @Column(name = "payment_no")
     private String paymentNo;
 
-    //退款状态
+    /**
+     * 退款状态
+     */
     @Column(name = "refund_status")
     private Integer refundStatus;
 
-    //退款时间
+    /**
+     * 退款时间
+     */
     @Column(name = "refund_time")
-    private Date refund_time;
+    private LocalDateTime refundTime;
 
-    //退款流水号
+    /**
+     * 退款流水号
+     */
     @Column(name = "refund_no")
     private String refundNo;
 
-    //退款回调时间
+    /**
+     * 退款回调时间
+     */
     @Column(name = "refund_callback_time")
-    private Date refundCallbackTime;
+    private String refundCallbackTime;
 
-    //订单ID
+    /**
+     * 订单ID
+     */
     @Column(name = "order_id")
     private Integer orderId;
 
-    //订单号
+    /**
+     * 订单编码
+     */
     @Column(name = "order_no")
     private String orderNo;
 
-    //支付时间
+    /**
+     * 支付时间
+     */
     @Column(name = "payment_time")
     private Date paymentTime;
 
+    /**
+     * 诊疗卡号
+     */
     @Column(name = "medical_card_no")
     private String medicalCardNo;
 
+    /**
+     * 后台取消预约时填写的备注
+     */
+    @Column(name = "cancel_remark")
+    private String cancelRemark;
+
+    @Column(name = "sub_hospital_id")
+    private Integer subHospitalId;
+
     public Integer getId() {
         return id;
     }
@@ -335,6 +357,14 @@ public class RegisteredOrder {
         this.hospitalId = hospitalId;
     }
 
+    public String getHospitalName() {
+        return hospitalName;
+    }
+
+    public void setHospitalName(String hospitalName) {
+        this.hospitalName = hospitalName;
+    }
+
     public Integer getDeptId() {
         return deptId;
     }
@@ -583,14 +613,6 @@ public class RegisteredOrder {
         this.hisTransactionId = hisTransactionId;
     }
 
-    public Integer getSource() {
-        return source;
-    }
-
-    public void setSource(Integer source) {
-        this.source = source;
-    }
-
     public String getHisClinicCode() {
         return hisClinicCode;
     }
@@ -599,6 +621,14 @@ public class RegisteredOrder {
         this.hisClinicCode = hisClinicCode;
     }
 
+    public Integer getSource() {
+        return source;
+    }
+
+    public void setSource(Integer source) {
+        this.source = source;
+    }
+
     public Integer getPatientSex() {
         return patientSex;
     }
@@ -671,12 +701,12 @@ public class RegisteredOrder {
         this.refundStatus = refundStatus;
     }
 
-    public Date getRefund_time() {
-        return refund_time;
+    public LocalDateTime getRefundTime() {
+        return refundTime;
     }
 
-    public void setRefund_time(Date refund_time) {
-        this.refund_time = refund_time;
+    public void setRefundTime(LocalDateTime refundTime) {
+        this.refundTime = refundTime;
     }
 
     public String getRefundNo() {
@@ -687,11 +717,11 @@ public class RegisteredOrder {
         this.refundNo = refundNo;
     }
 
-    public Date getRefundCallbackTime() {
+    public String getRefundCallbackTime() {
         return refundCallbackTime;
     }
 
-    public void setRefundCallbackTime(Date refundCallbackTime) {
+    public void setRefundCallbackTime(String refundCallbackTime) {
         this.refundCallbackTime = refundCallbackTime;
     }
 
@@ -727,12 +757,19 @@ public class RegisteredOrder {
         this.medicalCardNo = medicalCardNo;
     }
 
-    public String getHospitalName() {
-        return hospitalName;
+    public String getCancelRemark() {
+        return cancelRemark;
     }
 
-    public RegisteredOrder setHospitalName(String hospitalName) {
-        this.hospitalName = hospitalName;
-        return this;
+    public void setCancelRemark(String cancelRemark) {
+        this.cancelRemark = cancelRemark;
+    }
+
+    public Integer getSubHospitalId() {
+        return subHospitalId;
+    }
+
+    public void setSubHospitalId(Integer subHospitalId) {
+        this.subHospitalId = subHospitalId;
     }
 }

+ 24 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/RegisteredOrderRepository.java

@@ -68,8 +68,32 @@ public interface RegisteredOrderRepository extends JpaRepository<RegisteredOrder
 
     RegisteredOrder getFirstByOrderIdAndHospitalIdAndDeletedFalse(int orderId, int hospitalId);
 
+    /**
+     * 获取用户候诊列表记录(太和医院)
+     *
+     * @param userId 用户ID
+     * @param date   日期,格式:yyyy-M-d
+     * @return 候诊列表
+     */
+    @Query(value =
+            "select * from registered_order " +
+                    "where user_id = ?1 and deleted = 0 and hospital_id = ?3 " +
+                    "and registered_date >= ?2 " +
+                    "and (registered_status = 1 or registered_status = 5) " +
+                    "order by create_time desc;"
+            , nativeQuery = true)
+    List<RegisteredOrder> listQueueOrders(int userId, String date, int hospitalId);
+
+
     @Modifying
     @Transactional
     @Query(value = "update registered_order set registered_status = registered_status | ?1 where id = ?2", nativeQuery = true)
     void updateRegisteredStatus(int registeredStatus, int id);
+
+    RegisteredOrder getFirstByRefundNoAndDeletedFalse(String orderNo);
+
+    @Query(value = "select * from ywt_center.registered_order where doctor_id = ? and deleted = 0 and user_id = ? and payment_status = 2 and registered_status & 1= 1 and registered_date <= ? and hospital_id = ? order by registered_date desc limit 1;", nativeQuery = true)
+    RegisteredOrder getLatestRegOrderUntilDate(int doctorId, int userId, String endDate, int hospitalId);
+
+
 }

+ 3 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/entity/center/UserRepository.java

@@ -57,5 +57,8 @@ public interface UserRepository extends PagingAndSortingRepository<User, Integer
      * @return
      */
     User getById(int id);
+    
+    User getByIdAndIsDeletedFalse(int userId);
+
 
 }

+ 26 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/HisMedCardConfig.java

@@ -0,0 +1,26 @@
+package com.ywt.outpatient.domain.models;
+
+/**
+ * @author Walker
+ * Created on 2021/3/19
+ */
+public class HisMedCardConfig {
+    private Boolean nameAuth;// 是否开启实名验证
+    private Integer hospitalId;
+
+    public Integer getHospitalId() {
+        return hospitalId;
+    }
+
+    public void setHospitalId(Integer hospitalId) {
+        this.hospitalId = hospitalId;
+    }
+
+    public Boolean getNameAuth() {
+        return nameAuth;
+    }
+
+    public void setNameAuth(Boolean nameAuth) {
+        this.nameAuth = nameAuth;
+    }
+}

+ 35 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/MriBookConfig.java

@@ -0,0 +1,35 @@
+package com.ywt.outpatient.domain.models;
+
+/**
+ * @author Walker
+ * Created on 2020/8/7
+ */
+public class MriBookConfig {
+    private int maxBookDay;
+    private int maxBookNum;
+    private int blackListLimitation;
+
+    public int getMaxBookDay() {
+        return maxBookDay;
+    }
+
+    public void setMaxBookDay(int maxBookDay) {
+        this.maxBookDay = maxBookDay;
+    }
+
+    public int getMaxBookNum() {
+        return maxBookNum;
+    }
+
+    public void setMaxBookNum(int maxBookNum) {
+        this.maxBookNum = maxBookNum;
+    }
+
+    public int getBlackListLimitation() {
+        return blackListLimitation;
+    }
+
+    public void setBlackListLimitation(int blackListLimitation) {
+        this.blackListLimitation = blackListLimitation;
+    }
+}

+ 53 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/OutpatientConfig.java

@@ -0,0 +1,53 @@
+package com.ywt.outpatient.domain.models;
+
+/**
+ * @author Walker
+ * Created on 2020/10/13
+ */
+public class OutpatientConfig {
+    private String notifyUrl;
+    private String returnUrl;
+    private String openId;
+    private Integer hospitalId;
+    private String insuSupportCardType;// 支持医保结算的诊疗卡类型,多个类型用英文逗号分割
+
+    public String getNotifyUrl() {
+        return notifyUrl;
+    }
+
+    public void setNotifyUrl(String notifyUrl) {
+        this.notifyUrl = notifyUrl;
+    }
+
+    public String getReturnUrl() {
+        return returnUrl;
+    }
+
+    public void setReturnUrl(String returnUrl) {
+        this.returnUrl = returnUrl;
+    }
+
+    public String getOpenId() {
+        return openId;
+    }
+
+    public void setOpenId(String openId) {
+        this.openId = openId;
+    }
+
+    public Integer getHospitalId() {
+        return hospitalId;
+    }
+
+    public void setHospitalId(Integer hospitalId) {
+        this.hospitalId = hospitalId;
+    }
+
+    public String getInsuSupportCardType() {
+        return insuSupportCardType;
+    }
+
+    public void setInsuSupportCardType(String insuSupportCardType) {
+        this.insuSupportCardType = insuSupportCardType;
+    }
+}

+ 53 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/PatientInfo.java

@@ -0,0 +1,53 @@
+package com.ywt.outpatient.domain.models;
+
+/**
+ * @author Walker
+ * Created on 2020/7/14
+ */
+public class PatientInfo {
+    private String patientName;
+    private int sex;
+    private String birthday;
+    private String patientMobile;
+    private String address;
+
+    public String getPatientName() {
+        return patientName;
+    }
+
+    public void setPatientName(String patientName) {
+        this.patientName = patientName;
+    }
+
+    public int getSex() {
+        return sex;
+    }
+
+    public void setSex(int sex) {
+        this.sex = sex;
+    }
+
+    public String getBirthday() {
+        return birthday;
+    }
+
+    public void setBirthday(String birthday) {
+        this.birthday = birthday;
+    }
+
+    public String getPatientMobile() {
+        return patientMobile;
+    }
+
+    public void setPatientMobile(String patientMobile) {
+        this.patientMobile = patientMobile;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+}

+ 37 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/Question.java

@@ -0,0 +1,37 @@
+package com.ywt.outpatient.domain.models;
+
+import java.util.List;
+
+/**
+ * @author Walker
+ * Created on 2020/7/14
+ */
+public class Question {
+    private int questionId;
+    private String category;
+    private List<QuestionOption> options;
+
+    public int getQuestionId() {
+        return questionId;
+    }
+
+    public void setQuestionId(int questionId) {
+        this.questionId = questionId;
+    }
+
+    public String getCategory() {
+        return category;
+    }
+
+    public void setCategory(String category) {
+        this.category = category;
+    }
+
+    public List<QuestionOption> getOptions() {
+        return options;
+    }
+
+    public void setOptions(List<QuestionOption> options) {
+        this.options = options;
+    }
+}

+ 73 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/QuestionOption.java

@@ -0,0 +1,73 @@
+package com.ywt.outpatient.domain.models;
+
+import java.util.List;
+
+/**
+ * @author Walker
+ * Created on 2020/7/14
+ */
+public class QuestionOption {
+    private int id;
+    private String name;
+    private boolean value1;
+    private String value2;
+    private String value3;
+    private List<QuestionOption> children;
+    private int parentId;
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public boolean getValue1() {
+        return value1;
+    }
+
+    public void setValue1(boolean value1) {
+        this.value1 = value1;
+    }
+
+    public String getValue2() {
+        return value2;
+    }
+
+    public void setValue2(String value2) {
+        this.value2 = value2;
+    }
+
+    public String getValue3() {
+        return value3;
+    }
+
+    public void setValue3(String value3) {
+        this.value3 = value3;
+    }
+
+    public List<QuestionOption> getChildren() {
+        return children;
+    }
+
+    public void setChildren(List<QuestionOption> children) {
+        this.children = children;
+    }
+
+    public int getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(int parentId) {
+        this.parentId = parentId;
+    }
+}

+ 46 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/ScreeningTable.java

@@ -0,0 +1,46 @@
+package com.ywt.outpatient.domain.models;
+
+import java.util.List;
+
+/**
+ * @author Walker
+ * Created on 2020/7/14
+ */
+public class ScreeningTable {
+    private PatientInfo patientInfo;
+    private List<Question> questions;
+    private boolean completed;// 是否完成所有题目
+    private int tableId;
+
+    public PatientInfo getPatientInfo() {
+        return patientInfo;
+    }
+
+    public void setPatientInfo(PatientInfo patientInfo) {
+        this.patientInfo = patientInfo;
+    }
+
+    public List<Question> getQuestions() {
+        return questions;
+    }
+
+    public void setQuestions(List<Question> questions) {
+        this.questions = questions;
+    }
+
+    public boolean isCompleted() {
+        return completed;
+    }
+
+    public void setCompleted(boolean completed) {
+        this.completed = completed;
+    }
+
+    public int getTableId() {
+        return tableId;
+    }
+
+    public void setTableId(int tableId) {
+        this.tableId = tableId;
+    }
+}

+ 3 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/enums/ConfigTypeEnum.java

@@ -9,12 +9,15 @@ public enum ConfigTypeEnum {
     WeChat("微信配置", 3),
     VoiceSms("语音电话配置", 4),
     FMT("公医标识配置", 5),
+    MRI_BOOK("MRI 预约配置", 7),
     CLOUD_FILM_CFG("影像报告费用配置", 8),
     OUTPATIENT("门诊缴费约配置", 9),
     ICBC_PAY_CONFIG("工行支付配置", 10),
     COVID19_QUESTIONNAIRE("新型冠状病毒感染流行病学史调查问卷需求配置", 12),
+    HIS_CREAT_MEDCARD("HIS 建档配置", 13),
     OPEN_HIS_ICBC_PAY_CONFIG("工行支付配置", 18),
     SUBMIT_BANK_CARD_CONFIG("提交银行账户信息配置", 19),
+    HIS_REGISTERED_FEE("按HIS挂号金额收费", 21)
     ;
 
     private final String displayName;

+ 57 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/enums/Gender.java

@@ -0,0 +1,57 @@
+package com.ywt.outpatient.domain.models.enums;
+
+/**
+ * 性别枚举
+ *
+ * @author johnson lin
+ * @date 2019/4/30 11:58 AM
+ */
+public enum Gender {
+    /**
+     * 未知
+     */
+    UNKNOWN("未知", 0),
+    /**
+     * 男
+     */
+    MALE("男", 1),
+    /**
+     * 女
+     */
+    FEMALE("女", 2),
+    /**
+     * 未说明
+     */
+    UNSPECIFIED("未说明", 9);
+
+    private final String displayName;
+
+    private final int value;
+
+    Gender(String displayName, int value) {
+        this.displayName = displayName;
+        this.value = value;
+    }
+
+    public String getDisplayName() {
+        return displayName;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    public static Gender valueOf(int value) {
+        for (Gender sex : Gender.values()) {
+            if (sex.getValue() == value) {
+                return sex;
+            }
+        }
+        return null;
+    }
+
+    public static String getDisplayName(int value) {
+        Gender sex = valueOf(value);
+        return sex != null ? sex.getDisplayName() : UNKNOWN.getDisplayName();
+    }
+}

+ 9 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/domain/models/enums/RegisteredTypeEnum.java

@@ -23,4 +23,13 @@ public enum RegisteredTypeEnum {
     public int getValue() {
         return value;
     }
+
+    public static boolean isDefined(int value) {
+        for (RegisteredTypeEnum type : RegisteredTypeEnum.values()) {
+            if (type.value == value) {
+                return true;
+            }
+        }
+        return false;
+    }
 }

+ 140 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/Constants.java

@@ -0,0 +1,140 @@
+package com.ywt.outpatient.service.rpc;
+
+/**
+ * 常量定义
+ *
+ * @author johnson lin
+ * @date 2019-04-29 9:45 PM
+ */
+public class Constants {
+    /**
+     * 太和医院Id
+     */
+    public static final int TAIHE_HOSPITAL_ID = 12;
+
+    /**
+     * 白云分院医院 id
+     */
+    public static final int NFYYBYFY_HOSPITAL_ID = 41;
+
+    /**
+     * 南方医院白云分院名称
+     */
+    public static final String NFYYBYFY_HOSPITAL_NAME = "南方医科大学南方医院白云分院";
+    /**
+     * 太和医院名称
+     */
+    public static final String TAIHE_HOSPITAL_NAME = "南方医院太和分院";
+
+    /**
+     * 南方医院太和分院(互联网医院名医诊区/名医门诊)科室编码
+     */
+    public static final String TAIHE_NET_DEPT_CODE = "441";
+    /**
+     * 南方医院白云分院(互联网医院名医诊区/名医门诊)科室编码
+     */
+    public static final String NFYYBYFY_NET_DEPT_CODE = "";// TODO: 2020/12/7 待定
+    /**
+     * 南方医院太和分院(互联网医院名医诊区夜诊)科室编码
+     */
+    public static final String TAIHE_NET_DEPT_CODE_NIGHT_DIAGNOSIS = "729";
+    /**
+     * 太和支付代码
+     */
+    public static final String TAIHE_PAY_CODE = "1002";
+
+    /**
+     * 白云分院支付代码
+     */
+    public static final String NFYYBYFY_PAY_CODE = "1015";
+
+    /**
+     * 白云分院里太和挂号的支付代码
+     */
+    public static final String NFYYBYFY_TAIHE_REG_PAY_CODE = "1018";
+
+    /**
+     * 南方医院太和分院儿科科室编码
+     */
+    public static final String TAIHE_PEDIATRIC_DEPT_CODE = "419";
+
+    /**
+     * 南方医院白云分院儿科科室编码
+     */
+    public static final String NFYYBYFY_PEDIATRIC_DEPT_CODE = "";// TODO: 2020/12/7 待定
+    /**
+     * 南方医院太和分院内科科室编码
+     */
+    public static final String TAIHE_INTERNAL_MEDICINE_DEPT_CODE = "394";
+    /**
+     * 南方医院白云分院内科科室编码。若有多个,有英文逗号分隔。
+     */
+    public static final String NFYYBYFY_INTERNAL_MEDICINE_DEPT_CODE = "493,367";
+
+    /**
+     * 南方医院白云分院呼吸内科科室编码。
+     */
+    public static final String NFYYBYFY_INTERNAL_BREATHE_MEDICINE_DEPT_CODE = "367";
+
+    /**
+     * 系统出错统一提示语
+     */
+    public static final String ERROR_INFO = "系统开小差,请稍后重试";
+
+    /**
+     * 南方医院ID
+     */
+    public static final int NFYY_HOSPITAL_ID = 1;
+
+    /**
+     * 南方医院全名
+     */
+    public static final String NFYY_HOSPITAL_NAME = "南方医科大学南方医院";
+    /**
+     * 白云分院支付代码(支付宝)
+     */
+    public static final String NFYYBYFY_PAY_CODE_ALIPAY = "2000";
+    /**
+     * 太和支付宝支付代码
+     */
+    public static final String TH_PAY_CODE_ALIPAY = "2001";
+
+    /**
+     * 微信支付
+     */
+    public static final String PAY_MODE_WECHAT = "WECHATPAY";
+
+    /**
+     * 支付宝支付
+     */
+    public static final String PAY_MODE_ALI = "ALIPAY";
+
+
+    /**
+     * 南方白云分院小程序app id
+     */
+    public static final String NFYYBYFY_WXMP_APP_ID = "wxbc56e5794abdbb48";
+
+
+    /**
+     * 体检预约订单详情
+     */
+    public static final String BY_REG_CHECKIN_URL = "by/wait_treatment/reportDetail?areaId=%s&cardNo=%s";
+
+    public static final String BY_MEDICALCARD_URL = "offline_consult/cardList?hospitalId=%d&flag=%d";
+    public static final String TH_MEDICALCARD_URL = "https://m.ywtinfo.com/nfthwe/me/medicalCards/%d/%d";
+    /**
+     * 白云挂号成功通知推送链接,点击跳转进入详情
+     */
+    public static final String BY_REGISTER_INFO_ORDER_CENTER_LIST = "pages/index/index?entry=by/order_center/list";
+
+    /**
+     * 太和挂号成功通知推送链接,点击跳转进入详情
+     */
+    public static final String TH_REGISTER_INFO_ORDER_CENTER_URL = "/nfthwe/orderCenter";
+    public static String GET_YWT_HTTPS_MSITE_DOMAIN = "https://m.ywtinfo.com";
+
+    public static final String CHECK_IN_DETAIL = "pages/index/index?entry=by%%2Fwait_treatment%%2FreportDetail%%3FareaId%%3D%d%%26cardNo%%3D%d%%26sendMessage%%3D%d";
+
+    public static final String REGISTER_DETAIL = "pages/index/index?entry=by%2Forder_center%2Flist";
+}

+ 5 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/IdGenerator.java

@@ -653,4 +653,9 @@ public class IdGenerator {
     public int genDoctorBankCard() {
         return sequenceRepository.gen("doctor_bank_card");
     }
+
+    public int genMedicalCardId() {
+        return sequenceRepository.gen("medical_card");
+    }
+
 }

+ 63 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/VerifyCreateRegisteredResult.java

@@ -0,0 +1,63 @@
+package com.ywt.outpatient.service.rpc;
+
+
+import com.ywt.outpatient.domain.entity.center.MedicalCard;
+
+/**
+ * @author johnson lin
+ * @date 2019/5/13 2:08 PM
+ */
+public class VerifyCreateRegisteredResult {
+    private boolean success;
+
+    private String msg;
+
+    private MedicalCard medicalCard;
+
+    private String doctorTitle;
+
+    public VerifyCreateRegisteredResult() {
+    }
+
+    public VerifyCreateRegisteredResult failed(String msg) {
+        this.success = false;
+        this.msg = msg;
+        return this;
+    }
+
+    public boolean isSuccess() {
+        return success;
+    }
+
+    public VerifyCreateRegisteredResult setSuccess(boolean success) {
+        this.success = success;
+        return this;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public VerifyCreateRegisteredResult setMsg(String msg) {
+        this.msg = msg;
+        return this;
+    }
+
+    public MedicalCard getMedicalCard() {
+        return medicalCard;
+    }
+
+    public VerifyCreateRegisteredResult setMedicalCard(MedicalCard medicalCard) {
+        this.medicalCard = medicalCard;
+        return this;
+    }
+
+    public String getDoctorTitle() {
+        return doctorTitle;
+    }
+
+    public VerifyCreateRegisteredResult setDoctorTitle(String doctorTitle) {
+        this.doctorTitle = doctorTitle;
+        return this;
+    }
+}

+ 60 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/VerifyRegisterWithoutMedicalCardResult.java

@@ -0,0 +1,60 @@
+package com.ywt.outpatient.service.rpc;
+
+/**
+ * @author johnson lin
+ * @date 2019/6/11 11:27 AM
+ */
+public class VerifyRegisterWithoutMedicalCardResult {
+    private boolean success;
+
+    private String msg;
+
+//    private MedicalCard medicalCard;
+
+    private String doctorTitle;
+
+    public VerifyRegisterWithoutMedicalCardResult() {
+    }
+
+    public VerifyRegisterWithoutMedicalCardResult failed(String msg) {
+        this.success = false;
+        this.msg = msg;
+        return this;
+    }
+
+    public boolean isSuccess() {
+        return success;
+    }
+
+    public VerifyRegisterWithoutMedicalCardResult setSuccess(boolean success) {
+        this.success = success;
+        return this;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public VerifyRegisterWithoutMedicalCardResult setMsg(String msg) {
+        this.msg = msg;
+        return this;
+    }
+
+//    MedicalCard getMedicalCard() {
+//        return medicalCard;
+//    }
+
+//    VerifyCreateRegisteredResult setMedicalCard(MedicalCard medicalCard) {
+//        this.medicalCard = medicalCard;
+//        return this;
+//    }
+
+    public String getDoctorTitle() {
+        return doctorTitle;
+    }
+
+    public VerifyRegisterWithoutMedicalCardResult setDoctorTitle(String doctorTitle) {
+        this.doctorTitle = doctorTitle;
+        return this;
+    }
+}

+ 187 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/common/ConfigProvider.java

@@ -0,0 +1,187 @@
+package com.ywt.outpatient.service.rpc.common;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.ywt.biz.common.util.Checker;
+import com.ywt.biz.common.util.StringHelper;
+import com.ywt.biz.common.util.serializers.JsonSerializer;
+import com.ywt.outpatient.domain.entity.center.Config;
+import com.ywt.outpatient.domain.entity.center.ConfigRepository;
+import com.ywt.outpatient.domain.models.HisMedCardConfig;
+import com.ywt.outpatient.domain.models.MriBookConfig;
+import com.ywt.outpatient.domain.models.OutpatientConfig;
+import com.ywt.outpatient.domain.models.enums.ConfigTypeEnum;
+import com.ywt.outpatient.service.rpc.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Walker
+ * Created on 2020/6/10
+ */
+@Service
+public class ConfigProvider {
+    private final Logger logger = LoggerFactory.getLogger(ConfigProvider.class);
+    @Autowired
+    private ConfigRepository configRepository;
+
+    final static String FMT_HOSPITAL_ID = "hospitalId";
+    final static String FMT_TYPE_LIST = "typeList";
+
+    public List<String> getFmtFlagList(int hospitalId) {
+        List<String> list = new LinkedList<>();
+        Config config = configRepository.findOneByType(ConfigTypeEnum.FMT.getValue());
+        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
+            return list;
+        }
+        String content = config.getContent();
+        try {
+            if (hospitalId == 0) {
+                hospitalId = Constants.TAIHE_HOSPITAL_ID;
+            }
+            /**
+             * content 举例:
+             [{"hospitalId":12,"typeList":["白云区公医","公医","天河区公医"]},{"hospitalId":41,"typeList":["白云区公医41","公医41","天河区公医41"]}]
+             *
+             */
+            JsonNode node = JsonSerializer.readToNode(content);
+            if (node != null && node.isArray()) {
+                for (JsonNode jsonNode : node) {
+                    String obj = jsonNode.toString();
+                    Map<String, Object> map = JsonSerializer.from(obj, Map.class);
+                    if (map == null) {
+                        return new LinkedList<>();
+                    }
+                    int hospitalIdValue = (int) map.getOrDefault(FMT_HOSPITAL_ID, 0);
+                    if (hospitalIdValue == hospitalId) {
+                        List<String> typeList = (List<String>) map.getOrDefault(FMT_TYPE_LIST, null);
+                        if (typeList == null) {
+                            return new LinkedList<>();
+                        }
+                        typeList.stream().forEach(p -> {
+                            list.add(p);
+                        });
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.error("ConfigServiceProvider#getVoiceSmsPhone(content={}):Deserialize failed!\n{}", content, e.getMessage(), e);
+        }
+        return list;
+    }
+
+    public MriBookConfig getMriBookConfig() {
+        Config config = configRepository.findOneByType(ConfigTypeEnum.MRI_BOOK.getValue());
+
+        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
+            return null;
+        }
+        return JsonSerializer.from(config.getContent(), MriBookConfig.class);
+    }
+
+    public int getMriMaxBookDay() {
+        MriBookConfig mriBookConfig = getMriBookConfig();
+        return mriBookConfig == null ? 7 : mriBookConfig.getMaxBookDay();
+    }
+
+    public int getMriMaxBookNum() {
+        MriBookConfig mriBookConfig = getMriBookConfig();
+        return mriBookConfig == null ? 5 : mriBookConfig.getMaxBookNum();
+    }
+
+    public int getMriBlackListLimitation() {
+        MriBookConfig mriBookConfig = getMriBookConfig();
+        return mriBookConfig == null ? 3 : mriBookConfig.getBlackListLimitation();
+    }
+
+    public OutpatientConfig getOutpatientConfig(int hospitalId) {
+        Config config = configRepository.findOneByType(ConfigTypeEnum.OUTPATIENT.getValue());
+        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
+            return null;
+        }
+        String content = config.getContent();
+        try {
+            JsonNode node = JsonSerializer.readToNode(content);
+            if (node != null && node.isArray()) {
+                for (JsonNode jsonNode : node) {
+                    OutpatientConfig c = JsonSerializer.from(jsonNode.toString(), OutpatientConfig.class);
+                    if (c != null && Checker.getIntegerValue(c.getHospitalId()) == hospitalId) {
+                        return c;
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.error("ConfigProvider#getOutpatientConfig(content={}):Deserialize failed!\n{}", content, e.getMessage(), e);
+        }
+        return null;
+    }
+
+    public HisMedCardConfig getHisMedCardConfig(int hospitalId) {
+        Config config = configRepository.findOneByType(ConfigTypeEnum.HIS_CREAT_MEDCARD.getValue());
+        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
+            return null;
+        }
+        String content = config.getContent();
+        try {
+            JsonNode node = JsonSerializer.readToNode(content);
+            if (node != null && node.isArray()) {
+                for (JsonNode jsonNode : node) {
+                    HisMedCardConfig c = JsonSerializer.from(jsonNode.toString(), HisMedCardConfig.class);
+                    if (c != null && Checker.getIntegerValue(c.getHospitalId()) == hospitalId) {
+                        return c;
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.error("ConfigServiceProvider#getHisMedCardConfig(content={}):Deserialize failed!\n{}", content, e.getMessage(), e);
+        }
+        return null;
+    }
+
+    public List<String> getHisRegisteredFeeFlagList(int hospitalId) {
+        List<String> list = new LinkedList<>();
+        Config config = configRepository.findOneByType(ConfigTypeEnum.HIS_REGISTERED_FEE.getValue());
+        if (config == null || StringHelper.isNullOrEmpty(config.getContent())) {
+            return list;
+        }
+        String content = config.getContent();
+        try {
+            if (hospitalId == 0) {
+                hospitalId = Constants.NFYYBYFY_HOSPITAL_ID;
+            }
+            /**
+             * content 举例:
+             [{"hospitalId":12,"typeList":["白云区公医","公医","天河区公医"]},{"hospitalId":41,"typeList":["白云区公医41","公医41","天河区公医41"]}]
+             *
+             */
+            JsonNode node = JsonSerializer.readToNode(content);
+            if (node != null && node.isArray()) {
+                for (JsonNode jsonNode : node) {
+                    String obj = jsonNode.toString();
+                    Map<String, Object> map = JsonSerializer.from(obj, Map.class);
+                    if (map == null) {
+                        return new LinkedList<>();
+                    }
+                    int hospitalIdValue = (int) map.getOrDefault(FMT_HOSPITAL_ID, 0);
+                    if (hospitalIdValue == hospitalId) {
+                        List<String> typeList = (List<String>) map.getOrDefault(FMT_TYPE_LIST, null);
+                        if (typeList == null) {
+                            return new LinkedList<>();
+                        }
+                        typeList.stream().forEach(p -> {
+                            list.add(p);
+                        });
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.error("ConfigServiceProvider#getHisRegisteredFeeFlagList(content={}):Deserialize failed!\n{}", content, e.getMessage(), e);
+        }
+        return list;
+    }
+}

+ 116 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/common/MessageModel.java

@@ -0,0 +1,116 @@
+package com.ywt.outpatient.service.rpc.common;
+
+/**
+ * @author johnson lin
+ * @date 2019/6/27 4:17 PM
+ */
+public class MessageModel {
+    /**
+     * 用户ID
+     */
+    private int userId;
+
+    /**
+     * 模板编码
+     */
+    private String tplCode;
+
+    /**
+     * 跳转链接
+     */
+    private String url;
+
+    /**
+     * 跳转小程序
+     */
+    private String miniProgram;
+
+    /**
+     * first
+     */
+    private String first;
+
+    /**
+     * remark
+     */
+    private String remark;
+
+    /**
+     * keywords
+     */
+    private String[] keywords;
+
+    private String[] keynotes;
+
+    public int getUserId() {
+        return userId;
+    }
+
+    public MessageModel setUserId(int userId) {
+        this.userId = userId;
+        return this;
+    }
+
+    public String getTplCode() {
+        return tplCode;
+    }
+
+    public MessageModel setTplCode(String tplCode) {
+        this.tplCode = tplCode;
+        return this;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public MessageModel setUrl(String url) {
+        this.url = url;
+        return this;
+    }
+
+    public String getMiniProgram() {
+        return miniProgram;
+    }
+
+    public MessageModel setMiniProgram(String miniProgram) {
+        this.miniProgram = miniProgram;
+        return this;
+    }
+
+    public String getFirst() {
+        return first;
+    }
+
+    public MessageModel setFirst(String first) {
+        this.first = first;
+        return this;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public MessageModel setRemark(String remark) {
+        this.remark = remark;
+        return this;
+    }
+
+    public String[] getKeywords() {
+        return keywords;
+    }
+
+    public MessageModel setKeywords(String[] keywords) {
+        this.keywords = keywords;
+        return this;
+    }
+
+    public String[] getKeynotes() {
+        return keynotes;
+    }
+
+    public MessageModel setKeynotes(String[] keynotes) {
+        this.keynotes = keynotes;
+        return this;
+    }
+}

+ 182 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/common/NfYwtWeChatMsgService.java

@@ -0,0 +1,182 @@
+package com.ywt.outpatient.service.rpc.common;
+
+import com.google.gson.JsonObject;
+import com.ywt.biz.common.util.Checker;
+import com.ywt.biz.common.util.DateUtil;
+import com.ywt.biz.common.util.StringHelper;
+import com.ywt.outpatient.domain.entity.center.MedicalCard;
+import com.ywt.outpatient.domain.entity.center.MedicalCardRepository;
+import com.ywt.outpatient.domain.entity.center.RegisteredOrder;
+import com.ywt.outpatient.service.rpc.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * 《南方医务通》微信公众号模板消息、客服消息逻辑类
+ *
+ * @author johnson lin
+ * @date 2019/6/27 3:57 PM
+ */
+@Service
+public class NfYwtWeChatMsgService {
+    private static final Logger logger = LoggerFactory.getLogger(NfYwtWeChatMsgService.class);
+
+    /**
+     * 《南方医务通》公众号 -> 门诊记录 URL
+     */
+    private static final String ORDER_CENTER_URL = "https://m.ywtinfo.com/nfywtwe/orderCenter";
+
+    @Autowired
+    private WeChatMsgProvider weChatMsgProvider;
+
+    @Autowired
+    private MedicalCardRepository medicalCardRepository;
+
+    /**
+     * 发送挂号成功模板消息
+     * <p>
+     * 模板(TPL_1015):
+     * "{{first.DATA}}
+     * 就诊人:{{keyword1.DATA}}
+     * 就诊卡号:{{keyword2.DATA}}
+     * 挂号科室:{{keyword3.DATA}}
+     * 看诊医生:{{keyword4.DATA}}
+     * 就诊时间:{{keyword5.DATA}}
+     * {{remark.DATA}}"
+     *
+     * @param registeredOrder {@link com.ywt.outpatient.domain.entity.center.RegisteredOrder}
+     */
+    public void sendMsgForRegister(com.ywt.outpatient.domain.entity.center.RegisteredOrder registeredOrder) {
+        String first = "您好,您已预约成功!";
+        String hisAdmitAddr = Checker.getStringValue(registeredOrder.getHisAdmitAddress());
+        String remark =
+                String.format("挂号序号:%s\r\n温馨提示:", Checker.getStringValue(registeredOrder.getHisSeqCode())) +
+                        "1、预约挂号成功后,首次就诊患者,就诊前需到门诊一楼大厅圆台前打印健康码。" +
+                        "2、请持诊疗卡或健康码到对应诊区,自助机报到就诊,就诊先后以报到为准,过号请重新报到。" +
+                        "3、当日挂号当日有效。";
+        if (!StringHelper.isNullOrEmpty(hisAdmitAddr)) {
+            remark = "就诊地点:\r\n" + hisAdmitAddr + "\r\n" + remark;
+        }
+        String[] keywords = new String[]{
+                registeredOrder.getPatientName(),
+                registeredOrder.getHospitalName(),
+                registeredOrder.getDeptName(),
+                registeredOrder.getDoctorName(),
+                String.format("%s %s-%s"
+                        , DateUtil.formatDate(registeredOrder.getRegisteredDate(), "yyyy-MM-dd")
+                        , registeredOrder.getStartTime()
+                        , registeredOrder.getEndTime())
+        };
+        MessageModel model = new MessageModel()
+                .setUserId(registeredOrder.getUserId())
+                .setTplCode("TPL_1057")
+                .setUrl(ORDER_CENTER_URL)
+                .setMiniProgram("")
+                .setFirst(first)
+                .setRemark(remark)
+                .setKeywords(keywords);
+        weChatMsgProvider.sendTemplateMessage(model);
+    }
+
+    /**
+     * 预约取消成功通知
+     * <p>
+     * 模板(TPL_1056):
+     * <p>
+     * "{{first.DATA}}
+     * 就诊医院:{{keyword1.DATA}}
+     * 就诊科室:{{keyword2.DATA}}
+     * 就诊医生:{{keyword3.DATA}}
+     * 就诊人:{{keyword4.DATA}}
+     * 取消时间:{{keyword5.DATA}}
+     * {{remark.DATA}}"
+     * <p>
+     * "您好,您已成功取消预约!
+     * 就诊医院:南方医科大学南方医院
+     * 就诊科室:儿科
+     * 就诊医生:张三
+     * 就诊人:李四
+     * 取消时间:2017年6月26日 15:30
+     * "
+     *
+     * @param registeredOrder {@link RegisteredOrder}
+     */
+    public void sendMsgForCancel(RegisteredOrder registeredOrder) {
+        String first = "您好,您已成功退号!";
+        String[] keywords = new String[]{
+                registeredOrder.getHospitalName(),
+                registeredOrder.getDeptName(),
+                registeredOrder.getDoctorName(),
+                registeredOrder.getPatientName(),
+                LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm"))
+        };
+        MessageModel model = new MessageModel()
+                .setUserId(registeredOrder.getUserId())
+                .setTplCode("TPL_1056")
+                .setUrl(ORDER_CENTER_URL)
+                .setMiniProgram("")
+                .setFirst(first)
+                .setRemark("")
+                .setKeywords(keywords);
+        weChatMsgProvider.sendTemplateMessage(model);
+    }
+
+
+    /*
+     * 扫码报道消息推送
+     *
+     *
+     */
+    public void sendMsgForCheckIn(String name, String queueNo, String deptName, String areaId, String cardNo,
+                                  String doctorName, String regTime, String admBoroughDesc, int userId, int hospitalId) {
+        String first = "您已报道成功,序列号为" + queueNo + ",请在候诊区等候,,叫号后请到" + admBoroughDesc + "就诊。门诊开诊时间:周一到周五8:00-12:00,13:00-16:00,周六周日:8:00-12:00。";
+        String[] keywords = new String[]{
+                name, cardNo, deptName, doctorName, regTime
+        };
+        String remark = "请点击进入详情页面!";
+        String mpPath = String.format(Constants.BY_REG_CHECKIN_URL, areaId, cardNo);
+        String miniProgram = "";
+        if (hospitalId == 41) {
+            // todo: 白云小程序,"就诊卡号"字段变成"患者ID"
+            MedicalCard medicalCard = medicalCardRepository.getByUserIdAndCardNoAndHospitalId(userId, cardNo, hospitalId);
+            if (!Checker.isNone(medicalCard)){
+                keywords[1] = medicalCard.getHisPatientId();
+            }
+            miniProgram = getNfyybyfyMpParamString(mpPath);
+        }
+        MessageModel model = new MessageModel()
+                .setUserId(userId)
+                .setTplCode("TPL_2002")
+                .setUrl("")
+                .setMiniProgram(miniProgram)
+                .setFirst(first)
+                .setKeywords(keywords)
+                .setRemark(remark);
+        weChatMsgProvider.sendTemplateMessage(model);
+    }
+
+
+    private String getNfyybyfyMpParamString(String mpPath) {
+        JsonObject object = new JsonObject();
+        object.addProperty("appid", Constants.NFYYBYFY_WXMP_APP_ID);// 所需跳转到的小程序appid
+        object.addProperty("pagepath", "pages/index/index?entry=" + getEncodedURI(mpPath));// 所需跳转到小程序的具体页面路径
+        return object.toString();
+    }
+
+    private String getEncodedURI(String path) {
+        try {
+            return URLEncoder.encode(path, StandardCharsets.UTF_8.toString());
+        } catch (UnsupportedEncodingException e) {
+            logger.error("WxProvider#getEncodedURI(path={} ):\n {}", path, e.getMessage(), e);
+            return path;
+        }
+    }
+}

+ 4 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/common/ServiceResult.java

@@ -94,6 +94,10 @@ public class ServiceResult {
         return this.code == ServiceResultCode.SUCCEED;
     }
 
+    public boolean isSuccessful() {
+        return this.code == ServiceResultCode.SUCCEED;
+    }
+
     static class ServiceResultCode {
         static final int SUCCEED = 1;
         static final int FAILED = 0;

+ 347 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/common/TaiheWeChatMsgService.java

@@ -0,0 +1,347 @@
+package com.ywt.outpatient.service.rpc.common;
+
+
+import com.ywt.biz.common.util.Checker;
+import com.ywt.biz.common.util.DateUtil;
+import com.ywt.biz.common.util.StringHelper;
+import com.ywt.gapi.user.GetSnsUserInfoRequest;
+import com.ywt.gapi.user.GetSnsUserInfoResponse;
+import com.ywt.gapi.user.UserService;
+import com.ywt.outpatient.domain.entity.center.RegisterRecord;
+import com.ywt.outpatient.domain.entity.center.RegisteredOrder;
+import com.ywt.outpatient.service.rpc.Constants;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 太和微信公众号模板消息、客服消息逻辑类
+ *
+ * @author johnson lin
+ * @date 2019/4/29 9:51 PM
+ */
+@Service
+public class TaiheWeChatMsgService {
+    private static Logger logger = LoggerFactory.getLogger(TaiheWeChatMsgService.class);
+
+    @Autowired
+    private WeChatMsgProvider weChatMsgProvider;
+
+    @DubboReference
+    private UserService userServiceBlockingStub;
+
+    private static int OFFICAIL = 21;
+    private static int MIN = 20;
+
+
+    /**
+     * 发送挂号成功模板消息
+     * <p>
+     * 模板(TPL_1006):
+     * "{{first.DATA}}
+     * 就诊人:{{keyword1.DATA}}
+     * 就诊卡号:{{keyword2.DATA}}
+     * 挂号科室:{{keyword3.DATA}}
+     * 看诊医生:{{keyword4.DATA}}
+     * 就诊时间:{{keyword5.DATA}}
+     * {{remark.DATA}}"
+     *
+     * @param registeredOrder {@link RegisteredOrder}
+     */
+    public void sendMsgForRegister(RegisteredOrder registeredOrder) {
+        String hisAdmitAddr = Checker.getStringValue(registeredOrder.getHisAdmitAddress());
+        String remark =
+                String.format("挂号序号:%s\r\n温馨提示:", Checker.getStringValue(registeredOrder.getHisSeqCode())) +
+                        "1、预约挂号成功后,首次就诊患者,就诊前需到门诊一楼大厅圆台前打印健康码。" +
+                        "2、请持诊疗卡或健康码到对应诊区,自助机报到就诊,就诊先后以报到为准,过号请重新报到。" +
+                        "3、当日挂号当日有效。";
+        String remarkTaihe = remark;
+        String timeStr = String.format("%s %s (%s-%s)", DateUtil.formatDate(registeredOrder.getRegisteredDate(), "yyyy-MM-dd"),
+                Checker.getStringValue(registeredOrder.getHisAdmitRange()), registeredOrder.getStartTime(), registeredOrder.getEndTime());
+        // 新增对白云医院的兼容
+        if (registeredOrder.getHospitalId() == Constants.NFYYBYFY_HOSPITAL_ID) {
+            remark = String.format("挂号序号:%s\r\n温馨提示:", Checker.getStringValue(registeredOrder.getHisSeqCode())) +
+                    "1、请首次预约挂号的病人,就诊时先到门诊大厅挂号/收费⑤号窗进行身份确认后报到就诊" +
+                    "2、就诊请先到分诊台报到,请按预约时段就诊报到,过号请重新报到" +
+                    "3、就诊人员需携带身份证原件、佩戴口罩及出示健康码方可入院就诊" +
+                    "4、就诊当日有效";
+            // 白云显示具体时间段
+            timeStr = String.format("%s %s-%s", DateUtil.formatDate(registeredOrder.getRegisteredDate(), "yyyy-MM-dd"),
+                    Checker.getStringValue(registeredOrder.getStartTime()), Checker.getStringValue(registeredOrder.getEndTime()));
+        }
+        if (!StringHelper.isNullOrEmpty(hisAdmitAddr)) {
+            remark = "就诊地点:" + hisAdmitAddr + "\r\n" + remark;
+            remarkTaihe = "就诊地点:" + hisAdmitAddr + "\r\n" + remarkTaihe;
+        }
+        int hospitalId = Checker.getIntegerValue(registeredOrder.getHospitalId());
+        String[] keywords =
+                {
+                        registeredOrder.getPatientName(),
+                        registeredOrder.getMedicalCardNo(),
+                        registeredOrder.getDeptName(),
+                        registeredOrder.getDoctorName(),
+                        timeStr
+                };
+        // todo: 白云小程序,"就诊卡号"字段变成"患者ID"
+        if (hospitalId == Constants.NFYYBYFY_HOSPITAL_ID) {
+            keywords[1] = registeredOrder.getHisPatientId();
+        }
+        String url = "";
+        String miniProgram = "";
+        if (hospitalId == Constants.TAIHE_HOSPITAL_ID) {
+            // 太和跳往公众号
+            url = Constants.GET_YWT_HTTPS_MSITE_DOMAIN + Constants.TH_REGISTER_INFO_ORDER_CENTER_URL;
+        } else if (hospitalId == Constants.NFYYBYFY_HOSPITAL_ID) {
+            // 白云跳往小程序
+            String pagePath = Constants.BY_REGISTER_INFO_ORDER_CENTER_LIST;
+            miniProgram = weChatMsgProvider.getMiniProgramParam(Constants.NFYYBYFY_WXMP_APP_ID, pagePath);
+        }
+        MessageModel model = new MessageModel()
+                .setUserId(registeredOrder.getUserId())
+                .setTplCode(getTplMsgCodeForRegister(hospitalId))
+                .setUrl(url)
+                .setMiniProgram(miniProgram)
+                .setFirst("您好,您已预约成功!")
+                .setRemark(remark)
+                .setKeywords(keywords);
+        weChatMsgProvider.sendTemplateMessage(model);
+        // 白云小程序挂太和的号再发一条消息到白云公众号
+        if (hospitalId == Constants.TAIHE_HOSPITAL_ID && Checker.getIntegerValue(registeredOrder.getSource()) == 20) {
+            logger.info("TaiheWeChatMsgService#sendMsgForRegister(): 白云小程序挂太和的号再发一条消息到白云公众号");
+
+
+                GetSnsUserInfoResponse response = userServiceBlockingStub.getSnsUserInfo(GetSnsUserInfoRequest.newBuilder()
+                        .setUserId(registeredOrder.getUserId())
+                        .setTerminal(OFFICAIL)
+                        .build());
+                String openId = "";
+                String unionId = "";
+                if (response.getCode() != 0 || (response.getCode() == 0 && Checker.isNone(response.getSnsUserInfo().getOpenId()))) {
+
+                    String patientName = "";
+                    String hisPatientId = "";
+//                    MedicalCard card = medicalCardRepository.getById(request.getMedicalCardId());
+//                    if(!Checker.isNone(card)){
+//                        patientName = Checker.getStringValue(card.getPatientName());
+//                        hisPatientId = Checker.getStringValue(card.getHisPatientId());
+//                    }
+                    String templateId = "oc7voZXzm5s4UYQp-6LKSPfAjUIV9RW-B8rmTDx1DUU";
+                    String page = Constants.REGISTER_DETAIL;
+                    Map<String, String> keywordMap = new HashMap();
+                    keywordMap.put("thing22",  registeredOrder.getPatientName());
+                    keywordMap.put("character_string11", registeredOrder.getMedicalCardNo());
+                    keywordMap.put("thing5",    registeredOrder.getDeptName());
+                    keywordMap.put("thing19",  registeredOrder.getDoctorName());
+                    timeStr = String.format("%s %s-%s", DateUtil.formatDate(registeredOrder.getRegisteredDate(), "yyyyMMdd"),
+                             registeredOrder.getStartTime(), registeredOrder.getEndTime());
+                    keywordMap.put("thing16",  timeStr);
+                    logger.info("sendMsgForRegister, timeSrt: {}, size: {}", timeStr, timeStr.length());
+                    GetSnsUserInfoResponse snsResponse = userServiceBlockingStub.getSnsUserInfo(GetSnsUserInfoRequest.newBuilder()
+                            .setUserId(registeredOrder.getUserId())
+                            .setTerminal(MIN)
+                            .build());
+                    if (snsResponse.getCode() == 0 ) {
+                        openId = snsResponse.getSnsUserInfo().getOpenId();
+                        weChatMsgProvider.sendMPSubscribeMessage(MIN, openId, templateId, page, keywordMap);
+                    }
+
+
+                } else {
+                    model.setTplCode(getTplMsgCodeForRegister(Constants.NFYYBYFY_HOSPITAL_ID));
+                    model.setRemark(remarkTaihe);
+                    weChatMsgProvider.sendTemplateMessage(model);
+                }
+        }
+    }
+
+    private String getTplMsgCodeForRegister(Integer hospitalId) {
+        switch (Checker.getIntegerValue(hospitalId)) {
+            case Constants.TAIHE_HOSPITAL_ID:
+                return "TPL_1006";
+            case Constants.NFYYBYFY_HOSPITAL_ID:
+                return "TPL_2001";
+            default:
+                return "";
+        }
+    }
+
+    /**
+     * 无诊疗卡预约挂号成功模板消息
+     * <p>
+     * 模板(TPL_1006):
+     * "{{first.DATA}}
+     * 就诊人:{{keyword1.DATA}}
+     * 就诊卡号:{{keyword2.DATA}}
+     * 挂号科室:{{keyword3.DATA}}
+     * 看诊医生:{{keyword4.DATA}}
+     * 就诊时间:{{keyword5.DATA}}
+     * {{remark.DATA}}"
+     *
+     * @param record {@link RegisterRecord}
+     */
+    public void sendMsgForRegisterWithoutMedicalCard(RegisterRecord record) {
+        String first = "您好,您已预约成功!(境外人士专用)";
+        String remark = "温馨提醒:请就诊当天带上证件前往医院窗口进行取号,取号后直接前往门诊科室就诊。";
+        String[] keywords =
+                {
+                        record.getPatientName(),
+                        "境外人士",
+                        record.getDeptName(),
+                        record.getDoctorName(),
+                        String.format("%s %s-%s"
+                                , record.getRegisteredDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))
+                                , record.getStartTime()
+                                , record.getEndTime())
+                };
+        MessageModel model = new MessageModel()
+                .setUserId(record.getUserId())
+                .setTplCode(getTplMsgCodeForRegister(record.getHospitalId()))
+                .setUrl("")
+                .setMiniProgram("")
+                .setFirst(first)
+                .setRemark(remark)
+                .setKeywords(keywords);
+        weChatMsgProvider.sendTemplateMessage(model);
+    }
+
+    /**
+     * 发送取消预约挂号模板消息
+     * <p>
+     * 模板(TPL_1002):
+     *
+     * @param registeredOrder {@link RegisteredOrder}
+     */
+    public void sendMsgForCancel(RegisteredOrder registeredOrder) {
+        String[] keywords =
+                {
+                        Constants.TAIHE_HOSPITAL_NAME,
+                        registeredOrder.getDeptName(),
+                        registeredOrder.getDoctorName(),
+                        registeredOrder.getPatientName(),
+                        LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm"))
+                };
+        MessageModel model = new MessageModel()
+                .setUserId(registeredOrder.getUserId())
+                .setTplCode("TPL_1002")
+                .setUrl("https://m.ywtinfo.com/nfthwe/orderCenter")
+                .setMiniProgram("")
+                .setFirst("您好,您已成功退号!")
+                .setRemark("")
+                .setKeywords(keywords);
+        weChatMsgProvider.sendTemplateMessage(model);
+    }
+
+    public void notifyCancel4NFYYBYFY(int userId, String hospitalName, String patientName, String doctorName, String regDateStr) {
+        final String tplCode = "TPL_2006";
+        final String url = "";
+        final String miniProgram = "";
+        final String first = "您好,您预约的号源已经成功取消。取消号源信息如下:";
+        final String remark = "";
+        String[] keynotes = {
+                patientName,
+                regDateStr,
+                doctorName,
+                hospitalName
+        };
+        MessageModel model = new MessageModel()
+                .setUserId(userId)
+                .setTplCode(tplCode)
+                .setUrl(url)
+                .setMiniProgram(miniProgram)
+                .setFirst(first)
+                .setRemark(remark)
+                .setKeynotes(keynotes);
+        weChatMsgProvider.sendTemplateMessage(model);
+    }
+
+    /**
+     * 取号成功通知
+     *
+     * <p>
+     * 太和公众号优化需求V1.2.5修改(2019/4/22 18:24):
+     * 1、不显示当前排队人数
+     * 2、通知改为不可跳转,final String url = String.format("https://m.ywtinfo.com/nfthwe/waitingTreatmentCount/%s", registrationId);
+     * <p>
+     * <p>
+     * 模板(TPL_1005):
+     * {{first.DATA}}
+     * 当前排号:{{keyword1.DATA}}
+     * 取号时间:{{keyword2.DATA}}
+     * {{remark.DATA}}
+     * <p>
+     * 您好,取号成功!
+     * 当前排号:12
+     * 取号时间:2014-10-30 18:40
+     * "
+     *
+     * @param registeredOrder {@link RegisteredOrder}
+     */
+    public void sendMsgForTook(RegisteredOrder registeredOrder) {
+        String[] keywords =
+                {
+                        "--",
+                        LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
+                };
+        MessageModel model = new MessageModel()
+                .setUserId(registeredOrder.getUserId())
+                .setTplCode("TPL_1005")
+                .setUrl("")
+                .setMiniProgram("")
+                .setFirst("您好,取号成功!")
+                .setRemark("")
+                .setKeywords(keywords);
+        weChatMsgProvider.sendTemplateMessage(model);
+    }
+
+    public void sendMsgForMriBooking(int userId, String name, String mobile, String date) {
+        String[] keywords = {
+                name, mobile, date
+        };
+        String first = "您的预约已申请成功,预约信息为:";
+        String remark = "请等待客服人员电话联系";
+        MessageModel model = new MessageModel()
+                .setUserId(userId)
+                .setTplCode("TPL_8050")
+                .setUrl("")
+                .setMiniProgram("")
+                .setFirst(first)
+                .setRemark(remark)
+                .setKeywords(keywords);
+        weChatMsgProvider.sendTemplateMessage(model);
+    }
+
+    public void sendMsgForCreateMedicalCard(int userId, String cardNo, String name, String sexy, String age, int hospital) {
+        String first = "";
+        String remark = "";
+        String[] keywords = {
+                cardNo, name, sexy, age
+        };
+        String url = "";
+        if (hospital == Constants.TAIHE_HOSPITAL_ID) {
+            url = String.format(Constants.TH_MEDICALCARD_URL, 0, 0);
+        }
+        String tplCode = "TPL_012049";
+        if (hospital == Constants.NFYYBYFY_HOSPITAL_ID) {
+            tplCode = "TPL_021005";
+        }
+        String mpPath = String.format(Constants.BY_MEDICALCARD_URL, 0, 0);
+        String miniProgram = (hospital == Constants.NFYYBYFY_HOSPITAL_ID) ? weChatMsgProvider.getNfyybyfyMpParamString(mpPath) : "";
+        MessageModel model = new MessageModel()
+                .setUserId(userId)
+                .setTplCode(tplCode)
+                .setUrl(url)
+                .setMiniProgram(miniProgram)
+                .setFirst(first)
+                .setRemark(remark)
+                .setKeywords(keywords);
+        weChatMsgProvider.sendTemplateMessage(model);
+
+    }
+}

+ 72 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/common/WeChatMsgProvider.java

@@ -1,16 +1,23 @@
 package com.ywt.outpatient.service.rpc.common;
 
+import com.google.gson.JsonObject;
+import com.ywt.biz.common.util.Checker;
 import com.ywt.biz.common.util.serializers.JsonSerializer;
 import com.ywt.gapi.ResultCode;
 import com.ywt.gapi.message.*;
+import com.ywt.outpatient.core.utils.JsonUtil;
 import com.ywt.outpatient.domain.wechat.Keyword;
 import com.ywt.outpatient.service.rpc.BizConfigurer;
+import com.ywt.outpatient.service.rpc.Constants;
 import org.apache.dubbo.config.annotation.DubboReference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -833,4 +840,69 @@ public class WeChatMsgProvider {
             logger.error("send(): {}", e.getMessage(), e);
         }
     }
+    public String getNfyybyfyMpParamString(String mpPath) {
+        JsonObject object = new JsonObject();
+        object.addProperty("appid", Constants.NFYYBYFY_WXMP_APP_ID);// 所需跳转到的小程序appid
+        object.addProperty("pagepath", "pages/index/index?entry=" + getEncodedURI(mpPath));// 所需跳转到小程序的具体页面路径
+        return object.toString();
+    }
+
+    /**
+     * 生成模板消息跳转小程序所需的参数
+     *
+     * @param appId    跳转的小程序appId
+     * @param pagePath 页面
+     * @return param string
+     */
+    public String getMiniProgramParam(String appId, String pagePath) {
+        JsonObject jsonObject = new JsonObject();
+        jsonObject.addProperty("appid", appId);
+        jsonObject.addProperty("pagepath", pagePath);
+        return jsonObject.toString();
+    }
+
+    private String getEncodedURI(String path) {
+        try {
+            return URLEncoder.encode(path, StandardCharsets.UTF_8.toString());
+        } catch (UnsupportedEncodingException e) {
+            logger.error("WxProvider#getEncodedURI(path={} ):\n {}", path, e.getMessage(), e);
+            return path;
+        }
+    }
+    /**
+     * 发送模板消息
+     *
+     * @param model {@link MessageModel}
+     */
+    public void sendTemplateMessage(MessageModel model) {
+        try {
+            Map<String, Object> data = new HashMap<>();
+            data.put("first", new Keyword(model.getFirst()));
+            data.put("remark", new Keyword(model.getRemark()));
+
+            if (!Checker.isNone(model.getKeywords())) {
+                for (int i = 0; i < model.getKeywords().length; i++) {
+                    data.put(String.format("keyword%d", i + 1), new Keyword(model.getKeywords()[i]));
+                }
+            }
+
+            if (!Checker.isNone(model.getKeynotes())) {
+                for (int i = 0; i < model.getKeynotes().length; i++) {
+                    data.put(String.format("keynote%d", i + 1), new Keyword(model.getKeynotes()[i]));
+                }
+            }
+            SendTemplateMessageRequest req = SendTemplateMessageRequest.newBuilder()
+                    .setData(JsonUtil.toJson(data))
+                    .setTemplateCode(model.getTplCode())
+                    .setUrl(model.getUrl())
+                    .setMiniProgram(model.getMiniProgram())
+                    .setUserId(model.getUserId())
+                    .build();
+            weChatMessageServiceBlockingStub.sendTemplateMessage(req);
+        } catch (Exception e) {
+            logger.error("sendTemplateMessage(): {}", e.getMessage(), e);
+        }
+    }
+
+
 }

+ 113 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/handler/RestCallerApiProvider.java

@@ -0,0 +1,113 @@
+package com.ywt.outpatient.service.rpc.handler;
+
+import com.ywt.biz.common.util.Checker;
+import com.ywt.biz.common.util.HttpUtil;
+import com.ywt.biz.common.util.serializers.JsonSerializer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author daiyihua
+ * @create 2018-0904 上午09:27
+ * @desc 调用 nutrimeal api抽出来的公共方法
+ **/
+@Service
+public class RestCallerApiProvider {
+
+    @Value("${com.ywt.restServiceMap}")
+    private String restServiceMap;
+    private final Logger logger = LoggerFactory.getLogger(RestCallerApiProvider.class);
+
+    @Autowired
+    private RestTemplateHandler restTemplateHandler;
+    private static final String alipayMpRestServiceName = "com.ywt.AlipayMpRestService";
+
+    public HttpUtil.Resp postAlipayMpRestApi(String path, Map<String, Object> map) {
+        return postCommon(alipayMpRestServiceName, path, map);
+    }
+    public HttpUtil.Resp getAlipayMpRestApi(String path, Map<String, String> map) {
+        return getCommon(alipayMpRestServiceName, path, map);
+    }
+
+    /**
+     * 通用 post 方法
+     *
+     * @param serverName 服务名
+     * @param path       路径
+     * @param map        参数
+     * @return {@link HttpUtil.Resp}
+     */
+    private HttpUtil.Resp postCommon(String serverName, String path, Map<String, Object> map) {
+
+        Map<String, String> headers = new HashMap<>(16);
+        headers.put("Content-Type", "application/json;charset=UTF-8");
+
+        String ipPort = getRestIpPort(serverName);
+        if (!Checker.isNone(ipPort)){
+            serverName = ipPort;
+        }
+        logger.info("RestCallerApiProvider>>postCommon(serverName:{}, \tpath:{}, \tmap:{}, \theaders:{})", serverName, path, JsonSerializer.toJson(map), JsonSerializer.toJson(headers));
+
+        RestTemplateHandler.Resp resp = restTemplateHandler.httpPost(serverName, path, map, headers);
+        HttpUtil.Resp r = new HttpUtil.Resp();
+        r.setCode(resp.getCode());
+        r.setContent(resp.getContent());
+        return r;
+    }
+
+    /**
+     * 通用 get 方法
+     *
+     * @param serverName 服务名
+     * @param path       路径
+     * @param map        参数
+     * @return {@link HttpUtil.Resp}
+     */
+    private HttpUtil.Resp getCommon(String serverName, String path, Map<String, String> map) {
+
+        String ipPort = getRestIpPort(serverName);
+        if (!Checker.isNone(ipPort)){
+            serverName = ipPort;
+        }
+        logger.info("RestCallerApiProvider>>getCommon(serverName:{}, \tpath:{}, \tmap:{})", serverName, path, JsonSerializer.toJson(map));
+        RestTemplateHandler.Resp resp = restTemplateHandler.httpGet(serverName, path, map, null);
+        HttpUtil.Resp r = new HttpUtil.Resp();
+        r.setCode(resp.getCode());
+        r.setContent(resp.getContent());
+        return r;
+    }
+
+
+    public String getRestServiceMap() {
+        return restServiceMap;
+    }
+    public String getRestIpPort(String restName) {
+        String restIpPort = "";
+        String restServiceMapParam = getRestServiceMap();
+        try {
+            if (!Checker.isNone(restServiceMapParam)) {
+                List list = JsonSerializer.from(restServiceMapParam, List.class);
+                if (!Checker.isNone(list)) {
+                    for (Object o : list) {
+                        Map<String, Object> map = (Map<String, Object>) o;
+                        String restNameValue = (String) map.getOrDefault("restName", "");
+                        String restIpPortValue = (String) map.getOrDefault("restIpPort", "");
+                        if (!Checker.isNone(restNameValue) && restName.equals(restNameValue)) {
+                            return restIpPortValue;
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.error("RestCallerApiProvider#getRestServiceMap(restServiceMapParam{}参数有误,{})", restServiceMapParam, e.getMessage(), e);
+        }
+        return restIpPort;
+    }
+}

+ 35 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/handler/RestTemplateConfig.java

@@ -0,0 +1,35 @@
+package com.ywt.outpatient.service.rpc.handler;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.client.ClientHttpRequestFactory;
+import org.springframework.http.client.SimpleClientHttpRequestFactory;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.web.client.RestTemplate;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * @author Walker
+ * Created on 2023/11/17
+ */
+@Configuration
+public class RestTemplateConfig {
+
+    @Bean
+    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
+        RestTemplate restTemplate =  new RestTemplate(factory);
+        // 添加对utf的处理
+        restTemplate.getMessageConverters()
+                .add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
+        return restTemplate;
+    }
+
+    @Bean
+    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
+        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
+        factory.setReadTimeout(5000);
+        factory.setConnectTimeout(15000);
+        return factory;
+    }
+}

+ 234 - 0
ywt-platform-outpatient-sdk/src/main/java/com/ywt/outpatient/service/rpc/handler/RestTemplateHandler.java

@@ -0,0 +1,234 @@
+package com.ywt.outpatient.service.rpc.handler;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.HttpStatus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+@Slf4j
+public class RestTemplateHandler {
+
+    private static Logger log = LoggerFactory.getLogger(RestTemplateHandler.class);
+    private static String mgCenterApiService = "";
+
+    @Autowired
+    private  RestTemplate restTemplate;
+
+    public  Resp httpPost(String serviceName,String path,Map<String, Object> params , Map<String, String> headers)  {
+        String url ="";
+        try{
+            if(!StringUtils.hasText(serviceName)||!StringUtils.hasText(serviceName)){
+                log.error("RestTemplateHandler httpPost error,param has null, service:{},path :{}",serviceName,path);
+                return new Resp(HttpStatus.SC_SEE_OTHER,"参数异常");
+            }
+
+            url = "http://"+serviceName+path;
+
+            HttpHeaders httpHeaders = new HttpHeaders();
+            if(!headers.isEmpty()){
+                headers.forEach(httpHeaders::add);
+            }
+
+            httpHeaders.set("R-Service-Name", serviceName);
+            HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<>(params, httpHeaders);
+            ResponseEntity<String> result = restTemplate.postForEntity(url,httpEntity,String.class);
+            return new Resp(HttpStatus.SC_OK,result.getBody());
+        }catch (Exception e){
+            log.error("send HTTP error ; url:{},reason:{}",url,e.getMessage(),e);
+            return new Resp(HttpStatus.SC_SEE_OTHER,"参数异常");
+        }
+    }
+
+    public  Resp httpGet(String serviceName,String path,Map<String, String> params , Map<String, String> headers)  {
+        String url ="";
+        try{
+            if(!StringUtils.hasText(serviceName)||!StringUtils.hasText(serviceName)){
+                log.error("RestTemplateHandler httpGet error,param has null, service:{},path :{}",serviceName,path);
+                return new Resp(HttpStatus.SC_SEE_OTHER,"参数异常");
+            }
+
+            url = "http://"+serviceName+path;
+            StringBuilder stringBuilder = new StringBuilder();
+            if (params != null && params.size() > 0){
+                for (Map.Entry<String, String> entry : params.entrySet()){
+                    if (entry.getValue() == null || entry.getValue().equals("")){
+                        stringBuilder.append(entry.getKey()).append("=");
+                        stringBuilder.append("&");
+                        continue;
+                    }
+                    try {
+                        stringBuilder.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), "utf-8"));
+                    } catch (UnsupportedEncodingException e) {
+                    }
+                    stringBuilder.append("&");
+                }
+            }
+            if (stringBuilder.length() > 0) {
+                stringBuilder.replace(stringBuilder.length() - 1, stringBuilder.length() - 1, "&");
+            }
+            StringBuilder stringBuilder_url = new StringBuilder();
+            if (url.contains("?")){
+                if (url.endsWith("?")) stringBuilder_url.append(url).append(stringBuilder);
+                else if (url.endsWith("&")) stringBuilder_url.append(url).append(stringBuilder);
+                else stringBuilder_url.append(url).append("&").append(stringBuilder);
+            }else{
+                stringBuilder_url.append(url).append("?").append(stringBuilder);
+            }
+
+
+            HttpHeaders httpHeaders = new HttpHeaders();
+            if(!headers.isEmpty()){
+                headers.forEach(httpHeaders::add);
+            }
+            httpHeaders.set("R-Service-Name", serviceName);
+            HttpEntity entity = new HttpEntity(headers);
+
+
+            ResponseEntity<String> result = restTemplate.exchange(stringBuilder_url.toString(),HttpMethod.GET,entity,String.class);
+            return new Resp(HttpStatus.SC_OK,result.getBody());
+        }catch (Exception e){
+            log.error("send HTTP error ; url:{},reason:{}",url,e.getMessage(),e);
+            return new Resp(HttpStatus.SC_SEE_OTHER,"参数异常");
+        }
+    }
+
+
+    public  ByteArrayResp  httpGetBarry(String serviceName,String path,Map<String, String> params , Map<String, String> headers)  {
+        StringBuilder stringBuilder_url = new StringBuilder();
+        ByteArrayResp resp =  new ByteArrayResp();
+        String url = "";
+        try{
+            if(!StringUtils.hasText(serviceName)||!StringUtils.hasText(serviceName)){
+                log.error("RestTemplateHandler httpPost error,param has null, service:{},path :{}",serviceName,path);
+                resp.setCode(HttpStatus.SC_SEE_OTHER);
+                resp.setContent("param error".getBytes());
+            }
+            url = "http://"+serviceName+"/"+path;
+
+            StringBuilder stringBuilder = new StringBuilder();
+            if (params != null && params.size() > 0){
+                for (Map.Entry<String, String> entry : params.entrySet()){
+                    if (entry.getValue() == null || entry.getValue().equals("")){
+                        stringBuilder.append(entry.getKey()).append("=");
+                        stringBuilder.append("&");
+                        continue;
+                    }
+                    try {
+                        stringBuilder.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), "utf-8"));
+                    } catch (UnsupportedEncodingException e) {
+                    }
+                    stringBuilder.append("&");
+                }
+            }
+            if (stringBuilder.length() > 0) {
+                stringBuilder.replace(stringBuilder.length() - 1, stringBuilder.length() - 1, "&");
+            }
+            if (url.contains("?")){
+                if (url.endsWith("?")) stringBuilder_url.append(url).append(stringBuilder);
+                else if (url.endsWith("&")) stringBuilder_url.append(url).append(stringBuilder);
+                else stringBuilder_url.append(url).append("&").append(stringBuilder);
+            }else{
+                stringBuilder_url.append(url).append("?").append(stringBuilder);
+            }
+
+            HttpHeaders httpHeaders = new HttpHeaders();
+            if(!headers.isEmpty()){
+                headers.forEach(httpHeaders::add);
+            }
+            httpHeaders.set("R-Service-Name", serviceName);
+            HttpEntity request = new HttpEntity(httpHeaders);
+
+            ResponseEntity<byte[]> result = restTemplate.exchange(stringBuilder_url.toString(), HttpMethod.GET,request,byte[].class,params);
+            resp.setCode(HttpStatus.SC_OK);
+            resp.setContent(result.getBody());
+        }catch (Exception e){
+            log.error("send HTTP error ; url:{},reason:{}",stringBuilder_url.toString(),e.getMessage(),e);
+            resp.setCode(HttpStatus.SC_SEE_OTHER);
+            resp.setContent(null);
+        }
+        return resp;
+    }
+
+
+    public  Resp httpPostCommon(String serviceName,String path,Map<String, Object> params)  {
+        Map<String, String> headers = new HashMap<>(16);
+        headers.put("Content-Type", "application/json;charset=UTF-8");
+        return this.httpPost(serviceName,path,params,headers);
+    }
+
+
+
+    public  ByteArrayResp httpGetBarry(String serviceName,String path,Map<String, String> params)  {
+        Map<String, String> headers = new HashMap<>(16);
+        headers.put("Content-Type", "application/json;charset=UTF-8");
+        return this.httpGetBarry(serviceName,path,params,headers);
+    }
+
+
+    public static class Resp {
+        public int code;
+        public String content;
+
+        public Resp() {
+        }
+
+        public Resp(int code,String content) {
+            this.code = code ;
+            this.content = content ;
+        }
+
+        public int getCode() {
+            return this.code;
+        }
+
+        public void setCode(int code) {
+            this.code = code;
+        }
+
+        public String getContent() {
+            return this.content;
+        }
+
+        public void setContent(String content) {
+            this.content = content;
+        }
+    }
+
+    public static class ByteArrayResp {
+        public int code;
+        public byte[] content;
+
+        public ByteArrayResp() {
+        }
+
+        public int getCode() {
+            return this.code;
+        }
+
+        public void setCode(int code) {
+            this.code = code;
+        }
+
+        public byte[] getContent() {
+            return this.content;
+        }
+
+        public void setContent(byte[] content) {
+            this.content = content;
+        }
+    }
+}