diff --git a/pom.xml b/pom.xml
index a7a9e56..9013edb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -195,6 +195,36 @@
${fastjson.version}
+
+
+
+ com.alibaba
+ fastjson
+ 1.2.83
+
+
+
+
+ com.tencent.mip
+ med-request-data-sdk
+ 2.1.2
+
+
+
+ org.bouncycastle
+ bcprov-jdk15on
+ 1.70
+
+
+
+
+
+ com.taobao.arthas
+ arthas-spring-boot-starter
+ 3.7.2
+
+
+
diff --git a/src/main/java/com/szyx/tcm/supervision/config/HttpConfig.java b/src/main/java/com/szyx/tcm/supervision/config/HttpConfig.java
index 0a96e3e..caa107e 100644
--- a/src/main/java/com/szyx/tcm/supervision/config/HttpConfig.java
+++ b/src/main/java/com/szyx/tcm/supervision/config/HttpConfig.java
@@ -4,6 +4,7 @@ import org.asynchttpclient.DefaultAsyncHttpClient;
import org.asynchttpclient.DefaultAsyncHttpClientConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
/*******************************************************************
*
@@ -26,5 +27,10 @@ public class HttpConfig {
new DefaultAsyncHttpClientConfig.Builder().setMaxRequestRetry(3).setConnectTimeout(1000).setFollowRedirect(false).setMaxConnections(100).setMaxConnectionsPerHost(10).build());
}
+ @Bean
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+
}
diff --git a/src/main/java/com/szyx/tcm/supervision/config/InsuranceInterceptor.java b/src/main/java/com/szyx/tcm/supervision/config/InsuranceInterceptor.java
new file mode 100644
index 0000000..ffc58e6
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/config/InsuranceInterceptor.java
@@ -0,0 +1,78 @@
+package com.szyx.tcm.supervision.config;
+
+import com.fiftyonetrust.common.model.exception.CodeException;
+import com.szyx.tcm.supervision.enums.ResultEnum;
+import com.szyx.tcm.supervision.util.SZYXAccessUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/*******************************************************************
+ *
+ * @文件名称: InsuranceInterceptor.java
+ * @包 路 径: com.szyx.tcm.supervision.config
+ * @Copyright:wy (C) 2024 *
+ * @Description: 医保系统拦截器 只用满足鉴权的请求才能访问
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/26 16:13
+ * @Modify:
+ */
+@Slf4j
+@Component
+public class InsuranceInterceptor implements HandlerInterceptor {
+
+
+ public static void main(String[] args) {
+ long timestamp = System.currentTimeMillis();
+ System.out.println(SZYXAccessUtil.encryptTimeStamp(timestamp));
+ System.out.println(SZYXAccessUtil.encryptByAES(Long.toString(timestamp)));
+ }
+
+ @Value("${insurance.host}")
+ private String targetUrl;
+
+
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+
+ String requestUrl = request.getRequestURL().toString();
+ // 医保回调的直接转发
+ if (requestUrl.startsWith(targetUrl)) {
+ // If the request URL starts with targetUrl, bypass the interceptor
+ return true;
+ }
+
+ // 其他请求一律进行请求头校验
+ String timeStamp = request.getHeader("timestamp");
+ String accessToken = request.getHeader("accessToken");
+
+ if ( StringUtils.isBlank(timeStamp) || StringUtils.isBlank(accessToken) ) {
+ throw new CodeException(ResultEnum.VERIFY_ERROR.getCode(), ResultEnum.VERIFY_ERROR.getMessage());
+ }
+
+ if(!SZYXAccessUtil.verifyTimeStamp(timeStamp, accessToken)){
+ throw new CodeException(ResultEnum.VERIFY_ERROR.getCode(), ResultEnum.VERIFY_ERROR.getMessage());
+ }
+
+
+ return HandlerInterceptor.super.preHandle(request, response, handler);
+ }
+
+ @Override
+ public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
+ HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
+ }
+
+ @Override
+ public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+ HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
+ }
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/config/WebAppConfigAdapter.java b/src/main/java/com/szyx/tcm/supervision/config/WebAppConfigAdapter.java
new file mode 100644
index 0000000..1dba124
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/config/WebAppConfigAdapter.java
@@ -0,0 +1,35 @@
+package com.szyx.tcm.supervision.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import javax.annotation.Resource;
+
+/*******************************************************************
+ *
+ * @文件名称: WebAppConfigAdapter.java
+ * @包 路 径: com.szyx.tcm.supervision.config
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/26 18:05
+ * @Modify:
+ */
+@Configuration
+public class WebAppConfigAdapter implements WebMvcConfigurer {
+
+ @Resource
+ private InsuranceInterceptor insuranceInterceptor;
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+
+ // 走代理转发的接口添加拦截器
+ registry.addInterceptor(insuranceInterceptor)
+ .addPathPatterns("/proxy/**");
+
+ WebMvcConfigurer.super.addInterceptors(registry);
+ }
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/constant/WeChatInsurancePayConstant.java b/src/main/java/com/szyx/tcm/supervision/constant/WeChatInsurancePayConstant.java
new file mode 100644
index 0000000..66f798a
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/constant/WeChatInsurancePayConstant.java
@@ -0,0 +1,78 @@
+package com.szyx.tcm.supervision.constant;
+
+/*******************************************************************
+ *
+ * @文件名称: WeChatInsurancePayConstant.java
+ * @包 路 径: com.szyx.tcm.common.constant
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/24 14:09
+ * @Modify:
+ */
+public interface WeChatInsurancePayConstant {
+
+ // ================= 医保核心系统有关 ===========================
+
+ /**
+ * 系统版本号
+ */
+ String INSURANCE_CORE_SYSTEM_VERSION = "V1.0";
+
+ /**
+ * 接收方系统代码
+ */
+ String INSURANCE_CORE_RECEIVER_SYS_CODE = "SH_CLOUD";
+
+
+ /**
+ * 医保核心交易报文ID 【9001】签到
+ */
+ String INSURANCE_CORE_MSG_ID_SIGN_IN = "9001";
+
+
+
+ /**
+ * 医保核心交易报文ID 【1101】人员基本信息获取
+ */
+ String INSURANCE_CORE_BASIC_INFO = "1101";
+
+
+
+
+
+
+
+
+ // ================= 医保支付中台有关 ===========================
+
+ /**
+ * feeType 费用类型 05 互联网医院问诊
+ */
+ String INSURANCE_PAY_FEE_TYPE = "05";
+
+
+
+
+
+
+
+
+
+
+
+
+ // ================= 微信医保支付平台有关 ===========================
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/controller/insurance/HealthInsuranceController.java b/src/main/java/com/szyx/tcm/supervision/controller/insurance/HealthInsuranceController.java
new file mode 100644
index 0000000..3c850ca
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/controller/insurance/HealthInsuranceController.java
@@ -0,0 +1,119 @@
+package com.szyx.tcm.supervision.controller.insurance;
+
+import com.fiftyonetrust.common.model.result.R;
+import com.szyx.tcm.supervision.model.dto.insurance.*;
+import com.szyx.tcm.supervision.model.dto.insurance.core.Signinoutb;
+import com.szyx.tcm.supervision.service.manager.HealthInsuranceManager;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+
+/*******************************************************************
+ *
+ * @文件名称: HealthInsurenceController.java
+ * @包 路 径: com.szyx.tcm.web.patient.controller.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/16 10:12
+ * @Modify:
+ */
+@RestController
+@RequestMapping("/insurance")
+public class HealthInsuranceController {
+
+ @Resource
+ private HealthInsuranceManager healthInsuranceManager;
+
+
+ // 1 根据购药单id生成小程序医保授权链接
+ @GetMapping("/getAuthUrl/{platformOrderId}")
+ @ApiOperation(value = "生成小程序医保授权链接")
+ public R getAuthUrl(@PathVariable("platformOrderId") String medicineOrderId) {
+ return R.ok(healthInsuranceManager.getAuthUrl(medicineOrderId));
+ }
+
+
+ // 2 河南医保平台下单,获取订单医保分账
+
+ @PostMapping("/getOrder")
+ @ApiOperation(value = "河南医保平台下单,获取订单医保分账")
+ public R getOrder(@RequestBody InsuranceGetOrderReq req) {
+ return R.ok(healthInsuranceManager.getOrder(req));
+ }
+
+ // 3 根据医保平台下单分账信息,确认支付,微信统一下单
+ @PostMapping("/confirmPay")
+ @ApiOperation(value = "根据医保平台下单分账信息,确认支付,微信统一下单")
+ public R confirmPay(@RequestBody UnifiedOrderReq req) {
+ return R.ok(healthInsuranceManager.confirmPay(req));
+ }
+
+
+
+ // 根据授权码查询用户的医保电子凭证信息
+ @PostMapping("/getInsuranceInfo")
+ @ApiOperation(value = "根据授权码查询用户的医保电子凭证信息")
+ public R getInsuranceInfo(@RequestBody InsuranceReq req) {
+ return R.ok(healthInsuranceManager.getInsuranceInfo(req));
+ }
+
+ // 省医保核心系统「9001」 接口签到获取流水号 ,后续接口调用前需先调用此接口获取流水号
+ @PostMapping("/getSerialNumber")
+ @ApiOperation(value = "接口签到获取流水号")
+ public R getSerialNumber() {
+ return R.ok(healthInsuranceManager.getSerialNumber());
+ }
+
+
+ // 省医保核心系统「1101」获取医保人员基础信息
+ @PostMapping("/getBasicInsuranceInfo")
+ @ApiOperation(value = "获取医保人员基础信息")
+ public R getBasicInsuranceInfo() {
+ return R.ok(healthInsuranceManager.getBasicInsuranceInfo(new Signinoutb()));
+ }
+
+
+ // 省医保平台「6201」上传处方药费明细
+ @PostMapping("/uploadRecipeDetail")
+ @ApiOperation(value = "上传处方药费明细")
+ public R uploadRecipeDetail() {
+ return R.ok(healthInsuranceManager.uploadRecipeDetail(new InsuranceGetOrderReq(), new InsuranceRep(), new InsuranceCoreOutputMessage1101()));
+ }
+
+
+ // 省医保平台「6202」支付下单
+ @PostMapping("/payOrder")
+ @ApiOperation(value = "支付下单")
+ public R payOrder() {
+ return R.ok(healthInsuranceManager.payOrder(new InsuranceGetOrderReq() , new InsuranceRep(), new InsuranceUploadRecipeDetailOutputMessage()));
+ }
+
+
+ //获取微信医保移动支付access_token 服务商获取方式
+ @PostMapping("/getInsuranceAccessToken")
+ @ApiOperation(value = "获取微信医保移动支付access_token")
+ public R getInsuranceAccessToken(@RequestBody InsuranceAccessTokenReq req) {
+ return R.ok(healthInsuranceManager.InsuranceAccessToken(req));
+ }
+
+
+ // 微信医保平台统一下单
+ @PostMapping("/unifiedOrder")
+ @ApiOperation(value = "统一下单")
+ public R unifiedOrder() throws Exception {
+ return R.ok(healthInsuranceManager.unifiedOrder(new UnifiedOrderReq()));
+ }
+
+
+ // 读取当前配置信息
+ @GetMapping("/getInsuranceConfig")
+ @ApiOperation(value = "读取当前配置信息")
+ public R getInsuranceConfig() {
+ return R.ok(healthInsuranceManager.getInsuranceConfig());
+ }
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/controller/insurance/ProxyController.java b/src/main/java/com/szyx/tcm/supervision/controller/insurance/ProxyController.java
new file mode 100644
index 0000000..99cd1ed
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/controller/insurance/ProxyController.java
@@ -0,0 +1,66 @@
+package com.szyx.tcm.supervision.controller.insurance;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.*;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Enumeration;
+import java.util.Objects;
+
+/*******************************************************************
+ *
+ * @文件名称: ProxyController.java
+ * @包 路 径: com.szyx.tcm.supervision.controller.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description: 用于进行代理转发 所有从云端系统过来的请求都会经过这个controller
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/26 17:34
+ * @Modify:
+ */
+@RestController
+@RequestMapping("/proxy")
+public class ProxyController {
+
+ @Value("${insurance.host}")
+ private String targetUrl;
+
+ @Value("${server.servlet.context-path}")
+ private String contextPath;
+
+
+ private final RestTemplate restTemplate;
+
+
+ public ProxyController(RestTemplate restTemplate) {
+ this.restTemplate = restTemplate;
+ }
+
+
+ @RequestMapping("/**")
+ public ResponseEntity proxyRequest(HttpServletRequest request, @RequestBody(required = false) String body) {
+ String url = targetUrl + request.getRequestURI().substring(("/" + contextPath + "/proxy").length());
+
+ HttpHeaders headers = new HttpHeaders();
+ Enumeration headerNames = request.getHeaderNames();
+ while (headerNames.hasMoreElements()) {
+ String headerName = headerNames.nextElement();
+ headers.add(headerName, request.getHeader(headerName));
+ }
+
+ HttpHeaders responseHeaders = new HttpHeaders();
+ responseHeaders.setContentType(MediaType.APPLICATION_JSON);
+
+ HttpEntity entity = new HttpEntity<>(body, headers);
+ ResponseEntity response = restTemplate.exchange(url, Objects.requireNonNull(HttpMethod.resolve(request.getMethod())), entity, String.class);
+
+ return new ResponseEntity<>(response.getBody(), responseHeaders,response.getStatusCode());
+ }
+
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/enums/BannerEnum.java b/src/main/java/com/szyx/tcm/supervision/enums/BannerEnum.java
new file mode 100644
index 0000000..c41852a
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/enums/BannerEnum.java
@@ -0,0 +1,54 @@
+package com.szyx.tcm.supervision.enums;
+
+/**
+ * @author cj
+ */
+public enum BannerEnum {
+
+ /**
+ * banner 状态
+ */
+
+ PUBLISH(0,"已发布"),
+ RELEASED(1,"待发布"),
+ REVOKED(2,"已撤销"),
+ EXPIRED(3,"已过期"),
+
+ PERMANENT(4,"永久");
+
+
+ /**
+ * 字典类型
+ */
+ private Integer code;
+
+ /**
+ * 字典名称
+ */
+ private String name;
+
+
+
+
+ public Integer getCode() {
+ return code;
+ }
+
+ public void setCode(Integer code) {
+ this.code = code;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ BannerEnum(Integer code, String name){
+ this.code=code;
+ this.name=name;
+ }
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/enums/ResultEnum.java b/src/main/java/com/szyx/tcm/supervision/enums/ResultEnum.java
new file mode 100644
index 0000000..2df82b3
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/enums/ResultEnum.java
@@ -0,0 +1,66 @@
+package com.szyx.tcm.supervision.enums;
+
+import com.fiftyonetrust.common.model.pojo.ResultCode;
+
+/**
+ *
+ *
+ * @文件名称: ResultEnum
+ * @包 路 径: enums
+ * @Copyright:北京数字医信科技责任有限公司 (C) 2023 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: hq
+ * @Date: 2023/08/22 11:01
+ * @Modify:
+ */
+public enum ResultEnum implements ResultCode {
+
+ FREIGHT_SETTING_ERROR(20001, "获取二维码失败"),
+ UN_LOGIN_ERROR(20002, "未登录"),
+ TOKEN_EXPIRED_ERROR(20003, "登录已过期,请重新登录"),
+ DOCTOR_NOT_EXIST(20004, "账号未绑定!"),
+ SELECT_ERROR(20005, "查询失败"),
+ VERIFY_SIGNED_ERR(20006, "验证第三方签名摘要信息signed失败"),
+ RECIPE_SIGN_NO_EXIST(20007, "处方签名数据不存在"),
+ YWX_SYN_SIGN(20008, "调用医网信同步待签名数据失败"),
+ RECIPE_SIGN_UPDATE_ERROR(20009, "处方签名数据更新失败"),
+ HOS_SIGN_INSERT_ERROR(20010, "医院签章数据插入失败"),
+ RECIPE_HOSPITAL_SIGN_ERROR(20011, "处方互联网医院签章操作未找到医生已签数据"),
+ PDF_DOWNLOAD_ERROR(20012, "pdf下载失败"),
+ PDF_UPLOAD_ERROR(20013, "pdf上传失败"),
+ RECIPE_PATIENT_NOT_EXIST(20014, "处方患者信息不存在"),
+ PARAMS_ERROR(20015, "参数异常"),
+ PDF_PAGES_ERROR(20016, "pdf获取页数异常"),
+ UPDATE_RECIPE_ERROR(20017, "同步pdf到同仁堂失败"),
+ UNIQUE_ID_NO_EXIST(20018, "回调signId参数为空"),
+ SIGNED_PDF_BASE64_NO_EXIST(20019, "回调pdfBase64为空"),
+ OPEN_ID_NO_EXIST(20020, "openID为空"),
+ ADD_SIGN_IMAGE(20021,"添加签名图片异常"),
+ ADD_STAMP_IMAGE(20022,"添加签章图片异常"),
+
+ DECRYPT_ERROR(10055, "解密异常"),
+
+ REPETITION_ERROR(10056, "请勿重复操作"),
+
+ VERIFY_ERROR(10057, "鉴权失败,请检查请求头参数"),
+ ;
+
+ private final Integer code;
+ private final String message;
+
+ ResultEnum(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ @Override
+ public int getCode() {
+ return this.code;
+ }
+
+ @Override
+ public String getMessage() {
+ return this.message;
+ }
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/enums/WeekDayEnum.java b/src/main/java/com/szyx/tcm/supervision/enums/WeekDayEnum.java
new file mode 100644
index 0000000..18b9f83
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/enums/WeekDayEnum.java
@@ -0,0 +1,67 @@
+package com.szyx.tcm.supervision.enums;
+
+import lombok.Getter;
+
+/**
+ *
+ *
+ * @文件名称: WeekDayEnum
+ * @包 路 径: com.szyx.tcm.common.enums
+ * @Copyright:北京数字医信科技责任有限公司 (C) 2023 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: luzhenjie
+ * @Date:2023/6/1 12:03
+ * @Modify:
+ */
+@Getter
+public enum WeekDayEnum {
+
+ SUNDAY(1, "SUNDAY", "周日",7),
+ MONDAY(2, "MONDAY", "周一",1),
+ TUESDAY(3, "TUESDAY", "周二",2),
+ WEDNESDAY(4, "WEDNESDAY", "周三",3),
+ THURSDAY(5, "THURSDAY", "周四",4),
+ FRIDAY(6, "FRIDAY", "周五",5),
+ SATURDAY(7, "SATURDAY", "周六",6);
+
+ private final Integer code;
+ private final String name;
+ private final String desc;
+ //
+ private final Integer index;
+
+ WeekDayEnum(int code, String name, String desc, Integer index) {
+ this.code = code;
+ this.name = name;
+ this.desc = desc;
+ this.index = index;
+ }
+
+ public static String getByCode(Integer code) {
+ for (WeekDayEnum statusEnum : WeekDayEnum.values()) {
+ if (statusEnum.getCode().equals(code)) {
+ return statusEnum.desc;
+ }
+ }
+ return "";
+ }
+
+ public static String getByName(String name) {
+ for (WeekDayEnum statusEnum : WeekDayEnum.values()) {
+ if (statusEnum.getName().equals(name)) {
+ return statusEnum.desc;
+ }
+ }
+ return "";
+ }
+
+ public static Integer getIndexByCode(Integer code) {
+ for (WeekDayEnum statusEnum : WeekDayEnum.values()) {
+ if (statusEnum.getCode().equals(code)) {
+ return statusEnum.index;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/DiseInfo.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/DiseInfo.java
new file mode 100644
index 0000000..9aebd7f
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/DiseInfo.java
@@ -0,0 +1,68 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: DiseInfoList.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/17 14:52
+ * @Modify:
+ */
+@Data
+@ApiModel("省医保平台「6201」上传处方药费明细请求参数诊断或症状明细")
+public class DiseInfo {
+
+ /**
+ * diagType 诊断类别 字符型 3 Y 字典诊断类别(diag_type)
+ * 1 西医主要诊断 3 中医主病诊断
+ * 2 西医其他诊断 4 中医主证诊断
+ */
+ private String diagType;
+
+ /**
+ * diagSrtNo 诊断排序号 数值型 2 Y
+ */
+ private Integer diagSrtNo;
+
+ /**
+ * diagCode 诊断代码 字符型 20 Y
+ */
+ private String diagCode;
+
+ /**
+ * diagName 诊断名称 字符型 100 Y
+ */
+ private String diagName;
+
+ /**
+ * diagDept 诊断科室 字符型 50 Y
+ */
+ private String diagDept;
+
+ /**
+ * diseDorNo 诊断医生编码 字符型 30 Y
+ */
+ private String diseDorNo;
+
+ /**
+ * diseDorName 诊断医生姓名 字符型 50 Y
+ */
+ private String diseDorName;
+
+ /**
+ * diagTime 诊断时间 字符型 19 Y yyyy-MM-dd HH:mm:ss
+ */
+ private String diagTime;
+
+ /**
+ * valiFlag 有效标志 字符型 3 Y
+ */
+ private String valiFlag;
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/FeeDetail.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/FeeDetail.java
new file mode 100644
index 0000000..6c97599
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/FeeDetail.java
@@ -0,0 +1,131 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/*******************************************************************
+ *
+ * @文件名称: FeeDetailList.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/17 14:57
+ * @Modify:
+ */
+@Data
+@ApiModel("省医保平台「6201」上传处方药费明细请求参数费用明细")
+public class FeeDetail {
+
+ /**
+ * feedetlSn 费用明细流水号 字符型 30 Y 单次就诊内唯一
+ */
+ private String feedetlSn;
+
+ /**
+ * mdtrtId 就诊ID 字符型 30 N
+ */
+ private String mdtrtId;
+
+ /**
+ * psnNo 人员编号 字符型 30 Y
+ */
+ private String psnNo;
+
+ /**
+ * chrgBchno 收费批次号 字符型 30 Y 同一收费批次号病种编号必须一致
+ */
+ private String chrgBchno;
+
+ /**
+ * diseCodg 病种编码 字符型 30 N 按照标准编码填写:
+ * 按病种结算病种目录代码(bydise_setl_list_code)、
+ * 门诊慢特病病种目录代码(opsp_dise_cod)
+ */
+ private String diseCodg;
+
+ /**
+ * rxno 处方号 字符型 30 N 外购处方时,传入外购处方的处方号;非外购处方,传入医药机构处方号
+ */
+ private String rxno;
+
+ /**
+ * rxCircFlag 外购处方标志 字符型 3 Y
+ */
+ private String rxCircFlag;
+
+ // yyyy-MM-dd HH:mm:ss
+ /**
+ * feeOcurTime 费用发生时间 日期时间型 Y yyyy-MM-dd HH:mm:ss
+ */
+ private String feeOcurTime;
+
+ /**
+ * medListCodg 医疗目录编码 字符型 50 Y
+ */
+ private String medListCodg;
+
+ /**
+ * medinsListCodg 医药机构目录编码 字符型 150 Y
+ */
+ private String medinsListCodg;
+
+ /**
+ * detItemFeeSumamt 明细项目费用总额 数值型 16,2 Y
+ */
+ private BigDecimal detItemFeeSumamt;
+
+ /**
+ * cnt 数量 数值型 16,4 Y
+ */
+ private BigDecimal cnt;
+
+ /**
+ * pric 单价 数值型 16,6 Y
+ */
+ private BigDecimal pric;
+
+ /**
+ * bilgDeptCodg 开单科室编码 字符型 30 Y
+ */
+ private String bilgDeptCodg;
+
+ /**
+ * bilgDeptName 开单科室名称 字符型 100 Y
+ */
+ private String bilgDeptName;
+
+ /**
+ * bilgDrCodg 开单医生编码 字符型 30 Y 按照标准编码填写
+ */
+ private String bilgDrCodg;
+
+ /**
+ * bilgDrName 开单医师姓名 字符型 50 Y
+ */
+ private String bilgDrName;
+
+ /**
+ *hospApprFlag 医院审批标志 字符型 3 Y
+ */
+ private String hospApprFlag;
+
+ /**
+ * medType 医疗类别 字符型 6 Y
+ */
+ private String medType;
+
+ /**
+ * medListName 医疗目录名称 字符型 50 Y
+ */
+ private String medListName;
+
+ /**
+ * medListSpc 医疗目录规格 字符型 50 Y
+ */
+ private String medListSpc;
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceAccessTokenRep.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceAccessTokenRep.java
new file mode 100644
index 0000000..8f98e2f
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceAccessTokenRep.java
@@ -0,0 +1,82 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: InsuranceAccessTokenRep.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/16 11:31
+ * @Modify:
+ */
+@Data
+@ApiModel("获取AccessToken")
+public class InsuranceAccessTokenRep {
+
+ /**
+ * return_code
+ * 返回状态码
+ * string16
+ * Y
+ * SUCCESS/FAIL
+ */
+ private String returnCode;
+
+ /**
+ * return_msg
+ * return_msg
+ * string128
+ * N
+ * 返回信息,如非空,为错误原因
+ */
+ private String returnMsg;
+
+
+ /**
+ * result_code
+ * 业务结果
+ * String16
+ * Y
+ * SUCCESS/FAIL
+ */
+ private String resultCode;
+
+ /**
+ * err_code
+ * 错误代码
+ * String32
+ * N
+ */
+ private String errCode;
+
+ /**
+ * err_code_des
+ * 错误代码描述
+ * String128
+ * N
+ */
+ private String errCodeDes;
+
+ /**
+ * access_token
+ * 获取到的凭证
+ * String256
+ * Y
+ */
+ private String accessToken;
+
+ /**
+ * expires_in
+ * 凭证有效时间
+ * Uint32
+ * Y
+ * 单位:秒
+ */
+ private Integer expiresIn;
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceAccessTokenReq.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceAccessTokenReq.java
new file mode 100644
index 0000000..6758283
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceAccessTokenReq.java
@@ -0,0 +1,30 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: InsuranceAccessTokenReq.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/16 11:26
+ * @Modify:
+ */
+@Data
+@ApiModel("获取用户医保参数")
+public class InsuranceAccessTokenReq {
+
+ private String grant_type = "client_credential";
+
+ private String agentappid;
+
+ private String agentsecret;
+
+ private String appid;
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceCoreCommonInputMessage.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceCoreCommonInputMessage.java
new file mode 100644
index 0000000..9d34c58
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceCoreCommonInputMessage.java
@@ -0,0 +1,80 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: InsuranceCoreCommonMessage.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description: 河南医保核心系统公共报文 v1.4
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/22 10:18
+ * @Modify:
+ */
+@Data
+public class InsuranceCoreCommonInputMessage {
+
+ // infno 交易编号 字符型 4 Y 交易编号详见接口列表
+ private String infno;
+
+ // msgid 发送方报文ID 字符型 30 Y 定点医药机构编号(12)+时间(14)+顺序号(4)
+ //时间格式:yyyyMMddHHmmss
+ private String msgid;
+
+ // mdtrtarea_admvs 就医地医保区划 字符型 6 Y
+ private String mdtrtareaAdmvs;
+
+ // insuplc_admdvs 参保地医保区划 字符型 6 如果交易输入中含有人员编号,此项必填,可通过【1101】人员信息获取交易取得
+ private String insuplcAdmdvs;
+
+ // recer_sys_code 接收方系统代码 字符型 10 Y 用于多套系统接入,区分不同系统使用
+ private String recerSysCode;
+
+ // dev_no 设备编号 字符型 100
+ private String devNo;
+
+ // dev_safe_info 设备安全信息 字符型 2000
+ private String devSafeInfo;
+
+ // cainfo 数字签名信息 字符型 1024
+ private String cainfo;
+
+ // signtype 签名类型 字符型 10 建议使用SM2、SM3
+ private String signtype;
+
+ // infver 接口版本号 字符型 6 Y 例如:“V1.0”,版本号由医保下发通知。
+ private String infver;
+
+ // opter_type 经办人类别 3 Y Y 1-经办人;2-自助终端;3-移动终端
+ private String opterType;
+
+ // opter 经办人 字符型 20 Y 按地方要求传入经办人/终端编号
+ private String opter;
+
+ // opter_name 经办人姓名 字符型 50 Y 按地方要求传入经办人姓名/终端名称
+ private String opterName;
+
+ // inf_time 交易时间 日期时间型 19 Y
+ private String infTime;
+
+ // fixmedins_code 定点医药机构编号 字符型 12 Y
+ private String fixmedinsCode;
+
+ // fixmedins_name 定点医药机构名称 字符型 20 Y
+ private String fixmedinsName;
+
+ // sign_no 交易签到流水号 字符型 30 通过签到【9001】交易获取
+ private String signNo;
+
+ // input 交易输入 字符型 40000 Y
+ private String input;
+
+
+
+
+
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceCoreCommonOutputMessage.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceCoreCommonOutputMessage.java
new file mode 100644
index 0000000..6940c56
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceCoreCommonOutputMessage.java
@@ -0,0 +1,41 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: InsuranceCoreCommonOutputMessage.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description: 河南医保核心系统公共报文 v1.4
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/22 10:27
+ * @Modify:
+ */
+@Data
+public class InsuranceCoreCommonOutputMessage {
+
+ // infcode 交易状态码 数值型 4 Y
+ private Integer infcode;
+
+ // inf_refmsgid 接收方报文ID 字符型 30 Y 接收方返回,接收方医保区划代码(6)+时间(14)+流水号(10)
+ //时间格式:yyyyMMddHHmmss
+ private String infRefmsgid;
+
+ // refmsg_time 接收报文时间 字符型 17 格式:yyyyMMddHHmmssSSS
+ private String refmsgTime;
+
+ // respond_time 响应报文时间 字符型 17 格式:yyyyMMddHHmmssSSS
+ private String respondTime;
+
+ // err_msg 错误信息 字符型 200 交易失败状态下,业务返回的错误信息
+ private String errMsg;
+
+ // output 交易输出 字符型 40000
+ private String output;
+
+
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceCoreInputMessage1101.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceCoreInputMessage1101.java
new file mode 100644
index 0000000..ae3e859
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceCoreInputMessage1101.java
@@ -0,0 +1,55 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: InsuranceCoreInputMessage1101.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description: 1101 输入报文
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/22 14:12
+ * @Modify:
+ */
+@Data
+public class InsuranceCoreInputMessage1101 {
+
+ /**
+ * mdtrt_cert_type 就诊凭证类型 字符型 3 Y Y
+ */
+ private String mdtrtCertType;
+
+ /**
+ * mdtrt_cert_no 就诊凭证号码 字符型 50 Y Y
+ */
+ private String mdtrtCertNo;
+
+ /**
+ * card_sn 卡识别码 字符型 32 就诊凭证类型为“03”时必填
+ */
+ private String cardSn;
+
+ /**
+ * begntime 开始时间 日期时间型 获取历史参保信息时传入
+ */
+ private String begntime;
+
+ /**
+ * psn_cert_type 人员证件类型 字符型 6 Y 就诊凭证类型为“01”和“03”时必填
+ */
+ private String psnCertType;
+
+ /**
+ * certno 证件号码 字符型 50 就诊凭证类型为“01”和“03”时必填
+ */
+ private String certno;
+
+ /**
+ * psn_name 人员姓名 字符型 50 Y
+ */
+ private String psnName;
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceCoreOutputMessage1101.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceCoreOutputMessage1101.java
new file mode 100644
index 0000000..82d998f
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceCoreOutputMessage1101.java
@@ -0,0 +1,288 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.annotation.JSONField;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/*******************************************************************
+ *
+ * @文件名称: InsuranceCoreOutputMessage1101.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/22 14:23
+ * @Modify:
+ */
+@Data
+public class InsuranceCoreOutputMessage1101 {
+
+ /**
+ * 输出-基本信息
+ */
+ private Baseinfo baseinfo;
+
+ /**
+ * 输出-参保信息列表
+ */
+ private Insuinfo insuinfo;
+
+ /**
+ * 输出-身份信息列表
+ */
+ private List idetinfo;
+
+
+ @Data
+ public static class Baseinfo{
+ /**
+ * psn_no 人员编号 字符型 30 Y
+ */
+ @JSONField(name = "psn_no")
+ private String psnNo;
+
+ /**
+ * psn_cert_type 人员证件类型 字符型 6 Y Y
+ */
+ @JSONField(name = "psn_cert_type")
+ private String psnCertType;
+
+ /**
+ * certno 证件号码 字符型 50 Y
+ */
+ private String certno;
+
+ /**
+ * psn_name 人员姓名 字符型 50 Y
+ */
+ @JSONField(name = "psn_name")
+ private String psnName;
+
+ /**
+ * gend 性别 字符型 6 Y Y
+ */
+ private String gend;
+
+ /**
+ * naty 民族 字符型 3 Y
+ */
+ private String naty;
+
+ /**
+ * brdy 出生日期 日期型 yyyy-MM-dd
+ */
+ private String brdy;
+
+ /**
+ * age 年龄 数值型 4,1 Y
+ */
+ private String age;
+
+ /**
+ * exp_content 字段扩展 字符型 4000 只有居民返回
+ * 家庭账户余额
+ * 门诊统筹累计
+ * {
+ * “fm_acct_amt”:0
+ * “jmmztc_cum”:0
+ * }
+ */
+ private ExpContent expContent;
+
+ @Data
+ public class ExpContent {
+
+ /**
+ * fm_acct_amt 家庭账户余额 数值型 16,2 只有居民返回
+ */
+ private String fmAcctAmt;
+
+ /**
+ * jmmztc_cum 门诊统筹累计 数值型 16,2 只有居民返回
+ */
+ private String jmmztcCum;
+
+ /**
+ * mat_idet_flag 医疗救助标识 字符型 6 0否,1是
+ */
+ private String matIdetFlag;
+
+ /**
+ * mat_idet_code 救助对象身份 字符型 10 Y
+ */
+ private String matIdetCode;
+
+
+ }
+
+
+
+
+
+ }
+
+ @Data
+ public static class Insuinfo{
+
+ /**
+ * psn_insu_rlts_id 人员参保关系ID 字符型 20
+ */
+ @JSONField(name = "psn_insu_rlts_id")
+ private String psnInsuRltsId;
+
+ /**
+ * balc 余额 数值型 16,2 Y
+ */
+ private BigDecimal balc;
+
+ /**
+ * insutype 险种类型 字符型 6 Y Y
+ */
+ private String insutype;
+
+ /**
+ * psn_type 人员类别 字符型 6 Y Y
+ */
+ @JSONField(name = "psn_type")
+ private String psnType;
+
+ /**
+ * psn_insu_stas 人员参保状态 字符型 6 Y
+ */
+ @JSONField(name = "psn_insu_stas")
+ private String psnInsuStas;
+
+ /**
+ * psn_insu_date 个人参保日期 日期型
+ */
+ private String psnInsuDate;
+
+ /**
+ * paus_insu_date 暂停参保日期 日期型
+ */
+ private String pausInsuDate;
+
+ /**
+ * cvlserv_flag 公务员标志 字符型 3 Y Y
+ */
+ @JSONField(name = "cvlserv_flag")
+ private String cvlservFlag;
+
+ /**
+ * insuplc_admdvs 参保地医保区划 字符型 6 Y
+ */
+ private String insuplcAdmdvs;
+
+ /**
+ * emp_name 单位名称 字符型 200
+ */
+ @JSONField(name = "emp_name")
+ private String empName;
+
+ }
+
+ @Data
+ public class Idetinfo{
+
+ /**
+ * psn_idet_type 人员身份类别 字符型 10 Y Y
+ */
+ @JSONField(name = "psn_idet_type")
+ private String psnIdetType;
+
+ /**
+ * psn_type_lv 人员类别等级 字符型 3 Y 详见残疾等级字典
+ */
+ @JSONField(name = "psn_type_lv")
+ private String psnTypeLv;
+
+ /**
+ * memo 备注 字符型 500
+ */
+ private String memo;
+
+ /**
+ * begntime 开始时间 日期时间型 Y
+ */
+ private String begntime;
+
+ /**
+ * endtime 结束时间 日期时间型
+ */
+ private String endtime;
+
+ }
+
+
+ public static void main(String[] args) {
+
+ String s = "{\n" +
+ " \"infcode\": \"1\",\n" +
+ " \"inf_refmsgid\": \"000000202001041235391234567890\",\n" +
+ " \"refmsg_time\": \"20200201133411352\",\n" +
+ " \"respond_time\": \"20200202133731456\",\n" +
+ " \"err_msg\": \"\",\n" +
+ " \"output\": {\n" +
+ " \"baseinfo\": {\n" +
+ " \"psn_no\": \"131000202001001\",\n" +
+ " \"psn_cert_type\": \"2\",\n" +
+ " \"certno\": \"510000202001010000\",\n" +
+ " \"psn_name\": \"李四\",\n" +
+ " \"gend\": \"1\",\n" +
+ " \"naty\": \"01\",\n" +
+ " \"brdy\": \"2020-01-01\",\n" +
+ " \"age\": 18\n" +
+ " },\n" +
+ " \"insuinfo\": {\n" +
+ " \"psn_insu_rlts_id\": \"133241523001001\",\n" +
+ " \"balc\": 5000,\n" +
+ " \"insutype\": \"310\",\n" +
+ " \"psn_type\": \"1001\",\n" +
+ " \"cvlserv_flag\": \"0\",\n" +
+ " \"insu_admdvs\": \"131002\",\n" +
+ " \"emp_name\": \"测试单位\"\n" +
+ " },\n" +
+ " \"idetinfo\": [\n" +
+ " {\n" +
+ " \"psn_idet_type\": \"1\",\n" +
+ " \"psn_type_lv\": \"1\",\n" +
+ " \"memo\": \"\",\n" +
+ " \"begntime\": \"2020-01-01 00:00:00\",\n" +
+ " \"endtime\": \"\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"psn_idet_type\": \"2\",\n" +
+ " \"psn_type_lv\": \"1\",\n" +
+ " \"memo\": \"\",\n" +
+ " \"begntime\": \"2020-01-01 00:00:00\",\n" +
+ " \"endtime\": \"\"\n" +
+ " }\n" +
+ " ]\n" +
+ " }\n" +
+ "}";
+
+
+
+
+ InsuranceCoreCommonOutputMessage outputMessage = JSON.parseObject(s, InsuranceCoreCommonOutputMessage.class);
+
+ // 收到的1101报文
+ InsuranceCoreOutputMessage1101 insuranceCoreOutputMessage1101 = JSON.parseObject(outputMessage.getOutput(), InsuranceCoreOutputMessage1101.class);
+
+ System.out.println(insuranceCoreOutputMessage1101);
+
+ }
+
+
+
+
+
+
+
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceGetOrderReq.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceGetOrderReq.java
new file mode 100644
index 0000000..a813623
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceGetOrderReq.java
@@ -0,0 +1,55 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: InsuranceGetOrderReq.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/19 10:37
+ * @Modify:
+ */
+@Data
+@ApiModel("医保下单参数")
+public class InsuranceGetOrderReq {
+
+
+ @ApiModelProperty("购药单id 如果是购药单医保支付传购药单id,如果是问诊单医保支付传问诊单id")
+ private String platformOrderId;
+
+
+ @ApiModelProperty("医保支付订单类型 1: 问诊单 2: 购药单")
+ private Integer orderType = 1;
+
+ @ApiModelProperty("微信医保授权码")
+ private String authCode;
+
+
+ @ApiModelProperty("订单医疗费总额")
+ private String medfeeSumamt;
+
+
+ @ApiModelProperty("业务流水号")
+ private String orgBizSer;
+
+ @ApiModelProperty("收费批次号")
+ private String chrgBchno;
+
+ @ApiModelProperty("费用类别")
+ private String feeType;
+
+ @ApiModelProperty("就诊事件ID")
+ private String mdtrtId;
+
+ @ApiModelProperty("医疗机构订单号")
+ private String medOrgOrd;
+
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceMiddleGroundInputMessage.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceMiddleGroundInputMessage.java
new file mode 100644
index 0000000..f8ffe6f
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceMiddleGroundInputMessage.java
@@ -0,0 +1,56 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: InsuranceMiddleGroundInputMessage.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description: 省移动支付中台 公共请求报文
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/22 15:08
+ * @Modify:
+ */
+@Data
+public class InsuranceMiddleGroundInputMessage {
+
+ /**
+ * appId 渠道id String(32) N
+ */
+ private String appId;
+
+ /**
+ * version 版本号 String(6) N 2.0.1
+ */
+ private String version;
+
+ /**
+ * timestamp 当前时间 String(32) N 时间戳
+ */
+ private String timestamp;
+
+ /**
+ * encType 加密方式 String(6) N SM4
+ */
+ private String encType;
+
+ /**
+ * encData 加密数据 String(max) N
+ */
+ private String encData;
+
+ /**
+ * signType 签名方式 String(6) N SM2
+ */
+ private String signType;
+
+ /**
+ * signData 签名串 String(200) N
+ */
+ private String signData;
+
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceMiddleGroundOutputMessage.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceMiddleGroundOutputMessage.java
new file mode 100644
index 0000000..9bcd51c
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceMiddleGroundOutputMessage.java
@@ -0,0 +1,76 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: InsuranceMiddleGroundOutputMessage.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description: 省移动支付中台 公共响应报文
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/22 15:10
+ * @Modify:
+ */
+@Data
+public class InsuranceMiddleGroundOutputMessage {
+
+ /**
+ * code 响应状态码 int N
+ */
+ private Integer code;
+
+ /**
+ * appId 渠道id String(32) N
+ */
+ private String appId;
+
+ /**
+ * timestamp 当前时间 String(32) N 时间戳
+ */
+ private String timestamp;
+
+ /**
+ * encType 加密方式 String(6) N SM4
+ */
+ private String encType;
+
+ /**
+ * signType 签名方式 String(6) N SM2
+ */
+ private String signType;
+
+ /**
+ * signData 签名串 String(200) N
+ */
+ private String signData;
+
+ /**
+ * encData 加密数据 String(max) N
+ */
+ private String encData;
+
+ /**
+ * message 响应异常信息 String(max) Y
+ */
+ private String message;
+
+ /**
+ * success 响应标识 boolean Y
+ */
+ private Boolean success;
+
+ /**
+ * version 版本号 String(6) N 2.0.1
+ */
+ private String version;
+
+
+ /**
+ * data 响应数据 Object N
+ */
+ private String data;
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsurancePayOrderInputMessage.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsurancePayOrderInputMessage.java
new file mode 100644
index 0000000..ff8bbef
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsurancePayOrderInputMessage.java
@@ -0,0 +1,67 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: InsurancePayOrderInputMessage.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/23 17:26
+ * @Modify:
+ */
+@Data
+public class InsurancePayOrderInputMessage {
+
+ /**
+ * payAuthNo 支付授权码 字符型 40 Y 电子凭证线上渠道授权返回
+ */
+ private String payAuthNo;
+
+ /**
+ * payOrdId 待支付订单号 字符型 40 Y 费用上传返回
+ */
+ private String payOrdId;
+
+ /**
+ * payToken 支付订单对应的token 字符型 40 Y 费用上传返回
+ */
+ private String payToken;
+
+ /**
+ * orgCodg 定点机构编码 字符型 12 Y
+ */
+ private String orgCodg;
+
+ /**
+ * orgBizSer 业务流水号 字符型 40 Y 每一次请求唯一
+ */
+ private String orgBizSer;
+
+ /**
+ * chrgBchno 收费批次号 字符型 40 Y 与费用上传一致
+ */
+ private String chrgBchno;
+
+ /**
+ * feeType 费用类别 字符型 2 Y 与费用上传一致
+ */
+ private String feeType;
+
+ /**
+ * mdtrtId 就诊事件ID 字符型 40 Y 与费用上传一致
+ */
+ private String mdtrtId;
+
+ /**
+ * acctUsedFlag 个账使用标识 字符型 1 N 为空时默认使用费用上传时的值
+ */
+ private String acctUsedFlag;
+
+
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsurancePayOrderOutputMessage.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsurancePayOrderOutputMessage.java
new file mode 100644
index 0000000..2a1d627
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsurancePayOrderOutputMessage.java
@@ -0,0 +1,65 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/*******************************************************************
+ *
+ * @文件名称: InsurancePayOrderOutputMessage.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description: 6202 医保支付订单响应参数
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/23 17:52
+ * @Modify:
+ */
+@Data
+@ApiModel("医保支付订单响应参数")
+public class InsurancePayOrderOutputMessage {
+
+ /**
+ * payOrdId 支付订单号 字符型 40 Y
+ */
+ @ApiModelProperty("支付订单号")
+ private String payOrdId;
+
+ /**
+ * ordStas 订单状态 字符型 40 Y 字典订单状态(ordStas)
+ */
+ @ApiModelProperty("订单状态")
+ private String ordStas;
+
+ /**
+ * feeSumamt 费用总额 数值型 12,2 Y
+ */
+ @ApiModelProperty("费用总额")
+ private BigDecimal feeSumamt;
+
+ /**
+ * ownPayAmt 现金支付 数值型 12,2 Y
+ */
+ @ApiModelProperty("现金支付")
+ private BigDecimal ownPayAmt;
+
+ /**
+ * psnAcctPay 个人账户支出 数值型 12,2 Y
+ */
+ @ApiModelProperty("个人账户支出")
+ private BigDecimal psnAcctPay;
+
+ /**
+ * fundPay 医保基金支付 数值型 12,2 Y
+ */
+ @ApiModelProperty("医保基金支付")
+ private BigDecimal fundPay;
+
+ @ApiModelProperty("医保结构体")
+ private String requestContent;
+
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceRep.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceRep.java
new file mode 100644
index 0000000..1e1641d
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceRep.java
@@ -0,0 +1,80 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import com.alibaba.fastjson2.annotation.JSONField;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: InsuranceRep.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/16 10:50
+ * @Modify:
+ */
+@Data
+@ApiModel("获取用户医保参数")
+public class InsuranceRep {
+
+ /**
+ * code
+ * 业务返回码
+ * int
+ * Y
+ * 0成功,小于0系统错误,大于0逻辑错误
+ */
+ private Integer code;
+
+ /**
+ * message
+ * 业务返回信息
+ * string
+ * Y
+ */
+ private String message;
+
+ /**
+ * user_name
+ * 用户姓名
+ * string(32)
+ * N
+ * 姓名,如张三
+ */
+ private String userName;
+
+ /**
+ * city_id
+ * 用户参保地代码
+ * string(12)
+ * N
+ * 仅当mi_card_type=CERITIFICATE时,才返回有效值,多地参保用户若未选择主参保地,则该字段未空,并且不可使用后续业务。;
+ */
+ @JSONField(name = "city_id")
+ private String cityId;
+
+ /**
+ * pay_auth_no
+ * 医保线上核验payAuthNo
+ * string(32)
+ * Y
+ * 当使用医保线上支付功能时,返回payAuthNo
+ */
+ private String payAuthNo;
+
+ /**
+ * user_longitude_latitude
+ * 用户经纬度
+ *
+ *
+ *
+ *
+ * Y
+ * 当使用医保线上支付功能时,返回对应的经纬度
+ */
+ private UserLongitudeLatitude userLongitudeLatitude;
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceReq.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceReq.java
new file mode 100644
index 0000000..e39d947
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceReq.java
@@ -0,0 +1,32 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/*******************************************************************
+ *
+ * @文件名称: InsuranceReq.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/16 10:42
+ * @Modify:
+ */
+@Data
+@Accessors(chain = true)
+@ApiModel("获取用户医保参数")
+public class InsuranceReq {
+
+ @ApiModelProperty("授权码")
+ private String qrcode;
+
+ @ApiModelProperty("用户openId")
+ private String openid;
+
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceUploadRecipeDetailInputMessage.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceUploadRecipeDetailInputMessage.java
new file mode 100644
index 0000000..d7cf531
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceUploadRecipeDetailInputMessage.java
@@ -0,0 +1,297 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/*******************************************************************
+ *
+ * @文件名称: InsuranceUploadRecipeDetailDTO.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/17 14:36
+ * @Modify:
+ */
+@Data
+@ApiModel("省医保平台「6201」上传处方药费明细请求参数")
+public class InsuranceUploadRecipeDetailInputMessage {
+
+ /**
+ * orgCodg 机构编码 字符型 40 Y 医保分配
+ */
+ private String orgCodg;
+
+ /**
+ * orgId 电子凭证机构号 字符型 40 N 电子凭证中台分配,待机构电子凭证建设完毕后可获取该机构号
+ */
+ private String orgId;
+
+ /**
+ * psnNo 人员编号 字符型 30 Y
+ */
+ private String psnNo;
+
+ /**
+ * insutype 险种类型 字符型 6 Y 字典险种类型
+ * (insutype)
+ */
+ private String insutype;
+
+ /**
+ * medOrgOrd 医疗机构订单号 字符型 40 Y 院内产生惟一流水,可关联到一次结算记录,结算成功回调入参返回
+ */
+ private String medOrgOrd;
+
+ /**
+ * rxCircFlag 电子处方流转标志 字符型 1 N 1:电子处方 ,0不是电子处方,默认0,非电子处方
+ */
+ private String rxCircFlag = "0";
+
+ /**
+ * begntime 开始时间 字符型 19 Y 挂号时间
+ * yyyy-MM-dd HH:mm:ss
+ */
+ private String begntime;
+
+ /**
+ * idNo 证件号码 字符型 40 Y
+ */
+ private String idNo;
+
+ /**
+ *userName 用户姓名 字符型 40 Y
+ */
+ private String userName;
+
+ /**
+ * idType 证件类别 字符型 3 Y 字典人员证件类型(psn_cert_type) 01:身份证
+ */
+ private String idType;
+
+ /**
+ * ecToken 电子凭证授权ecToken 字符型 64 Y 电子凭证解码返回
+ */
+ private String ecToken;
+
+ /**
+ * insuCode 就诊参保地行政区划 字符型 6 N 为空(null)时取用户电子凭证默认参保地
+ */
+ private String insuCode;
+
+ /**
+ * iptOtpNo 住院/门诊号 字符型 30 Y 院内唯一流水
+ */
+ private String iptOtpNo;
+
+ // ==================非必需字段===================
+
+ /**
+ * atddrNo 医师编码 字符型 30 N
+ */
+ private String atddrNo;
+
+ /**
+ *drName 医师姓名 字符型 50 N
+ */
+ private String drName;
+
+ /**
+ * deptCode 科室编码 字符型 30 N
+ */
+ private String deptCode;
+
+
+ // =====================================
+
+ /**
+ *deptName 科室名称 字符型 100 Y
+ */
+ private String deptName;
+
+ /**
+ * caty 科别 字符型 6 Y
+ */
+ private String caty;
+
+ /**
+ * mdtrtId 就诊ID 字符型 30 N
+ */
+ private String mdtrtId;
+
+ /**
+ *medType 医疗类别 字符型 6 Y 字典医疗类别
+ * (med_type) 91 其他门诊
+ */
+ private String medType;
+
+ /**
+ * feeType 费用类型 字符型 3 Y 字典费用类型(feeType) 05 互联网医院问诊
+ */
+ private String feeType;
+
+ /**
+ * medfeeSumamt 医疗费总额 数值型 16,2 Y
+ */
+ private BigDecimal medfeeSumamt;
+
+ // todo 貌似目前为海南医保的特有字段
+ /**
+ * acctUsedFlag 个人账户使用标志 字符型 1 Y 药店上传费用时必填
+ */
+ private String acctUsedFlag;
+
+ /**
+ * mainCondDscr 主要病情描述 字符型 1000 N
+ */
+ private String mainCondDscr;
+
+ /**
+ *diseCodg 病种编码 字符型 30 Y 按照标准编码填写:
+ * 按病种结算病种目录代码(bydise_setl_list_code)、
+ * 门诊慢特病病种目录代码(opsp_dise_cod)、
+ */
+ private String diseCodg;
+
+ /**
+ * diseName 病种名称 字符型 500 Y
+ */
+ private String diseName;
+
+ // todo 貌似目前为海南医保的特有字段
+ /**
+ * psnSetlway 个人结算方式 字符型 6 Y
+ */
+ private String psnSetlway;
+
+ /**
+ * chrgBchno 收费批次号 字符型 30 Y
+ */
+ private String chrgBchno;
+
+ /**
+ * pubHospRfomFlag 公立医院改革标志 字符型 6 Y 可参考FSI的接口要求
+ */
+ private String pubHospRfomFlag;
+
+ /**
+ * diseinfoList 诊断或症状明细 Y 见下方diseinfoList定义
+ */
+ private List diseinfoList;
+
+ /**
+ * feedetailList 费用明细 Y 见下方feedetailList定义
+ */
+ private List feedetailList;
+
+ /**
+ * payAuthNo 支付授权码 字符型 40 N 线上授权返回
+ */
+ private String payAuthNo;
+
+
+ public static void main(String[] args) {
+
+ String s = "{\n" +
+ "\t\"configId\": \"cs1\",(部分省份无该参数,可去除)\n" +
+ "\t\"payAuthNo\": \"AUTH430100202206132005090000100\",\n" +
+ "\t\"uldLatlnt\": \"112.88211,28.230932\",\n" +
+ "\t\"idType\": \"01\",\n" +
+ "\t\"mdtrtCertType\": \"02\",\n" +
+ "\t\"orgCodg\": \"H43010000001\",\n" +
+ "\t\"orgId\": \"\",\n" +
+ "\t\"psnNo\": \"430000201000000000\",\n" +
+ "\t\"insutype\": \"310\",\n" +
+ "\t\"medOrgOrd\": \"46515950\",\n" +
+ "\t\"begntime\": \"2022-06-13 17:57:07\",\n" +
+ "\t\"idNo\": \"430602199111111111\",\n" +
+ "\t\"userName\": \"刘军\",\n" +
+ "\t\"ecToken\": \"\",\n" +
+ "\t\"iptOtpNo\": \"4441829\",\n" +
+ "\t\"deptCode\": \"2101\",\n" +
+ "\t\"deptName\": \"心血管内科诊室(一)\",\n" +
+ "\t\"caty\": \"2101\",\n" +
+ "\t\"mdtrtId\": \"359999999\",\n" +
+ "\t\"medType\": \"11\",\n" +
+ "\t\"feeType\": \"01\",\n" +
+ "\t\"medfeeSumamt\": 53.69,\n" +
+ "\t\"acctUsedFlag\": \"\",\n" +
+ "\t\"diseCodg\": \"J00.x00x002\",\n" +
+ "\t\"diseName\": \"病毒性感冒\",\n" +
+ "\t\"psnSetlway\": \"01\",\n" +
+ "\t\"chrgBchno\": \"4441829694.42\",\n" +
+ "\t\"pubHospRfomFlag\": \"01\",\n" +
+ "\t\"fetts\": \"\",\n" +
+ "\t\"diseinfoList\": [{\n" +
+ "\t\t\"diagType\": \"0\",\n" +
+ "\t\t\"diagSrtNo\": 1,\n" +
+ "\t\t\"diagCode\": \"J00.x00x002\",\n" +
+ "\t\t\"diagName\": \"病毒性感冒\",\n" +
+ "\t\t\"diagDept\": \"心血管内科诊室(一)\",\n" +
+ "\t\t\"diseDorNo\": \"0824\",\n" +
+ "\t\t\"diseDorName\": \"马丽霞\",\n" +
+ "\t\t\"diagTime\": \"2022-06-13 17:57:23\",\n" +
+ "\t\t\"valiFlag\": \"1\"\n" +
+ "\t}],\n" +
+ "\t\"feedetailList\": [{\n" +
+ "\t\t\t\"feedetlSn\": \"97657430\",\n" +
+ "\t\t\t\"mdtrtId\": \"4441888\",\n" +
+ "\t\t\t\"psnNo\": \"430000201000000000\",\n" +
+ "\t\t\t\"chrgBchno\": \"444182920220613175815266\",\n" +
+ "\t\t\t\"rxCircFlag\": \"0\",\n" +
+ "\t\t\t\"feeOcurTime\": \"2022-06-13 17:57:08\",\n" +
+ "\t\t\t\"medListCodg\": \"F00000019080\",\n" +
+ "\t\t\t\"medinsListCodg\": \"H43010500027\",\n" +
+ "\t\t\t\"detItemFeeSumamt\": 16,\n" +
+ "\t\t\t\"cnt\": 1,\n" +
+ "\t\t\t\"pric\": 16,\n" +
+ "\t\t\t\"bilgDeptCodg\": \"2101\",\n" +
+ "\t\t\t\"bilgDeptName\": \"心血管内科诊室(一)\",\n" +
+ "\t\t\t\"bilgDrCodg\": \"0824\",\n" +
+ "\t\t\t\"bilgDrName\": \"马丽霞\",\n" +
+ "\t\t\t\"hospApprFlag\": \"1\",\n" +
+ "\t\t\t\"medType\": \"11\",\n" +
+ "\t\t\t\"medListName\": \"副主任医师普通门诊诊查费\",\n" +
+ "\t\t\t\"medListSpc\": \"\"\n" +
+ "\t\t},\n" +
+ "\t\t{\n" +
+ "\t\t\t\"feedetlSn\": \"97657431\",\n" +
+ "\t\t\t\"mdtrtId\": \"4441888\",\n" +
+ "\t\t\t\"psnNo\": \"430000201000000000\",\n" +
+ "\t\t\t\"chrgBchno\": \"444182920220613175815266\",\n" +
+ "\t\t\t\"rxCircFlag\": \"0\",\n" +
+ "\t\t\t\"feeOcurTime\": \"2022-06-13 17:57:36\",\n" +
+ "\t\t\t\"medListCodg\": \"Y00000020302\",\n" +
+ "\t\t\t\"medinsListCodg\": \"H43010500027\",\n" +
+ "\t\t\t\"detItemFeeSumamt\": 678.42,\n" +
+ "\t\t\t\"cnt\": 18,\n" +
+ "\t\t\t\"pric\": 37.69,\n" +
+ "\t\t\t\"bilgDeptCodg\": \"2101\",\n" +
+ "\t\t\t\"bilgDeptName\": \"心血管内科诊室(一)\",\n" +
+ "\t\t\t\"bilgDrCodg\": \"0824\",\n" +
+ "\t\t\t\"bilgDrName\": \"马丽霞\",\n" +
+ "\t\t\t\"hospApprFlag\": \"1\",\n" +
+ "\t\t\t\"medType\": \"11\",\n" +
+ "\t\t\t\"medListName\": \"小儿肺咳颗粒\",\n" +
+ "\t\t\t\"medListSpc\": \"2g/袋*18袋/盒\"\n" +
+ "\t\t}\n" +
+ "\t]\n" +
+ "}\n";
+
+
+
+
+
+
+
+
+
+ }
+
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceUploadRecipeDetailOutputMessage.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceUploadRecipeDetailOutputMessage.java
new file mode 100644
index 0000000..c7822d2
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/InsuranceUploadRecipeDetailOutputMessage.java
@@ -0,0 +1,43 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: InsuranceUploadRecipeDetailOutputMessage.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description: 【6201】 上传医保费用明细响应参数
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/22 15:34
+ * @Modify:
+ */
+@Data
+public class InsuranceUploadRecipeDetailOutputMessage {
+
+ /**
+ * payOrdId 支付订单号 字符型 40 Y 医保结算中心订单号
+ */
+ private String payOrdId;
+
+ /**
+ * payToken 支付token 字符型 40 Y 下单支付使用
+ */
+ private String payToken;
+
+ /**
+ * cashierUrl 医保支付收银台h5地址 字符型 4000 N 见下方拼接说明
+ */
+ private String cashierUrl;
+
+ /**
+ * extData 医保扩展数据 N 根据各地方医保要求传不同数据内容
+ */
+ private String extData;
+
+
+
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/UnifiedOrderRep.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/UnifiedOrderRep.java
new file mode 100644
index 0000000..fd8e13d
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/UnifiedOrderRep.java
@@ -0,0 +1,49 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: UnifiedOrderRep.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/24 10:13
+ * @Modify:
+ */
+@Data
+@ApiModel("统一下单返回参数")
+public class UnifiedOrderRep {
+
+ /**
+ *
+
+ pay_url
+ 支付链接
+ String256
+ Y
+ 下单后跳转到此url,用户完成支付,使用app支付时1.5 APP支付说明
+
+ */
+ @ApiModelProperty("支付链接")
+ private String payUrl;
+
+ /**
+ *
+
+ pay_appid
+ 支付小程序
+ String64
+ N
+ 当使用医院小程序进行下单时,会返回此参数,医院小程序跳转至该支付小程序进行支付
+ */
+ @ApiModelProperty("支付小程序")
+ private String payAppid;
+
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/UnifiedOrderReq.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/UnifiedOrderReq.java
new file mode 100644
index 0000000..93126f6
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/UnifiedOrderReq.java
@@ -0,0 +1,68 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: UnifiedOrderReq.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description: 微信统一下单请求参数
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/23 23:53
+ * @Modify:
+ */
+@ApiModel("微信统一下单请求参数")
+@Data
+public class UnifiedOrderReq {
+
+ @ApiModelProperty("支付类型: IntReDiagPay=互联网医院复诊支付\n" +
+ "IntPscPay=互联网医院处方支付 \n")
+ private String orderType;
+
+ @ApiModelProperty("分账信息")
+ private InsurancePayOrderOutputMessage insurancePayOrder;
+
+ /**
+ * spbill_create_ip
+ * 用户端ip
+ * String16
+ * Y
+ * 10.193.0.1
+ */
+ @ApiModelProperty("用户ip")
+ private String spbillCreateIp;
+
+
+
+
+ @ApiModelProperty(hidden = true)
+ private InsuranceAccessTokenRep accessToken;
+
+ @ApiModelProperty(hidden = true)
+ private String openId;
+
+
+ @ApiModelProperty(hidden = true)
+ /**
+ * 证件号码 user_card_no 证件号码的MD5,目前只支持身份证(身份证中如果有字母需要转成大写再做MD5,15位身份证号需要转为18位). 示例:44030019000101123x的MD5为09eb26e839ff3a2e3980352ae45ef09e
+ */
+ private String userCardNo;
+
+
+
+ @ApiModelProperty(hidden = true)
+ /**
+ * 真实姓名 user_name 张三
+ */
+ private String userName;
+
+
+
+
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/UserLongitudeLatitude.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/UserLongitudeLatitude.java
new file mode 100644
index 0000000..5aecdea
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/UserLongitudeLatitude.java
@@ -0,0 +1,25 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: user_longitude_latitude.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/16 10:53
+ * @Modify:
+ */
+@Data
+@ApiModel("获取用户经纬度")
+public class UserLongitudeLatitude {
+
+ private String longitude;
+
+ private String latitude;
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/UserQueryReq.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/UserQueryReq.java
new file mode 100644
index 0000000..ccfeb33
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/UserQueryReq.java
@@ -0,0 +1,29 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: UserQueryReq.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/16 11:12
+ * @Modify:
+ */
+@Data
+@ApiModel("获取用户信息")
+public class UserQueryReq {
+
+ @ApiModelProperty("授权码")
+ private String qrcode;
+
+ @ApiModelProperty("openid")
+ private String openid;
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/WechatUnifiedOrderReq.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/WechatUnifiedOrderReq.java
new file mode 100644
index 0000000..cab3a3f
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/WechatUnifiedOrderReq.java
@@ -0,0 +1,325 @@
+package com.szyx.tcm.supervision.model.dto.insurance;
+
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: WechatUnifiedOrderReq.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance
+ * @Copyright:wy (C) 2024 *
+ * @Description: 微信统一下单请求参数
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/23 23:23
+ * @Modify:
+ */
+@Data
+public class WechatUnifiedOrderReq {
+
+ /**
+ * order_type
+ * 支付类型
+ * String16
+ * Y
+ * RegPay=挂号支付
+ * MedPay=药费支付
+ * DiagPay=诊间支付
+ * InHospPay=住院费支付
+ * PharmacyPay=药店支付
+ * InsurancePay=保险费支付
+ * IntRegPay=互联网医院挂号支付
+ * IntReDiagPay=互联网医院复诊支付
+ * IntPscPay=互联网医院处方支付
+ * CovidExamPay=新冠检测费用
+ * CvidAntigenPay=新冠抗原检测
+ */
+ private String orderType;
+
+ /**
+ * appid
+ * 公众账号ID
+ * String32
+ * Y
+ * 微信分配的公众账号ID
+ */
+ private String appid;
+
+ /**
+ * mch_id
+ * 商户号
+ * String32
+ * Y
+ * 微信支付分配的商户号
+ */
+ private String mchId;
+
+ /**
+ * sub_appid
+ * 子商户公众号ID
+ * String32
+ * N
+ * 微信分配的子商户公众账号ID,如需在支付完成后获取sub_openid则此参数必传。
+ */
+ private String subAppid;
+
+ /**
+ * sub_mch_id
+ * 子商户号
+ * String32
+ * N
+ * 微信支付分配的子商户号,如果是服务商模式,必填
+ */
+ private String subMchId;
+
+ /**
+ * openid
+ * 用户标识
+ * String128
+ * 二选一
+ * openid和sub_openid可以选传其中之一,如果选择传sub_openid,则必须传sub_appid。
+ */
+ private String openid;
+
+
+
+ /**
+ * hosp_out_trade_no
+ * 第三方服务商订单号
+ * String64
+ * Y
+ * 第三方服务商平台自动生成的一个订单号
+ */
+ private String hospOutTradeNo;
+
+ /**
+ * hospital_name
+ * 医院名称
+ * string128
+ * Y
+ * 医院名称
+ */
+ private String hospitalName;
+
+ /**
+ * nonce_str
+ * 随机字符串
+ * String32
+ * Y
+ */
+ private String nonceStr;
+
+ /**
+ * total_fee
+ * 总共需要支付现金金额
+ * Uint64
+ * Y
+ * 单位为分>0
+ * 表示订单总额即全额现金的价格。由于医保局支付有优惠,全额现金的价格可能会大于cash_fee+ insurance_fee的和,不一定等于cash_fee+insurance_fee。
+ */
+ private String totalFee;
+
+ /**
+ * cash_fee
+ * 现金需要支付的金额
+ * Uint64
+ * Y
+ * 单位为分>=0
+ * 线上预结算模式金额填0
+ * 线下预结算模式填实际自费金额
+ */
+ private String cashFee;
+
+ /**
+ * cash_add_fee
+ * 由医疗机构额外增加的现金金额
+ * Uint64
+ * N
+ * 单位为分,默认0
+ * 用于医院在医保预结算之外增加现
+ * 金扣费,举例:原需要
+ * 支付的是:
+ * total_ fee 200
+ * cash_ fee 100
+ * insurance fee 100。
+ * 现新增现金50,则入参为:
+ * total_ _fee 250 ( 总额加上额外现
+ * 金)
+ * cash fee 150(自费加上额外现
+ * 金)
+ * cash_add_ fee 50 (额外现金)
+ * insurance_ fee 100
+ */
+
+ private String cashAddFee;
+
+ /**
+ * cash_add_wording
+ * 额外现金金额文案
+ * String16
+ * N
+ * 额外现金金额,如:快递费
+ * 目前不会在前端显示,可不传
+ */
+ private String cashAddWording;
+
+ /**
+ * cash_reduced_wording
+ * 减免金额文案
+ * String16
+ * N
+ * 减免金额的文案类型,
+ * 1为:预交金支付
+ * 2为:医院减免
+ * 3为:药店优惠
+ * 4为:优惠金
+ * 5为:押金抵扣
+ * 不填则为默认的“机构优惠金额”
+ */
+ private String cashReducedWording;
+
+ /**
+ * allow_fee_change
+ * 是否允许预结算费用发生变化
+ * uint8
+ * Y
+ * 0:不允许
+ * 1:允许
+ * 当医保局返回的预结算金额与医院上传的金额不一致时,此字段为0则直接报错,为1则以医保局金额为准
+ */
+ private String allowFeeChange;
+
+ /**
+ * spbill_create_ip
+ * 用户端ip
+ * String16
+ * Y
+ * 10.193.0.1
+ */
+ private String spbillCreateIp;
+
+ /**
+ * notify_url
+ * 回调url
+ * String256
+ * Y
+ * 接收微信支付异步通知回调地址
+ */
+ private String notifyUrl;
+
+ /**
+ * body
+ * 商品描述
+ * String128
+ * Y
+ * 参照
+ * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_2
+ */
+ private String body;
+
+ /**
+ * return_url
+ * 支付后回跳的页面,不论成功或者失败均会回跳
+ * string128
+ * Y
+ * 调用方可以在链接中加上支付单号,回跳后查询调用方订单状态,如果订单已支付则成功, 如果订单未支付则进行查单操作确认订单结果
+ */
+ private String returnUrl;
+
+ /**
+ * pay_type
+ * 支付方式
+ * uint8
+ * Y
+ * 1:现金 2:医保 3:现金+医保
+ * 备注说明:
+ * 1、当订单要走医保支付时,
+ * (1)cash_fee>0, paytype填3
+ * (2)cash_fee=0, paytype填2
+ * 2、当订单不使用医保支付时 paytype填1。
+ * 3、当订单有走医保【6201】相关接口时,如果订单为纯自费订单,paytype填3。
+ */
+ private String payType;
+
+ /**
+ * city_id
+ * 城市ID
+ * String32
+ * Y
+ * 一般为申请接入城市的编码,由腾讯侧对接时提供。
+ */
+ private String cityId;
+
+
+ /**
+ * consume_type
+ * 医保部分扣
+ * 费类型
+ * int8
+ * N
+ * 默认为 0:统筹+个账
+ * 1:个账
+ * 2:统筹
+ */
+ private String consumeType;
+
+ /**
+ * insurance_fee
+ * 医保支付金额
+ * Uint64
+ * Y
+ * 填实际医保金额
+ */
+ private String insuranceFee;
+
+ /**
+ * 证件类型 user_card_type 1 居民身份证 9 户口本 8 外国人护照 5 台湾居民来往大陆通行证 4 澳门居民往来内地通行证 6 香港居民往来内地通行证 7 外国人永久居留证
+ */
+ private String userCardType;
+
+ /**
+ * 证件号码 user_card_no 证件号码的MD5,目前只支持身份证(身份证中如果有字母需要转成大写再做MD5,15位身份证号需要转为18位). 示例:44030019000101123x的MD5为09eb26e839ff3a2e3980352ae45ef09e
+ */
+ private String userCardNo;
+
+ /**
+ * 真实姓名 user_name 张三
+ */
+ private String userName;
+
+ /**
+ * 医保标识 is_dept is_dept=4 医保电子凭证支付;
+ */
+ private String isDept;
+
+ /**
+ * 医院HIS系统订单号 serial_no 医院HIS系统订单号
+ */
+ private String serialNo;
+
+ /**
+ * 医疗机构编码(医保局分配给机构) org_no 医保局局提供的医疗机构编码
+ */
+ private String orgNo;
+
+ /**
+ * 医院下单时间 gmt_out_create 格式为yyyyMMddHHmmss 如20160501163102
+ */
+ private String gmtOutCreate;
+
+ /**
+ * 参考医保结构体(医疗机构透传医保) request_content 示例: {"payAuthNo":"AUTH****","payOrdId":"ORD****","setlLatlnt":"118.096435,24.485407"} payAuthNo:授权码 payOrdId:对应处方上传的出参单号 setlLatlnt:用户地 理定位信息, 经纬 度信息,如“118.096435,24.485407”。未获取到用户定位时,传“0,0”。
+ */
+ private String requestContent;
+
+ /**
+ * 业务单据号 bill_no
+ */
+ private String billNo;
+
+ /**
+ * 签名 sign
+ */
+ private String sign;
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/core/SignIn.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/core/SignIn.java
new file mode 100644
index 0000000..f6fdaea
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/core/SignIn.java
@@ -0,0 +1,38 @@
+package com.szyx.tcm.supervision.model.dto.insurance.core;
+
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: SignIn.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance.core
+ * @Copyright:wy (C) 2024 *
+ * @Description: 9001 输入-录入的基本信息
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/22 10:41
+ * @Modify:
+ */
+@Data
+public class SignIn {
+
+ /**
+ * opter_no 操作员编号 字符型 20 Y
+ */
+ private String opterNo;
+
+ /**
+ * mac 签到MAC地址 字符型 20 Y
+ */
+ private String mac;
+
+ /**
+ * ip 签到IP地址 字符型 20 Y
+ */
+ private String ip;
+
+
+
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/core/Signinoutb.java b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/core/Signinoutb.java
new file mode 100644
index 0000000..791ae47
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/model/dto/insurance/core/Signinoutb.java
@@ -0,0 +1,32 @@
+package com.szyx.tcm.supervision.model.dto.insurance.core;
+
+import lombok.Data;
+
+/*******************************************************************
+ *
+ * @文件名称: Signinoutb.java
+ * @包 路 径: com.szyx.tcm.web.patient.dto.insurance.core
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/22 10:44
+ * @Modify:
+ */
+@Data
+public class Signinoutb {
+
+ /**
+ * sign_time 签到时间 日期型 Y yyyy-MM-dd HH:mm:ss
+ */
+ private String signTime;
+
+ /**
+ * sign_no 签到编号 字符型 30 Y
+ */
+ private String signNo;
+
+
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/service/manager/ClientDemo.java b/src/main/java/com/szyx/tcm/supervision/service/manager/ClientDemo.java
new file mode 100644
index 0000000..07d1194
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/service/manager/ClientDemo.java
@@ -0,0 +1,102 @@
+package com.szyx.tcm.supervision.service.manager;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.UUID;
+
+
+/*******************************************************************
+ *
+ * @文件名称: ClientDemo.java
+ * @包 路 径: com.szyx.tcm.web.patient.service.manager
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/16 11:07
+ * @Modify:
+ */
+public class ClientDemo {
+
+ private final static String partnerId = "20000011";
+ private final static String partnerSecret = "5dd6f0926a2e2b2cb19a5bcecb0e2df6";
+ private final static String urlPath = "https://mip-receiver.tengmed.com/testapi/mipuserquery/userQuery/20000011";
+ private final static char[] hexArray = "0123456789abcdef".toCharArray();
+
+
+ private String bytesToHex(byte[] bytes) {
+ char[] hexChars = new char[bytes.length * 2];
+ for (int j = 0; j < bytes.length; j++) {
+ int v = bytes[j] & 0Xff;
+ hexChars[j * 2] = hexArray[v >>> 4];
+ hexChars[j * 2 + 1] = hexArray[v & 0x0F];
+ }
+ return new String(hexChars);
+ }
+
+ private String createSignature(String partnerSecret, String partnerId, String timestamp)
+ throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
+ Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
+ SecretKeySpec secret_key = new SecretKeySpec(partnerSecret.getBytes("UTF-8"), "HmacSHA256");
+ sha256_HMAC.init(secret_key);
+ return bytesToHex(sha256_HMAC.doFinal((partnerId + timestamp).getBytes("UTF-8")));
+ }
+
+
+ private String postData(String businessName, String funcName, String partnerId, String data)
+ throws IOException, NoSuchAlgorithmException, InvalidKeyException {
+ HttpURLConnection conn = null;
+ URL url = new URL(urlPath);
+ conn = (HttpURLConnection) url.openConnection();
+ conn.setDoOutput(true);
+ conn.setDoInput(true);
+ conn.setRequestMethod("POST");
+ conn.setUseCaches(false);
+ conn.setInstanceFollowRedirects(true);
+ conn.setRequestProperty("Content-Type", "application/json");
+ conn.setRequestProperty("Accept", "application/json");
+ String timestamp = Long.toString(System.currentTimeMillis());
+ String signature = createSignature(partnerSecret, partnerId, timestamp);
+ String requestId = UUID.randomUUID().toString().replaceAll("-", "");
+ conn.setRequestProperty("god-portal-timestamp", timestamp);
+ conn.setRequestProperty("god-portal-signature", signature);
+ conn.setRequestProperty("god-portal-request-id", requestId);
+ conn.connect();
+ OutputStream os = conn.getOutputStream();
+ os.write(data.getBytes());
+ os.flush();
+ os.close();
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ InputStream inputStream = conn.getInputStream();
+ byte[] bytes = new byte[1024];
+ int readBytes;
+ while ((readBytes = inputStream.read(bytes)) != -1) {
+ byteArrayOutputStream.write(bytes, 0, readBytes);
+ }
+ bytes = byteArrayOutputStream.toByteArray();
+ inputStream.close();
+ conn.disconnect();
+ return new String(bytes, "utf-8");
+
+ }
+
+
+ public static void main(String[] args) {
+ ClientDemo demo = new ClientDemo();
+ try {
+ System.out.println(demo.postData("test", "test2", demo.partnerId, "{}"));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+}
+
+
+
+
diff --git a/src/main/java/com/szyx/tcm/supervision/service/manager/HealthInsuranceManager.java b/src/main/java/com/szyx/tcm/supervision/service/manager/HealthInsuranceManager.java
new file mode 100644
index 0000000..e1acb46
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/service/manager/HealthInsuranceManager.java
@@ -0,0 +1,1015 @@
+package com.szyx.tcm.supervision.service.manager;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.JSONWriter;
+import com.szyx.tcm.supervision.constant.WeChatInsurancePayConstant;
+import com.szyx.tcm.supervision.model.dto.insurance.*;
+import com.szyx.tcm.supervision.model.dto.insurance.core.SignIn;
+import com.szyx.tcm.supervision.model.dto.insurance.core.Signinoutb;
+import com.szyx.tcm.supervision.util.DateUtils;
+import com.szyx.tcm.supervision.util.HttpUtil;
+import com.szyx.tcm.supervision.util.InsuranceWechatUtil;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.*;
+import java.math.BigDecimal;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.*;
+
+import static com.szyx.tcm.supervision.constant.WeChatInsurancePayConstant.*;
+
+
+/*******************************************************************
+ *
+ * @文件名称: HealthInsuranceManager.java
+ * @包 路 径: com.szyx.tcm.web.patient.service.manager
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/16 10:37
+ * @Modify:
+ */
+@Slf4j
+@Service
+//@RefreshScope
+public class HealthInsuranceManager {
+
+// @Resource
+// private PatientUserMapper patientUserMapper;
+
+// @Resource
+// private MedicineOrderMapper medicineOrderMapper;
+
+// @Resource
+// private InquiryService inquiryService;
+
+ // 获取信息服务接口 测试环境
+ // todo 合作方id 密钥
+ String getInsuranceAPI = "https://mip-receiver.tengmed.com/testapi/mipuserquery/userQuery/%s";
+
+ // 获取支付access_token
+ // 调用医保支付平台的API(即https://api.weixin.qq.com/payinsurance/前缀的API)需要使用单独的key 进行MD5签名
+ String getInsuranceAccess = "https://api.weixin.qq.com/payinsurance/gettoken?grant_type=%s&agentappid=%s&agentsecret=%s&appid=%s";
+
+
+ // 微信医保平台统一下单API接口
+ String unifiedOrderAPI = "https://api.weixin.qq.com/payinsurance/unifiedorder?access_token=%s";
+
+ // 获取授权码
+ String weChatPayAPI = "auth/pages/bindcard/auth/index?openType=getAuthCode&cityCode=%s&channel=%s&redirectUrl=%s";
+
+ // 合作方 id
+// @Value("${insurance.partnerId}")
+ private String partnerId;
+
+
+ // 合作方密钥
+// @Value("${insurance.partnerSecret}")
+ private String partnerSecret;
+
+ // 代理帐号id
+// @Value("${insurance.agentappid}")
+ private String agentappid;
+
+ // 代理帐号appsecret
+// @Value("${insurance.agentsecret}")
+ private String agentsecret;
+
+
+ // 医院小程序帐号id
+// @Value("${insurance.appid}")
+ private String appid;
+
+ /**
+ * 医院小程序商户号
+ */
+// @Value("${insurance.mchId}")
+ private String mchId;
+
+ /**
+ * 服务商商户号
+ */
+// @Value("${insurance.subMchId}")
+ private String subMchId;
+
+ // 医保区划
+// @Value("${insurance.cityCode}")
+ private String cityCode;
+
+ /**
+ * 腾讯医保城市ID
+ */
+// @Value("${insurance.cityId}")
+ private String cityId;
+
+ // 渠道号(微信医保平台分配)
+// @Value("${insurance.channel}")
+ private String channel;
+
+ // 回跳地址
+// @Value("${insurance.redirectUrl}")
+ private String redirectUrl;
+
+ // 机构渠道认证编码 小程序授权不需要encode
+// @Value("${insurance.orgChnlCrtfCodg}")
+ private String orgChnlCrtfCodg;
+
+ // 定点医药机构编码 来源于国家局医保移动支付反馈单
+// @Value("${insurance.orgCodg}")
+ private String orgCodg;
+
+ // 线上核验业务类型编码 医保移动支付业务填04107
+// @Value("${insurance.bizType}")
+ private String bizType;
+
+ // orgAppId 定点医药机构应用ID 来源于国家局医保移动支付反馈单
+// @Value("${insurance.orgAppId}")
+ private String orgAppId;
+
+
+ // 微信医保平台 获取支付授权码
+// @Value("${insurance.getAuthUrl}")
+ private String authUrlPath;
+
+
+ // 9001 测试接口地址
+// @Value("${insurance.getSerialNumber}")
+ private String getSerialNumberPath;
+
+ // 1101 测试接口地址
+// @Value("${insurance.getBasicInsuranceInfo}")
+ private String getBasicInsuranceInfoPath;
+
+ // 6201 测试接口地址
+// @Value("${insurance.uploadRecipeDetail}")
+ private String uploadRecipeDetailPath;
+
+ // 6202 测试接口地址
+// @Value("${insurance.payOrder}")
+ private String payOrderPath;
+
+
+ /**
+ * 医保定点医药机构编号
+ */
+// @Value("${insurance.fixmedinsCode}")
+ private String fixmedinsCode;
+
+ /**
+ * 医保定点医药机构名称
+ */
+// @Value("${insurance.fixmedinsName}")
+ private String fixmedinsName;
+
+
+ /**
+ * 就医地医保区划
+ */
+// @Value("${insurance.mdtrtareaAdmvs}")
+ private String mdtrtareaAdmvs;
+
+ /**
+ * 接收方系统代码
+ */
+// @Value("${insurance.recerSysCode}")
+ private String recerSysCode;
+
+
+ /**
+ * 测试就诊凭证编号
+ */
+// @Value("${insurance.mdtrtCertNo}")
+ private String mdtrtCertNo;
+
+ /**
+ * 测试就诊凭证姓名
+ */
+// @Value("${insurance.mdtrtCertName}")
+ private String mdtrtCertName;
+
+
+ private final static char[] hexArray = "0123456789abcdef".toCharArray();
+
+
+ /**
+ * 生成小程序医保授权链接
+ *
+ * @param medicineOrderId 购药单id
+ * @return 授权链接
+ */
+ public String getAuthUrl(String medicineOrderId) {
+ return String.format(authUrlPath, cityCode, channel, orgChnlCrtfCodg, orgCodg, bizType, orgAppId);
+ }
+
+
+ /**
+ * 获取微信医保移动支付access_token
+ *
+ * @param req 请求参数
+ * @return 返回结果
+ */
+ @SneakyThrows
+ public InsuranceAccessTokenRep InsuranceAccessToken(InsuranceAccessTokenReq req) {
+ String pathUrl = String.format(getInsuranceAccess, "client_credential", agentappid, agentsecret, appid);
+ String s = postData("payinsurance", "gettoken", pathUrl, partnerId, req.toString());
+ log.info("InsuranceAccessToken: {}", s);
+ return JSON.parseObject(s, InsuranceAccessTokenRep.class);
+ }
+
+ /**
+ * 根据医保平台下单分账信息,确认支付,微信统一下单
+ * @return
+ */
+ @SneakyThrows
+ public UnifiedOrderRep confirmPay(UnifiedOrderReq req){
+ // 获取订单信息 todo
+ req.setOpenId("");
+
+ // 获取AccessToken
+ InsuranceAccessTokenRep accessToken = InsuranceAccessToken(new InsuranceAccessTokenReq());
+ req.setAccessToken(accessToken);
+ // 微信统一下单
+ return unifiedOrder( req);
+
+ }
+
+
+ /**
+ * 河南医保平台下单,获取订单医保分账
+ *
+ * @return 分账数据
+ */
+ public InsurancePayOrderOutputMessage getOrder(InsuranceGetOrderReq req) {
+
+// //读取当前订单信息 todo
+// if (req.getOrderType() == 1){
+// Inquiry inquiry = inquiryService.getInquiryByRecipeId(Integer.parseInt(req.getPlatformOrderId()));
+// req.setOrgBizSer(inquiry.getBizOrderNo());
+// req.setChrgBchno(inquiry.getBizOrderNo());
+// req.setMedOrgOrd(inquiry.getBizOrderNo());
+// req.setFeeType(INSURANCE_PAY_FEE_TYPE);
+// req.setMdtrtId(inquiry.getId().toString());
+//
+// }
+
+
+
+
+
+
+
+
+ //微信获取用户信息服务接口
+ InsuranceRep insuranceInfo = getInsuranceInfo(new InsuranceReq().setQrcode(req.getAuthCode()));
+ // 获取用户在河南医保平台当地的医保信息「1101」
+ InsuranceCoreOutputMessage1101 insuranceCoreInfo = getInsuranceInfo();
+
+ // 省医保上传
+ InsuranceUploadRecipeDetailOutputMessage uploadDetail = new InsuranceUploadRecipeDetailOutputMessage();
+ if(req.getOrderType() == 1){
+ uploadDetail = uploadInquiryDetail(req, insuranceInfo, insuranceCoreInfo);
+ }else{
+ uploadDetail = uploadRecipeDetail(req, insuranceInfo, insuranceCoreInfo);
+ }
+
+
+ // 省医保下单
+ InsurancePayOrderOutputMessage paidOrder = payOrder(req, insuranceInfo, uploadDetail);
+
+ // 追加医保结构体 用于微信统一下单 requestContent;
+ Map requestContent = new HashMap<>();
+ requestContent.put("payOrdId", paidOrder.getPayOrdId());
+ requestContent.put("payAuthNo", req.getAuthCode());
+ requestContent.put("setlLatlnt", insuranceInfo.getUserLongitudeLatitude().getLatitude() + "," + insuranceInfo.getUserLongitudeLatitude().getLongitude());
+
+
+ String requestContentStr = JSON.toJSONString(requestContent);
+ paidOrder.setRequestContent(requestContentStr);
+
+ //返回分账
+ InsurancePayOrderOutputMessage outputMessage = new InsurancePayOrderOutputMessage();
+ // todo
+ outputMessage.setPayOrdId("123456");
+ outputMessage.setOrdStas("1");
+ outputMessage.setFeeSumamt(new BigDecimal("0.01"));
+ outputMessage.setOwnPayAmt(new BigDecimal("0.01"));
+ outputMessage.setPsnAcctPay(new BigDecimal("0.01"));
+ outputMessage.setFundPay(new BigDecimal("0.01"));
+
+
+ return outputMessage;
+ }
+
+
+ // 获取用户在河南医保平台当地的医保信息
+ public InsuranceCoreOutputMessage1101 getInsuranceInfo() {
+ // 9001 签到
+ Signinoutb serialNumber = getSerialNumber();
+
+ // 1101 获取医保人员基础信息
+ return getBasicInsuranceInfo(serialNumber);
+ }
+
+
+ /**
+ * 省医保平台「9001」 接口签到获取流水号 ,后续接口调用前需先调用此接口获取流水号
+ *
+ * @return
+ */
+ public Signinoutb getSerialNumber() {
+
+ // ===========参数梳理 ===========
+ // infno 交易编号
+ // msgid 发送方报文ID
+ // mdtrtarea_admvs 就医地医保区划
+ // recer_sys_code 接收方系统代码
+ // infver 接口版本号
+ // opter_type 操作员类型 1-经办人;2-自助终端;3-移动终端
+ // opter 操作员
+
+ InsuranceCoreCommonInputMessage inputMessage = new InsuranceCoreCommonInputMessage();
+ SignIn signIn = new SignIn();
+ inputMessage.setInfno(WeChatInsurancePayConstant.INSURANCE_CORE_MSG_ID_SIGN_IN);
+ inputMessage.setMsgid(InsuranceWechatUtil.getMsgId(fixmedinsCode));
+ inputMessage.setMdtrtareaAdmvs(mdtrtareaAdmvs);
+ inputMessage.setRecerSysCode(recerSysCode);
+ inputMessage.setInfver(INSURANCE_CORE_SYSTEM_VERSION);
+ inputMessage.setOpterType("3");
+ inputMessage.setOpter("wy");
+ inputMessage.setInfTime(DateUtils.format(new Date(), DateUtils.PATTERN_DATE_TIME));
+ inputMessage.setFixmedinsCode(fixmedinsCode);
+ inputMessage.setFixmedinsName(fixmedinsName);
+ inputMessage.setInput(JSONObject.toJSONString(signIn));
+ signIn.setOpterNo("wy");
+ signIn.setMac("00-00-00-00-00-00");
+ signIn.setIp("127.0.0.1");
+
+
+ String result = HttpUtil.postByJson(getSerialNumberPath, JSONObject.toJSONString(inputMessage));
+ log.info("getSerialNumber: {}", result);
+
+ InsuranceCoreCommonOutputMessage outputMessage = JSON.parseObject(result, InsuranceCoreCommonOutputMessage.class);
+
+ if (outputMessage.getInfcode() != null && outputMessage.getInfcode() == 0) {
+ String output = outputMessage.getOutput();
+ return JSON.parseObject(output, Signinoutb.class);
+ }
+
+ return null;
+ }
+
+ /**
+ * 省医保核心系统「1101」获取医保人员基础信息
+ *
+ * @return
+ */
+ public InsuranceCoreOutputMessage1101 getBasicInsuranceInfo(Signinoutb serialNumber) {
+
+ // ===========参数梳理 ===========
+ // mdtrt_cert_type 就诊凭证类型
+ // mdtrt_cert_no 就诊凭证编号 todo 测试使用 电子凭证令牌 还是 身份证号
+ // begntime 开始时间
+ // psn_cert_type 人员证件类型 使用电子凭证必填
+ // certno 证件号码
+ // psn_name 人员姓名
+
+ // =============== 响应参数 ===============
+ // baseinfo 基础信息
+ // -psn_no 人员编号
+ // -psn_cert_type 人员证件类型
+ // -certno 证件号码
+ // -psn_name 人员姓名
+ // -gend 性别
+ // -naty 民族
+ // -brdy 出生日期
+ // -age 年龄
+ // insuinfo
+ // -balc 余额
+ // -insutype 险种类型
+ // -psn_type 人员类型
+ // -psn_insu_stas 人员参保状态
+ // -psn_insu_date 个人参保日期
+ // -paus_insu_date 暂停参保日期
+ // -cvlserv_flag 公务员标志
+ // -insuplc_admdvs 参保地医保区划
+ // -emp_name 单位名称
+ // idetinfo
+ // -psn_idet_type 识别类型
+ // -psn_type_lv 人员类别级别
+ // -
+ InsuranceCoreCommonInputMessage inputMessage = new InsuranceCoreCommonInputMessage();
+ Map map = new HashMap<>();
+ InsuranceCoreInputMessage1101 inputMessage1101 = new InsuranceCoreInputMessage1101();
+ map.put("data", inputMessage1101);
+ inputMessage.setInfno(INSURANCE_CORE_BASIC_INFO);
+ inputMessage.setMsgid(InsuranceWechatUtil.getMsgId(fixmedinsCode));
+ inputMessage.setMdtrtareaAdmvs(mdtrtareaAdmvs);
+ inputMessage.setRecerSysCode(recerSysCode);
+ inputMessage.setInfver(INSURANCE_CORE_SYSTEM_VERSION);
+ inputMessage.setOpterType("3");
+ inputMessage.setOpter("wy");
+ inputMessage.setInfTime(DateUtils.format(new Date(), DateUtils.PATTERN_DATE_TIME));
+ inputMessage.setFixmedinsCode(fixmedinsCode);
+ inputMessage.setFixmedinsName(fixmedinsName);
+ inputMessage.setSignNo(serialNumber.getSignNo());
+ inputMessage.setInput(JSONObject.toJSONString(map));
+ inputMessage1101.setMdtrtCertType("02");
+ // 明文身份证号
+ inputMessage1101.setMdtrtCertNo(mdtrtCertNo);
+ inputMessage1101.setPsnName(mdtrtCertName);
+
+ String result = HttpUtil.postByJson(getBasicInsuranceInfoPath, JSONObject.toJSONString(inputMessage));
+ log.info("getBasicInsuranceInfo: {}", result);
+
+ InsuranceCoreCommonOutputMessage outputMessage = JSON.parseObject(result, InsuranceCoreCommonOutputMessage.class);
+
+ if (outputMessage.getInfcode() != null && outputMessage.getInfcode() == 0) {
+ String output = outputMessage.getOutput();
+
+ return JSON.parseObject(output, InsuranceCoreOutputMessage1101.class);
+ }
+ return null;
+ }
+
+ /**
+ * 省医保平台「6201」上传问诊费用明细
+ *
+ * @return
+ */
+ public InsuranceUploadRecipeDetailOutputMessage uploadInquiryDetail(InsuranceGetOrderReq req, InsuranceRep insuranceInfo, InsuranceCoreOutputMessage1101 insuranceCoreInfo) {
+
+
+ // ============ 参数梳理 ===========
+
+ // orgCodg 机构编码
+ // orgId 电子凭证机构号
+ // psnNo 人员编号 来源于 医保中心 医保核心系统 「1101」接口
+ // insutype 险种类型 310:职工基本医疗保险 390:城乡居民基本医疗保险 320:公务员医疗补助 392:城乡居民大病保险 330:大额医疗费用补助 340:离休人员医疗保障 510:生育保险
+ // medOrgOrd 医疗机构订单号 todo 使用药费订单号
+ // rxCircFlag 电子处方流转标志 todo 确认是否需要
+ // begntime 开始时间 挂号时间 格式: yyyy-MM-dd HH:mm:ss
+ // idNo 患者证件号码
+ // userName 用户姓名
+ // idType 证件类别 居民身份证 01
+ // ecToken 电子凭证授权
+ // insuCode 就诊参保地行政区划 todo 确认是否需要 为空(null)时取用户电子凭证默认参保地
+ // iptOtpNo 住院/门诊号 todo 确认是否可以用问诊单号
+ // deptName 科室名称
+ // caty 科别
+ // medType 医疗类别 todo 确认互联网医院处方的医疗类别
+ // feeType 费用类别 todo 确认互联网医院处方的费用类别 互联网医院问诊 05
+ // medfeeSumamt 医疗费总额
+ // acctUsedFlag 是否使用个人账户 todo 确认是否需要 药店上传费用时必填
+ // diseCodg 疾病编码 todo 确认类型
+ // diseName 疾病名称
+ // psnSetlway 个人结算方式 todo 确认字典
+ // chrgBchno 收费批次号
+ // pubHospRfomFlag 公立医院改革标志
+
+ // -diseinfoList 诊断或症状明细
+ // -diagType 诊断类型 1 西医主要诊断 2 西医其他诊断 3 中医主病诊断 4 中医主证诊断
+ // -diagSrtNo 诊断排序号
+ // -diagCode 诊断代码
+ // -diagName 诊断名称
+ // -diagDept 诊断科室
+ // -diseDorNo 诊断医生编码
+ // -diseDorName 诊断医生姓名
+ // -diagTime 诊断时间 yyyy-MM-dd HH:mm:ss
+ // -valiFlag 有效标志 0 无效 1 有效
+ // -feedetailList 费用明细
+ // -feedetlSn 费用明细序号
+ // -psnNo 人员编号 来源于 医保中心 医保核心系统 「1101」接口
+ // -chrgBchno 收费批次号
+ // -diseCodg 疾病编码
+ // -rxno 处方号 todo 外购处方时,传入外购处方的处方号;非外购处方,传入医药机构处方号
+ // -rxCircFlag todo 外购处方标志 需要确认互联网医院的处方是否为外购处方
+ // -feeOcurTime 费用发生时间 yyyy-MM-dd HH:mm:ss
+ // -medListCodg 医疗目录编码 todo 确认互联网医院处方的医疗目录编码
+ // -medinsListCodg 医药机构目录编码 todo 确认互联网医院处方的医药机构目录编码
+ // -detItemFeeSumamt 明细项目费用总额
+ // -cnt 数量
+ // -pric 单价
+ // -bilgDeptCodg 开单科室编码
+ // -bilgDeptName 开单科室名称
+ // -bilgDrCodg 开单医生编码 todo 医生标准编码
+ // -bilgDrName 开单医师姓名
+ // -hospApprFlag 医院审批标志 1
+ // -medType 医疗类别 todo 确认互联网医院处方的医疗类别
+ // -medListName 医疗目录名称
+ // -medListSpc 医疗目录规格
+ // payAuthNo 支付授权码
+ // uldLatlnt 用户经纬度 定位失败情况下传0,0
+ // mdtrtCertType 就诊凭证类型 02 身份证 01 电子凭证 todo 确认填身份证还是电子凭证
+
+
+ // todo 校验必填项
+
+ InsuranceUploadRecipeDetailInputMessage uploadData = new InsuranceUploadRecipeDetailInputMessage();
+ // 医保核心系统患者基本信息
+ InsuranceCoreOutputMessage1101.Baseinfo baseinfo = insuranceCoreInfo.getBaseinfo();
+ // 医保核心系统保信息
+ InsuranceCoreOutputMessage1101.Insuinfo insuinfo = insuranceCoreInfo.getInsuinfo();
+ // 费用明细
+ List feedetail = new ArrayList<>();
+ // 诊断或状态明细
+ List diseinfo = new ArrayList<>();
+
+
+ uploadData.setOrgCodg(fixmedinsCode);
+// uploadData.setOrgId();
+ uploadData.setPsnNo(baseinfo.getPsnNo());
+ uploadData.setIdType(insuinfo.getInsutype());
+ uploadData.setMedOrgOrd(req.getMedOrgOrd());
+ // 电子处方流转标志 todo 目前河南省并未测试过电子处方线上医保支付
+ uploadData.setRxCircFlag("0");
+ uploadData.setBegntime(DateUtils.format(new Date(), DateUtils.PATTERN_DATE_TIME));
+ uploadData.setIdNo(baseinfo.getCertno());
+ uploadData.setUserName(baseinfo.getPsnName());
+ uploadData.setIdType("01");
+ uploadData.setEcToken(req.getAuthCode());
+ uploadData.setInsuCode(mdtrtareaAdmvs);
+ // 取问诊单id
+ uploadData.setIptOtpNo(req.getPlatformOrderId());
+ // 字典 dept
+ uploadData.setDeptName("预防保健科");
+ uploadData.setCaty("A01");
+ uploadData.setMedType("91");
+ uploadData.setFeeType(INSURANCE_PAY_FEE_TYPE);
+ uploadData.setMedfeeSumamt(new BigDecimal("0.01"));
+// uploadData.setAcctUsedFlag("0");
+ uploadData.setDiseCodg("A01");
+ uploadData.setDiseName("感冒");
+ uploadData.setPsnSetlway("01");
+ // 公立医院内容 // 疑问点1 互联网医院是否为公立医院 公立医院改革标志 如何传参
+ uploadData.setChrgBchno(req.getChrgBchno());
+ uploadData.setDiseinfoList(diseinfo);
+ uploadData.setFeedetailList(feedetail);
+
+
+ // 组装诊断数据
+ DiseInfo diseInfo = new DiseInfo();
+ diseInfo.setDiagType("1");
+ diseInfo.setDiagSrtNo(1);
+ diseInfo.setDiagCode("A01");
+ diseInfo.setDiagName("感冒");
+ diseInfo.setDiagDept("预防保健科");
+ // todo 确认医生编码
+ diseInfo.setDiseDorNo("wy");
+ diseInfo.setDiseDorName("wy");
+ diseInfo.setDiagTime(DateUtils.format(new Date(), DateUtils.PATTERN_DATE_TIME));
+ diseInfo.setValiFlag("1");
+
+
+ // 组装费用数据
+ FeeDetail feeDetail = new FeeDetail();
+ feeDetail.setFeedetlSn(req.getOrgBizSer());
+ feeDetail.setPsnNo(baseinfo.getPsnNo());
+ feeDetail.setChrgBchno(req.getChrgBchno());
+ feeDetail.setFeeOcurTime(DateUtils.format(new Date(), DateUtils.PATTERN_DATE_TIME));
+ // todo 确定医疗目录 机构目录编码
+ feeDetail.setMedListCodg("A01");
+ feeDetail.setMedinsListCodg("A01");
+ feeDetail.setHospApprFlag("1");
+ feeDetail.setMedListName("感冒");
+ feeDetail.setMedListSpc("感冒");
+ // todo 医疗类别
+ feeDetail.setMedType("91");
+ feeDetail.setDetItemFeeSumamt(new BigDecimal("0.01"));
+ feeDetail.setCnt(new BigDecimal("1"));
+ feeDetail.setPric(new BigDecimal("0.01"));
+ feeDetail.setBilgDeptCodg("A01");
+ feeDetail.setBilgDeptName("预防保健科");
+ // todo 医生编码
+ feeDetail.setBilgDrCodg("wy");
+ feeDetail.setBilgDrName("wy");
+
+
+ // =============== 上传响应参数 ===============
+ // payOrdId 支付订单号
+ // payToken 支付token
+ // cashierUrl 医保支付收银台h5地址 不对接收银台模式 忽略
+
+
+ return null;
+ }
+
+
+ public InsuranceUploadRecipeDetailOutputMessage uploadRecipeDetail(InsuranceGetOrderReq req, InsuranceRep insuranceInfo, InsuranceCoreOutputMessage1101 insuranceCoreInfo) {
+
+
+ // ============ 参数梳理 ===========
+
+ // orgCodg 机构编码
+ // orgId 电子凭证机构号
+ // psnNo 人员编号 来源于 医保中心 医保核心系统 「1101」接口
+ // insutype 险种类型 310:职工基本医疗保险 390:城乡居民基本医疗保险 320:公务员医疗补助 392:城乡居民大病保险 330:大额医疗费用补助 340:离休人员医疗保障 510:生育保险
+ // medOrgOrd 医疗机构订单号 todo 使用药费订单号
+ // rxCircFlag 电子处方流转标志 todo 确认是否需要
+ // begntime 开始时间 挂号时间 格式: yyyy-MM-dd HH:mm:ss
+ // idNo 患者证件号码
+ // userName 用户姓名
+ // idType 证件类别 居民身份证 01
+ // ecToken 电子凭证授权
+ // insuCode 就诊参保地行政区划 todo 确认是否需要 为空(null)时取用户电子凭证默认参保地
+ // iptOtpNo 住院/门诊号 todo 确认是否可以用问诊单号
+ // deptName 科室名称
+ // caty 科别
+ // medType 医疗类别 todo 确认互联网医院处方的医疗类别
+ // feeType 费用类别 todo 确认互联网医院处方的费用类别 互联网医院问诊 05
+ // medfeeSumamt 医疗费总额
+ // acctUsedFlag 是否使用个人账户 todo 确认是否需要 药店上传费用时必填
+ // diseCodg 疾病编码 todo 确认类型
+ // diseName 疾病名称
+ // psnSetlway 个人结算方式 todo 确认字典
+ // chrgBchno 收费批次号
+ // pubHospRfomFlag 公立医院改革标志
+
+ // -diseinfoList 诊断或症状明细
+ // -diagType 诊断类型 1 西医主要诊断 2 西医其他诊断 3 中医主病诊断 4 中医主证诊断
+ // -diagSrtNo 诊断排序号
+ // -diagCode 诊断代码
+ // -diagName 诊断名称
+ // -diagDept 诊断科室
+ // -diseDorNo 诊断医生编码
+ // -diseDorName 诊断医生姓名
+ // -diagTime 诊断时间 yyyy-MM-dd HH:mm:ss
+ // -valiFlag 有效标志 0 无效 1 有效
+ // -feedetailList 费用明细
+ // -feedetlSn 费用明细序号
+ // -psnNo 人员编号 来源于 医保中心 医保核心系统 「1101」接口
+ // -chrgBchno 收费批次号
+ // -diseCodg 疾病编码
+ // -rxno 处方号 todo 外购处方时,传入外购处方的处方号;非外购处方,传入医药机构处方号
+ // -rxCircFlag todo 外购处方标志 需要确认互联网医院的处方是否为外购处方
+ // -feeOcurTime 费用发生时间 yyyy-MM-dd HH:mm:ss
+ // -medListCodg 医疗目录编码 todo 确认互联网医院处方的医疗目录编码
+ // -medinsListCodg 医药机构目录编码 todo 确认互联网医院处方的医药机构目录编码
+ // -detItemFeeSumamt 明细项目费用总额
+ // -cnt 数量
+ // -pric 单价
+ // -bilgDeptCodg 开单科室编码
+ // -bilgDeptName 开单科室名称
+ // -bilgDrCodg 开单医生编码 todo 医生标准编码
+ // -bilgDrName 开单医师姓名
+ // -hospApprFlag 医院审批标志 1
+ // -medType 医疗类别 todo 确认互联网医院处方的医疗类别
+ // -medListName 医疗目录名称
+ // -medListSpc 医疗目录规格
+ // payAuthNo 支付授权码
+ // uldLatlnt 用户经纬度 定位失败情况下传0,0
+ // mdtrtCertType 就诊凭证类型 02 身份证 01 电子凭证 todo 确认填身份证还是电子凭证
+
+
+ // todo 校验必填项
+
+
+ InsuranceUploadRecipeDetailInputMessage uploadData = new InsuranceUploadRecipeDetailInputMessage();
+ // 医保核心系统患者基本信息
+ InsuranceCoreOutputMessage1101.Baseinfo baseinfo = insuranceCoreInfo.getBaseinfo();
+ // 医保核心系统保信息
+ InsuranceCoreOutputMessage1101.Insuinfo insuinfo = insuranceCoreInfo.getInsuinfo();
+ // 费用明细
+ List feedetailList = new ArrayList<>();
+ // 诊断或状态明细
+ List diseinfoList = new ArrayList<>();
+
+
+ uploadData.setOrgCodg(fixmedinsCode);
+ // uploadData.setOrgId();
+ uploadData.setPsnNo(baseinfo.getPsnNo());
+ uploadData.setIdType(insuinfo.getInsutype());
+ uploadData.setMedOrgOrd(req.getMedOrgOrd());
+ // 电子处方流转标志 todo 目前河南省并未测试过电子处方线上医保支付
+ uploadData.setRxCircFlag("0");
+ uploadData.setBegntime(DateUtils.format(new Date(), DateUtils.PATTERN_DATE_TIME));
+ uploadData.setIdNo(baseinfo.getCertno());
+ uploadData.setUserName(baseinfo.getPsnName());
+ uploadData.setIdType("01");
+ uploadData.setEcToken(req.getAuthCode());
+ uploadData.setInsuCode(mdtrtareaAdmvs);
+ uploadData.setIptOtpNo(req.getPlatformOrderId());
+ // 字典 dept
+ uploadData.setDeptName("预防保健科");
+ uploadData.setCaty("A01");
+ uploadData.setMedType("91");
+ uploadData.setFeeType("05");
+ uploadData.setMedfeeSumamt(new BigDecimal("0.01"));
+ // uploadData.setAcctUsedFlag("0");
+ uploadData.setDiseCodg("A01.001");
+ uploadData.setDiseName("感冒");
+ uploadData.setPsnSetlway("01");
+ // 公立医院内容 todo 疑问点 互联网医院是否为公立医院 公立医院改革标志 如何传参
+ uploadData.setChrgBchno(req.getChrgBchno());
+ uploadData.setDiseinfoList(diseinfoList);
+ uploadData.setFeedetailList(feedetailList);
+
+ // ========组装诊断数据========
+ DiseInfo diseInfo = new DiseInfo();
+ diseinfoList.add(diseInfo);
+ // 西医诊断
+ diseInfo.setDiagType("1");
+ // todo 确认诊断排序号
+ diseInfo.setDiagSrtNo(1);
+ diseInfo.setDiagCode("A01.001");
+ diseInfo.setDiagName("感冒");
+ diseInfo.setDiagDept("预防保健科");
+ diseInfo.setDiseDorNo("wy");
+ diseInfo.setDiseDorName("wy");
+ diseInfo.setDiagTime(DateUtils.format(new Date(), DateUtils.PATTERN_DATE_TIME));
+ diseInfo.setValiFlag("1");
+
+ //========组装费用数据========
+ FeeDetail feeDetail = new FeeDetail();
+
+ feedetailList.add(feeDetail);
+ // 如果是诊疗 传问诊单号
+ feeDetail.setFeedetlSn("10086");
+ feeDetail.setMdtrtId(req.getMdtrtId());
+ feeDetail.setPsnNo(baseinfo.getPsnNo());
+ feeDetail.setChrgBchno(uploadData.getChrgBchno());
+ // 同一收费批次号病种编号必须一致 todo 确认 多药品多问题
+ feeDetail.setDiseCodg("A01.001");
+ feeDetail.setRxno("100866");
+ feeDetail.setRxCircFlag("0");
+ feeDetail.setFeeOcurTime(DateUtils.format(new Date(), DateUtils.PATTERN_DATE_TIME));
+ // 医疗目录编码 todo 确认互联网医院处方的医疗目录编码
+ feeDetail.setMedListCodg("A01.001");
+ // 医药机构目录编码 todo 确认互联网医院处方的医药机构目录编码
+ feeDetail.setMedinsListCodg("A01.001");
+ feeDetail.setDetItemFeeSumamt(new BigDecimal("0.01"));
+ feeDetail.setCnt(new BigDecimal("1"));
+ feeDetail.setPric(new BigDecimal("0.01"));
+ feeDetail.setBilgDeptCodg("A01.001");
+ feeDetail.setBilgDeptName("预防保健科");
+ feeDetail.setBilgDrCodg("wy");
+ feeDetail.setBilgDrName("wy");
+ feeDetail.setHospApprFlag("1");
+ // todo 确认互联网医院处方的医疗类别
+ feeDetail.setMedType("医疗类别");
+ feeDetail.setMedListName("医疗目录名称");
+ feeDetail.setMedListSpc("医疗目录规格");
+
+
+ String result = HttpUtil.postByJson(uploadRecipeDetailPath, JSONObject.toJSONString(uploadData));
+ log.info("uploadRecipeDetailPath: {}", result);
+ InsuranceMiddleGroundOutputMessage outputMessage = JSON.parseObject(result, InsuranceMiddleGroundOutputMessage.class);
+
+ // =============== 上传响应参数 ===============
+ // payOrdId 支付订单号
+ // payToken 支付token
+ // cashierUrl 医保支付收银台h5地址 不对接收银台模式 忽略
+ if (outputMessage.getCode() != null) {
+ // 解密outputMessage
+ decryptMiddleGroundOutputMessage(outputMessage);
+
+
+ return JSON.parseObject(outputMessage.getData(), InsuranceUploadRecipeDetailOutputMessage.class);
+ }
+
+
+ return null;
+ }
+
+
+ private void decryptMiddleGroundOutputMessage(InsuranceMiddleGroundOutputMessage outputMessage) {
+ // 解密outputMessage todo
+ String data = outputMessage.getEncData();
+ outputMessage.setData(data);
+ }
+
+
+ /**
+ * 省医保平台「6202」支付下单
+ *
+ * @return
+ */
+ public InsurancePayOrderOutputMessage payOrder(InsuranceGetOrderReq req, InsuranceRep insuranceRep, InsuranceUploadRecipeDetailOutputMessage uploadRecipeDetail) {
+
+ // ============ 参数梳理 ===========
+ // payAuthNo 支付授权码
+ // payOrdId 待支付订单号 费用上传接口
+ // payToken 支付订单对应的token 费用上传接口
+ // orgCodg 定点机构编码
+ // orgBizSer 业务流水号 每次请求唯一
+ // chrgBchno 收费批次号 费用上传一致
+ // feeType 费用类别 与费用上传一致
+ // mdtrtId 就诊事件ID 与费用上传一致
+
+ InsurancePayOrderInputMessage payOrder = new InsurancePayOrderInputMessage();
+
+ payOrder.setPayAuthNo(insuranceRep.getPayAuthNo());
+ payOrder.setPayOrdId(uploadRecipeDetail.getPayOrdId());
+ payOrder.setPayToken(uploadRecipeDetail.getPayToken());
+ payOrder.setOrgCodg(fixmedinsCode);
+ payOrder.setOrgBizSer(req.getOrgBizSer());
+ payOrder.setChrgBchno(req.getChrgBchno());
+
+
+ String result = HttpUtil.postByJson(payOrderPath, JSONObject.toJSONString(payOrder));
+ log.info("payOrder: {}", result);
+ InsuranceMiddleGroundOutputMessage outputMessage = JSON.parseObject(result, InsuranceMiddleGroundOutputMessage.class);
+
+
+ // =============== 下单响应参数 ===============
+ // payOrdId 支付订单号
+ // ordStas 支付订单状态 0 已保存 1 预结算完成 2 结算中 3 自费完成 4 医保支付完成 5 院内结算完成 6 结算完成
+ // feeSumamt 费用总额
+ // ownPayAmt 现金支付
+ // psnAcctPay 个人账户支出
+ // fundPay 医保基金支付
+ if (outputMessage.getCode() != null) {
+ // 解密outputMessage
+ decryptMiddleGroundOutputMessage(outputMessage);
+
+ return JSON.parseObject(outputMessage.getData(), InsurancePayOrderOutputMessage.class);
+ }
+
+
+
+ return null;
+
+
+ }
+
+ /**
+ * 获取用户医保信息
+ * 目前测试由配置文件获取
+ * @param req 请求参数
+ * @return 返回用户医保信息
+ */
+ @SneakyThrows
+ public InsuranceRep getInsuranceInfo(InsuranceReq req) {
+// Integer patientUserId = TokenUtil.getPatientUserId();
+// PatientUser patientUser = patientUserMapper.selectById(patientUserId);
+
+ UserQueryReq queryReq = new UserQueryReq();
+ queryReq.setOpenid("");
+ queryReq.setQrcode(req.getQrcode());
+ String pathUrl = String.format(getInsuranceAPI, partnerId);
+ String s = postData("mipuserquery", "userQuery", pathUrl, partnerId, queryReq.toString());
+ log.info("getInsuranceInfo: {}", s);
+ return JSON.parseObject(s, InsuranceRep.class);
+
+ }
+
+
+ /**
+ * 微信支付平台统一下单
+ *
+ * @return
+ */
+ @SneakyThrows
+ public UnifiedOrderRep unifiedOrder(UnifiedOrderReq req) {
+
+ InsuranceAccessTokenRep accessToken = req.getAccessToken();
+ // 医保下单信息
+ InsurancePayOrderOutputMessage order = req.getInsurancePayOrder();
+
+
+ // ========== 参数梳理 ==========
+ WechatUnifiedOrderReq orderReq = new WechatUnifiedOrderReq();
+ orderReq.setOrderType(req.getOrderType());
+ orderReq.setAppid(appid);
+ orderReq.setMchId(mchId);
+ orderReq.setSubMchId(subMchId);
+ orderReq.setOpenid(req.getOpenId());
+ orderReq.setHospOutTradeNo(UUID.randomUUID().toString());
+ orderReq.setHospitalName(fixmedinsName);
+ orderReq.setNonceStr(UUID.randomUUID().toString().replace("-", ""));
+ // 总额 转换为分
+ orderReq.setTotalFee(Integer.toString(order.getFeeSumamt().multiply(new BigDecimal("100")).intValue()));
+ // 现金支付 转换为分
+ orderReq.setCashFee(Integer.toString(order.getOwnPayAmt().multiply(new BigDecimal("100")).intValue()));
+ // 减免、 运费 todo .......后续可拓展
+ orderReq.setCashAddFee("0");
+ // 当医保局返回的预结算金额与医院上传的金额不一致时,此字段为0则直接报错,为1则以医保局金额为准
+ orderReq.setAllowFeeChange("0");
+ orderReq.setSpbillCreateIp(req.getSpbillCreateIp());
+ orderReq.setNotifyUrl("");
+ orderReq.setBody("医保支付");
+ // todo 确认跳转地址
+ orderReq.setReturnUrl("");
+ // 当订单要走医保支付时,
+ //(1)cash_fee>0, paytype填3
+ //(2)cash_fee=0, paytype填2
+ Integer payType = orderReq.getCashFee().compareTo("0") == 0 ? 2 : 3;
+ orderReq.setPayType(payType.toString());
+ orderReq.setCityId(cityId);
+ orderReq.setConsumeType("0");
+ orderReq.setInsuranceFee(Integer.toString(order.getFundPay().multiply(new BigDecimal("100")).intValue()));
+ // sfz 1 身份证
+ orderReq.setUserCardType("1");
+ // todo MD5处理
+ orderReq.setUserCardNo(req.getUserCardNo());
+ orderReq.setUserName(req.getUserName());
+ // is_dept is_dept=4 医保电子凭证支付;
+ orderReq.setIsDept("4");
+ orderReq.setSerialNo(UUID.randomUUID().toString());
+ orderReq.setOrgNo(orgCodg);
+ orderReq.setGmtOutCreate(DateUtils.format(new Date(), DateUtils.PATTERN_YYYYMMDDHHMMSS));
+ orderReq.setRequestContent(order.getRequestContent());
+ orderReq.setSign("");
+
+ String url = String.format(unifiedOrderAPI, accessToken.getAccessToken());
+
+ String s = postData("mipunifiedorder", "unifiedOrder", url, agentappid, orderReq.toString());
+
+
+ return null;
+ }
+
+ /**
+ * 获取当前HealthInsuranceManager的所有属性
+ *
+ * @return 返回当前HealthInsuranceManager的所有属性
+ */
+ public Object getInsuranceConfig() {
+ // 返回当前HealthInsuranceManager的所有属性
+
+ Map map = new HashMap<>();
+ map.put("partnerId", partnerId);
+ map.put("partnerSecret", partnerSecret);
+ map.put("agentappid", agentappid);
+ map.put("agentsecret", agentsecret);
+ map.put("appid", appid);
+ map.put("cityCode", cityCode);
+ map.put("channel", channel);
+ map.put("redirectUrl", redirectUrl);
+ map.put("orgChnlCrtfCodg", orgChnlCrtfCodg);
+ map.put("orgCodg", orgCodg);
+ map.put("bizType", bizType);
+ map.put("orgAppId", orgAppId);
+
+ return JSON.toJSON(map, JSONWriter.Feature.WriteNulls);
+ }
+
+
+ // ====================== 签名方法 调用微信医保平台接口时使用 =====================
+
+
+ private String bytesToHex(byte[] bytes) {
+ char[] hexChars = new char[bytes.length * 2];
+ for (int j = 0; j < bytes.length; j++) {
+ int v = bytes[j] & 0Xff;
+ hexChars[j * 2] = hexArray[v >>> 4];
+ hexChars[j * 2 + 1] = hexArray[v & 0x0F];
+ }
+ return new String(hexChars);
+ }
+
+ private String createSignature(String partnerSecret, String partnerId, String timestamp)
+ throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
+ Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
+ SecretKeySpec secret_key = new SecretKeySpec(partnerSecret.getBytes("UTF-8"), "HmacSHA256");
+ sha256_HMAC.init(secret_key);
+ return bytesToHex(sha256_HMAC.doFinal((partnerId + timestamp).getBytes("UTF-8")));
+ }
+
+
+ private String postData(String businessName, String funcName, String urlPath, String partnerId, String data)
+ throws IOException, NoSuchAlgorithmException, InvalidKeyException {
+ HttpURLConnection conn = null;
+ URL url = new URL(urlPath);
+ conn = (HttpURLConnection) url.openConnection();
+ conn.setDoOutput(true);
+ conn.setDoInput(true);
+ conn.setRequestMethod("POST");
+ conn.setUseCaches(false);
+ conn.setInstanceFollowRedirects(true);
+ conn.setRequestProperty("Content-Type", "application/json");
+ conn.setRequestProperty("Accept", "application/json");
+ String timestamp = Long.toString(System.currentTimeMillis());
+ String signature = createSignature(partnerSecret, partnerId, timestamp);
+ String requestId = UUID.randomUUID().toString().replaceAll("-", "");
+ conn.setRequestProperty("god-portal-timestamp", timestamp);
+ conn.setRequestProperty("god-portal-signature", signature);
+ conn.setRequestProperty("god-portal-request-id", requestId);
+ conn.connect();
+ OutputStream os = conn.getOutputStream();
+ os.write(data.getBytes());
+ os.flush();
+ os.close();
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ InputStream inputStream = conn.getInputStream();
+ byte[] bytes = new byte[1024];
+ int readBytes;
+ while ((readBytes = inputStream.read(bytes)) != -1) {
+ byteArrayOutputStream.write(bytes, 0, readBytes);
+ }
+ bytes = byteArrayOutputStream.toByteArray();
+ inputStream.close();
+ conn.disconnect();
+ return new String(bytes, "utf-8");
+ }
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/util/DateUtils.java b/src/main/java/com/szyx/tcm/supervision/util/DateUtils.java
new file mode 100644
index 0000000..cffb88e
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/util/DateUtils.java
@@ -0,0 +1,585 @@
+package com.szyx.tcm.supervision.util;
+
+
+import com.szyx.tcm.supervision.enums.BannerEnum;
+import com.szyx.tcm.supervision.enums.WeekDayEnum;
+import lombok.SneakyThrows;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.time.DateFormatUtils;
+import org.dromara.hutool.core.date.DateUtil;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.*;
+
+/**
+ * @author chenjie
+ */
+public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
+
+ public static final String PATTERN_DATE_TIME = "yyyy-MM-dd HH:mm:ss";
+ public static final String PATTERN_DATE_TIME_YEAR = "yyyy-MM-dd HH:mm";
+ public static final String PATTERN_DATE = "yyyy-MM-dd";
+ public static final String PATTERN_DATE_SIDE= "yyyyMMdd";
+ public static final String PATTERN_DATE_HOUR = "HH:mm";
+ public static final String PATTERN_DATE_HOUR_MS = "HH:mm:ss";
+ public static final String PATTERN_YYYYMMDDHHMMSSSSS = "yyyyMMddHHmmssSSS";
+ public static final String PATTERN_YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
+ public static final String PATTERN_DATE_YEAR = "yyyy";
+ public static final String UTC_WITH_ZONE_OFFSET_PATTERN = "yyyy-MM-dd'T'HH:mm:ss+08:00";
+
+ public static final String PATTERN_MONTH_DATE = "MM.dd";
+
+ public static final String PATTERN_YEAR_DATE = "yyyy.MM.dd";
+ public static Date parseDate(String str) {
+ try {
+ return parseDate(str, PATTERN_DATE_TIME);
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ public static Date parseDateHours(String str) {
+ try {
+ return parseDate(str, PATTERN_DATE_HOUR_MS);
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+
+ public static String format(Date date) {
+ return DateFormatUtils.format(date, PATTERN_DATE_TIME);
+ }
+
+ public static String formatString(Date date) {
+ return DateFormatUtils.format(date, PATTERN_DATE);
+ }
+
+ public static String formatStringToYear(Date date) {
+ return DateFormatUtils.format(date, PATTERN_DATE_YEAR);
+ }
+
+ public static String formatString1(String date) throws ParseException {
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat(PATTERN_DATE);
+ return formatString(simpleDateFormat.parse(date));
+ }
+
+ public static String formatStringYear(Date date){
+ return new SimpleDateFormat("yyyy年MM月dd日").format(date);
+ }
+
+ public static String formatYear(Date date) {
+ return DateFormatUtils.format(date, PATTERN_DATE_TIME_YEAR);
+ }
+
+ public static String format(Date date, String pattern) {
+ return DateFormatUtils.format(date, pattern);
+ }
+
+ public static Date parse(String dateStr) throws Exception {
+ SimpleDateFormat formatter = new SimpleDateFormat(PATTERN_DATE);
+ return formatter.parse(dateStr);
+ }
+
+ public static Date parse(String dateStr, String pattern_date) throws Exception {
+ SimpleDateFormat formatter = new SimpleDateFormat(pattern_date);
+ return formatter.parse(dateStr);
+ }
+
+ /**
+ * 计算当前日期与{@code endDate}的间隔天数
+ *
+ * @param date
+ * @return 间隔天数
+ */
+ public static long until(Date date) {
+
+ LocalDate endDate = dateLocalDate(date);
+ return LocalDate.now().until(endDate, ChronoUnit.DAYS);
+ }
+
+ /**
+ * 计算日期{@code startDate}与{@code endDate}的间隔天数
+ *
+ * @param startDate
+ * @param endDate
+ * @return 间隔天数
+ */
+ public static long until(LocalDate startDate, LocalDate endDate) {
+ return startDate.until(endDate, ChronoUnit.DAYS);
+ }
+
+ /**
+ * Date转LocalDate
+ *
+ * @param date
+ */
+ public static LocalDate dateLocalDate(Date date) {
+ if (null == date) {
+ return null;
+ }
+ return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+ }
+
+ public static String getDatePoor(Date endDate, Date nowDate, Integer status) {
+
+ long nd = 1000 * 24 * 60 * 60;//每天毫秒数
+
+ long nh = 1000 * 60 * 60;//每小时毫秒数
+
+ long nm = 1000 * 60;//每分钟毫秒数
+
+ long diff = endDate.getTime() - nowDate.getTime(); // 获得两个时间的毫秒时间差异
+
+ long day = diff / nd; // 计算差多少天
+
+ long hour = diff % nd / nh; // 计算差多少小时
+
+ long min = diff % nd % nh / nm; // 计算差多少分钟
+ if (status == 1) {
+ if (day > 0) {
+ return day + "天" + hour + "小时";
+ } else {
+ return hour + "小时";
+ }
+ } else {
+ if (day == 0 && hour == 0) {
+ return String.valueOf(min);
+ } else {
+ return String.valueOf(100);
+ }
+ }
+ }
+
+ /**
+ * LocalDate转Date
+ *
+ * @param localDate
+ * @return
+ */
+ public static Date localDate2Date(LocalDate localDate) {
+ if (null == localDate) {
+ return null;
+ }
+ ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
+ return Date.from(zonedDateTime.toInstant());
+ }
+
+ /**
+ * Date转LocalDate
+ *
+ * @param date
+ */
+ public static LocalDate date2LocalDate(Date date) {
+ if (null == date) {
+ return null;
+ }
+ return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+ }
+
+ /**
+ * LocalDate 转string
+ *
+ * @param localDate
+ * @return
+ */
+ public static String localDate2String(LocalDate localDate) {
+ if (null == localDate) {
+ return null;
+ }
+ DateTimeFormatter fmt = DateTimeFormatter.ofPattern(PATTERN_DATE);
+ return localDate.format(fmt);
+ }
+
+ public static String localDateTimeToString(LocalDateTime localDate, String patternDate) {
+ if (null == localDate) {
+ return null;
+ }
+
+ DateTimeFormatter fmt = DateTimeFormatter.ofPattern(patternDate);
+ return localDate.format(fmt);
+ }
+
+ /**
+ * 计算当前日期与{@code endDate}的间隔天数
+ *
+ * @param endDate
+ * @return 间隔天数
+ */
+ static long until(LocalDate endDate) {
+ return LocalDate.now().until(endDate, ChronoUnit.DAYS);
+ }
+
+ /**
+ * 计算日期{@code startDate}与{@code endDate}的间隔天数
+ *
+ * @param startDate
+ * @param endDate
+ * @return 间隔天数
+ */
+ static long untilDiffer(LocalDate startDate, LocalDate endDate) {
+ return startDate.until(endDate, ChronoUnit.DAYS);
+ }
+
+ public static String betweenTwoTimes(LocalDate startDate, LocalDate endDate) {
+ Period p = Period.between(endDate, startDate);
+ return p.getYears() + "年" + p.getMonths() + "月" + p.getDays() + "日";
+ }
+
+ public final static Map digit = new HashMap<>();
+ public final static Map position = new HashMap<>();
+
+ static {
+ digit.put('零', 0);
+ digit.put('一', 1);
+ digit.put('二', 2);
+ digit.put('三', 3);
+ digit.put('四', 4);
+ digit.put('五', 5);
+ digit.put('六', 6);
+ digit.put('七', 7);
+ digit.put('八', 8);
+ digit.put('九', 9);
+ position.put('十', 1);
+ position.put('百', 2);
+ position.put('千', 3);
+ }
+
+ public static int s2(String num) {
+ //一共八位
+ char[] nums = new char[8];
+ int p = 7, now = 7;
+ char[] c = num.toCharArray();
+ /**
+ * 从右到左逐个字符解析
+ * 通过p控制万位,pp控制万以下的单位,now记录当前单位
+ */
+ for (int i = c.length - 1; i >= 0; i--) {
+ if (c[i] == '万') {
+ now = p = 3;
+ } else {
+ int d = digit.getOrDefault(c[i], -1);
+ if (d == 0) {
+ continue;
+ }
+ if (d == -1) {
+ int pp = position.getOrDefault(c[i], -1);
+ if (pp == -1) {
+ throw new RuntimeException("\"" + num + "\"中存在无法解析的字符: " + i + ":" + c[i]);
+ } else {
+ now = p - pp;
+ //允许"一十"省略"一",即"十"
+ if (now == 6) {
+ nums[now] = 1;
+ }
+ }
+ } else {
+ nums[now] = (char)d;
+ }
+ }
+ }
+ for (int i = 0; i < nums.length; i++) {
+ nums[i] = (char)(nums[i] + '0');
+ }
+ return Integer.parseInt(new String(nums));
+ }
+
+ /**
+ * 把 Thu Dec 14 00:00:00 CST 2017 转换成自己想要的格式
+ *
+ * @param date
+ * @param pattern
+ * @return
+ */
+
+ public static String dateStringFormat(String date, String pattern) {
+ if (date == null || pattern == null) {
+ return null;
+ }
+ try {
+ Date formDate = new SimpleDateFormat("MMM dd yyyy", Locale.US).parse(date);
+ return new SimpleDateFormat(pattern, Locale.CHINA).format(formDate);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static Date dateFormatConvert(String Date, String format, String newFormat) {
+ try {
+ SimpleDateFormat newSDF = new SimpleDateFormat(newFormat);
+ SimpleDateFormat oldSDF = new SimpleDateFormat(format);
+ Date inDate = oldSDF.parse(Date);
+ String outDate = newSDF.format(inDate);
+ return newSDF.parse(outDate);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public static Date getDate(String sFormat, String sDate) {
+ SimpleDateFormat sdf = new SimpleDateFormat(sFormat);
+ Date d = null;
+ try {
+ sdf.setLenient(false);
+ d = sdf.parse(sDate);
+ } catch (Exception e) {
+ return null;
+ }
+ return d;
+ }
+
+ public static String getDate(String sDate) {
+ String[] sa =
+ {"yyyy-MM-dd", "yyyyMMdd", "yyyy.MM.dd", "yyyy/MM/dd", "yyyy年MM月dd日", "dd/MM/yyyy", "d/M/yyyy", "MM-dd-yyyy", "dd-MM-yyyy", "MM/yyyy", "yyyy--M-dd",
+ "yyyy-MM", "yyyy"};
+
+ for (String s : sa) {
+ Date d = getDate(s, sDate);
+ if (d != null) {
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+ return simpleDateFormat.format(d);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 把 mm/dd/yyyy 转换成
+ *
+ * @param date
+ * @return
+ */
+
+ public static String dateStringFormat(String date) {
+ if (StringUtils.isNotBlank(date)) {
+ String[] split = date.split("/");
+ if (split.length == 3 && split[2].length() == 4) {
+ return split[2] + "-" + split[0] + "-" + split[1];
+ }
+ return date;
+ }
+ return "";
+ }
+
+ public static String dataToUpper(String dateString) {
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+ Date dateTime = null;
+ try {
+ dateTime = simpleDateFormat.parse(dateString);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ Calendar ca = Calendar.getInstance();
+ ca.setTime(dateTime);
+ int year = ca.get(Calendar.YEAR);
+ int month = ca.get(Calendar.MONTH) + 1;
+ int day = ca.get(Calendar.DAY_OF_MONTH);
+ return numToUpper(year) + "年" + monthToUppder(month) + "月" + dayToUppder(day) + "日";
+ }
+
+ // 将数字转化为大写(字体格式可自己定义)
+ public static String numToUpper(int num) {
+ //String u[] = {"零","壹","贰","叁","肆","伍","陆","柒","捌","玖"};
+ String[] u = {"零","一","二","三","四","五","六","七","八","九"};
+ char[] str = String.valueOf(num).toCharArray();
+ String rstr = "";
+ for (int i = 0; i < str.length; i++) {
+ rstr = rstr + u[Integer.parseInt(String.valueOf(str[i]))];
+ }
+ return rstr;
+ }
+
+ // 月转化为大写
+ public static String monthToUppder(int month) {
+ if(month < 10) {
+ return numToUpper(month);
+ } else if(month == 10){
+ return "十";
+ } else {
+ return "十" + numToUpper(month - 10);
+ }
+ }
+
+ // 日转化为大写
+ public static String dayToUppder(int day) {
+ if(day < 20) {
+ return monthToUppder(day);
+ } else {
+ char[] str = String.valueOf(day).toCharArray();
+ if(str[1] == '0') {
+ return numToUpper(Integer.parseInt(String.valueOf(str[0]))) + "十";
+ }else {
+ return numToUpper(Integer.parseInt(String.valueOf(str[0]))) + "十" + numToUpper(Integer.parseInt(String.valueOf(str[1])));
+ }
+ }
+ }
+
+ /**
+ * 判断当前日期是否在指定日期内
+ * @param start
+ * @param end
+ * @return
+ */
+ public static Integer beforeTimeCalendar(Date start, Date end) {
+
+ LocalDate startDate = dateToLocalDate(start);
+
+ LocalDate endDate = dateToLocalDate(end);
+ // 当前日期
+ LocalDate today = LocalDate.now();
+ if (today.isAfter(startDate) && today.isBefore(endDate)) {
+ return BannerEnum.PUBLISH.getCode();
+ } else {
+ if(today.isBefore(startDate)) {
+ return BannerEnum.EXPIRED.getCode();
+ }
+ if(today.isAfter(endDate)) {
+ return BannerEnum.RELEASED.getCode();
+ }
+ }
+ return BannerEnum.PUBLISH.getCode();
+ }
+
+ /**
+ * JAVA计算两个日期相差多少天
+ * @param date2
+ * @param date2
+ * @return
+ */
+ public static int daysBetween(Date date1,Date date2) {
+ int count = 0;
+ try {
+ if(date1 == null || date2 == null ) {
+ return 0;
+ }
+ count = Math.abs((int) ((date1.getTime() - date2.getTime()) / (1000*3600*24)));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return count;
+ }
+
+
+ /**
+ * Date 转为 LocalDate
+ *
+ * @param date
+ * @return LocalDate;
+ */
+ public static LocalDate dateToLocalDate(Date date) {
+ return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+ }
+
+ @SneakyThrows
+ public static Date formatDate(Date date, String pattern) {
+ if (pattern == null) {
+ pattern = "yyyy-MM-dd";
+ }
+
+ SimpleDateFormat formatter = new SimpleDateFormat(pattern);
+ DateFormat dateFormat = new SimpleDateFormat(pattern);
+ Date formatDate = dateFormat.parse(formatter.format(date));
+ return formatDate;
+ }
+
+ /**
+ * 获取年龄
+ * @param birthday
+ * @return
+ */
+ public static Integer getAge(Date birthday) {
+ int compare = DateUtil.compare(birthday, new Date());
+ if (compare > 0) {
+ //如果出生日期大于当前时间,返回0
+ return 0;
+ } else {
+ return DateUtil.ageOfNow(birthday);
+ }
+ }
+
+
+ /**
+ * 根据日期获得星期
+ * @param date
+ * @return
+ */
+ public static String getWeekOfDate(Date date) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(date);
+ int intWeek = calendar.get(Calendar.DAY_OF_WEEK);
+ return WeekDayEnum.getByCode(intWeek);
+ }
+
+ public static Date getWholeTime(Date date,int addDay){
+ if (date == null) {
+ date = new Date();
+ }
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(date);
+ calendar.add(Calendar.DAY_OF_MONTH, addDay);
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
+ return calendar.getTime();
+ }
+
+ public static Integer dayForWeeks(Date date) {
+ Calendar c = Calendar.getInstance();
+ c.setTime(date);
+ int dayForWeek = 0 ;
+ if (c.get(Calendar.DAY_OF_WEEK) == 1 ){
+ dayForWeek = 7 ;
+ }else {
+ dayForWeek = c.get(Calendar.DAY_OF_WEEK) - 1 ;
+ }
+ return dayForWeek;
+ }
+
+ public static int getCompareResult(Date date, Date targetDate) {
+ return formatDate(date, DateUtils.PATTERN_DATE_TIME_YEAR).compareTo(DateUtils.formatDate(targetDate, DateUtils.PATTERN_DATE_TIME_YEAR));
+ }
+
+ /**
+ * 方法注释:
+ * 〈时间增加一个小时〉
+ * @param hour
+ * @return java.util.Date
+ * @author cj 🤡
+ * @date 2024/1/17 19:15
+ */
+ public static Date timeSubtraction(Integer hour){
+ // 当前时间
+ LocalDateTime currentDateTime = LocalDateTime.now();
+
+ // 添加小时
+ LocalDateTime newDateTime = currentDateTime.plusHours(hour);
+
+ Date date = Date.from(newDateTime.atZone(ZoneId.systemDefault()).toInstant());
+
+
+ return date;
+ }
+
+ public static void main(String[] args) {
+ Date startTime= DateUtils.formatDate(new Date(), DateUtils.PATTERN_DATE_HOUR_MS);
+ startTime.setDate(new Date().getDate());
+ Date start= DateUtils.parseDateHours("16:30:00");
+
+ Date end= DateUtils.parseDateHours("23:30:00");
+ if ((start.after(startTime))) {
+ System.out.println(true);
+ }
+
+ if ((end.before(startTime))) {
+ System.out.println(true);
+ }
+ }
+}
+
+
diff --git a/src/main/java/com/szyx/tcm/supervision/util/InsuranceWechatUtil.java b/src/main/java/com/szyx/tcm/supervision/util/InsuranceWechatUtil.java
new file mode 100644
index 0000000..82d1319
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/util/InsuranceWechatUtil.java
@@ -0,0 +1,192 @@
+package com.szyx.tcm.supervision.util;
+
+import com.tencent.mip.DataHandler;
+import org.dromara.hutool.core.util.RandomUtil;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Date;
+import java.util.UUID;
+
+/*******************************************************************
+ *
+ * @文件名称: InsuranceWechatUtil.java
+ * @包 路 径: com.szyx.tcm.common.utils
+ * @Copyright:wy (C) 2024 *
+ * @Description: 医保支付参数封装工具类
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/22 13:42
+ * @Modify:
+ */
+public class InsuranceWechatUtil {
+
+ // ================= 医保核心系统有关方法 ===========================
+
+ /**
+ * 医保核心系统-生成发送报文ID
+ *
+ * @param Code 医院机构编码 K开头
+ */
+ public static String getMsgId(String Code) {
+
+ // 时间类型 yyyyMMddHHmmss
+ // 顺序号 待定 todo
+ if (Code == null) {
+ Code = "";
+ }
+ return Code + DateUtils.format(new Date(), DateUtils.PATTERN_YYYYMMDDHHMMSS) + RandomUtil.randomNumbers(4);
+ }
+
+
+ // ================= 医保支付中台有关方法 ===========================
+
+ /**
+ * 根据公私钥和appID生成请求报文
+ */
+ public static String getReqMessageForInsuranceCore(String appid, String appSecret, String publicKey,String privateKey,String plainJSON) throws Exception {
+ DataHandler dataHandler = DataHandler.newInstance(appid,appSecret,publicKey,privateKey);
+ dataHandler.setVersion("2.0.1");
+
+ return dataHandler.buildReqData(plainJSON);
+
+ }
+
+
+
+
+
+
+ // ================= 微信医保支付平台有关方法 ===========================
+
+ /**
+ *
+ */
+ private final static char[] hexArray = "0123456789abcdef".toCharArray();
+
+ //签名工具 获取信息服务接口
+ private static String createSignature(String partnerSecret, String partnerId, String timestamp)
+ throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
+ Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
+ SecretKeySpec secret_key = new SecretKeySpec(partnerSecret.getBytes("UTF-8"), "HmacSHA256");
+ sha256_HMAC.init(secret_key);
+ return bytesToHex(sha256_HMAC.doFinal((partnerId + timestamp).getBytes("UTF-8")));
+ }
+
+ private static String bytesToHex(byte[] bytes) {
+ char[] hexChars = new char[bytes.length * 2];
+ for (int j = 0; j < bytes.length; j++) {
+ int v = bytes[j] & 0Xff;
+ hexChars[j * 2] = hexArray[v >>> 4];
+ hexChars[j * 2 + 1] = hexArray[v & 0x0F];
+ }
+ return new String(hexChars);
+ }
+
+ /**
+ * 发送请求
+ * 微信免密授权请求
+ * @param businessName 自定义业务名称
+ * @param funcName 自定义功能名称
+ * @param urlPath 请求路径
+ * @param partnerId 合作方ID
+ * @param data 请求数据
+ * @return 返回结果
+ * @throws IOException
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidKeyException
+ */
+ public static String postData(String businessName, String funcName, String partnerSecret, String urlPath, String partnerId, String data)
+ throws IOException, NoSuchAlgorithmException, InvalidKeyException {
+ HttpURLConnection conn = null;
+ URL url = new URL(urlPath);
+ conn = (HttpURLConnection) url.openConnection();
+ conn.setDoOutput(true);
+ conn.setDoInput(true);
+ conn.setRequestMethod("POST");
+ conn.setUseCaches(false);
+ conn.setInstanceFollowRedirects(true);
+ conn.setRequestProperty("Content-Type", "application/json");
+ conn.setRequestProperty("Accept", "application/json");
+ String timestamp = Long.toString(System.currentTimeMillis());
+ String signature = createSignature(partnerSecret, partnerId, timestamp);
+ String requestId = UUID.randomUUID().toString().replaceAll("-", "");
+ conn.setRequestProperty("god-portal-timestamp", timestamp);
+ conn.setRequestProperty("god-portal-signature", signature);
+ conn.setRequestProperty("god-portal-request-id", requestId);
+ conn.connect();
+ OutputStream os = conn.getOutputStream();
+ os.write(data.getBytes());
+ os.flush();
+ os.close();
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ InputStream inputStream = conn.getInputStream();
+ byte[] bytes = new byte[1024];
+ int readBytes;
+ while ((readBytes = inputStream.read(bytes)) != -1) {
+ byteArrayOutputStream.write(bytes, 0, readBytes);
+ }
+ bytes = byteArrayOutputStream.toByteArray();
+ inputStream.close();
+ conn.disconnect();
+ return new String(bytes, "utf-8");
+ }
+
+
+ public static void main(String[] args) {
+ // 收到的1101报文
+ String s = "{\n" +
+ " \"infcode\": \"1\",\n" +
+ " \"inf_refmsgid\": \"000000202001041235391234567890\",\n" +
+ " \"refmsg_time\": \"20200201133411352\",\n" +
+ " \"respond_time\": \"20200202133731456\",\n" +
+ " \"err_msg\": \"\",\n" +
+ " \"output\": {\n" +
+ " \"baseinfo\": {\n" +
+ " \"psn_no\": \"131000202001001\",\n" +
+ " \"psn_cert_type\": \"2\",\n" +
+ " \"certno\": \"510000202001010000\",\n" +
+ " \"psn_name\": \"李四\",\n" +
+ " \"gend\": \"1\",\n" +
+ " \"naty\": \"01\",\n" +
+ " \"brdy\": \"2020-01-01\",\n" +
+ " \"age\": 18\n" +
+ " },\n" +
+ " \"insuinfo\": {\n" +
+ " \"psn_insu_rlts_id\": \"133241523001001\",\n" +
+ " \"balc\": 5000,\n" +
+ " \"insutype\": \"310\",\n" +
+ " \"psn_type\": \"1001\",\n" +
+ " \"cvlserv_flag\": \"0\",\n" +
+ " \"insu_admdvs\": \"131002\",\n" +
+ " \"emp_name\": \"测试单位\"\n" +
+ " },\n" +
+ " \"idetinfo\": [\n" +
+ " {\n" +
+ " \"psn_idet_type\": \"1\",\n" +
+ " \"psn_type_lv\": \"1\",\n" +
+ " \"memo\": \"\",\n" +
+ " \"begntime\": \"2020-01-01 00:00:00\",\n" +
+ " \"endtime\": \"\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"psn_idet_type\": \"2\",\n" +
+ " \"psn_type_lv\": \"1\",\n" +
+ " \"memo\": \"\",\n" +
+ " \"begntime\": \"2020-01-01 00:00:00\",\n" +
+ " \"endtime\": \"\"\n" +
+ " }\n" +
+ " ]\n" +
+ " }\n" +
+ "}";
+
+
+ }
+
+
+}
diff --git a/src/main/java/com/szyx/tcm/supervision/util/SZYXAccessUtil.java b/src/main/java/com/szyx/tcm/supervision/util/SZYXAccessUtil.java
new file mode 100644
index 0000000..c3d63ae
--- /dev/null
+++ b/src/main/java/com/szyx/tcm/supervision/util/SZYXAccessUtil.java
@@ -0,0 +1,187 @@
+package com.szyx.tcm.supervision.util;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+
+/*******************************************************************
+ *
+ * @文件名称: SZYXAccessUtil.java
+ * @包 路 径: com.szyx.tcm.supervision.util
+ * @Copyright:wy (C) 2024 *
+ * @Description:
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/26 17:02
+ * @Modify:
+ */
+public class SZYXAccessUtil {
+
+
+ private static final String[] STAND = {"2", "3", "5", "7"};
+ private static final String[] CLOCK = {"0", "1", "4", "6", "8", "9"};
+
+ private static final String AES_KEY = "szyx6666szyx6666";
+
+ // 获取加密时间戳
+
+ /**
+ * 获取加密时间戳
+ *
+ * @param timeStamp 时间戳
+ * @return 加密时间戳
+ */
+ public static String encryptTimeStamp(Long timeStamp) {
+ String last3 = splitLast3(timeStamp);
+ String encrypteded = encryptedSwitch(last3);
+ return timeStamp.toString().substring(0, 10) + encrypteded;
+ }
+
+ // 验证时间戳
+ public static boolean verifyTimeStamp(final String timeStamp, final String accessToken) {
+ long ts = Long.parseLong(timeStamp);
+ long now = System.currentTimeMillis();
+ if (now - ts > 1000 * 60 * 5) {
+ return false;
+ }
+ return decryptByAES(accessToken).equals(replaceEncryptedLast3(Long.parseLong(timeStamp)));
+ }
+
+ // 使用AES加密时间戳
+
+ /**
+ * 使用AES加密时间戳
+ *
+ * @param content 时间戳
+ * @return aes报文
+ */
+ public static String encryptByAES(final String content) {
+ byte[] bytes = new byte[0];
+ try {
+ SecretKeySpec secretKeySpec = new SecretKeySpec(AES_KEY.getBytes(), "AES");
+ Cipher cipher = Cipher.getInstance("AES");
+ cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
+ bytes = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
+ } catch (NoSuchAlgorithmException | IllegalBlockSizeException | InvalidKeyException | NoSuchPaddingException
+ | BadPaddingException e) {
+ throw new RuntimeException(e);
+ }
+ return Base64.getEncoder().encodeToString(bytes);
+ }
+
+ // 使用AES解密获取校验时间戳
+
+ /**
+ * 使用AES解密获取校验时间戳
+ *
+ * @param content aes报文
+ * @return 时间戳
+ */
+ public static String decryptByAES(final String content) {
+ byte[] bytes = new byte[0];
+ try {
+ SecretKeySpec secretKeySpec = new SecretKeySpec(AES_KEY.getBytes(), "AES");
+ Cipher cipher = Cipher.getInstance("AES");
+ cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
+ bytes = cipher.doFinal(Base64.getDecoder().decode(content));
+ } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException
+ | BadPaddingException e) {
+ throw new RuntimeException(e);
+ }
+ return new String(bytes, StandardCharsets.UTF_8);
+ }
+
+ public static String replaceEncryptedLast3(Long timeStamp) {
+ String last3 = splitLast3(timeStamp);
+ String decrypted = decryptedSwitch(last3);
+ return timeStamp.toString().substring(0, 10) + decrypted;
+ }
+
+ private static String splitLast3(Long timeStamp) {
+ return timeStamp.toString().substring(10);
+ }
+
+ private static String encryptedSwitch(String num) {
+ StringBuilder switched = new StringBuilder();
+ int index = 1;
+ for (int i = num.length() - 1; i >= 0; i--) {
+ int digit = Integer.parseInt(String.valueOf(num.charAt(i)));
+ switched.insert(0, encrypted(digit, index));
+ index++;
+ }
+ return switched.toString();
+ }
+
+ private static String decryptedSwitch(String num) {
+ StringBuilder switched = new StringBuilder();
+ int index = 1;
+ for (int i = num.length() - 1; i >= 0; i--) {
+ int digit = Integer.parseInt(String.valueOf(num.charAt(i)));
+ switched.insert(0, decrypted(digit, index));
+ index++;
+ }
+ return switched.toString();
+ }
+
+ private static int encrypted(int n, int index) {
+ if (isStand(n)) {
+ return n;
+ } else {
+ return index % 2 == 0 ? getClockWise(n, index) : getAntiClockWise(n, index);
+ }
+
+ }
+
+ private static int decrypted(int n, int index) {
+ if (isStand(n)) {
+ return n;
+ } else {
+ return index % 2 == 0 ? getAntiClockWise(n, index) : getClockWise(n, index);
+
+ }
+ }
+
+ private static boolean isStand(int n) {
+ for (String s : STAND) {
+ if (s.equals(String.valueOf(n))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static int getClockWise(int n, int step) {
+ int len = CLOCK.length;
+ int index = 0;
+ for (int i = 0; i < len; i++) {
+ if (CLOCK[i].equals(String.valueOf(n))) {
+ index = i;
+ break;
+ }
+ }
+ int newIndex = (index + step) % len;
+ return Integer.parseInt(CLOCK[newIndex]);
+ }
+
+ private static int getAntiClockWise(int n, int step) {
+ int len = CLOCK.length;
+ int index = 0;
+ for (int i = 0; i < len; i++) {
+ if (CLOCK[i].equals(String.valueOf(n))) {
+ index = i;
+ break;
+ }
+ }
+ int newIndex = (index - step + len) % len;
+ return Integer.parseInt(CLOCK[newIndex]);
+ }
+
+
+
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index abef9ac..db5fc13 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -12,6 +12,10 @@ spring.servlet.multipart.max-request-size=150MB
spring.servlet.multipart.enabled=true
spring.main.allow-bean-definition-overriding=true
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
+arthas.slient-init=true
+
+# \u533B\u4FDD\u4E13\u7F51\u914D\u7F6E
+insurance.host =http://localhost:9345/
## \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 mysql \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014
diff --git a/src/test/java/com/szyx/tcm/supervision/InsuranceCoreDemo.java b/src/test/java/com/szyx/tcm/supervision/InsuranceCoreDemo.java
new file mode 100644
index 0000000..3325038
--- /dev/null
+++ b/src/test/java/com/szyx/tcm/supervision/InsuranceCoreDemo.java
@@ -0,0 +1,215 @@
+package com.szyx.tcm.supervision;
+
+
+import com.alibaba.fastjson.JSONObject;
+
+import com.szyx.tcm.supervision.model.dto.insurance.DiseInfo;
+import com.szyx.tcm.supervision.model.dto.insurance.FeeDetail;
+import com.szyx.tcm.supervision.model.dto.insurance.InsuranceCoreOutputMessage1101;
+import com.szyx.tcm.supervision.model.dto.insurance.InsuranceUploadRecipeDetailInputMessage;
+import com.szyx.tcm.supervision.util.DateUtils;
+import com.szyx.tcm.supervision.util.InsuranceWechatUtil;
+import com.tencent.mip.DataHandler;
+import com.tencent.mip.MIPayInvoker;
+import com.tencent.mip.model.DetailUploadReq;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+
+/*******************************************************************
+ *
+ * @文件名称: InsuranceCoreDemo.java
+ * @包 路 径: org.szyx.tcm.applet
+ * @Copyright:wy (C) 2024 *
+ * @Description: 河南医保局 医保核心系统调用demo
+ * @Version: V1.0
+ * @Author: wy
+ * @Date: 2024/7/17 16:41
+ * @Modify:
+ */
+public class InsuranceCoreDemo {
+
+ private static final String url = "http://localhost:8097/fsi/api/rsfComIfsService/callService";
+
+// private static final
+
+ private static String appSecret = "cb5405c1053da6e27ac2e6c5ea63c25b"; // 应⽤密钥
+ private static String appId = "wx988658e383760cea"; // 应⽤ID
+ private static String publicKey = "IYNKr8u66CDfzTkChz44e7AocWNqLTEO"; // 平台公钥
+ private static String privateKey = "IYNKr8u66CDfzTkChz44e7AocWNqLTEO"; // 渠道私钥
+ private static String reqUrl = "********************";
+
+ private static String fixmedinsCode = "H41148100267"; // 定点医疗机构编码
+
+ private static String mdtrtareaAdmvs = "411401"; // 就诊地医保区划
+
+ private static String authCode = "AUTH410100202205241618510007210"; // 授权码
+
+
+
+
+
+ public static void main(String[] args) throws IOException {
+ // 6201、6202 签名sdk
+ // 请求报文
+ DataHandler dataHandler = DataHandler.newInstance(appId,appSecret,publicKey,privateKey);
+ dataHandler.setVersion("2.0.1");
+
+ MIPayInvoker miPayInvoker = MIPayInvoker.newInstance(dataHandler);
+ DetailUploadReq detailUploadReq = new DetailUploadReq();
+
+
+
+
+ }
+
+
+ @Test
+ public void test1() throws Exception {
+ System.out.println("test1");
+
+
+ InsuranceUploadRecipeDetailInputMessage uploadData = new InsuranceUploadRecipeDetailInputMessage();
+ buildText(uploadData);
+
+
+
+ String reqMessageForInsuranceCore = InsuranceWechatUtil
+ .getReqMessageForInsuranceCore(appId, appSecret, publicKey, privateKey, JSONObject.toJSONString(uploadData));
+
+ System.out.println(reqMessageForInsuranceCore);
+
+
+ }
+
+ private void buildText(InsuranceUploadRecipeDetailInputMessage uploadData){
+
+ // 医保核心系统患者基本信息
+ InsuranceCoreOutputMessage1101.Baseinfo baseinfo = new InsuranceCoreOutputMessage1101.Baseinfo();
+ baseinfo.setPsnNo("131000202001001");
+ baseinfo.setPsnCertType("2");
+ baseinfo.setCertno("510000202001010000");
+ baseinfo.setPsnName("李四");
+ baseinfo.setGend("1");
+ baseinfo.setNaty("01");
+ baseinfo.setBrdy("2020-01-01");
+ baseinfo.setAge("18");
+
+
+ // 医保核心系统保信息
+ InsuranceCoreOutputMessage1101.Insuinfo insuinfo = new InsuranceCoreOutputMessage1101.Insuinfo();
+ insuinfo.setPsnInsuRltsId("133241523001001");
+ insuinfo.setBalc(new BigDecimal("5000"));
+ insuinfo.setInsutype("310");
+ insuinfo.setPsnType("1001");
+ insuinfo.setCvlservFlag("0");
+ insuinfo.setInsuplcAdmdvs("131002");
+ insuinfo.setEmpName("测试单位");
+
+
+
+
+
+ // 费用明细
+ List feedetailList = new ArrayList<>();
+ // 诊断或状态明细
+ List diseinfoList = new ArrayList<>();
+
+
+ uploadData.setOrgCodg(fixmedinsCode);
+ // uploadData.setOrgId();
+ uploadData.setPsnNo(baseinfo.getPsnNo());
+ uploadData.setIdType(insuinfo.getInsutype());
+ uploadData.setMedOrgOrd(UUID.randomUUID().toString().replace("-", ""));
+ // 电子处方流转标志 todo 目前河南省并未测试过电子处方线上医保支付
+ uploadData.setRxCircFlag("0");
+ uploadData.setBegntime(DateUtils.format(new Date(), DateUtils.PATTERN_DATE_TIME));
+ uploadData.setIdNo(baseinfo.getCertno());
+ uploadData.setUserName(baseinfo.getPsnName());
+ uploadData.setIdType("01");
+ uploadData.setEcToken(authCode);
+ uploadData.setInsuCode(mdtrtareaAdmvs);
+ uploadData.setIptOtpNo(UUID.randomUUID().toString().replace("-", ""));
+ // 字典 dept
+ uploadData.setDeptName("预防保健科");
+ uploadData.setCaty("A01");
+ uploadData.setMedType("91");
+ uploadData.setFeeType("05");
+ uploadData.setMedfeeSumamt(new BigDecimal("0.01"));
+ // uploadData.setAcctUsedFlag("0");
+ uploadData.setDiseCodg("A01.001");
+ uploadData.setDiseName("感冒");
+ uploadData.setPsnSetlway("01");
+ // 公立医院内容 todo 疑问点 互联网医院是否为公立医院 公立医院改革标志 如何传参
+ uploadData.setChrgBchno(UUID.randomUUID().toString().replace("-", ""));
+ uploadData.setDiseinfoList(diseinfoList);
+ uploadData.setFeedetailList(feedetailList);
+
+ // ========组装诊断数据========
+ DiseInfo diseInfo = new DiseInfo();
+ diseinfoList.add(diseInfo);
+ // 西医诊断
+ diseInfo.setDiagType("1");
+ // todo 确认诊断排序号
+ diseInfo.setDiagSrtNo(1);
+ diseInfo.setDiagCode("A01.001");
+ diseInfo.setDiagName("感冒");
+ diseInfo.setDiagDept("预防保健科");
+ diseInfo.setDiseDorNo("wy");
+ diseInfo.setDiseDorName("wy");
+ diseInfo.setDiagTime(DateUtils.format(new Date(), DateUtils.PATTERN_DATE_TIME));
+ diseInfo.setValiFlag("1");
+
+ //========组装费用数据========
+ FeeDetail feeDetail = new FeeDetail();
+
+ feedetailList.add(feeDetail);
+ // 如果是诊疗 传问诊单号
+ feeDetail.setFeedetlSn("10086");
+ feeDetail.setMdtrtId(UUID.randomUUID().toString().replace("-", ""));
+ feeDetail.setPsnNo(baseinfo.getPsnNo());
+ feeDetail.setChrgBchno(uploadData.getChrgBchno());
+ // 同一收费批次号病种编号必须一致 todo 确认 多药品多问题
+ feeDetail.setDiseCodg("A01.001");
+ feeDetail.setRxno("100866");
+ feeDetail.setRxCircFlag("0");
+ feeDetail.setFeeOcurTime(DateUtils.format(new Date(), DateUtils.PATTERN_DATE_TIME));
+ // 医疗目录编码 todo 确认互联网医院处方的医疗目录编码
+ feeDetail.setMedListCodg("A01.001");
+ // 医药机构目录编码 todo 确认互联网医院处方的医药机构目录编码
+ feeDetail.setMedinsListCodg("A01.001");
+ feeDetail.setDetItemFeeSumamt(new BigDecimal("0.01"));
+ feeDetail.setCnt(new BigDecimal("1"));
+ feeDetail.setPric(new BigDecimal("0.01"));
+ feeDetail.setBilgDeptCodg("A01.001");
+ feeDetail.setBilgDeptName("预防保健科");
+ feeDetail.setBilgDrCodg("wy");
+ feeDetail.setBilgDrName("wy");
+ feeDetail.setHospApprFlag("1");
+ // todo 确认互联网医院处方的医疗类别
+ feeDetail.setMedType("医疗类别");
+ feeDetail.setMedListName("医疗目录名称");
+ feeDetail.setMedListSpc("医疗目录规格");
+
+
+
+
+
+
+
+
+
+ }
+
+
+
+
+
+
+}