diff --git a/src/main/java/com/ynxbd/common/TestA.java b/src/main/java/com/ynxbd/common/TestA.java index 9d223c6..0798101 100644 --- a/src/main/java/com/ynxbd/common/TestA.java +++ b/src/main/java/com/ynxbd/common/TestA.java @@ -1,42 +1,31 @@ package com.ynxbd.common; -import com.ynxbd.wx.wxfactory.AesWxHelper; +import cn.hutool.core.util.HexUtil; +import com.ynxbd.common.helper.common.RSAHelper; -public class TestA { - -// public static void main(String[] args) { -// String respXML = "\n" + -// "\t1002\n" + -// "\t0\n" + -// "\t成功\n" + -// "\t932606\n" + -// "\t300349719\n" + -// "\t137087\n" + -// ""; -// JsonResult result = JsonResult.xmlToBean(respXML, JsonResultEnum.SYS_HIS); -// if (result == null) { -// return; -// } -// Patient patient = result.dataMapToBean(Patient.class); -// System.out.println(patient); -// } +import javax.crypto.Cipher; +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; +public class TestA { + private static final String PUB_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5klqI5STWTcbfjR093j+hvCEjNlZMQscIJg8jxZGqKW84AdFmSqPWEPu9ilqP+QUASiVSZ1QevGr2DWODFZ8Zw35aDA2bqCEprUx81gDdVPO7H7Bij+r8zAg8fT2c0Bi5rFq0xWMEQiTI+CyWwc5prOpquJU/P5yauEAdkRzlDwIDAQAB"; -// public static void main(String[] args) { -// System.out.println(AesWxHelper.encode("524404")); -// -// String dataJson = "[{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":3,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":3,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":3,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"}]\n"; + public static void main(String[] args) throws Exception{ + String content = "533103198212184014"; + byte[] bytes = RSAHelper.enBytePKCS1Padding(content, PUB_KEY); + System.out.println("【Java最终hex】:" + HexUtil.encodeHexStr(bytes)); + } // -// List doctors = JsonHelper.parseArray(dataJson, Doctor.class); -// doctors = new DoctorService().doctorListFilter(doctors); -// System.out.println(doctors); -// } -// public static void main(String[] args) { -// // System.out.println(AesWxHelper.encode("624091")); -// -// // System.out.println(AesWxHelper.decode("A25BF2DD5820B151B8AB2E333E05565E")); -// } -} +// public static void main(String[] args) throws Exception { +// String content = "533103198212184014"; +// String encrypt = RSAHelper.enPKCS1Padding(content, PUB_KEY); +// System.out.println(HexUtil.encodeHexStr(encrypt)); +// } +} \ No newline at end of file diff --git a/src/main/java/com/ynxbd/common/action/PatientAction.java b/src/main/java/com/ynxbd/common/action/PatientAction.java index b6dddf7..caae95b 100644 --- a/src/main/java/com/ynxbd/common/action/PatientAction.java +++ b/src/main/java/com/ynxbd/common/action/PatientAction.java @@ -278,13 +278,13 @@ public class PatientAction extends BaseAction { return Result.error("[医共体]不支持无证绑定!"); } - fTel = getString("fTel"); - fName = getString("fName"); - fIDCardNo = getString("fIDCardNo"); + fTel = getReqParamByKey("fTel"); + fName = getReqParamByKey("fName"); + fIDCardNo = getReqParamByKey("fIDCardNo"); - mTel = getString("mTel"); - mName = getString("mName"); - mIDCardNo = getString("mIDCardNo"); + mTel = getReqParamByKey("mTel"); + mName = getReqParamByKey("mName"); + mIDCardNo = getReqParamByKey("mIDCardNo"); Result result = new PatientService().noCardParamsValid(fTel, fName, fIDCardNo, mTel, mName, mIDCardNo); if (!result.isOK()) { diff --git a/src/main/java/com/ynxbd/common/action/XBDAction.java b/src/main/java/com/ynxbd/common/action/XBDAction.java index 3a42bb4..123d6d6 100644 --- a/src/main/java/com/ynxbd/common/action/XBDAction.java +++ b/src/main/java/com/ynxbd/common/action/XBDAction.java @@ -1,5 +1,7 @@ package com.ynxbd.common.action; +import cn.hutool.core.util.HexUtil; +import cn.hutool.crypto.asymmetric.RSA; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.ynxbd.common.action.base.BaseAction; @@ -10,8 +12,9 @@ import com.ynxbd.common.bean.xbd.MedicalRecord; import com.ynxbd.common.config.interceptor.AesDecode; import com.ynxbd.common.helper.common.Base64Helper; import com.ynxbd.common.helper.common.JsonHelper; +import com.ynxbd.common.helper.common.RSAHelper; import com.ynxbd.common.helper.xbd.XBDEnum; -import com.ynxbd.common.helper.xbd.XBDHelper; +import com.ynxbd.common.helper.xbd.XbdConfigHelper; import com.ynxbd.common.helper.xbd.XBDHttpHelper; import com.ynxbd.common.result.Result; import com.ynxbd.common.result.ResultEnum; @@ -25,6 +28,7 @@ import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Namespace; import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; import java.util.List; /** @@ -54,7 +58,7 @@ public class XBDAction extends BaseAction { public Result cloudFilm(String info) { try { log.info("[云胶片]info={}", info); - String path = XBDHelper.outTeamDao.getCloudFilmPath(info); + String path = XbdConfigHelper.outTeamDao.getCloudFilmPath(info); return Result.success(path); } catch (Exception e) { log.error("[云胶片]{}", e.getMessage()); @@ -280,20 +284,16 @@ public class XBDAction extends BaseAction { } /** - * 查询体检报告 + * 查询体检影像报告 */ @Action("getPeisByCardNo") public Result getPeisByCardNo(@AesDecode String cardNo, String begDate, String endDate) { - log.info("[查询体检记录] cardNo={}, begDate={}, endDate={}", cardNo, begDate, endDate); + log.info("[体检影像报告]查询 cardNo={}, begDate={}, endDate={}", cardNo, begDate, endDate); if (ObjectUtils.isEmpty(cardNo) || ObjectUtils.isEmpty(begDate) || ObjectUtils.isEmpty(endDate)) { return Result.error(ResultEnum.PARAM_IS_DEFECT); } - String encode = Base64Helper.encode(cardNo); - if (ObjectUtils.isEmpty(encode)) { - return Result.error(ResultEnum.PARAM_IS_INVALID); - } try { - JSONArray dataList = new PEISService().queryPEISRecordByCardNo(encode, begDate, endDate); + JSONArray dataList = new PEISService().queryPEISRecordByCardNo(cardNo, begDate, endDate); for (int i = 0; i < dataList.size(); i++) { JSONObject dataItem = dataList.getJSONObject(i); String eid = dataItem.getString("eid"); diff --git a/src/main/java/com/ynxbd/common/action/base/BaseAction.java b/src/main/java/com/ynxbd/common/action/base/BaseAction.java index 67477e0..661d0b7 100644 --- a/src/main/java/com/ynxbd/common/action/base/BaseAction.java +++ b/src/main/java/com/ynxbd/common/action/base/BaseAction.java @@ -1,6 +1,8 @@ package com.ynxbd.common.action.base; import com.alibaba.fastjson.JSONObject; +import com.ynxbd.common.bean.form.FormBlob; +import com.ynxbd.common.bean.form.FormData; import com.ynxbd.common.helper.common.HttpHelper; import com.ynxbd.common.helper.common.JsonHelper; import com.ynxbd.wx.wxfactory.AesWxHelper; @@ -9,6 +11,8 @@ import org.apache.commons.lang3.StringUtils; import org.apache.struts2.ServletActionContext; import org.apache.struts2.action.ServletRequestAware; import org.apache.struts2.convention.annotation.ParentPackage; +import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper; +import org.apache.struts2.dispatcher.multipart.UploadedFile; import org.slf4j.MDC; import javax.servlet.ServletContext; @@ -17,8 +21,9 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.*; import java.math.BigDecimal; -import java.util.HashMap; -import java.util.Map; +import java.nio.file.Files; +import java.util.*; +import java.util.function.Function; /** @@ -45,7 +50,7 @@ public class BaseAction implements Serializable, ServletRequestAware { MDC.remove("ip"); MDC.put("ip", HttpHelper.getIpAddress(request)); } catch (UnsupportedEncodingException e) { - e.printStackTrace(); + log.error("", e); } this.request = request; @@ -80,60 +85,61 @@ public class BaseAction implements Serializable, ServletRequestAware { return ServletActionContext.getServletContext(); } - protected String getString(String param) { - String parameter = this.request.getParameter(param); - if ("".equals(parameter)) { - return null; - } - return parameter; - } protected String decodeReqString(String param) { return AesWxHelper.decode(param); } - protected Integer getInteger(String param) { - try { - String val = this.request.getParameter(param); - return StringUtils.isEmpty(val) ? null : Integer.valueOf(val); - } catch (Exception e) { - return null; - } - } - - protected Long getLong(String param) { - try { - String val = this.request.getParameter(param); - return StringUtils.isEmpty(val) ? null : Long.valueOf(val); - } catch (Exception e) { - return null; - } - } - - protected Double getDouble(String param) { - try { - String val = this.request.getParameter(param); - return StringUtils.isEmpty(val) ? null : Double.valueOf(val); - } catch (Exception e) { + protected String getReqParamByKey(String key) { + String val = this.request.getParameter(key); + if ("".equals(val)) { return null; } + return val; } - - protected BigDecimal getBigDecimal(String param) { + /** + * 通用转换方法 + * + * @param key key + * @param clazz 目标类型 Integer.class / Long.class / BigDecimal.class ... + * @return 转换后对象,空/格式错误返回null + */ + @SuppressWarnings("unchecked") + protected T getReqParamByKey(String key, Class clazz) { try { - String val = this.request.getParameter(param); - return StringUtils.isEmpty(val) ? null : new BigDecimal(val); - } catch (Exception e) { - return null; - } - } + if (clazz == null) { + return null; + } + String val = this.request.getParameter(key); + if (StringUtils.isEmpty(val)) { + return null; + } + val = val.trim(); - protected Boolean getBoolean(String param) { - try { - String val = this.request.getParameter(param); - return StringUtils.isEmpty(val) ? null : Boolean.valueOf(val); + Function converter; + if (String.class == clazz) { + return clazz.cast(val); + } else if (Integer.class == clazz) { + converter = Integer::valueOf; + } else if (Long.class == clazz) { + converter = Long::valueOf; + } else if (Double.class == clazz) { + converter = Double::valueOf; + } else if (BigDecimal.class == clazz) { + converter = BigDecimal::new; + } else if (Boolean.class == clazz) { + if (!val.equalsIgnoreCase("true") && !val.equalsIgnoreCase("false")) { + return null; + } + converter = Boolean::valueOf; + } else { + log.error("不支持的类型:{}", clazz.getName()); + return null; + } + Object obj = converter.apply(val); + return (T) obj; } catch (Exception e) { return null; } @@ -218,4 +224,157 @@ public class BaseAction implements Serializable, ServletRequestAware { Map params = reqParamsToMap(); return JsonHelper.parseObject(JsonHelper.toJsonString(params), clazz); } + + + /** + * Struts2获取FormData[表单参数+上传文件] + */ + protected FormData getReqFormData() { + MultiPartRequestWrapper multiWrapper = null; + if (request instanceof MultiPartRequestWrapper) { + multiWrapper = (MultiPartRequestWrapper) request; + } + if (multiWrapper == null) { + log.info("[请求类型]不是-multipart/form-data"); + return null; + } + + if (multiWrapper.hasErrors()) { // 检查上传解析是否报错 + log.error("[multipart解析]存在错误:{}", multiWrapper.getErrors()); + return null; + } + + FormData formData = new FormData(); + Map params = new HashMap<>(); + Map files = new HashMap<>(); + + // ========= 读取普通表单文本参数 ========= + Enumeration parameterNames = multiWrapper.getParameterNames(); + String field; + String[] values; + while (parameterNames.hasMoreElements()) { + field = (String) parameterNames.nextElement(); + values = multiWrapper.getParameterValues(field); + if (values != null && values.length > 0) { + params.put(field, values[0]); + } + } + + + // ========= 读取所有上传文件 ========= + Enumeration fileFieldEnum = multiWrapper.getFileParameterNames(); + String fileName; + FormBlob formBlob; + UploadedFile[] uploadedFiles; + while (fileFieldEnum.hasMoreElements()) { + field = fileFieldEnum.nextElement(); + uploadedFiles = multiWrapper.getFiles(field); + if (uploadedFiles == null) { + continue; + } + + for (UploadedFile uf : uploadedFiles) { + if (!uf.isFile()) { + continue; + } + formBlob = new FormBlob(); + fileName = uf.getOriginalName(); + if (fileName != null) { // 清除IE浏览器全路径文件名 + int idx = fileName.lastIndexOf("\\"); + if (idx > 0) { + fileName = fileName.substring(idx + 1); + } + } + formBlob.setFileName(fileName); + formBlob.setContentType(uf.getContentType()); + + try { + byte[] data = null; + Object contentObj = uf.getContent(); + if (contentObj instanceof byte[]) { + data = (byte[]) contentObj; + } else if (contentObj instanceof File) { + File tempFile = (File) contentObj; + data = Files.readAllBytes(tempFile.toPath()); + } + if (data != null) { + formBlob.setContent(data); + files.put(field, formBlob); + } + } catch (Exception e) { + log.error("解析上传文件失败,field={}, fileName={}", field, fileName, e); + } + } + } + + formData.setData(params); + formData.setFiles(files); + return formData; + } + + + // /** +// * 获取FormData +// */ +// protected FormData getFormData() { +// try { +// boolean isMultipart = ServletFileUpload.isMultipartContent(request); +// if (!isMultipart) { +// System.out.println("[请求类型]不是multipart/form-data"); +// return null; +// } +// +// // 判断是否multipart请求(使用Struts工具方法) +// MultiPartRequestWrapper multiWrapper = RequestUtils.getMultiPartRequestWrapper(request); +// if (multiWrapper == null) { +// System.out.println("[请求类型]不是multipart/form-data"); +// return null; +// } +// +// FormData formData = new FormData(); +// Map params = new HashMap<>(); +// ArrayList files = new ArrayList<>(); +// +// String a = null; +// // 1. 获取所有普通表单字段 +// Enumeration paramNames = multiWrapper.getParameterNames(); +// +// String a = request.getParameter("a"); +// System.out.println(a); +// +// // 初始化解析器 +// FileItemFactory factory = new DiskFileItemFactory(); +// ServletFileUpload upload = new ServletFileUpload(factory); +// // 限制最大文件 10MB,根据截图业务调整 +// upload.setFileSizeMax(10 * 1024 * 1024L); +// +// List itemList = upload.parseRequest(request); +// FormData formData = new FormData(); +// +// Map params = new HashMap<>(); +// ArrayList files = new ArrayList<>(); +// // 遍历所有上传项 +// FormBlob formBlob; +// for (FileItem item : itemList) { +// System.out.println(item.getFieldName()); +// if (item.isFormField()) { // 普通文本参数 +// params.put(item.getFieldName(), item.getString("UTF-8")); +// } else { +// formBlob = new FormBlob(); // 文件 +// formBlob.setFileName(item.getName()); +// formBlob.setContent(item.get()); +// formBlob.setContentType(item.getContentType()); +// files.add(formBlob); +// } +// } +// formData.setFiles(files); +// formData.setData(params); +// +// return formData; +// } catch (Exception e) { +// log.error(e.getMessage()); +// return null; +// } +// } +// } diff --git a/src/main/java/com/ynxbd/common/action/healthcard/HCReportAction.java b/src/main/java/com/ynxbd/common/action/healthcard/HCReportAction.java index b34460f..7cc4a32 100644 --- a/src/main/java/com/ynxbd/common/action/healthcard/HCReportAction.java +++ b/src/main/java/com/ynxbd/common/action/healthcard/HCReportAction.java @@ -2,11 +2,15 @@ package com.ynxbd.common.action.healthcard; import com.alibaba.fastjson.JSONObject; import com.ynxbd.common.action.base.BaseAction; +import com.ynxbd.common.bean.form.FormBlob; +import com.ynxbd.common.bean.form.FormData; import com.ynxbd.common.config.healthcard.HCReportConfig; import com.ynxbd.common.config.healthcard.HCSignHelper; -import com.ynxbd.common.config.interceptor.AesDecode; +import com.ynxbd.common.helper.common.Base64Helper; import com.ynxbd.common.helper.http.OkHttpHelper; import com.ynxbd.common.result.Result; +import com.ynxbd.common.result.ResultEnum; +import com.ynxbd.wx.wxfactory.AesWxHelper; import lombok.extern.slf4j.Slf4j; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Namespace; @@ -18,42 +22,65 @@ import java.util.Map; @Namespace("/hc_report") public class HCReportAction extends BaseAction { - + // 报告解读:https://open.ai.tengmed.com/openAccess/docs/access#6 @Action("pushUserReport") - public Result pushUserReport(@AesDecode String patientId, String reportId, String healthCardId, String msgId, String reportContent) { + public Result pushUserReport() { + FormData formData = getReqFormData(); + if (formData == null) { + return Result.error(ResultEnum.PARAM_IS_BLANK); + } + FormBlob reportFile = formData.getFiles().get("reportContent"); + if (reportFile == null || reportFile.getContent() == null) { + return Result.error(ResultEnum.PARAM_IS_BLANK); + } + String reportContentBase64 = Base64Helper.encode(reportFile.getContent()); + if (reportContentBase64 == null) { + return Result.error(ResultEnum.PARAM_IS_INVALID); + } + + String patientId = AesWxHelper.decode(formData.getParamByKey("patientId", String.class)); + String healthCardId = formData.getParamByKey("healthCardId", String.class); + String reportId = formData.getParamByKey("reportId", String.class); + String msgId = formData.getParamByKey("msgId", String.class); + log.info("[报告解读] msgId={}, patientId={}, reportId={}", msgId, patientId, reportId); + if (patientId == null || healthCardId == null || reportId == null || msgId == null) { + return Result.error(ResultEnum.PARAM_IS_DEFECT); + } String url = HCReportConfig.IS_DEV ? "https://med-biz-pre.wecity.qq.com/api/report/PushUserReport/" : "https://med-biz.wecity.qq.com/api/report/PushUserReport/"; + HCSignHelper config = HCReportConfig.createSign(); String requestId = config.getRequestId(); Map reqHead = new HashMap<>(); reqHead.put("requestId", requestId); - Map textReportInfo = new HashMap<>(); +// Map textReportInfo = new HashMap<>(); // Map patientInfo = new HashMap<>(); // Map reportInfo = new HashMap<>(); // partnerId:合作方ID 腾讯健康提供 - JSONObject jsonObject = OkHttpHelper.postJson(url + HCReportConfig.PARTNER_ID, params -> { - params.put("reqHead", reqHead); - params.put("hospitalId", HCReportConfig.HOSP_ID); - params.put("outerId", reportId); - params.put("healthCardId", healthCardId); - params.put("patientId", patientId); - params.put("msgId", msgId); - params.put("reportFileType", 2); // [ 1:pdf;2:图片;3:文本] - params.put("reportContent", reportContent); // 报告内容:报告文件base64编码、体积需要在30MB以内 当reportFileType 取值为 1, 2时,将报告文件base64编码放在该字段 - params.put("textReportInfo", textReportInfo); // 当reportFileType 取值为 3 时,将文本报告内容放下该字段。 + JSONObject jsonObject = OkHttpHelper.postJson(url + HCReportConfig.PARTNER_ID, req -> { + req.put("reqHead", reqHead); + req.put("hospitalId", HCReportConfig.HOSP_ID); + req.put("outerId", reportId); + req.put("healthCardId", healthCardId); + req.put("patientId", patientId); + req.put("msgId", msgId); + req.put("reportFileType", 2); // [ 1:pdf;2:图片;3:文本] + req.put("reportContent", reportContentBase64); // 报告内容:报告文件base64编码、体积需要在30MB以内 当reportFileType 取值为 1, 2时,将报告文件base64编码放在该字段 +// req.put("textReportInfo", textReportInfo); // 当reportFileType 取值为 3 时,将文本报告内容放下该字段。 +// log.warn("[报告解读] req={}", JsonHelper.toJsonString(req)); }, headers -> { headers.add("Content-Type", "application/json"); headers.add("god-portal-signature", config.getSignature()); headers.add("god-portal-timestamp", config.getTimestamp()); headers.add("god-portal-request-id", requestId); }); - log.warn("[报告解读] resp={}", jsonObject); + log.info("[报告解读] msgId={}, patientId={}, reportId={}, resp={}", msgId, patientId, reportId, jsonObject); return Result.success(); } } diff --git a/src/main/java/com/ynxbd/common/action/pay/JYPayAction.java b/src/main/java/com/ynxbd/common/action/pay/JYPayAction.java new file mode 100644 index 0000000..e72e188 --- /dev/null +++ b/src/main/java/com/ynxbd/common/action/pay/JYPayAction.java @@ -0,0 +1,71 @@ +package com.ynxbd.common.action.pay; + +import com.ynxbd.bcm.config.BCMHelper; +import com.ynxbd.common.action.base.BaseAction; +import com.ynxbd.common.bean.pay.PayResult; +import com.ynxbd.common.helper.common.DateHelper; +import com.ynxbd.common.result.Result; +import lombok.extern.slf4j.Slf4j; +import org.apache.struts2.convention.annotation.Action; +import org.apache.struts2.convention.annotation.Namespace; + +import java.math.BigDecimal; + +@Slf4j +@Namespace("/jy_pay") +public class JYPayAction extends BaseAction { + + /** + * 【交行】处方支付通知 + * + * @return 是否成功 + */ + @Action("notify") + public Result notify(String notifyType) { +// if (ObjectUtils.isEmpty(notifyType)) { +// Result.respJson(BCMHelper.respError(String.format("【京颐】获取回调参数失败,结束请求 notifyType={%s}", notifyType))); +// return null; +// } + + try { + PayResult notifyInfo = BCMHelper.payNotify(request); + Result.respJson(BCMHelper.respOk()); // 成功 + + String openid = notifyInfo.getOpenid(); + String bankTransNo = notifyInfo.getTransId(); + String outTradeNo = notifyInfo.getOutTradeNo(); + BigDecimal totalFee = notifyInfo.getTotalFee(); + + String payInfo = notifyInfo.getInfo(); + String payDate = DateHelper.getCurDate(); + String payTime = DateHelper.getCurTime(); + String bankMerchantNo = notifyInfo.getBankMerchantNo(); + log.info("【京颐】[{}] 收到通知 outTradeNo={}, bankTransNo={}, bankMerchantNo={}", notifyType, outTradeNo, bankTransNo, bankMerchantNo); + + switch (PEnum.toEnum(notifyType)) { + case RECIPE: +// openid = new RecipeService().queryOpenIdByOutTradeNo(outTradeNo); +// new RecipeService().recipeListPay(MerchantEnum.JY, totalFee.toString(), openid, outTradeNo, bankTransNo, bankMerchantNo, payDate, payTime, payInfo); +// + break; + + case REG: // 挂号 +// try { +// openid = new RegService().queryOpenIdByOutTradeNo(outTradeNo); +// new RegService().regPaidNotify(MerchantEnum.JY, totalFee, openid, bankTransNo, outTradeNo, bankMerchantNo, payDate, payTime, payInfo, new Date()); +// } catch (ServiceException e) { +// log.info("【京颐]挂号通知错误 outTradeNo={}, bankTransNo={}, message={}", outTradeNo, bankTransNo, e.getMessage()); +// } + break; + + default: + log.info("【京颐】通知类型错误,结束请求"); + break; + } + + } catch (Exception e) { + log.error(e.getMessage()); + } + return null; + } +} diff --git a/src/main/java/com/ynxbd/common/action/pay/MedicalAction.java b/src/main/java/com/ynxbd/common/action/pay/MedicalAction.java index 129949b..0a7fa13 100644 --- a/src/main/java/com/ynxbd/common/action/pay/MedicalAction.java +++ b/src/main/java/com/ynxbd/common/action/pay/MedicalAction.java @@ -63,7 +63,7 @@ public class MedicalAction extends BaseAction { MedicalInfo medicalInfo; switch (PEnum.toEnum(callNo)) { case REG: - Boolean isSplitTime = getBoolean("isSplitTime"); + Boolean isSplitTime = getReqParamByKey("isSplitTime", Boolean.class); Register reg = new Register().getRegParams(new RequestParams(request), true); if ("*".equals(reg.getRegCode())) { @@ -77,10 +77,10 @@ public class MedicalAction extends BaseAction { break; case RECIPE: - String ybAttrib = getString("ybAttrib"); - String ybBZCode = getString("ybBZCode"); - String ybBZName = getString("ybBZName"); - String recipeJson = getString("recipeJson"); // 处方JSON集 [{ recipeId: item.id, recipeFee: item.amount }] + String ybAttrib = getReqParamByKey("ybAttrib"); + String ybBZCode = getReqParamByKey("ybBZCode"); + String ybBZName = getReqParamByKey("ybBZName"); + String recipeJson = getReqParamByKey("recipeJson"); // 处方JSON集 [{ recipeId: item.id, recipeFee: item.amount }] log.info("[医保-处方]上传明细下单 treatNum={}, ybAttrib={}, ybBZCode={}, ybBZName={}, recipeJson={}", treatNum, ybAttrib, ybBZCode, ybBZName, recipeJson); if (treatNum == null || recipeJson == null) { return Result.error(ResultEnum.PARAM_IS_DEFECT); @@ -207,11 +207,11 @@ public class MedicalAction extends BaseAction { familyType, familyName, familyCardNo, medicalCardInstId, medicalCardId); case RECIPE: - String recipeJson = getString("recipeJson"); + String recipeJson = getReqParamByKey("recipeJson"); if (recipeJson == null) { return Result.error(ResultEnum.PARAM_IS_BLANK); } - String payWay = getString("payWay"); + String payWay = getReqParamByKey("payWay"); return new MedicalService().createRxOrder(payCode, payOpenId, openid, patientId, cardNo, realName, ip, payOrdId, payAuthNo, mdTrtId, chrgBchno, mdUserId, totalFee, acctFee, hifpFee, insuranceFee, cashFee, diff --git a/src/main/java/com/ynxbd/common/action/pay/PayAction.java b/src/main/java/com/ynxbd/common/action/pay/PayAction.java index bdae783..ae96ade 100644 --- a/src/main/java/com/ynxbd/common/action/pay/PayAction.java +++ b/src/main/java/com/ynxbd/common/action/pay/PayAction.java @@ -13,7 +13,7 @@ import com.ynxbd.common.dao.his.HisRecipeDao; import com.ynxbd.common.dao.sys.SysUserDao; import com.ynxbd.common.helper.common.*; import com.ynxbd.common.helper.his.HisHelper; -import com.ynxbd.common.helper.xbd.XBDHelper; +import com.ynxbd.common.helper.xbd.XbdConfigHelper; import com.ynxbd.common.result.JsonResult; import com.ynxbd.common.result.Result; import com.ynxbd.common.result.ResultEnum; @@ -887,7 +887,7 @@ public class PayAction extends BaseAction { return Result.error(ResultEnum.PAY_TYPE_ERROR); } - if (ObjectUtils.isEmpty(XBDHelper.PEIS_URL)) { + if (ObjectUtils.isEmpty(XbdConfigHelper.PEIS_URL)) { return Result.error(ResultEnum.SYSTEM_CONFIG_ERROR); } diff --git a/src/main/java/com/ynxbd/common/action/test/TestAction.java b/src/main/java/com/ynxbd/common/action/test/TestAction.java index 85afca8..00f380a 100644 --- a/src/main/java/com/ynxbd/common/action/test/TestAction.java +++ b/src/main/java/com/ynxbd/common/action/test/TestAction.java @@ -1,27 +1,26 @@ package com.ynxbd.common.action.test; import com.ynxbd.common.action.base.BaseAction; -import com.ynxbd.common.bean.pay.Register; +import com.ynxbd.common.bean.form.FormBlob; +import com.ynxbd.common.bean.form.FormData; import com.ynxbd.common.bean.sms.SmsTempEnum; +import com.ynxbd.common.helper.common.Base64Helper; import com.ynxbd.common.helper.common.DateHelper; import com.ynxbd.common.helper.common.SmsHelper; import com.ynxbd.common.result.Result; import com.ynxbd.common.result.ResultEnum; import com.ynxbd.common.result.ServiceException; import com.ynxbd.wx.config.MessagePushConfig; -import com.ynxbd.wx.config.TZReserveConfig; import com.ynxbd.wx.config.WeChatConfig; -import com.ynxbd.wx.wxfactory.WxMedHelper; import com.ynxbd.wx.wxfactory.WxPayHelper; import com.ynxbd.wx.wxfactory.medical.WxMedConfig; -import com.ynxbd.wx.wxfactory.medical.models.WxMedOrder; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.ObjectUtils; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Namespace; import java.math.BigDecimal; import java.util.Date; +import java.util.Map; /** * @Author wsq @@ -51,7 +50,7 @@ public class TestAction extends BaseAction { // 医保退费 @Action("refund_med_test") public Result refund_med_test() throws ServiceException { -// WxMedOrder order = WxMedHelper.refundCash("WX_M02f373d25b94475b60aa9860977c", ("R" + "ORD530100202605181442001740995"), "ORD530100202605181442001740995", new BigDecimal("24.71"), "已有缴费记录,不能再次缴费"); + // WxMedOrder order = WxMedHelper.refundCash("WX_M02f373d25b94475b60aa9860977c", ("R" + "ORD530100202605181442001740995"), "ORD530100202605181442001740995", new BigDecimal("24.71"), "已有缴费记录,不能再次缴费"); return Result.success(); } @@ -126,25 +125,23 @@ public class TestAction extends BaseAction { @Action("r_test") public Result r_test() throws ServiceException { - String url = WeChatConfig.getHttpsBaseURL() + "ali_qrcode" + "?p=123"; - System.out.println(url); - System.out.println(); - return Result.redirect("/wx/test02/log_test"); + return Result.success(); } @Action("wx_push_test") public Result wx_push_test() { System.out.println("HOST_URL:" + MessagePushConfig.HOST_URL); - System.out.println("[挂号]缴费通知:" + MessagePushConfig.REG_PAID_URL); - System.out.println("[挂号]取消预约:" + MessagePushConfig.REG_CANCEL_URL); - System.out.println("[挂号]AI:" + MessagePushConfig.REG_AI_URL); + System.out.println("[挂号]缴费通知:" + MessagePushConfig.REG_PAID_API); + System.out.println("[挂号]取消预约:" + MessagePushConfig.REG_CANCEL_API); + System.out.println("[挂号]AI:" + MessagePushConfig.REG_AI_API); - System.out.println("[处方]缴费通知:" + MessagePushConfig.RX_PAID_URL); + System.out.println("[处方]缴费通知:" + MessagePushConfig.RX_PAID_API); - System.out.println("产科建档:" + MessagePushConfig.OBS_DOCUMENT_URL); + System.out.println("产科建档:" + MessagePushConfig.OBS_DOCUMENT_API); return Result.success(); } + // @Action("lock") // public String lock() { // return Result.success(update()); diff --git a/src/main/java/com/ynxbd/common/bean/enums/MerchantEnum.java b/src/main/java/com/ynxbd/common/bean/enums/MerchantEnum.java index 971229f..2a4b54b 100644 --- a/src/main/java/com/ynxbd/common/bean/enums/MerchantEnum.java +++ b/src/main/java/com/ynxbd/common/bean/enums/MerchantEnum.java @@ -58,6 +58,14 @@ public enum MerchantEnum { "", WX.PAY_WAY_IN, WX.PAY_WAY_QR, WX.PAY_WAY_MICRO), + ALI_MEDICAL("ali_medical", "【支付宝医保】", AliConfig.APP_ID, ALI.OUT_TRADE_NO_PREFIX, + AliMedConfig.IS_DEV, + "3", + "25,26,27,28,29,30", + "ali_pay/medical_notify", + "", + "10", "11", "12"), + BCM("bcm", "【交行】", "", "BCM", false, "4", @@ -66,14 +74,13 @@ public enum MerchantEnum { "", "20", "21", "22"), - - ALI_MEDICAL("ali_medical", "【支付宝医保】", AliConfig.APP_ID, ALI.OUT_TRADE_NO_PREFIX, - AliMedConfig.IS_DEV, - "3", - "25,26,27,28,29,30", - "ali_pay/medical_notify", + JY("jy", "【京颐】", "", "JY", + false, + "4", "", - "10", "11", "12"), + "jy_pay/notify", + "", + WX.PAY_WAY_IN, WX.PAY_WAY_QR, WX.PAY_WAY_MICRO), ; diff --git a/src/main/java/com/ynxbd/common/bean/form/FormBlob.java b/src/main/java/com/ynxbd/common/bean/form/FormBlob.java new file mode 100644 index 0000000..505b403 --- /dev/null +++ b/src/main/java/com/ynxbd/common/bean/form/FormBlob.java @@ -0,0 +1,19 @@ +package com.ynxbd.common.bean.form; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +@NoArgsConstructor +public class FormBlob { + // 内容 + private byte[] content; + // 文件名 + private String fileName; + // 内容类型 + private String contentType; +} diff --git a/src/main/java/com/ynxbd/common/bean/form/FormData.java b/src/main/java/com/ynxbd/common/bean/form/FormData.java new file mode 100644 index 0000000..d47bf37 --- /dev/null +++ b/src/main/java/com/ynxbd/common/bean/form/FormData.java @@ -0,0 +1,73 @@ +package com.ynxbd.common.bean.form; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +@Getter +@Setter +@ToString +@NoArgsConstructor +@Slf4j +public class FormData { + + private Map files; + + private Map data; + + + /** + * 通用转换方法 + * + * @param param key + * @param clazz 目标类型 Integer.class / Long.class / BigDecimal.class ... + * @return 转换后对象,空/格式错误返回null + */ + @SuppressWarnings("unchecked") + public T getParamByKey(String param, Class clazz) { + try { + if (clazz == null) { + return null; + } + String val = data.get(param); + if (StringUtils.isEmpty(val)) { + return null; + } + val = val.trim(); + + Function converter; + if (String.class == clazz) { + return clazz.cast(val); + } else if (Integer.class == clazz) { + converter = Integer::valueOf; + } else if (Long.class == clazz) { + converter = Long::valueOf; + } else if (Double.class == clazz) { + converter = Double::valueOf; + } else if (BigDecimal.class == clazz) { + converter = BigDecimal::new; + } else if (Boolean.class == clazz) { + if (!val.equalsIgnoreCase("true") && !val.equalsIgnoreCase("false")) { + return null; + } + converter = Boolean::valueOf; + } else { + log.error("不支持的类型:{}", clazz.getName()); + return null; + } + Object obj = converter.apply(val); + return (T) obj; + } catch (Exception e) { + return null; + } + } +} diff --git a/src/main/java/com/ynxbd/common/bean/pay/ReqOrder.java b/src/main/java/com/ynxbd/common/bean/pay/ReqOrder.java new file mode 100644 index 0000000..b498e77 --- /dev/null +++ b/src/main/java/com/ynxbd/common/bean/pay/ReqOrder.java @@ -0,0 +1,63 @@ +package com.ynxbd.common.bean.pay; + + +import com.ynxbd.jy.bean.JYOrder; +import com.ynxbd.jy.bean.enums.JYBusinessTypeEnum; +import com.ynxbd.jy.bean.enums.JYOrderTypeEnum; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +import java.io.Serializable; +import java.math.BigDecimal; + +// 医保请求参数 + +@Setter +@Getter +@ToString +@NoArgsConstructor +public class ReqOrder implements Serializable { + private static final long serialVersionUID = 2026072810440001L; + // 现金部分 + public BigDecimal cashFee; + // 医保金额-个账 + 统筹支付金额 + public BigDecimal insuranceFee; + // 医保-个人账户支付金额 + public BigDecimal acctFee; + // 医保-统筹支付金额 + public BigDecimal hifpFee; + + // 订单金额 + public BigDecimal totalFee; + // ip + public String ip; + // 回退地址 + public String returnUrl; + + // 医院HIS系统订单号 + public String serialNo; + // 参考医保结构体(医疗机构透传医保) + public String requestContent; + // 亲情移动支付时 + public String extendInfo; + // 门诊号 | 住院号 + public String treatNum; + // 患者id + public String patientId; + // 患者姓名 + public String patientName; + // + public String patientAge; + // 患者性别。综合支付对应用权限控制是否必传 1男 2女 9其他 最大不超过4位 + public String patientGender; + + public String patientIdCardNo; + + public String patientTel; + + public JYOrder jyOrder; + + +} diff --git a/src/main/java/com/ynxbd/common/config/interceptor/MethodInterceptor.java b/src/main/java/com/ynxbd/common/config/interceptor/MethodInterceptor.java index 575157b..a0382e2 100644 --- a/src/main/java/com/ynxbd/common/config/interceptor/MethodInterceptor.java +++ b/src/main/java/com/ynxbd/common/config/interceptor/MethodInterceptor.java @@ -4,6 +4,7 @@ import com.ynxbd.common.helper.common.AesHelper; import com.ynxbd.common.helper.common.ErrorHelper; import com.ynxbd.common.helper.common.JsonHelper; import com.ynxbd.common.result.Result; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; import org.apache.struts2.ActionContext; import org.apache.struts2.ActionInvocation; @@ -21,6 +22,7 @@ import java.util.List; /** * 方法拦截器 */ +@Slf4j public class MethodInterceptor extends org.apache.struts2.interceptor.AbstractInterceptor { @@ -133,7 +135,7 @@ public class MethodInterceptor extends org.apache.struts2.interceptor.AbstractIn } return "SUCCESS"; } catch (Exception e) { - e.printStackTrace(); + log.error("", e); if (e.getMessage() == null) { System.out.println("异常1"); Throwable cause = e.getCause(); diff --git a/src/main/java/com/ynxbd/common/helper/common/RSAHelper.java b/src/main/java/com/ynxbd/common/helper/common/RSAHelper.java index ab0b493..48af689 100644 --- a/src/main/java/com/ynxbd/common/helper/common/RSAHelper.java +++ b/src/main/java/com/ynxbd/common/helper/common/RSAHelper.java @@ -106,7 +106,6 @@ public class RSAHelper { } - /** * RSA私钥解密 * @@ -154,6 +153,50 @@ public class RSAHelper { return null; } + public static PublicKey getPublicKey(String base64PubKey) { + try { + byte[] keyBytes = java.util.Base64.getDecoder().decode(base64PubKey); + X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return keyFactory.generatePublic(spec); + } catch (Exception e) { + log.error("", e); + return null; + } + } + + /** + * PKCS8 格式私钥字符串转 PrivateKey + * + * @param privateKeyStr 带/不带头尾标记的base64私钥 + * @return PrivateKey + */ + public static PrivateKey getPrivateKey(String privateKeyStr) { + try { + // 去除头尾标记、换行、空格 + String privateKeyPEM = privateKeyStr + .replace("-----BEGIN PRIVATE KEY-----", "") + .replace("-----END PRIVATE KEY-----", "") + .replaceAll("\\s+", ""); + byte[] keyBytes = java.util.Base64.getDecoder().decode(privateKeyPEM); + PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return keyFactory.generatePrivate(spec); + } catch (Exception e) { + log.error("", e); + return null; + } + } + + // 加密方法(PKCS#1 v1.5填充) + public static byte[] enBytePKCS1Padding(String content, String base64PublicKey) throws Exception { + PublicKey publicKey = getPublicKey(base64PublicKey); + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + byte[] rawData = content.getBytes(StandardCharsets.UTF_8); + return cipher.doFinal(rawData); + } + // 加密方法(PKCS#1 v1.5填充) public static String enPKCS1Padding(String plaintext, PublicKey publicKey) throws Exception { Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); diff --git a/src/main/java/com/ynxbd/common/helper/common/SmsHelper.java b/src/main/java/com/ynxbd/common/helper/common/SmsHelper.java index 7107251..da33ea4 100644 --- a/src/main/java/com/ynxbd/common/helper/common/SmsHelper.java +++ b/src/main/java/com/ynxbd/common/helper/common/SmsHelper.java @@ -178,7 +178,11 @@ public class SmsHelper { * @param smsTemplate 模板参数 */ public static boolean sendAli(String template, String tel, String signName, SmsTemplate smsTemplate) { - if (StringUtils.isEmpty(signName)) { + if (ObjectUtils.isEmpty(tel)) { + System.out.println("[短信]tel参数为空!"); + return false; + } + if (ObjectUtils.isEmpty(signName)) { signName = SIGN_NAME; } diff --git a/src/main/java/com/ynxbd/common/helper/xbd/XBDHttpHelper.java b/src/main/java/com/ynxbd/common/helper/xbd/XBDHttpHelper.java index 3b9b003..59c3c97 100644 --- a/src/main/java/com/ynxbd/common/helper/xbd/XBDHttpHelper.java +++ b/src/main/java/com/ynxbd/common/helper/xbd/XBDHttpHelper.java @@ -78,7 +78,7 @@ public class XBDHttpHelper { private static String UsePost(String methodName, RequestBody requestBody) { OkHttpClient httpClient = OkHttpHelper.creatClient(); Headers.Builder headersBuilder = new Headers.Builder(); - HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(XBDHelper.CASEBOOK_URL + "/api/SqlContext/PostMethodByNameEncryption")).newBuilder(); + HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(XbdConfigHelper.CASEBOOK_URL + "/api/SqlContext/PostMethodByNameEncryption")).newBuilder(); try (Response response = httpClient.newCall(new Request.Builder().url(urlBuilder.build()).post(requestBody).headers(headersBuilder.build()).build()).execute()) { JSONObject respJson = respFilter(response, methodName); String code = respJson.getString("Code"); @@ -171,7 +171,7 @@ public class XBDHttpHelper { private static String UseGet(String methodName, Object paramDic) { try { OkHttpClient httpClient = OkHttpHelper.creatClient(); - HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(XBDHelper.CASEBOOK_URL + "/api/SqlContext/ExecMethodByNameEncryption")).newBuilder(); + HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(XbdConfigHelper.CASEBOOK_URL + "/api/SqlContext/ExecMethodByNameEncryption")).newBuilder(); // 加密序列化 String paramJson = JSONObject.toJSONString(paramDic == null ? "" : paramDic); log.info("[病历GET]未加密前get请求入参:[methodName:{}] {}", methodName, paramJson); diff --git a/src/main/java/com/ynxbd/common/helper/xbd/XBDHelper.java b/src/main/java/com/ynxbd/common/helper/xbd/XbdConfigHelper.java similarity index 64% rename from src/main/java/com/ynxbd/common/helper/xbd/XBDHelper.java rename to src/main/java/com/ynxbd/common/helper/xbd/XbdConfigHelper.java index d4c970d..a96d7c9 100644 --- a/src/main/java/com/ynxbd/common/helper/xbd/XBDHelper.java +++ b/src/main/java/com/ynxbd/common/helper/xbd/XbdConfigHelper.java @@ -11,7 +11,7 @@ import lombok.extern.slf4j.Slf4j; * @date 2023/3/30 17:02 */ @Slf4j -public class XBDHelper { +public class XbdConfigHelper { private static final String PACS_CLOUD_URL; public static final String CASEBOOK_URL; public static final String PEIS_URL; @@ -19,19 +19,16 @@ public class XBDHelper { public static OutTeamDao outTeamDao; static { - XmlConfigHelper config = new XmlConfigHelper().read("xbd-config.xml", "tz_sms"); + XmlConfigHelper config = new XmlConfigHelper().read("xbd-config.xml", "xbd"); - PACS_CLOUD_URL = config.getString("pacs_cloud_url"); + PACS_CLOUD_URL = config.getString("pacs_cloud_url", ""); - CASEBOOK_URL = config.getString("casebook_url"); + CASEBOOK_URL = config.getString("casebook_url", ""); + + PEIS_URL = config.getString("peis_url", ""); - PEIS_URL = config.getString("peis_url"); - if (PACS_CLOUD_URL == null) { - log.error("新八达200团队配置文件读取失败"); - } outTeamDao = new OutTeamDao(PACS_CLOUD_URL); } - } diff --git a/src/main/java/com/ynxbd/common/service/PEISService.java b/src/main/java/com/ynxbd/common/service/PEISService.java index fa65ea9..0da8d6f 100644 --- a/src/main/java/com/ynxbd/common/service/PEISService.java +++ b/src/main/java/com/ynxbd/common/service/PEISService.java @@ -1,5 +1,6 @@ package com.ynxbd.common.service; +import cn.hutool.core.util.HexUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.ynxbd.common.action.pay.PEnum; @@ -9,8 +10,9 @@ import com.ynxbd.common.bean.pay.PEISOrderInfo; import com.ynxbd.common.bean.pay.PEISReserve; import com.ynxbd.common.dao.peis.PEISDao; import com.ynxbd.common.helper.common.JsonHelper; +import com.ynxbd.common.helper.common.RSAHelper; import com.ynxbd.common.helper.http.OkHttpHelper; -import com.ynxbd.common.helper.xbd.XBDHelper; +import com.ynxbd.common.helper.xbd.XbdConfigHelper; import com.ynxbd.common.result.*; import lombok.extern.slf4j.Slf4j; import okhttp3.FormBody; @@ -18,6 +20,7 @@ import okhttp3.RequestBody; import org.apache.commons.lang3.ObjectUtils; import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; import java.util.Date; /** @@ -102,7 +105,7 @@ public class PEISService { return; } - JsonResult jsonResult = postForm(XBDHelper.PEIS_URL + "/wxUse/wxPay", params -> { + JsonResult jsonResult = postForm(XbdConfigHelper.PEIS_URL + "/wxUse/wxPay", params -> { params.put("orderNo", noticeOrderNo); params.put("payStatus", "OK"); params.put("payFailReason", ""); @@ -138,7 +141,7 @@ public class PEISService { * @return bean */ public PEISOrderInfo queryPEISOrderByNoticeOrderNo(String noticeOrderNo) throws ServiceException { - JsonResult jsonResult = get(XBDHelper.PEIS_URL + "/wxUse/GetOrder", params -> { + JsonResult jsonResult = get(XbdConfigHelper.PEIS_URL + "/wxUse/GetOrder", params -> { params.put("orderNo", noticeOrderNo); }); log.info("[体检预约]订单查询 {}", JsonHelper.toJsonString(jsonResult)); @@ -224,7 +227,7 @@ public class PEISService { * @return bool */ public boolean cancelPEISReserve(String noticeOrderNo, String refundStatus, String refundFailReason) throws ServiceException { - JsonResult jsonResult = postForm(XBDHelper.PEIS_URL + "/wxUse/wxRefund", params -> { + JsonResult jsonResult = postForm(XbdConfigHelper.PEIS_URL + "/wxUse/wxRefund", params -> { params.put("orderNo", noticeOrderNo); params.put("refundStatus", refundStatus); // 退费状态(成功:OK,失败:FAIL) params.put("refundFailReason", refundFailReason); @@ -238,19 +241,28 @@ public class PEISService { return true; } - public JSONArray queryPEISRecordByCardNo(String cardNo, String begDate, String endDate) throws ServiceException { + /** + * 体检影像报告 + * + * @param cardNo 加密后的证件号 + * @param begDate 开始时间 + * @param endDate 结束时间 + */ + public JSONArray queryPEISRecordByCardNo(String cardNo, String begDate, String endDate) throws Exception { + String enIdCard = HexUtil.encodeHexStr(RSAHelper.enBytePKCS1Padding(cardNo, "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5klqI5STWTcbfjR093j+hvCEjNlZMQscIJg8jxZGqKW84AdFmSqPWEPu9ilqP+QUASiVSZ1QevGr2DWODFZ8Zw35aDA2bqCEprUx81gDdVPO7H7Bij+r8zAg8fT2c0Bi5rFq0xWMEQiTI+CyWwc5prOpquJU/P5yauEAdkRzlDwIDAQAB")); + RequestBody formBody = new FormBody.Builder(). - add("enIdCard", cardNo) + add("enIdCard", enIdCard) .add("begDate", begDate) .add("endDate", endDate) .build(); - String result = OkHttpHelper.post(XBDHelper.PEIS_URL + "/WxUse/GetPeisOfPacsResult", formBody); + String result = OkHttpHelper.post(XbdConfigHelper.PEIS_URL + "/WxUse/GetPeisOfPacsResult", formBody); if (ObjectUtils.isEmpty(result)) { - throw new ServiceException("请求失败"); + throw new ServiceException("[体检]请求异常"); } JSONObject jsonResult = JsonHelper.parseObject(result); if (jsonResult == null) { - throw new ServiceException("请求失败"); + throw new ServiceException("[体检]请求解析失败"); } String code = jsonResult.getString("code"); String message = jsonResult.getString("message"); diff --git a/src/main/java/com/ynxbd/common/service/PayService.java b/src/main/java/com/ynxbd/common/service/PayService.java index cfbdcbd..5bc1f92 100644 --- a/src/main/java/com/ynxbd/common/service/PayService.java +++ b/src/main/java/com/ynxbd/common/service/PayService.java @@ -3,6 +3,7 @@ package com.ynxbd.common.service; import com.alibaba.fastjson.JSONObject; import com.ynxbd.ali.helper.AliHelper; import com.ynxbd.bcm.config.BCMHelper; +import com.ynxbd.common.action.pay.JYPayAction; import com.ynxbd.common.action.pay.PEnum; import com.ynxbd.common.bean.enums.MerchantEnum; import com.ynxbd.common.bean.pay.*; @@ -15,6 +16,7 @@ import com.ynxbd.common.result.Result; import com.ynxbd.common.result.ResultEnum; import com.ynxbd.common.result.ServiceException; import com.ynxbd.common.service.cache.PayCache; +import com.ynxbd.jy.helper.JYPayHelper; import com.ynxbd.wx.wxfactory.WxMedHelper; import com.ynxbd.wx.wxfactory.WxPayHelper; import com.ynxbd.wx.wxfactory.payment.jsapi.models.WxPayNotify; @@ -551,9 +553,12 @@ public class PayService { } else if (MerchantEnum.ALI.equals(merchantEnum)) { // 支付宝下单 return AliHelper.createOrder(merchantEnum, title, outTradeNo, totalFee, notifyType, payOpenId); - } else if (MerchantEnum.BCM.equals(merchantEnum)) { + } else if (MerchantEnum.BCM.equals(merchantEnum)) { // 交行 return BCMHelper.createOrder(merchantEnum, title, outTradeNo, totalFee, notifyType); + } else if (MerchantEnum.JY.equals(merchantEnum)) { // 京颐 + return JYPayHelper.createOrder(merchantEnum, title, outTradeNo, totalFee, notifyType, ip, payOpenId, msgOpenId, new ReqOrder()); + } return null; } diff --git a/src/main/java/com/ynxbd/jy/bean/JYOrder.java b/src/main/java/com/ynxbd/jy/bean/JYOrder.java new file mode 100644 index 0000000..715a4d8 --- /dev/null +++ b/src/main/java/com/ynxbd/jy/bean/JYOrder.java @@ -0,0 +1,113 @@ +package com.ynxbd.jy.bean; + + +import com.ynxbd.common.bean.pay.Order; +import com.ynxbd.common.bean.pay.ReqOrder; +import com.ynxbd.jy.bean.enums.JYBusinessTypeEnum; +import com.ynxbd.jy.bean.enums.JYOrderTypeDetailEnum; +import com.ynxbd.jy.bean.enums.JYOrderTypeEnum; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; + +import java.math.BigDecimal; + +@Slf4j +@Getter +@Setter +@ToString +@NoArgsConstructor +public class JYOrder extends ReqOrder { + private String clinicNo; + private String hisTransDoneTime; + private String hisOperatorNo; + private String hisOperatorName; + private String receiptNo; + // ================================== + private String applicationId; + private String merchantId; + // 应用方订单号 + private String merOrderNum; + // 支付平台订单号 + private String orderId; + // 支付平台支付流水号 + private String orderTransId; + // 支付网关订单号 + private String threeTradeNo; + // 银行流水号 + private String finalTransNo; + // 订单金额 + private String orderAmt; + // 退款金额 + private String refundAmt; + // 支付交易发起时间 + private String tranDateTime; + // 支付时间-YYYYMMDDHHMMSS(订单支付时间)未支付时,为空字符串 + private String paymentTime; + // 支付方式 + private String payType; + // 订单状态[详见字典数据5.2 没有发生过退款业务的数据会包含此字段,如果发生过退款业务,则不会返回此字段,请以退款明细中状态为准;] + private String orderState; + // 订单状态描述 + private String orderStateMessage; + // 订单费用类型[如:001:挂号费 002:医疗费 详见字典数据5.2订单费用类型] + private String orderType; + // 微信公众号用户标识 + private String openId; + // 订单最后退款次数,未退款时无此字段。 + private String refundCount; + // 订单最后退款时间,未退款时无此字段。 + private String refundTime; + // 商户ID + private String appId; + // 商户号 + private String merchantNo; + // 医保局返回信息 + private String responseContent; + // 由接入方生成的签名 + private String signValue; + // ==================================== + + // 支付类型明细 + private String orderTypeDetail; + + public JYOrderTypeEnum orderTypeEnum; + + public JYBusinessTypeEnum businessTypeEnum; + // 支付类型明细 + public JYOrderTypeDetailEnum orderTypeDetailEnum; + + + public int toInsurancePayType() { + int payType = 0; + if (super.totalFee.compareTo(super.insuranceFee) == 0) { + payType = 2; // 医保 + } else if (super.totalFee.compareTo(super.cashFee) == 0) { + payType = 1; // 现金(1) + } else { + payType = 3; // 医保+现金 + } + return payType; + } + + public int toConsumeType() { + if (acctFee == null || insuranceFee == null) { + return 0; + } + + if (acctFee.compareTo(BigDecimal.ZERO) > 0 && insuranceFee.compareTo(BigDecimal.ZERO) > 0) { + return 0; // 0:统筹+个账 + } + + if (acctFee.compareTo(BigDecimal.ZERO) > 0 && insuranceFee.compareTo(BigDecimal.ZERO) == 0) { + return 1; // 1:个账 + } + + if (acctFee.compareTo(BigDecimal.ZERO) == 0 && insuranceFee.compareTo(BigDecimal.ZERO) > 0) { + return 2; // 2:统筹 + } + return 0; + } +} diff --git a/src/main/java/com/ynxbd/jy/bean/JYRefund.java b/src/main/java/com/ynxbd/jy/bean/JYRefund.java new file mode 100644 index 0000000..46a6d03 --- /dev/null +++ b/src/main/java/com/ynxbd/jy/bean/JYRefund.java @@ -0,0 +1,35 @@ +package com.ynxbd.jy.bean; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Getter +@Setter +@ToString +@NoArgsConstructor +public class JYRefund { + // 支付平台退款流水号 + private String orderTransId; + // 应用方退款流水号 + private String refundTransId; + // 支付网关流水号 + private String threeTransId; + // 银行流水号 + private String finalTransId; + // 退款金额 + private String refundAmt; + // 交易流水状态 + private String transState; + // 交易流水状态描述 + private String transStateMessage; + // 交易代码[002撤销 004退费 005冲正 详细请参考数据字典5.2;$n为下标,从0开始编号] + private String transCode; + // 退款(冲正、撤销)请求创建时间YYYYMMDDHHMMSS ;$n为下标,从0开始编号 + private String tranDateTime; + // 退款(冲正、撤销)请求完成时间YYYYMMDDHHMMSS ;$n为下标,从0开始编号 + private String refundTime; +} diff --git a/src/main/java/com/ynxbd/jy/bean/enums/JYBusinessTypeEnum.java b/src/main/java/com/ynxbd/jy/bean/enums/JYBusinessTypeEnum.java new file mode 100644 index 0000000..3f012f9 --- /dev/null +++ b/src/main/java/com/ynxbd/jy/bean/enums/JYBusinessTypeEnum.java @@ -0,0 +1,39 @@ +package com.ynxbd.jy.bean.enums; + + +import lombok.ToString; + +@ToString +public enum JYBusinessTypeEnum { + B101("B101", "预约"), + B102("B102", "挂号"), + B201("B201", "门诊缴费"), + B202("B202", "门诊预缴"), + B301("B301", "住院预缴"), + B302("B302", "住院结算补交"), + B401("B401", "卡押金"), + B999("B999", "其他"); + + public final String CODE; + public final String DESC; + + JYBusinessTypeEnum(String CODE, String DESC) { + this.CODE = CODE; + this.DESC = DESC; + } + + /** + * 根据code获取枚举 + */ + public static JYBusinessTypeEnum findEnum(String code) { + if (code == null) { + return null; + } + for (JYBusinessTypeEnum item : values()) { + if (item.CODE.equals(code)) { + return item; + } + } + return null; + } +} diff --git a/src/main/java/com/ynxbd/jy/bean/enums/JYOrderTypeDetailEnum.java b/src/main/java/com/ynxbd/jy/bean/enums/JYOrderTypeDetailEnum.java new file mode 100644 index 0000000..770b32b --- /dev/null +++ b/src/main/java/com/ynxbd/jy/bean/enums/JYOrderTypeDetailEnum.java @@ -0,0 +1,26 @@ +package com.ynxbd.jy.bean.enums; + + +import lombok.ToString; + +@ToString +public enum JYOrderTypeDetailEnum { + RegPay("RegPay", "挂号支付"), + DiagPay("DiagPay", "诊间支付"), + CovidExamPay("CovidExamPay", "新冠检测费用(核酸)"), + InHospPay("InHospPay", "住院费支付"), + PharmacyPay("PharmacyPay", "药店支付"), + InsurancePay("InsurancePay", "保险费支付"), + IntRegPay("IntRegPay", "互联网医院挂号支付"), + IntReDiagPay("IntReDiagPay", "互联网医院复诊支付"), + IntPscPay("IntPscPay", "互联网医院处方支付"), + CvidAntigenPay("CvidAntigenPay", "新冠抗原检测"); + + public final String CODE; + public final String DESC; + + JYOrderTypeDetailEnum(String CODE, String DESC) { + this.CODE = CODE; + this.DESC = DESC; + } +} \ No newline at end of file diff --git a/src/main/java/com/ynxbd/jy/bean/enums/JYOrderTypeEnum.java b/src/main/java/com/ynxbd/jy/bean/enums/JYOrderTypeEnum.java new file mode 100644 index 0000000..014e1f4 --- /dev/null +++ b/src/main/java/com/ynxbd/jy/bean/enums/JYOrderTypeEnum.java @@ -0,0 +1,44 @@ +package com.ynxbd.jy.bean.enums; + + +import lombok.ToString; + +@ToString +public enum JYOrderTypeEnum { + _001("001", "挂号费"), + _002("002", "医药费"), + _003("003", "住院预交金"), + _004("004", "药品费"), + _005("005", "就诊卡充值"), + _006("006", "新农合缴费"), + _007("007", "网费充值"), + _008("008", "健康卡充值"), + _010("010", "咨询费"), + _012("012", "复印费"), + _101("101", "陪诊费"), + _801("801", "停车费"), + _902("902", "卡押金"), + _903("903", "住院结算补交"), + _904("904", "体检费"), + _905("905", "处方药品费"), + _906("906", "陪护床押金"), + _907("907", "病历押金"), + _908("908", "病理切片押金"); + + public final String CODE; + public final String NAME; + + JYOrderTypeEnum(String CODE, String name) { + this.CODE = CODE; + this.NAME = name; + } + + public static JYOrderTypeEnum findEnum(String code) { + for (JYOrderTypeEnum value : JYOrderTypeEnum.values()) { + if (value.CODE.equals(code)) { + return value; + } + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/ynxbd/jy/helper/JYPayConfig.java b/src/main/java/com/ynxbd/jy/helper/JYPayConfig.java new file mode 100644 index 0000000..a79dae0 --- /dev/null +++ b/src/main/java/com/ynxbd/jy/helper/JYPayConfig.java @@ -0,0 +1,36 @@ +package com.ynxbd.jy.helper; + +import com.ynxbd.common.helper.common.XmlConfigHelper; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class JYPayConfig { + private JYPayConfig() { + } + + // 请求地址 + public final static String URL; + + // 应用编号 + public final static String APPLICATION_ID; + // 应用商户编号 + public final static String MERCHANT_ID; + + public final static String HOSP_ID; + + public final static String PRIVATE_KEY; + + static { + XmlConfigHelper config = new XmlConfigHelper().read("xbd-config.xml", "pay"); + + URL = config.getString("url"); + APPLICATION_ID = config.getString("application_id"); + MERCHANT_ID = config.getString("merchant_id"); + HOSP_ID = config.getString("hosp_id"); + PRIVATE_KEY = config.getString("private_key"); + + if (URL == null) { + log.error("[京颐-支付]配置文件读取失败"); + } + } +} diff --git a/src/main/java/com/ynxbd/jy/helper/JYPayHelper.java b/src/main/java/com/ynxbd/jy/helper/JYPayHelper.java index c048f4e..83b76d3 100644 --- a/src/main/java/com/ynxbd/jy/helper/JYPayHelper.java +++ b/src/main/java/com/ynxbd/jy/helper/JYPayHelper.java @@ -2,17 +2,24 @@ package com.ynxbd.jy.helper; import com.alibaba.fastjson.JSONObject; import com.ynxbd.common.bean.enums.MerchantEnum; +import com.ynxbd.common.bean.pay.ReqOrder; import com.ynxbd.common.helper.common.ErrorHelper; import com.ynxbd.common.helper.common.JsonHelper; +import com.ynxbd.common.helper.common.RSAHelper; +import com.ynxbd.common.helper.http.OkHttpHelper; +import com.ynxbd.jy.bean.JYOrder; import com.ynxbd.wx.config.WeChatConfig; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; -import weixin.popular.api.PayMchAPI; -import weixin.popular.bean.paymch.Unifiedorder; -import weixin.popular.bean.paymch.UnifiedorderResult; import java.math.BigDecimal; -import java.util.UUID; +import java.nio.charset.StandardCharsets; +import java.security.PrivateKey; +import java.security.Signature; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; // 京颐支付 @Slf4j @@ -31,70 +38,284 @@ public class JYPayHelper { * @param msgOpenId 用于推送的openId * @return 成功返回 json, 否则返回null */ - public static JSONObject createOrder(MerchantEnum merchantEnum, String title, String totalFee, String outTradeNo, String notifyType, String ip, String payOpenId, String msgOpenId) { -// try { -// if (ObjectUtils.isEmpty(payOpenId) || ObjectUtils.isEmpty(outTradeNo) -// || merchantEnum == null || totalFee == null || notifyType == null) { -// log.info("【京硕】下单参数缺失"); -// return null; -// } -// -// String cents; -// try { -// cents = new BigDecimal(totalFee).movePointRight(2).toString(); // 金额转换=>单位分 -// } catch (Exception e) { -// ErrorHelper.println(e); -// log.info("【京硕】统一下单金额转换异常"); -// return null; -// } -// -// String appId = merchantEnum.APP_ID; -// String mchId = WeChatConfig.MCH_ID; -// String mchKey = WeChatConfig.MCH_KEY; -// String nonce = UUID.randomUUID().toString().replace("-", ""); -// -// Unifiedorder unifiedorder = new Unifiedorder(); -// unifiedorder.setAppid(appId); -// unifiedorder.setMch_id(mchId); -// unifiedorder.setNonce_str(nonce); -// unifiedorder.setOpenid(payOpenId); -// unifiedorder.setOut_trade_no(outTradeNo); -// unifiedorder.setBody(title); -// -// unifiedorder.setTotal_fee(cents); // 金额分 -// unifiedorder.setSpbill_create_ip(ip); -// unifiedorder.setNotify_url(WeChatConfig.getBaseURL() + merchantEnum.NOTIFY_URL); -// unifiedorder.setTrade_type("JSAPI"); -// // 额外参数 -// unifiedorder.setAttach(notifyType); -// -// log.info("【京硕】统一下单 {},{},{},{},{},{},{},{}", appId, mchId, nonce, title, outTradeNo, totalFee, ip, merchantEnum.NOTIFY_URL); -// -// // 微信统一下单 -// UnifiedorderResult unifiedorderResult = PayMchAPI.payUnifiedorder(unifiedorder, mchKey); -// log.info("【京硕】统一下单返回:{}", JsonHelper.toJsonString(unifiedorderResult)); -// if (unifiedorderResult == null) { -// log.info("【京硕】统一下单失败"); -// return null; -// } + public static JSONObject createOrder(MerchantEnum merchantEnum, String title, String totalFee, String outTradeNo, String notifyType, String ip, String payOpenId, String msgOpenId, ReqOrder reqOrder) { + try { + if (ObjectUtils.isEmpty(payOpenId) || ObjectUtils.isEmpty(outTradeNo) + || merchantEnum == null || totalFee == null || notifyType == null) { + log.info("【京硕】下单参数缺失"); + return null; + } + + String cents; + try { + cents = new BigDecimal(totalFee).movePointRight(2).toString(); // 金额转换=>单位分 + } catch (Exception e) { + ErrorHelper.println(e); + log.info("【京硕】下单金额转换异常"); + return null; + } + + log.info("【京硕】下单 {},{},{},{},{}", title, outTradeNo, totalFee, ip, merchantEnum.NOTIFY_URL); + + JYOrder jyOrder = reqOrder.jyOrder; + + Map req = new HashMap<>(); + req.put("openId", payOpenId); + req.put("hospitalId", JYPayConfig.HOSP_ID); // 医院ID + req.put("applicationId", JYPayConfig.APPLICATION_ID); + req.put("merchantId", JYPayConfig.MERCHANT_ID); + req.put("merOrderNum", outTradeNo); // 商户订单号 + req.put("hisOrderNum", null); // HIS订单号:可以为发票号[该接口若不传,在业务完成后调用2.1.6接口] + req.put("hisTransNum", null); // HIS流水号:可以为发票号[该接口若不传,在业务完成后调用2.1.6接口] + // 金额 + req.put("orderAmt", cents); // 交易金额:只接收整数,单位:分,例如100表示壹圆整;支付宝医保支付传总金额 + + req.put("orderType", jyOrder.orderTypeEnum.CODE); // 如:001:挂号费 002:医药费; + req.put("backURL", WeChatConfig.getBaseURL() + merchantEnum.NOTIFY_URL); // 商户异步回调地址:后台发起异步回调地址, 扫码枪支付方式无需回调的可以不 +// params.put("backParamsType", "key-value"); // 商户异步回调入参格式:后台发起异步回调时参数格式,取值有:key-value和json,默认值是key-value。 + req.put("payType", "WX_PUBLIC"); // 如:UPOP_APP, UPOP_WEB;详见附录5.1[微信公众号支付(WX_PUBLIC)] + req.put("bussinessType", jyOrder.businessTypeEnum.CODE); // 业务类型:综合支付对应用权限控制是否必传 最大不超过4位,详见数据字典5.2 该接口若不传,需要调用2.1.6接口再次更新 + req.put("patientName", reqOrder.getPatientName()); // 微信医保支付必传。其余支付方式若该接口若不传,需要调用2.1.6接口再次更新 + req.put("patientGender", reqOrder.getPatientGender()); // 患者性别。综合支付对应用权限控制是否必传 1男 2女 9其他 最大不超过4位 该接口若不传,需要调用2.1.6接口再次更新 + req.put("patientAge", reqOrder.getPatientAge()); // 患者年龄。综合支付对应用权限控制是否必传 该接口若不传,需要调用2.1.6接口再次更新 + req.put("patientIdNo", reqOrder.getPatientTel()); // 微信医保支付必传。其余支付方式若该接口若不传,需要调用2.1.6接口再次更新 + req.put("patientPhoneNumber", reqOrder.getPatientTel()); // 综合支付对应用权限控制是否必传 最大不超过16位 该接口若不传,需要调用2.1.6接口再次更新 + req.put("patientId", reqOrder.getPatientId()); // 患者ID:综合支付对应用权限控制是否必传 最大不超过32位 该接口若不传,需要调用2.1.6接口再次更新 + req.put("patientCardNo", reqOrder.getPatientId()); // 患者卡号:综合支付对应用权限控制是否必传 最大不超过32位该接口若不传,需要调用2.1.6接口再次更新 + req.put("clinicNo", reqOrder.getTreatNum()); // 门诊号:综合支付对应用权限控制是否必传 最大不超过32位该接口若不传,需要调用2.1.6接口再次更新 + req.put("inpNo", reqOrder.getTreatNum()); // 住院号:综合支付对应用权限控制是否必传 最大不超过32位该接口若不传,需要调用2.1.6接口再次更新 + req.put("hisTransDoneTime", null); // HIS业务完成时间:综合支付对应用权限控制是否必传 YYYY-MM-DD HH:MM:SS 该接口若不传,需要调用2.1.6接口再次更新 + req.put("hisOperatorNo", jyOrder.getHisOperatorNo()); // HIS操作员编号:综合支付对应用权限控制是否必传HIS操作员编号和HIS操作员姓名必须成对出现该接口若不传,需要调用2.1.6接口再次更新 + req.put("hisOperatorName", jyOrder.getHisOperatorName()); // HIS操作员姓名:综合支付对应用权限控制是否必传 HIS操作员编号和HIS操作员姓名必须成对出现 该接口若不传,需要调用2.1.6接口再次更新 + req.put("receiptNo", null); // 综合支付对应用权限控制是否必传最大不超过200位 该接口若不传,需要调用2.1.6接口再次更新 + req.put("remarks", ""); // 备注 建行渠道格式为json,参考样式:{"REMARK1":"REM1","REMARK2":"REM2"} 农行渠道参考样式:{"TerminalNo":"1234567"} + + // 医保支付====================================== +// params.put("orderTotalAmt", cents); // orderTotalAmt:微信医保支付必传,有社保交易数据时,订单总金额=自费实际金额+社保金额+减免金额 +// params.put("orderTypeDetail", jyOrder.orderTypeDetailEnum.CODE); // 支付类型明细:由接入方生成的签名,支付平台根据该字段对入参进行验签;签名生成规则参考4加签验签规则 +// params.put("cashFee", reqOrder.getCashFee()); // 现金需要支付的金额:单位为分>=0 线下预结算模式填实际自费金额 +// params.put("insuranceFee", reqOrder.getInsuranceFee()); // 单位为分>=0填实际医保金额 // -// String result_code = unifiedorderResult.getResult_code(); -// // 下单是否成功 -// Boolean sign_status = unifiedorderResult.getSign_status(); -// if (!SUCCESS.equals(result_code) || sign_status == null || !sign_status) { -// log.info("【京硕】统一下单返回异常信息:sign_status={}, err_code=[ {} ], err_code_des=[ {} ]", sign_status, unifiedorderResult.getErr_code(), unifiedorderResult.getErr_code_des()); -// return null; -// } -// String json = weixin.popular.util.PayUtil.generateMchPayJsRequestJson(unifiedorderResult.getPrepay_id(), appId, mchKey); -// if (json != null) { -// return JsonHelper.parseObject(json); -// } -// } catch (Exception e) { -// log.error("【京硕】统一下单异常信息:{}", e.getMessage()); -// ErrorHelper.println(e); -// } -// return null; +// params.put("allowFeeChange", "0"); // 是否允许预结算费用发生变化:0:不允许;1:允许 当医保局返回的预结算金额与医院上传的金额不一致时,此字段为0则直接报错,为1则以医保局金额为准 +// params.put("spbillCreateIp", reqOrder.getIp()); // 用户端ip +// params.put("returnUrl", reqOrder.getReturnUrl()); // 调用方可以在链接中加上支付单号,回跳后查询调用方订单状态,如果订单已支付则成功, 如果订单未支付则进行查单操作确认订单结果。不论成功或者失败均会回跳 +// params.put("insurancePayType", jyOrder.toInsurancePayType()); // 微信医保支付方式:1:现金;2:医保;3:现金+医保 +// params.put("consumeType", jyOrder.toConsumeType()); // 医保部分扣费类型:0:统筹+个账;1:个账;2:统筹。默认为0 +// params.put("userCardType", "1"); // 1 居民身份证 +// params.put("isDept", "4"); // 医保标识:is_dept=4 医保电子凭证支付; +// params.put("serialNo", reqOrder.getSerialNo()); // 医院HIS系统订单号 +// params.put("requestContent", reqOrder.getRequestContent()); // 参考医保结构体(医疗机构透传医保) 示例: {"payAuthNo":"AUTH****","payOrdId":"ORD****","setlLatlnt":"118.096435,24.485407"} payAuthNo:授权码 payOrdId:对应处方上传的出参单号 setlLatlnt:用户地理定位信息, 经纬度信息,如“118.096435,24.485407”。未获取到用户定位时,传“0,0”。 +//// params.put("extendInfo", ""); //亲情移动支付时,为必填。 (就诊亲属姓名md5 - rel_user_name_md5,就诊亲属身份证件号md5 - rel_user_card_no_md5 ) { "rel_user_name_md5": "XXX","rel_user_card_no_md5": "XXX"} MD5为32位小写,uft-8编码(身份证中如果有字母需要转成大写再做MD5) + + String signValue = createSign(req); + if (signValue == null) { + return null; + } + req.put("signValue", signValue); // 数字签名:由接入方生成的签名,支付平台根据该字段对入参进行验签;签名生成规则参考4加签验签规则 + + JSONObject resp = OkHttpHelper.postJson(JYPayConfig.URL + "/qy_iips_pay/paycore/prePayOrder", params -> { + params.putAll(req); + }, headers -> { + headers.add("content-type", "application/x-www-form-urlencoded"); + }); + log.info("【京硕】下单返回 {}", JsonHelper.toJsonString(resp)); + } catch (Exception e) { + log.error("【京硕】下单异常信息:", e); + } return null; } + + /** + * 支付状态查询 + * + * @param merchantEnum 枚举 + * @param title 商品标题 + * @param totalFee 订单金额 + * @param outTradeNo 订单号 + * @return 成功返回 json, 否则返回null + */ + public static JSONObject queryPayOrderInfo(MerchantEnum merchantEnum, String title, String totalFee, String outTradeNo, String bankTransNo, String tradeNo) { + try { + log.info("【京硕】支付状态查询 {},{},{},{}", title, outTradeNo, totalFee, merchantEnum.NOTIFY_URL); + if (ObjectUtils.isEmpty(outTradeNo) && ObjectUtils.isEmpty(bankTransNo) && ObjectUtils.isEmpty(tradeNo)) { + return null; + } + + if (ObjectUtils.isEmpty(outTradeNo) && (ObjectUtils.isEmpty(bankTransNo) || ObjectUtils.isEmpty(tradeNo))) { + return null; + } + + Map req = new HashMap<>(); + req.put("applicationId", JYPayConfig.APPLICATION_ID); + req.put("merchantId", JYPayConfig.MERCHANT_ID); + req.put("merOrderNum", outTradeNo); // 商户订单号 + req.put("orderId", bankTransNo); // 支付平台订单号 + req.put("outTransNo", tradeNo); // 应用流水号:应用流水号outTransNo”和“支付平台订单号orderId”这两个参数必须同时传。该参数指“应用方流水号”,不许有重复 + + String signValue = createSign(req); + if (signValue == null) { + return null; + } + req.put("signValue", signValue); // 应用流水号:应用流水号outTransNo”和“支付平台订单号orderId”这两个参数必须同时传。该参数指“应用方流水号”,不许有重复 + + JSONObject resp = OkHttpHelper.postJson(JYPayConfig.URL + "/qy_iips_pay/paycore/queryPayOrderInfo", params -> { + params.putAll(req); + }, headers -> { + headers.add("content-type", "application/x-www-form-urlencoded"); + }); + log.info("【京硕】支付状态查询返回 {}", JsonHelper.toJsonString(resp)); + } catch (Exception e) { + log.error("【京硕】支付状态查询异常信息:", e); + } + return null; + } + + + /** + * 退款申请 + * + * @param merchantEnum 枚举 + * @param title 商品标题 + * @param totalFee 订单金额 + * @param outTradeNo 订单号 + * @return 成功返回 json, 否则返回null + */ + public static JSONObject refundPayOrder(MerchantEnum merchantEnum, String title, String totalFee, String outTradeNo, String bankTransNo, String tradeNo, String sign) { + try { + log.info("【京硕】退款申请 {},{},{},{}", title, outTradeNo, totalFee, merchantEnum.NOTIFY_URL); + if (ObjectUtils.isEmpty(outTradeNo) && ObjectUtils.isEmpty(bankTransNo) && ObjectUtils.isEmpty(tradeNo)) { + return null; + } + + if (ObjectUtils.isEmpty(outTradeNo) && (ObjectUtils.isEmpty(bankTransNo) || ObjectUtils.isEmpty(tradeNo))) { + return null; + } + Map req = new HashMap<>(); + req.put("applicationId", JYPayConfig.APPLICATION_ID); + req.put("merchantId", JYPayConfig.MERCHANT_ID); + req.put("merOrderNum", outTradeNo); // 商户订单号 + req.put("orderId", bankTransNo); // 支付平台订单号 + req.put("outTransNo", tradeNo); // 应用流水号:应用流水号outTransNo”和“支付平台订单号orderId”这两个参数必须同时传。该参数指“应用方流水号”,不许有重复 + req.put("signValue", sign); // 应用流水号:应用流水号outTransNo”和“支付平台订单号orderId”这两个参数必须同时传。该参数指“应用方流水号”,不许有重复 + req.put("refundStateSync", "0"); // 退费状态是否同步返回[0:否,1:是,不传默认为否 若传值为1,则退款状态不明确,开始轮询] + req.put("requestContent", "0"); // 微信医保支付必传。示例:{“payOrdId”:”******”,“ref_reason”:”******”ref_reason  退款原因payOrdId: 对应处方上传的出参单号 + + String signValue = createSign(req); + if (signValue == null) { + return null; + } + req.put("signValue", signValue); // 数字签名:由接入方生成的签名,支付平台根据该字段对入参进行验签;签名生成规则参考4加签验签规则 + + JSONObject resp = OkHttpHelper.postJson(JYPayConfig.URL + "/qy_iips_pay/paycore/refundPayOrder", params -> { + params.putAll(req); + }, headers -> { + headers.add("content-type", "application/x-www-form-urlencoded"); + }); + log.info("【京硕】退款申请返回 {}", JsonHelper.toJsonString(resp)); + } catch (Exception e) { + log.error("【京硕】退款申请异常信息:", e); + } + return null; + } + + /** + * 更新业务信息 + * + * @param merchantEnum 枚举 + * @param title 商品标题 + * @param totalFee 订单金额 + * @param outTradeNo 订单号 + * @return 成功返回 json, 否则返回null + */ + public static JSONObject modifyBusinessInfo(MerchantEnum merchantEnum, String title, String totalFee, String outTradeNo, String bankTransNo, String tradeNo, String sign) { + try { + log.info("【京硕】更新业务信息 {},{},{},{}", title, outTradeNo, totalFee, merchantEnum.NOTIFY_URL); + if (ObjectUtils.isEmpty(outTradeNo) && ObjectUtils.isEmpty(bankTransNo) && ObjectUtils.isEmpty(tradeNo)) { + return null; + } + + if (ObjectUtils.isEmpty(outTradeNo) && (ObjectUtils.isEmpty(bankTransNo) || ObjectUtils.isEmpty(tradeNo))) { + return null; + } + + JSONObject resp = OkHttpHelper.postJson(JYPayConfig.URL + "/qy_iips_pay/paycore/modifyBusinessInfo", params -> { + params.put("applicationId", JYPayConfig.APPLICATION_ID); // 应用编号 + params.put("merchantId", JYPayConfig.MERCHANT_ID); // 应用商户编号 +// params.put("merOrderNum", merOrderNum); // 商户订单号 +// params.put("refundTransId", refundTransId); // 商户退款流水号,非支付交易必传 +// params.put("orderId", orderId); // 支付平台订单号 +// params.put("orderTransId", orderTransId); // 支付平台流水号 +// params.put("hisOrderNum", hisOrderNum); // HIS订单号,对账场景必传 +// params.put("hisTransNum", hisTransNum); // HIS交易流水号,对账场景必传 +// params.put("hisTransAmt", hisTransAmt); // 交易金额,单位:分,整数 +// params.put("bussinessType", bussinessType); // 业务类型,最大4位 +// params.put("patientName", patientName); // 患者姓名 +// params.put("patientGender", patientGender); // 患者性别:1男 2女 9其他 +// params.put("patientAge", patientAge); // 患者年龄 +// params.put("patientIdNo", patientIdNo); // 患者身份证号,最长18位 +// params.put("patientPhoneNumber", patientPhoneNumber); // 患者手机号码,最长16位 +// params.put("patientId", patientId); // 患者ID +// params.put("patientCardNo", patientCardNo); // 患者卡号 +// params.put("clinicNo", clinicNo); // 门诊号 +// params.put("inpNo", inpNo); // 住院号 +// params.put("hisTransDoneTime", hisTransDoneTime); // HIS业务完成时间 YYYY-MM-DD HH:MM:SS +// params.put("hisOperatorNo", hisOperatorNo); // HIS操作员编号 +// params.put("hisOperatorName", hisOperatorName); // HIS操作员姓名 +// params.put("receiptNo", receiptNo); // HIS票据号 +// params.put("hospitalId", hospitalId); // 医院ID +// params.put("iipsApiVersion", iipsApiVersion); // API版本号,不传默认v1.0 + }, headers -> { + headers.add("content-type", "application/x-www-form-urlencoded"); + }); + log.info("【京硕】更新业务信息返回 {}", JsonHelper.toJsonString(resp)); + } catch (Exception e) { + log.error("【京硕】更新业务信息异常信息:", e); + } + return null; + } + + + /** + * 【可选】排除signValue自身(标准支付签名规范推荐) + * + * @param params 原始参数map + * @return 待签名字符串 + */ + public static String createSign(Map params) { + try { + String signString = buildSignString(params); + return sign(signString, RSAHelper.getPrivateKey(JYPayConfig.PRIVATE_KEY)); + } catch (Exception e) { + log.error("", e); + return null; + } + } + + /** + * 【可选】排除signValue自身(标准支付签名规范推荐) + * + * @param params 原始参数map + * @return 待签名字符串 + */ + public static String buildSignString(Map params) { + return params.entrySet().stream().filter(entry -> entry.getValue() != null && !entry.getValue().trim().isEmpty() && !"signValue".equals(entry.getKey())) + .sorted(Map.Entry.comparingByKey()) + .map(entry -> entry.getKey() + "=" + entry.getValue()) + .collect(Collectors.joining("&")); + } + + /** + * 使用私钥按照指定算法进行签名 + * + * @param message 待签名串 + * @param privateKey 签名用私钥对象 + * @return 签名结果 + */ + public static String sign(String message, PrivateKey privateKey) throws Exception { + Signature signature = Signature.getInstance("SHA256WithRSA"); + signature.initSign(privateKey); + signature.update(message.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(signature.sign()); + } } diff --git a/src/main/java/com/ynxbd/wx/config/MessagePushConfig.java b/src/main/java/com/ynxbd/wx/config/MessagePushConfig.java index f464c06..72cae33 100644 --- a/src/main/java/com/ynxbd/wx/config/MessagePushConfig.java +++ b/src/main/java/com/ynxbd/wx/config/MessagePushConfig.java @@ -28,35 +28,36 @@ public class MessagePushConfig { */ public static final String HOST_URL; - // [挂号]导航推送 + // [挂号]导航推送 https://map.ipsmap.com?id=opBdKy87Gs&appKey=fnAs1mE5HP&poi=科室编码 public static final boolean REG_NAVIGATE_IS_ENABLE; - public static final String REG_NAVIGATE_URL; + public static final String REG_NAVIGATE_API; + // [挂号]缴费通知 public static final boolean REG_PAID_IS_ENABLE; - public static final String REG_PAID_URL; + public static final String REG_PAID_API; // [挂号]取消预约 public static final boolean REG_CANCEL_IS_ENABLE; - public static final String REG_CANCEL_URL; + public static final String REG_CANCEL_API; // [挂号]AI - public static final String REG_AI_URL; public static final boolean REG_AI_IS_ENABLE; + public static final String REG_AI_API; // [处方]缴费通知 public static final boolean RX_PAID_IS_ENABLE; - public static final String RX_PAID_URL; + public static final String RX_PAID_API; // 产科建档 public static final boolean OBS_DOCUMENT_IS_ENABLE; - public static final String OBS_DOCUMENT_URL; + public static final String OBS_DOCUMENT_API; static { XmlConfigHelper config = new XmlConfigHelper().read("wx-msg-push.xml"); - HOST_URL = config.getString("host_url",""); + HOST_URL = config.getString("host_url", ""); if (ObjectUtils.isEmpty(HOST_URL)) { log.error("【消息推送】配置文件wx-msg-push.xml读取失败"); } @@ -64,32 +65,32 @@ public class MessagePushConfig { // [挂号]导航推送 XmlConfigHelper regNavigateConfig = config.getConfigNode("reg_navigate"); REG_NAVIGATE_IS_ENABLE = regNavigateConfig.getBoolean("is_enable", false); - REG_NAVIGATE_URL = HOST_URL + regNavigateConfig.getString("api"); + REG_NAVIGATE_API = HOST_URL + regNavigateConfig.getString("api"); // [挂号]缴费通知 XmlConfigHelper regPaidConfig = config.getConfigNode("reg_paid"); REG_PAID_IS_ENABLE = regPaidConfig.getBoolean("is_enable", false); - REG_PAID_URL = HOST_URL + regPaidConfig.getString("api"); + REG_PAID_API = HOST_URL + regPaidConfig.getString("api"); // [挂号]取消预约 XmlConfigHelper regCancelConfig = config.getConfigNode("reg_cancel"); REG_CANCEL_IS_ENABLE = regCancelConfig.getBoolean("is_enable", false); - REG_CANCEL_URL = HOST_URL + regCancelConfig.getString("api"); + REG_CANCEL_API = HOST_URL + regCancelConfig.getString("api"); // [挂号]AI XmlConfigHelper regAIConfig = config.getConfigNode("reg_ai"); REG_AI_IS_ENABLE = regAIConfig.getBoolean("is_enable", false); - REG_AI_URL = HOST_URL + regAIConfig.getString("api"); + REG_AI_API = HOST_URL + regAIConfig.getString("api"); // [处方]缴费通知 XmlConfigHelper rxPaidConfig = config.getConfigNode("rx_paid"); RX_PAID_IS_ENABLE = rxPaidConfig.getBoolean("is_enable", false); - RX_PAID_URL = HOST_URL + rxPaidConfig.getString("api"); + RX_PAID_API = HOST_URL + rxPaidConfig.getString("api"); // 产科建档 XmlConfigHelper obsDocumentConfig = config.getConfigNode("obs_document"); OBS_DOCUMENT_IS_ENABLE = obsDocumentConfig.getBoolean("is_enable", false); - OBS_DOCUMENT_URL = HOST_URL + obsDocumentConfig.getString("api"); + OBS_DOCUMENT_API = HOST_URL + obsDocumentConfig.getString("api"); } @@ -100,7 +101,7 @@ public class MessagePushConfig { */ public static void regNavigatePush(MerchantEnum merchantEnum, Register reg) { try { - if (!merchantEnum.equals(MerchantEnum.WX) || !REG_NAVIGATE_IS_ENABLE || ObjectUtils.isEmpty(REG_NAVIGATE_URL)) { + if (!merchantEnum.equals(MerchantEnum.WX) || !REG_NAVIGATE_IS_ENABLE || ObjectUtils.isEmpty(REG_NAVIGATE_API)) { return; } @@ -112,14 +113,14 @@ public class MessagePushConfig { String doctName = reg.getDoctName(); String deptName = reg.getDeptName(); String deptCode = reg.getDeptCode(); - if (openid == null || patientId == null) { - log.warn("[推送]挂号导航通知失败,参数缺失~openid={}, patientId={}", openid, patientId); + if (ObjectUtils.isEmpty(openid) || ObjectUtils.isEmpty(patientId)) { + log.warn("[推送]挂号导航通知失败,参数缺失 openid={}, patientId={}", openid, patientId); return; } Patient patient = new PatientDao().selectByOpenidAndEPId(openid, patientId); if (patient == null) { - log.warn("[推送]挂号导航通知失败,患者信息不存在~"); + log.warn("[推送]挂号导航通知失败,未找到患者信息"); return; } @@ -127,7 +128,7 @@ public class MessagePushConfig { String time = (ObjectUtils.isEmpty(begTime) || ObjectUtils.isEmpty(endTime)) ? "" : (" " + begTime + "-" + endTime); - OkHttpHelper.getAsync(REG_NAVIGATE_URL, params -> { + OkHttpHelper.getAsync(REG_NAVIGATE_API, params -> { params.put("patientName", patient.getName() + " ID:" + patientId); params.put("content", "就诊时间:" + regDate + time); params.put("deptName", deptName); @@ -145,8 +146,7 @@ public class MessagePushConfig { */ public static void regPush(MerchantEnum merchantEnum, Register reg) { try { - if (!merchantEnum.equals(MerchantEnum.WX) - || !REG_PAID_IS_ENABLE || reg == null || ObjectUtils.isEmpty(REG_PAID_URL)) { + if (!merchantEnum.equals(MerchantEnum.WX) || !REG_PAID_IS_ENABLE || reg == null || ObjectUtils.isEmpty(REG_PAID_API)) { return; } @@ -174,7 +174,7 @@ public class MessagePushConfig { String time = (ObjectUtils.isEmpty(begTime) || ObjectUtils.isEmpty(endTime)) ? "" : (" " + begTime + "-" + endTime); - OkHttpHelper.getAsync(REG_PAID_URL, params -> { + OkHttpHelper.getAsync(REG_PAID_API, params -> { params.put("openId", DesEncryptHelper.enCode(openid)); params.put("patientName", patient.getName() + " ID:" + patientId); params.put("deptName", deptName); @@ -196,7 +196,7 @@ public class MessagePushConfig { */ public static void regAI(MerchantEnum merchantEnum, Register reg) { try { - if (!merchantEnum.equals(MerchantEnum.WX) || !REG_AI_IS_ENABLE || reg == null || ObjectUtils.isEmpty(REG_AI_URL)) { + if (!merchantEnum.equals(MerchantEnum.WX) || !REG_AI_IS_ENABLE || reg == null || ObjectUtils.isEmpty(REG_AI_API)) { return; } @@ -219,7 +219,7 @@ public class MessagePushConfig { .add("url", url) .add("organizeName", ORGANIZENAME) .build(); - OkHttpHelper.post(REG_AI_URL, requestBody); + OkHttpHelper.post(REG_AI_API, requestBody); } catch (Exception e) { log.warn("[推送]AI智能问诊推送通知错误-{}", e.getMessage()); } @@ -246,7 +246,7 @@ public class MessagePushConfig { .add("url", url) .add("organizeName", ORGANIZENAME) .build(); - OkHttpHelper.post(REG_AI_URL, requestBody); + OkHttpHelper.post(REG_AI_API, requestBody); } @@ -257,7 +257,7 @@ public class MessagePushConfig { */ public static void regAIReport(String patientId, String outTradeNo, String openId) { try { - if (!REG_AI_IS_ENABLE || ObjectUtils.isEmpty(REG_AI_URL)) { + if (!REG_AI_IS_ENABLE || ObjectUtils.isEmpty(REG_AI_API)) { return; } log.info("[推送]AI问诊报告推送..."); @@ -277,7 +277,7 @@ public class MessagePushConfig { .add("url", url) .add("organizeName", ORGANIZENAME) .build(); - OkHttpHelper.post(REG_AI_URL, requestBody); + OkHttpHelper.post(REG_AI_API, requestBody); } catch (Exception e) { log.warn("[推送]AI问诊报告推送通知错误-{}", e.getMessage()); } @@ -293,7 +293,7 @@ public class MessagePushConfig { public static void regObsDocument(MerchantEnum merchantEnum, Register reg) { try { if (!merchantEnum.equals(MerchantEnum.WX) - || reg == null || ObjectUtils.isEmpty(OBS_DOCUMENT_URL)) { + || reg == null || ObjectUtils.isEmpty(OBS_DOCUMENT_API)) { return; } @@ -311,7 +311,7 @@ public class MessagePushConfig { .add("organizeName", ORGANIZENAME) .add("buttonName", "进入产科建档系统") .build(); - OkHttpHelper.post(OBS_DOCUMENT_URL, requestBody); + OkHttpHelper.post(OBS_DOCUMENT_API, requestBody); } catch (Exception e) { log.warn("[推送]产科建档推送通知错误-{}", e.getMessage()); } @@ -324,7 +324,7 @@ public class MessagePushConfig { public static void regCancelPush(MerchantEnum merchantEnum, Register reg) { try { if (!merchantEnum.equals(MerchantEnum.WX) - || !REG_CANCEL_IS_ENABLE || reg == null || ObjectUtils.isEmpty(REG_CANCEL_URL)) { + || !REG_CANCEL_IS_ENABLE || reg == null || ObjectUtils.isEmpty(REG_CANCEL_API)) { return; } log.info("[推送]取消预约..."); @@ -350,7 +350,7 @@ public class MessagePushConfig { String time = (ObjectUtils.isEmpty(begTime) || ObjectUtils.isEmpty(endTime)) ? "" : (" " + begTime + "-" + endTime); - OkHttpHelper.getAsync(REG_CANCEL_URL, params -> { + OkHttpHelper.getAsync(REG_CANCEL_API, params -> { params.put("openId", DesEncryptHelper.enCode(openid)); params.put("patientName", patient.getName() + " ID:" + patientId); params.put("deptName", deptName); @@ -370,7 +370,7 @@ public class MessagePushConfig { */ public static void recipePush(List recipeList, String treatNum, String patientId, String openid, String tip) { try { - if (!RX_PAID_IS_ENABLE || ObjectUtils.isEmpty(RX_PAID_URL)) { + if (!RX_PAID_IS_ENABLE || ObjectUtils.isEmpty(RX_PAID_API)) { return; } @@ -394,7 +394,7 @@ public class MessagePushConfig { return; } - OkHttpHelper.getAsync(RX_PAID_URL, params -> { + OkHttpHelper.getAsync(RX_PAID_API, params -> { params.put("openId", DesEncryptHelper.enCode(openid)); params.put("patientName", patient.getName() + " ID:" + patientId); params.put("content", tip); diff --git a/src/main/java/com/ynxbd/wx/wxfactory/payment/WXPayUtility.java b/src/main/java/com/ynxbd/wx/wxfactory/payment/WXPayUtility.java index 37b6a21..ec8e840 100644 --- a/src/main/java/com/ynxbd/wx/wxfactory/payment/WXPayUtility.java +++ b/src/main/java/com/ynxbd/wx/wxfactory/payment/WXPayUtility.java @@ -91,6 +91,7 @@ public class WXPayUtility { .create(); private static final char[] SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); + private static final SecureRandom random = new SecureRandom(); /** diff --git a/src/main/resources/copy/healthcard/石林县人民医院-hc-config.xml b/src/main/resources/copy/healthcard/石林县人民医院-hc-config.xml index 9233575..5b88cf6 100644 --- a/src/main/resources/copy/healthcard/石林县人民医院-hc-config.xml +++ b/src/main/resources/copy/healthcard/石林县人民医院-hc-config.xml @@ -1,18 +1,16 @@ - - + - - + true - true + false 100000637 @@ -25,6 +23,6 @@ 暂无介绍 二级甲等 暂无地址 - 0871-67798120 + \ No newline at end of file diff --git a/src/main/resources/hc-config.xml b/src/main/resources/hc-config.xml index b32b842..89cb015 100644 --- a/src/main/resources/hc-config.xml +++ b/src/main/resources/hc-config.xml @@ -1,11 +1,10 @@ - true 31737 - 20009251 - 3bee9edc0a2f41ac911b9b714c854cad + 20009250 + c4a39049d4b1c29ffaa9a312687fdcfc 20009250 3bee9edc0a2f41ac911b9b714c854cad @@ -22,9 +21,9 @@ 34edf7cd14e646ae9c1bbca791b7b685 - b26188e6142d43b88f01453853d52a0a - - b26188e6142d43b88f01453853d52a0a + b26188e6142d43b88f01453853d52a0a + + b26188e6142d43b88f01453853d52a0a 800002723 diff --git a/src/main/resources/jy-config.xml b/src/main/resources/jy-config.xml new file mode 100644 index 0000000..ee92db4 --- /dev/null +++ b/src/main/resources/jy-config.xml @@ -0,0 +1,11 @@ + + + + http://127.0.0.1 + 1 + 1 + MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD1eiOktZm8bUwjHA2bFlrULg9v/VAmBfUWb8/1+xyZH5eSa7itvAG2Kdzv7L59nRIspXyO6ZW+gGmofnX8CqI5ofLrpissgoqZadNfz5v/k2Q78YTBM8BEMwkrPwOsbFX62poPSKr4kZRHgMADJkgS6AhsaDNBLdH6uRE8R0H6lQIDAQAB + MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAPV6I6S1mbxtTCMcDZsWWtQuD2/9UCYF9RZvz/X7HJkfl5JruK28AbYp3O/svn2dEiylfI7plb6Aaah+dfwKojmh8uumKyyCiplp01/Pm/+TZDvxhMEzwEQzCSs/A6xsVframg9IqviRlEeAwAMmSBLoCGxoM0Et0fq5ETxHQfqVAgMBAAECgYAf8F9Y2+P/1zyzyL+gcR0qRD/v80aNW/MSk0O8noqPBcRD4c4qlK6oU/QSJ3x1fY1Sz8lQEuZP3gdhS+rv+zY2BjbfSq4HcZexmbBmh0NQ4Swd7i0hfkSM+koHZjVoPY/FJ/TW/Ks3iV+kpAZuVLCh60B66H8y9K5xu331nLxeYQJBAPzFeQPVJThxIBbk5g8/fYD/gbglEGqdurTJlo9tmCuqzty19fApBE+41ir9Sl2vguDnY1d9Zbuf1AlS21jsVx0CQQD4nNC1FyDKK6GxQvOm6Do+b663ft0WK7dum0c4pM57VPTRqxag4p6lYCu5KYmVvUL20KGE5LVZ9LaOIMIurD/ZAkEA4z4My1tFuPZKqQpjoXWsuNn7nrcDiTX/8iQBDTSzxx4qFtYnIh9d1uYO9Fr+DjeJa/PZpYAAg6rujutEcy8WKQJARir0WPgjIAx6gW5VGHmY3sBkvpOG0Ngb2JLo4hrZ0ENlKbwxEc2EW0aucH9BvsqBGOo/fCOU78O6tpiWVdf12QJAP8ENPIBQCLwHq0U5bzV+X94BmuOfTAqwvy/r6XQcOct0k/M/Lln0FUcPwAb6rl/1R55Xj1/DxI2UbTc4KNNpng== + + + diff --git a/src/main/resources/jy-pay-config.xml b/src/main/resources/jy-pay-config.xml deleted file mode 100644 index 953af87..0000000 --- a/src/main/resources/jy-pay-config.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/main/resources/xbd-config.xml b/src/main/resources/xbd-config.xml index 038330f..2e0fcde 100644 --- a/src/main/resources/xbd-config.xml +++ b/src/main/resources/xbd-config.xml @@ -1,9 +1,9 @@ - + http://200.200.200.71:5050/peisReserve http://192.168.0.183:3307/wx3307 - http://192.168.0.183:3307/wx3307 +