新增京颐支付类型

新增formData类型的参数接收和进行文件上传
部分配置调整
debug
王绍全 21 hours ago
parent 3d36e15159
commit 2a53cbf4fd
  1. 55
      src/main/java/com/ynxbd/common/TestA.java
  2. 12
      src/main/java/com/ynxbd/common/action/PatientAction.java
  3. 18
      src/main/java/com/ynxbd/common/action/XBDAction.java
  4. 249
      src/main/java/com/ynxbd/common/action/base/BaseAction.java
  5. 57
      src/main/java/com/ynxbd/common/action/healthcard/HCReportAction.java
  6. 71
      src/main/java/com/ynxbd/common/action/pay/JYPayAction.java
  7. 14
      src/main/java/com/ynxbd/common/action/pay/MedicalAction.java
  8. 4
      src/main/java/com/ynxbd/common/action/pay/PayAction.java
  9. 27
      src/main/java/com/ynxbd/common/action/test/TestAction.java
  10. 21
      src/main/java/com/ynxbd/common/bean/enums/MerchantEnum.java
  11. 19
      src/main/java/com/ynxbd/common/bean/form/FormBlob.java
  12. 73
      src/main/java/com/ynxbd/common/bean/form/FormData.java
  13. 63
      src/main/java/com/ynxbd/common/bean/pay/ReqOrder.java
  14. 4
      src/main/java/com/ynxbd/common/config/interceptor/MethodInterceptor.java
  15. 45
      src/main/java/com/ynxbd/common/helper/common/RSAHelper.java
  16. 6
      src/main/java/com/ynxbd/common/helper/common/SmsHelper.java
  17. 4
      src/main/java/com/ynxbd/common/helper/xbd/XBDHttpHelper.java
  18. 15
      src/main/java/com/ynxbd/common/helper/xbd/XbdConfigHelper.java
  19. 30
      src/main/java/com/ynxbd/common/service/PEISService.java
  20. 7
      src/main/java/com/ynxbd/common/service/PayService.java
  21. 113
      src/main/java/com/ynxbd/jy/bean/JYOrder.java
  22. 35
      src/main/java/com/ynxbd/jy/bean/JYRefund.java
  23. 39
      src/main/java/com/ynxbd/jy/bean/enums/JYBusinessTypeEnum.java
  24. 26
      src/main/java/com/ynxbd/jy/bean/enums/JYOrderTypeDetailEnum.java
  25. 44
      src/main/java/com/ynxbd/jy/bean/enums/JYOrderTypeEnum.java
  26. 36
      src/main/java/com/ynxbd/jy/helper/JYPayConfig.java
  27. 353
      src/main/java/com/ynxbd/jy/helper/JYPayHelper.java
  28. 66
      src/main/java/com/ynxbd/wx/config/MessagePushConfig.java
  29. 1
      src/main/java/com/ynxbd/wx/wxfactory/payment/WXPayUtility.java
  30. 10
      src/main/resources/copy/healthcard/石林县人民医院-hc-config.xml
  31. 11
      src/main/resources/hc-config.xml
  32. 11
      src/main/resources/jy-config.xml
  33. 4
      src/main/resources/jy-pay-config.xml
  34. 4
      src/main/resources/xbd-config.xml

@ -1,42 +1,31 @@
package com.ynxbd.common; 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 { import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
// public static void main(String[] args) { import java.nio.charset.StandardCharsets;
// String respXML = "<Response>\n" + import java.security.KeyFactory;
// "\t<TransactionCode>1002</TransactionCode>\n" + import java.security.PublicKey;
// "\t<ResponseCode>0</ResponseCode>\n" + import java.security.spec.X509EncodedKeySpec;
// "\t<ResponseMessage>成功</ResponseMessage>\n" + import java.util.Base64;
// "\t<PatientID>932606</PatientID>\n" +
// "\t<Empi_Id>300349719</Empi_Id>\n" +
// "\t<HISTrasNo>137087</HISTrasNo>\n" +
// "</Response>";
// JsonResult result = JsonResult.xmlToBean(respXML, JsonResultEnum.SYS_HIS);
// if (result == null) {
// return;
// }
// Patient patient = result.dataMapToBean(Patient.class);
// System.out.println(patient);
// }
public class TestA {
private static final String PUB_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5klqI5STWTcbfjR093j+hvCEjNlZMQscIJg8jxZGqKW84AdFmSqPWEPu9ilqP+QUASiVSZ1QevGr2DWODFZ8Zw35aDA2bqCEprUx81gDdVPO7H7Bij+r8zAg8fT2c0Bi5rFq0xWMEQiTI+CyWwc5prOpquJU/P5yauEAdkRzlDwIDAQAB";
// public static void main(String[] args) { public static void main(String[] args) throws Exception{
// System.out.println(AesWxHelper.encode("524404")); String content = "533103198212184014";
// byte[] bytes = RSAHelper.enBytePKCS1Padding(content, PUB_KEY);
// 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"; System.out.println("【Java最终hex】:" + HexUtil.encodeHexStr(bytes));
}
// //
// List<Doctor> 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));
// }
}

@ -278,13 +278,13 @@ public class PatientAction extends BaseAction {
return Result.error("[医共体]不支持无证绑定!"); return Result.error("[医共体]不支持无证绑定!");
} }
fTel = getString("fTel"); fTel = getReqParamByKey("fTel");
fName = getString("fName"); fName = getReqParamByKey("fName");
fIDCardNo = getString("fIDCardNo"); fIDCardNo = getReqParamByKey("fIDCardNo");
mTel = getString("mTel"); mTel = getReqParamByKey("mTel");
mName = getString("mName"); mName = getReqParamByKey("mName");
mIDCardNo = getString("mIDCardNo"); mIDCardNo = getReqParamByKey("mIDCardNo");
Result result = new PatientService().noCardParamsValid(fTel, fName, fIDCardNo, mTel, mName, mIDCardNo); Result result = new PatientService().noCardParamsValid(fTel, fName, fIDCardNo, mTel, mName, mIDCardNo);
if (!result.isOK()) { if (!result.isOK()) {

@ -1,5 +1,7 @@
package com.ynxbd.common.action; 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.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.ynxbd.common.action.base.BaseAction; 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.config.interceptor.AesDecode;
import com.ynxbd.common.helper.common.Base64Helper; import com.ynxbd.common.helper.common.Base64Helper;
import com.ynxbd.common.helper.common.JsonHelper; 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.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.helper.xbd.XBDHttpHelper;
import com.ynxbd.common.result.Result; import com.ynxbd.common.result.Result;
import com.ynxbd.common.result.ResultEnum; 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 org.apache.struts2.convention.annotation.Namespace;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
/** /**
@ -54,7 +58,7 @@ public class XBDAction extends BaseAction {
public Result cloudFilm(String info) { public Result cloudFilm(String info) {
try { try {
log.info("[云胶片]info={}", info); log.info("[云胶片]info={}", info);
String path = XBDHelper.outTeamDao.getCloudFilmPath(info); String path = XbdConfigHelper.outTeamDao.getCloudFilmPath(info);
return Result.success(path); return Result.success(path);
} catch (Exception e) { } catch (Exception e) {
log.error("[云胶片]{}", e.getMessage()); log.error("[云胶片]{}", e.getMessage());
@ -280,20 +284,16 @@ public class XBDAction extends BaseAction {
} }
/** /**
* 查询体检报告 * 查询体检影像报告
*/ */
@Action("getPeisByCardNo") @Action("getPeisByCardNo")
public Result getPeisByCardNo(@AesDecode String cardNo, String begDate, String endDate) { 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)) { if (ObjectUtils.isEmpty(cardNo) || ObjectUtils.isEmpty(begDate) || ObjectUtils.isEmpty(endDate)) {
return Result.error(ResultEnum.PARAM_IS_DEFECT); return Result.error(ResultEnum.PARAM_IS_DEFECT);
} }
String encode = Base64Helper.encode(cardNo);
if (ObjectUtils.isEmpty(encode)) {
return Result.error(ResultEnum.PARAM_IS_INVALID);
}
try { 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++) { for (int i = 0; i < dataList.size(); i++) {
JSONObject dataItem = dataList.getJSONObject(i); JSONObject dataItem = dataList.getJSONObject(i);
String eid = dataItem.getString("eid"); String eid = dataItem.getString("eid");

@ -1,6 +1,8 @@
package com.ynxbd.common.action.base; package com.ynxbd.common.action.base;
import com.alibaba.fastjson.JSONObject; 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.HttpHelper;
import com.ynxbd.common.helper.common.JsonHelper; import com.ynxbd.common.helper.common.JsonHelper;
import com.ynxbd.wx.wxfactory.AesWxHelper; 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.ServletActionContext;
import org.apache.struts2.action.ServletRequestAware; import org.apache.struts2.action.ServletRequestAware;
import org.apache.struts2.convention.annotation.ParentPackage; 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 org.slf4j.MDC;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
@ -17,8 +21,9 @@ import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import java.io.*; import java.io.*;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.HashMap; import java.nio.file.Files;
import java.util.Map; import java.util.*;
import java.util.function.Function;
/** /**
@ -45,7 +50,7 @@ public class BaseAction implements Serializable, ServletRequestAware {
MDC.remove("ip"); MDC.remove("ip");
MDC.put("ip", HttpHelper.getIpAddress(request)); MDC.put("ip", HttpHelper.getIpAddress(request));
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
e.printStackTrace(); log.error("", e);
} }
this.request = request; this.request = request;
@ -80,60 +85,61 @@ public class BaseAction implements Serializable, ServletRequestAware {
return ServletActionContext.getServletContext(); 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) { protected String decodeReqString(String param) {
return AesWxHelper.decode(param); return AesWxHelper.decode(param);
} }
protected Integer getInteger(String param) { protected String getReqParamByKey(String key) {
try { String val = this.request.getParameter(key);
String val = this.request.getParameter(param); if ("".equals(val)) {
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) {
return null; 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> T getReqParamByKey(String key, Class<T> clazz) {
try { try {
String val = this.request.getParameter(param); if (clazz == null) {
return StringUtils.isEmpty(val) ? null : new BigDecimal(val); return null;
} catch (Exception e) { }
return null; String val = this.request.getParameter(key);
} if (StringUtils.isEmpty(val)) {
} return null;
}
val = val.trim();
protected Boolean getBoolean(String param) { Function<String, ?> converter;
try { if (String.class == clazz) {
String val = this.request.getParameter(param); return clazz.cast(val);
return StringUtils.isEmpty(val) ? null : Boolean.valueOf(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) { } catch (Exception e) {
return null; return null;
} }
@ -218,4 +224,157 @@ public class BaseAction implements Serializable, ServletRequestAware {
Map<String, String> params = reqParamsToMap(); Map<String, String> params = reqParamsToMap();
return JsonHelper.parseObject(JsonHelper.toJsonString(params), clazz); 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<String, String> params = new HashMap<>();
Map<String, FormBlob> 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<String> 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<String, String> params = new HashMap<>();
// ArrayList<FormBlob> files = new ArrayList<>();
//
// String a = null;
// // 1. 获取所有普通表单字段
// Enumeration<String> 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<FileItem> itemList = upload.parseRequest(request);
// FormData formData = new FormData();
//
// Map<String, String> params = new HashMap<>();
// ArrayList<FormBlob> 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;
// }
// }
//
} }

@ -2,11 +2,15 @@ package com.ynxbd.common.action.healthcard;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.ynxbd.common.action.base.BaseAction; 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.HCReportConfig;
import com.ynxbd.common.config.healthcard.HCSignHelper; 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.helper.http.OkHttpHelper;
import com.ynxbd.common.result.Result; import com.ynxbd.common.result.Result;
import com.ynxbd.common.result.ResultEnum;
import com.ynxbd.wx.wxfactory.AesWxHelper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace; import org.apache.struts2.convention.annotation.Namespace;
@ -18,42 +22,65 @@ import java.util.Map;
@Namespace("/hc_report") @Namespace("/hc_report")
public class HCReportAction extends BaseAction { public class HCReportAction extends BaseAction {
// 报告解读:https://open.ai.tengmed.com/openAccess/docs/access#6
@Action("pushUserReport") @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); 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 String url = HCReportConfig.IS_DEV
? "https://med-biz-pre.wecity.qq.com/api/report/PushUserReport/" ? "https://med-biz-pre.wecity.qq.com/api/report/PushUserReport/"
: "https://med-biz.wecity.qq.com/api/report/PushUserReport/"; : "https://med-biz.wecity.qq.com/api/report/PushUserReport/";
HCSignHelper config = HCReportConfig.createSign(); HCSignHelper config = HCReportConfig.createSign();
String requestId = config.getRequestId(); String requestId = config.getRequestId();
Map<String, Object> reqHead = new HashMap<>(); Map<String, Object> reqHead = new HashMap<>();
reqHead.put("requestId", requestId); reqHead.put("requestId", requestId);
Map<String, Object> textReportInfo = new HashMap<>(); // Map<String, Object> textReportInfo = new HashMap<>();
// Map<String, Object> patientInfo = new HashMap<>(); // Map<String, Object> patientInfo = new HashMap<>();
// Map<String, Object> reportInfo = new HashMap<>(); // Map<String, Object> reportInfo = new HashMap<>();
// partnerId:合作方ID 腾讯健康提供 // partnerId:合作方ID 腾讯健康提供
JSONObject jsonObject = OkHttpHelper.postJson(url + HCReportConfig.PARTNER_ID, params -> { JSONObject jsonObject = OkHttpHelper.postJson(url + HCReportConfig.PARTNER_ID, req -> {
params.put("reqHead", reqHead); req.put("reqHead", reqHead);
params.put("hospitalId", HCReportConfig.HOSP_ID); req.put("hospitalId", HCReportConfig.HOSP_ID);
params.put("outerId", reportId); req.put("outerId", reportId);
params.put("healthCardId", healthCardId); req.put("healthCardId", healthCardId);
params.put("patientId", patientId); req.put("patientId", patientId);
params.put("msgId", msgId); req.put("msgId", msgId);
params.put("reportFileType", 2); // [ 1:pdf;2:图片;3:文本] req.put("reportFileType", 2); // [ 1:pdf;2:图片;3:文本]
params.put("reportContent", reportContent); // 报告内容:报告文件base64编码、体积需要在30MB以内 当reportFileType 取值为 1, 2时,将报告文件base64编码放在该字段 req.put("reportContent", reportContentBase64); // 报告内容:报告文件base64编码、体积需要在30MB以内 当reportFileType 取值为 1, 2时,将报告文件base64编码放在该字段
params.put("textReportInfo", textReportInfo); // 当reportFileType 取值为 3 时,将文本报告内容放下该字段。 // req.put("textReportInfo", textReportInfo); // 当reportFileType 取值为 3 时,将文本报告内容放下该字段。
// log.warn("[报告解读] req={}", JsonHelper.toJsonString(req));
}, headers -> { }, headers -> {
headers.add("Content-Type", "application/json"); headers.add("Content-Type", "application/json");
headers.add("god-portal-signature", config.getSignature()); headers.add("god-portal-signature", config.getSignature());
headers.add("god-portal-timestamp", config.getTimestamp()); headers.add("god-portal-timestamp", config.getTimestamp());
headers.add("god-portal-request-id", requestId); headers.add("god-portal-request-id", requestId);
}); });
log.warn("[报告解读] resp={}", jsonObject); log.info("[报告解读] msgId={}, patientId={}, reportId={}, resp={}", msgId, patientId, reportId, jsonObject);
return Result.success(); return Result.success();
} }
} }

@ -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;
}
}

@ -63,7 +63,7 @@ public class MedicalAction extends BaseAction {
MedicalInfo medicalInfo; MedicalInfo medicalInfo;
switch (PEnum.toEnum(callNo)) { switch (PEnum.toEnum(callNo)) {
case REG: case REG:
Boolean isSplitTime = getBoolean("isSplitTime"); Boolean isSplitTime = getReqParamByKey("isSplitTime", Boolean.class);
Register reg = new Register().getRegParams(new RequestParams(request), true); Register reg = new Register().getRegParams(new RequestParams(request), true);
if ("*".equals(reg.getRegCode())) { if ("*".equals(reg.getRegCode())) {
@ -77,10 +77,10 @@ public class MedicalAction extends BaseAction {
break; break;
case RECIPE: case RECIPE:
String ybAttrib = getString("ybAttrib"); String ybAttrib = getReqParamByKey("ybAttrib");
String ybBZCode = getString("ybBZCode"); String ybBZCode = getReqParamByKey("ybBZCode");
String ybBZName = getString("ybBZName"); String ybBZName = getReqParamByKey("ybBZName");
String recipeJson = getString("recipeJson"); // 处方JSON集 [{ recipeId: item.id, recipeFee: item.amount }] String recipeJson = getReqParamByKey("recipeJson"); // 处方JSON集 [{ recipeId: item.id, recipeFee: item.amount }]
log.info("[医保-处方]上传明细下单 treatNum={}, ybAttrib={}, ybBZCode={}, ybBZName={}, recipeJson={}", treatNum, ybAttrib, ybBZCode, ybBZName, recipeJson); log.info("[医保-处方]上传明细下单 treatNum={}, ybAttrib={}, ybBZCode={}, ybBZName={}, recipeJson={}", treatNum, ybAttrib, ybBZCode, ybBZName, recipeJson);
if (treatNum == null || recipeJson == null) { if (treatNum == null || recipeJson == null) {
return Result.error(ResultEnum.PARAM_IS_DEFECT); return Result.error(ResultEnum.PARAM_IS_DEFECT);
@ -207,11 +207,11 @@ public class MedicalAction extends BaseAction {
familyType, familyName, familyCardNo, medicalCardInstId, medicalCardId); familyType, familyName, familyCardNo, medicalCardInstId, medicalCardId);
case RECIPE: case RECIPE:
String recipeJson = getString("recipeJson"); String recipeJson = getReqParamByKey("recipeJson");
if (recipeJson == null) { if (recipeJson == null) {
return Result.error(ResultEnum.PARAM_IS_BLANK); 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, return new MedicalService().createRxOrder(payCode, payOpenId, openid, patientId, cardNo, realName, ip,
payOrdId, payAuthNo, mdTrtId, chrgBchno, mdUserId, payOrdId, payAuthNo, mdTrtId, chrgBchno, mdUserId,
totalFee, acctFee, hifpFee, insuranceFee, cashFee, totalFee, acctFee, hifpFee, insuranceFee, cashFee,

@ -13,7 +13,7 @@ import com.ynxbd.common.dao.his.HisRecipeDao;
import com.ynxbd.common.dao.sys.SysUserDao; import com.ynxbd.common.dao.sys.SysUserDao;
import com.ynxbd.common.helper.common.*; import com.ynxbd.common.helper.common.*;
import com.ynxbd.common.helper.his.HisHelper; 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.JsonResult;
import com.ynxbd.common.result.Result; import com.ynxbd.common.result.Result;
import com.ynxbd.common.result.ResultEnum; import com.ynxbd.common.result.ResultEnum;
@ -887,7 +887,7 @@ public class PayAction extends BaseAction {
return Result.error(ResultEnum.PAY_TYPE_ERROR); 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); return Result.error(ResultEnum.SYSTEM_CONFIG_ERROR);
} }

@ -1,27 +1,26 @@
package com.ynxbd.common.action.test; package com.ynxbd.common.action.test;
import com.ynxbd.common.action.base.BaseAction; 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.bean.sms.SmsTempEnum;
import com.ynxbd.common.helper.common.Base64Helper;
import com.ynxbd.common.helper.common.DateHelper; import com.ynxbd.common.helper.common.DateHelper;
import com.ynxbd.common.helper.common.SmsHelper; import com.ynxbd.common.helper.common.SmsHelper;
import com.ynxbd.common.result.Result; import com.ynxbd.common.result.Result;
import com.ynxbd.common.result.ResultEnum; import com.ynxbd.common.result.ResultEnum;
import com.ynxbd.common.result.ServiceException; import com.ynxbd.common.result.ServiceException;
import com.ynxbd.wx.config.MessagePushConfig; import com.ynxbd.wx.config.MessagePushConfig;
import com.ynxbd.wx.config.TZReserveConfig;
import com.ynxbd.wx.config.WeChatConfig; import com.ynxbd.wx.config.WeChatConfig;
import com.ynxbd.wx.wxfactory.WxMedHelper;
import com.ynxbd.wx.wxfactory.WxPayHelper; import com.ynxbd.wx.wxfactory.WxPayHelper;
import com.ynxbd.wx.wxfactory.medical.WxMedConfig; import com.ynxbd.wx.wxfactory.medical.WxMedConfig;
import com.ynxbd.wx.wxfactory.medical.models.WxMedOrder;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace; import org.apache.struts2.convention.annotation.Namespace;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import java.util.Map;
/** /**
* @Author wsq * @Author wsq
@ -51,7 +50,7 @@ public class TestAction extends BaseAction {
// 医保退费 // 医保退费
@Action("refund_med_test") @Action("refund_med_test")
public Result refund_med_test() throws ServiceException { 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(); return Result.success();
} }
@ -126,25 +125,23 @@ public class TestAction extends BaseAction {
@Action("r_test") @Action("r_test")
public Result r_test() throws ServiceException { public Result r_test() throws ServiceException {
String url = WeChatConfig.getHttpsBaseURL() + "ali_qrcode" + "?p=123"; return Result.success();
System.out.println(url);
System.out.println();
return Result.redirect("/wx/test02/log_test");
} }
@Action("wx_push_test") @Action("wx_push_test")
public Result wx_push_test() { public Result wx_push_test() {
System.out.println("HOST_URL:" + MessagePushConfig.HOST_URL); System.out.println("HOST_URL:" + MessagePushConfig.HOST_URL);
System.out.println("[挂号]缴费通知:" + MessagePushConfig.REG_PAID_URL); System.out.println("[挂号]缴费通知:" + MessagePushConfig.REG_PAID_API);
System.out.println("[挂号]取消预约:" + MessagePushConfig.REG_CANCEL_URL); System.out.println("[挂号]取消预约:" + MessagePushConfig.REG_CANCEL_API);
System.out.println("[挂号]AI:" + MessagePushConfig.REG_AI_URL); 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(); return Result.success();
} }
// @Action("lock") // @Action("lock")
// public String lock() { // public String lock() {
// return Result.success(update()); // return Result.success(update());

@ -58,6 +58,14 @@ public enum MerchantEnum {
"", "",
WX.PAY_WAY_IN, WX.PAY_WAY_QR, WX.PAY_WAY_MICRO), 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", BCM("bcm", "【交行】", "", "BCM",
false, false,
"4", "4",
@ -66,14 +74,13 @@ public enum MerchantEnum {
"", "",
"20", "21", "22"), "20", "21", "22"),
JY("jy", "【京颐】", "", "JY",
ALI_MEDICAL("ali_medical", "【支付宝医保】", AliConfig.APP_ID, ALI.OUT_TRADE_NO_PREFIX, false,
AliMedConfig.IS_DEV, "4",
"3",
"25,26,27,28,29,30",
"ali_pay/medical_notify",
"", "",
"10", "11", "12"), "jy_pay/notify",
"",
WX.PAY_WAY_IN, WX.PAY_WAY_QR, WX.PAY_WAY_MICRO),
; ;

@ -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;
}

@ -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<String, FormBlob> files;
private Map<String, String> data;
/**
* 通用转换方法
*
* @param param key
* @param clazz 目标类型 Integer.class / Long.class / BigDecimal.class ...
* @return 转换后对象/格式错误返回null
*/
@SuppressWarnings("unchecked")
public <T> T getParamByKey(String param, Class<T> clazz) {
try {
if (clazz == null) {
return null;
}
String val = data.get(param);
if (StringUtils.isEmpty(val)) {
return null;
}
val = val.trim();
Function<String, ?> 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;
}
}
}

@ -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;
}

@ -4,6 +4,7 @@ import com.ynxbd.common.helper.common.AesHelper;
import com.ynxbd.common.helper.common.ErrorHelper; import com.ynxbd.common.helper.common.ErrorHelper;
import com.ynxbd.common.helper.common.JsonHelper; import com.ynxbd.common.helper.common.JsonHelper;
import com.ynxbd.common.result.Result; import com.ynxbd.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.apache.struts2.ActionContext; import org.apache.struts2.ActionContext;
import org.apache.struts2.ActionInvocation; import org.apache.struts2.ActionInvocation;
@ -21,6 +22,7 @@ import java.util.List;
/** /**
* 方法拦截器 * 方法拦截器
*/ */
@Slf4j
public class MethodInterceptor extends org.apache.struts2.interceptor.AbstractInterceptor { public class MethodInterceptor extends org.apache.struts2.interceptor.AbstractInterceptor {
@ -133,7 +135,7 @@ public class MethodInterceptor extends org.apache.struts2.interceptor.AbstractIn
} }
return "SUCCESS"; return "SUCCESS";
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); log.error("", e);
if (e.getMessage() == null) { if (e.getMessage() == null) {
System.out.println("异常1"); System.out.println("异常1");
Throwable cause = e.getCause(); Throwable cause = e.getCause();

@ -106,7 +106,6 @@ public class RSAHelper {
} }
/** /**
* RSA私钥解密 * RSA私钥解密
* *
@ -154,6 +153,50 @@ public class RSAHelper {
return null; 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填充) // 加密方法(PKCS#1 v1.5填充)
public static String enPKCS1Padding(String plaintext, PublicKey publicKey) throws Exception { public static String enPKCS1Padding(String plaintext, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

@ -178,7 +178,11 @@ public class SmsHelper {
* @param smsTemplate 模板参数 * @param smsTemplate 模板参数
*/ */
public static boolean sendAli(String template, String tel, String signName, SmsTemplate 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; signName = SIGN_NAME;
} }

@ -78,7 +78,7 @@ public class XBDHttpHelper {
private static String UsePost(String methodName, RequestBody requestBody) { private static String UsePost(String methodName, RequestBody requestBody) {
OkHttpClient httpClient = OkHttpHelper.creatClient(); OkHttpClient httpClient = OkHttpHelper.creatClient();
Headers.Builder headersBuilder = new Headers.Builder(); 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()) { try (Response response = httpClient.newCall(new Request.Builder().url(urlBuilder.build()).post(requestBody).headers(headersBuilder.build()).build()).execute()) {
JSONObject respJson = respFilter(response, methodName); JSONObject respJson = respFilter(response, methodName);
String code = respJson.getString("Code"); String code = respJson.getString("Code");
@ -171,7 +171,7 @@ public class XBDHttpHelper {
private static String UseGet(String methodName, Object paramDic) { private static String UseGet(String methodName, Object paramDic) {
try { try {
OkHttpClient httpClient = OkHttpHelper.creatClient(); 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); String paramJson = JSONObject.toJSONString(paramDic == null ? "" : paramDic);
log.info("[病历GET]未加密前get请求入参:[methodName:{}] {}", methodName, paramJson); log.info("[病历GET]未加密前get请求入参:[methodName:{}] {}", methodName, paramJson);

@ -11,7 +11,7 @@ import lombok.extern.slf4j.Slf4j;
* @date 2023/3/30 17:02 * @date 2023/3/30 17:02
*/ */
@Slf4j @Slf4j
public class XBDHelper { public class XbdConfigHelper {
private static final String PACS_CLOUD_URL; private static final String PACS_CLOUD_URL;
public static final String CASEBOOK_URL; public static final String CASEBOOK_URL;
public static final String PEIS_URL; public static final String PEIS_URL;
@ -19,19 +19,16 @@ public class XBDHelper {
public static OutTeamDao outTeamDao; public static OutTeamDao outTeamDao;
static { 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); outTeamDao = new OutTeamDao(PACS_CLOUD_URL);
} }
} }

@ -1,5 +1,6 @@
package com.ynxbd.common.service; package com.ynxbd.common.service;
import cn.hutool.core.util.HexUtil;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.ynxbd.common.action.pay.PEnum; 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.bean.pay.PEISReserve;
import com.ynxbd.common.dao.peis.PEISDao; import com.ynxbd.common.dao.peis.PEISDao;
import com.ynxbd.common.helper.common.JsonHelper; 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.http.OkHttpHelper;
import com.ynxbd.common.helper.xbd.XBDHelper; import com.ynxbd.common.helper.xbd.XbdConfigHelper;
import com.ynxbd.common.result.*; import com.ynxbd.common.result.*;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import okhttp3.FormBody; import okhttp3.FormBody;
@ -18,6 +20,7 @@ import okhttp3.RequestBody;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.Date; import java.util.Date;
/** /**
@ -102,7 +105,7 @@ public class PEISService {
return; 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("orderNo", noticeOrderNo);
params.put("payStatus", "OK"); params.put("payStatus", "OK");
params.put("payFailReason", ""); params.put("payFailReason", "");
@ -138,7 +141,7 @@ public class PEISService {
* @return bean * @return bean
*/ */
public PEISOrderInfo queryPEISOrderByNoticeOrderNo(String noticeOrderNo) throws ServiceException { 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); params.put("orderNo", noticeOrderNo);
}); });
log.info("[体检预约]订单查询 {}", JsonHelper.toJsonString(jsonResult)); log.info("[体检预约]订单查询 {}", JsonHelper.toJsonString(jsonResult));
@ -224,7 +227,7 @@ public class PEISService {
* @return bool * @return bool
*/ */
public boolean cancelPEISReserve(String noticeOrderNo, String refundStatus, String refundFailReason) throws ServiceException { 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("orderNo", noticeOrderNo);
params.put("refundStatus", refundStatus); // 退费状态(成功:OK,失败:FAIL) params.put("refundStatus", refundStatus); // 退费状态(成功:OK,失败:FAIL)
params.put("refundFailReason", refundFailReason); params.put("refundFailReason", refundFailReason);
@ -238,19 +241,28 @@ public class PEISService {
return true; 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(). RequestBody formBody = new FormBody.Builder().
add("enIdCard", cardNo) add("enIdCard", enIdCard)
.add("begDate", begDate) .add("begDate", begDate)
.add("endDate", endDate) .add("endDate", endDate)
.build(); .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)) { if (ObjectUtils.isEmpty(result)) {
throw new ServiceException("请求失败"); throw new ServiceException("[体检]请求异常");
} }
JSONObject jsonResult = JsonHelper.parseObject(result); JSONObject jsonResult = JsonHelper.parseObject(result);
if (jsonResult == null) { if (jsonResult == null) {
throw new ServiceException("请求失败"); throw new ServiceException("[体检]请求解析失败");
} }
String code = jsonResult.getString("code"); String code = jsonResult.getString("code");
String message = jsonResult.getString("message"); String message = jsonResult.getString("message");

@ -3,6 +3,7 @@ package com.ynxbd.common.service;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.ynxbd.ali.helper.AliHelper; import com.ynxbd.ali.helper.AliHelper;
import com.ynxbd.bcm.config.BCMHelper; import com.ynxbd.bcm.config.BCMHelper;
import com.ynxbd.common.action.pay.JYPayAction;
import com.ynxbd.common.action.pay.PEnum; import com.ynxbd.common.action.pay.PEnum;
import com.ynxbd.common.bean.enums.MerchantEnum; import com.ynxbd.common.bean.enums.MerchantEnum;
import com.ynxbd.common.bean.pay.*; 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.ResultEnum;
import com.ynxbd.common.result.ServiceException; import com.ynxbd.common.result.ServiceException;
import com.ynxbd.common.service.cache.PayCache; import com.ynxbd.common.service.cache.PayCache;
import com.ynxbd.jy.helper.JYPayHelper;
import com.ynxbd.wx.wxfactory.WxMedHelper; import com.ynxbd.wx.wxfactory.WxMedHelper;
import com.ynxbd.wx.wxfactory.WxPayHelper; import com.ynxbd.wx.wxfactory.WxPayHelper;
import com.ynxbd.wx.wxfactory.payment.jsapi.models.WxPayNotify; import com.ynxbd.wx.wxfactory.payment.jsapi.models.WxPayNotify;
@ -551,9 +553,12 @@ public class PayService {
} else if (MerchantEnum.ALI.equals(merchantEnum)) { // 支付宝下单 } else if (MerchantEnum.ALI.equals(merchantEnum)) { // 支付宝下单
return AliHelper.createOrder(merchantEnum, title, outTradeNo, totalFee, notifyType, payOpenId); 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); 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; return null;
} }

@ -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;
}
}

@ -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;
}

@ -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;
}
}

@ -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;
}
}

@ -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;
}
}

@ -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("[京颐-支付]配置文件读取失败");
}
}
}

@ -2,17 +2,24 @@ package com.ynxbd.jy.helper;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.ynxbd.common.bean.enums.MerchantEnum; 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.ErrorHelper;
import com.ynxbd.common.helper.common.JsonHelper; 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 com.ynxbd.wx.config.WeChatConfig;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils; 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.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 @Slf4j
@ -31,70 +38,284 @@ public class JYPayHelper {
* @param msgOpenId 用于推送的openId * @param msgOpenId 用于推送的openId
* @return 成功返回 json, 否则返回null * @return 成功返回 json, 否则返回null
*/ */
public static JSONObject createOrder(MerchantEnum merchantEnum, String title, String totalFee, String outTradeNo, String notifyType, String ip, String payOpenId, String msgOpenId) { public static JSONObject createOrder(MerchantEnum merchantEnum, String title, String totalFee, String outTradeNo, String notifyType, String ip, String payOpenId, String msgOpenId, ReqOrder reqOrder) {
// try { try {
// if (ObjectUtils.isEmpty(payOpenId) || ObjectUtils.isEmpty(outTradeNo) if (ObjectUtils.isEmpty(payOpenId) || ObjectUtils.isEmpty(outTradeNo)
// || merchantEnum == null || totalFee == null || notifyType == null) { || merchantEnum == null || totalFee == null || notifyType == null) {
// log.info("【京硕】下单参数缺失"); log.info("【京硕】下单参数缺失");
// return null; return null;
// } }
//
// String cents; String cents;
// try { try {
// cents = new BigDecimal(totalFee).movePointRight(2).toString(); // 金额转换=>单位分 cents = new BigDecimal(totalFee).movePointRight(2).toString(); // 金额转换=>单位分
// } catch (Exception e) { } catch (Exception e) {
// ErrorHelper.println(e); ErrorHelper.println(e);
// log.info("【京硕】统一下单金额转换异常"); log.info("【京硕】下单金额转换异常");
// return null; return null;
// } }
//
// String appId = merchantEnum.APP_ID; log.info("【京硕】下单 {},{},{},{},{}", title, outTradeNo, totalFee, ip, merchantEnum.NOTIFY_URL);
// String mchId = WeChatConfig.MCH_ID;
// String mchKey = WeChatConfig.MCH_KEY; JYOrder jyOrder = reqOrder.jyOrder;
// String nonce = UUID.randomUUID().toString().replace("-", "");
// Map<String, String> req = new HashMap<>();
// Unifiedorder unifiedorder = new Unifiedorder(); req.put("openId", payOpenId);
// unifiedorder.setAppid(appId); req.put("hospitalId", JYPayConfig.HOSP_ID); // 医院ID
// unifiedorder.setMch_id(mchId); req.put("applicationId", JYPayConfig.APPLICATION_ID);
// unifiedorder.setNonce_str(nonce); req.put("merchantId", JYPayConfig.MERCHANT_ID);
// unifiedorder.setOpenid(payOpenId); req.put("merOrderNum", outTradeNo); // 商户订单号
// unifiedorder.setOut_trade_no(outTradeNo); req.put("hisOrderNum", null); // HIS订单号:可以为发票号[该接口若不传,在业务完成后调用2.1.6接口]
// unifiedorder.setBody(title); req.put("hisTransNum", null); // HIS流水号:可以为发票号[该接口若不传,在业务完成后调用2.1.6接口]
// // 金额
// unifiedorder.setTotal_fee(cents); // 金额分 req.put("orderAmt", cents); // 交易金额:只接收整数,单位:分,例如100表示壹圆整;支付宝医保支付传总金额
// unifiedorder.setSpbill_create_ip(ip);
// unifiedorder.setNotify_url(WeChatConfig.getBaseURL() + merchantEnum.NOTIFY_URL); req.put("orderType", jyOrder.orderTypeEnum.CODE); // 如:001:挂号费 002:医药费;
// unifiedorder.setTrade_type("JSAPI"); req.put("backURL", WeChatConfig.getBaseURL() + merchantEnum.NOTIFY_URL); // 商户异步回调地址:后台发起异步回调地址, 扫码枪支付方式无需回调的可以不
// // 额外参数 // params.put("backParamsType", "key-value"); // 商户异步回调入参格式:后台发起异步回调时参数格式,取值有:key-value和json,默认值是key-value。
// unifiedorder.setAttach(notifyType); 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接口再次更新
// log.info("【京硕】统一下单 {},{},{},{},{},{},{},{}", appId, mchId, nonce, title, outTradeNo, totalFee, ip, merchantEnum.NOTIFY_URL); 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接口再次更新
// UnifiedorderResult unifiedorderResult = PayMchAPI.payUnifiedorder(unifiedorder, mchKey); req.put("patientIdNo", reqOrder.getPatientTel()); // 微信医保支付必传。其余支付方式若该接口若不传,需要调用2.1.6接口再次更新
// log.info("【京硕】统一下单返回:{}", JsonHelper.toJsonString(unifiedorderResult)); req.put("patientPhoneNumber", reqOrder.getPatientTel()); // 综合支付对应用权限控制是否必传 最大不超过16位 该接口若不传,需要调用2.1.6接口再次更新
// if (unifiedorderResult == null) { req.put("patientId", reqOrder.getPatientId()); // 患者ID:综合支付对应用权限控制是否必传 最大不超过32位 该接口若不传,需要调用2.1.6接口再次更新
// log.info("【京硕】统一下单失败"); req.put("patientCardNo", reqOrder.getPatientId()); // 患者卡号:综合支付对应用权限控制是否必传 最大不超过32位该接口若不传,需要调用2.1.6接口再次更新
// return null; 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(); // params.put("allowFeeChange", "0"); // 是否允许预结算费用发生变化:0:不允许;1:允许 当医保局返回的预结算金额与医院上传的金额不一致时,此字段为0则直接报错,为1则以医保局金额为准
// // 下单是否成功 // params.put("spbillCreateIp", reqOrder.getIp()); // 用户端ip
// Boolean sign_status = unifiedorderResult.getSign_status(); // params.put("returnUrl", reqOrder.getReturnUrl()); // 调用方可以在链接中加上支付单号,回跳后查询调用方订单状态,如果订单已支付则成功, 如果订单未支付则进行查单操作确认订单结果。不论成功或者失败均会回跳
// if (!SUCCESS.equals(result_code) || sign_status == null || !sign_status) { // params.put("insurancePayType", jyOrder.toInsurancePayType()); // 微信医保支付方式:1:现金;2:医保;3:现金+医保
// log.info("【京硕】统一下单返回异常信息:sign_status={}, err_code=[ {} ], err_code_des=[ {} ]", sign_status, unifiedorderResult.getErr_code(), unifiedorderResult.getErr_code_des()); // params.put("consumeType", jyOrder.toConsumeType()); // 医保部分扣费类型:0:统筹+个账;1:个账;2:统筹。默认为0
// return null; // params.put("userCardType", "1"); // 1 居民身份证
// } // params.put("isDept", "4"); // 医保标识:is_dept=4 医保电子凭证支付;
// String json = weixin.popular.util.PayUtil.generateMchPayJsRequestJson(unifiedorderResult.getPrepay_id(), appId, mchKey); // params.put("serialNo", reqOrder.getSerialNo()); // 医院HIS系统订单号
// if (json != null) { // params.put("requestContent", reqOrder.getRequestContent()); // 参考医保结构体(医疗机构透传医保) 示例: {"payAuthNo":"AUTH****","payOrdId":"ORD****","setlLatlnt":"118.096435,24.485407"} payAuthNo:授权码 payOrdId:对应处方上传的出参单号 setlLatlnt:用户地理定位信息, 经纬度信息,如“118.096435,24.485407”。未获取到用户定位时,传“0,0”。
// return JsonHelper.parseObject(json); //// 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)
// }
// } catch (Exception e) { String signValue = createSign(req);
// log.error("【京硕】统一下单异常信息:{}", e.getMessage()); if (signValue == null) {
// ErrorHelper.println(e); return 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; 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<String, String> 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<String, String> 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<String, String> 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<String, String> 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());
}
} }

@ -28,35 +28,36 @@ public class MessagePushConfig {
*/ */
public static final String HOST_URL; 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 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 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 boolean REG_CANCEL_IS_ENABLE;
public static final String REG_CANCEL_URL; public static final String REG_CANCEL_API;
// [挂号]AI // [挂号]AI
public static final String REG_AI_URL;
public static final boolean REG_AI_IS_ENABLE; 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 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 boolean OBS_DOCUMENT_IS_ENABLE;
public static final String OBS_DOCUMENT_URL; public static final String OBS_DOCUMENT_API;
static { static {
XmlConfigHelper config = new XmlConfigHelper().read("wx-msg-push.xml"); 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)) { if (ObjectUtils.isEmpty(HOST_URL)) {
log.error("【消息推送】配置文件wx-msg-push.xml读取失败"); log.error("【消息推送】配置文件wx-msg-push.xml读取失败");
} }
@ -64,32 +65,32 @@ public class MessagePushConfig {
// [挂号]导航推送 // [挂号]导航推送
XmlConfigHelper regNavigateConfig = config.getConfigNode("reg_navigate"); XmlConfigHelper regNavigateConfig = config.getConfigNode("reg_navigate");
REG_NAVIGATE_IS_ENABLE = regNavigateConfig.getBoolean("is_enable", false); 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"); XmlConfigHelper regPaidConfig = config.getConfigNode("reg_paid");
REG_PAID_IS_ENABLE = regPaidConfig.getBoolean("is_enable", false); 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"); XmlConfigHelper regCancelConfig = config.getConfigNode("reg_cancel");
REG_CANCEL_IS_ENABLE = regCancelConfig.getBoolean("is_enable", false); 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 // [挂号]AI
XmlConfigHelper regAIConfig = config.getConfigNode("reg_ai"); XmlConfigHelper regAIConfig = config.getConfigNode("reg_ai");
REG_AI_IS_ENABLE = regAIConfig.getBoolean("is_enable", false); 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"); XmlConfigHelper rxPaidConfig = config.getConfigNode("rx_paid");
RX_PAID_IS_ENABLE = rxPaidConfig.getBoolean("is_enable", false); 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"); XmlConfigHelper obsDocumentConfig = config.getConfigNode("obs_document");
OBS_DOCUMENT_IS_ENABLE = obsDocumentConfig.getBoolean("is_enable", false); 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) { public static void regNavigatePush(MerchantEnum merchantEnum, Register reg) {
try { 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; return;
} }
@ -112,14 +113,14 @@ public class MessagePushConfig {
String doctName = reg.getDoctName(); String doctName = reg.getDoctName();
String deptName = reg.getDeptName(); String deptName = reg.getDeptName();
String deptCode = reg.getDeptCode(); String deptCode = reg.getDeptCode();
if (openid == null || patientId == null) { if (ObjectUtils.isEmpty(openid) || ObjectUtils.isEmpty(patientId)) {
log.warn("[推送]挂号导航通知失败,参数缺失~openid={}, patientId={}", openid, patientId); log.warn("[推送]挂号导航通知失败,参数缺失 openid={}, patientId={}", openid, patientId);
return; return;
} }
Patient patient = new PatientDao().selectByOpenidAndEPId(openid, patientId); Patient patient = new PatientDao().selectByOpenidAndEPId(openid, patientId);
if (patient == null) { if (patient == null) {
log.warn("[推送]挂号导航通知失败,患者信息不存在~"); log.warn("[推送]挂号导航通知失败,未找到患者信息");
return; return;
} }
@ -127,7 +128,7 @@ public class MessagePushConfig {
String time = (ObjectUtils.isEmpty(begTime) || ObjectUtils.isEmpty(endTime)) ? "" : (" " + begTime + "-" + endTime); 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("patientName", patient.getName() + " ID:" + patientId);
params.put("content", "就诊时间:" + regDate + time); params.put("content", "就诊时间:" + regDate + time);
params.put("deptName", deptName); params.put("deptName", deptName);
@ -145,8 +146,7 @@ public class MessagePushConfig {
*/ */
public static void regPush(MerchantEnum merchantEnum, Register reg) { public static void regPush(MerchantEnum merchantEnum, Register reg) {
try { try {
if (!merchantEnum.equals(MerchantEnum.WX) if (!merchantEnum.equals(MerchantEnum.WX) || !REG_PAID_IS_ENABLE || reg == null || ObjectUtils.isEmpty(REG_PAID_API)) {
|| !REG_PAID_IS_ENABLE || reg == null || ObjectUtils.isEmpty(REG_PAID_URL)) {
return; return;
} }
@ -174,7 +174,7 @@ public class MessagePushConfig {
String time = (ObjectUtils.isEmpty(begTime) || ObjectUtils.isEmpty(endTime)) ? "" : (" " + begTime + "-" + endTime); 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("openId", DesEncryptHelper.enCode(openid));
params.put("patientName", patient.getName() + " ID:" + patientId); params.put("patientName", patient.getName() + " ID:" + patientId);
params.put("deptName", deptName); params.put("deptName", deptName);
@ -196,7 +196,7 @@ public class MessagePushConfig {
*/ */
public static void regAI(MerchantEnum merchantEnum, Register reg) { public static void regAI(MerchantEnum merchantEnum, Register reg) {
try { 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; return;
} }
@ -219,7 +219,7 @@ public class MessagePushConfig {
.add("url", url) .add("url", url)
.add("organizeName", ORGANIZENAME) .add("organizeName", ORGANIZENAME)
.build(); .build();
OkHttpHelper.post(REG_AI_URL, requestBody); OkHttpHelper.post(REG_AI_API, requestBody);
} catch (Exception e) { } catch (Exception e) {
log.warn("[推送]AI智能问诊推送通知错误-{}", e.getMessage()); log.warn("[推送]AI智能问诊推送通知错误-{}", e.getMessage());
} }
@ -246,7 +246,7 @@ public class MessagePushConfig {
.add("url", url) .add("url", url)
.add("organizeName", ORGANIZENAME) .add("organizeName", ORGANIZENAME)
.build(); .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) { public static void regAIReport(String patientId, String outTradeNo, String openId) {
try { try {
if (!REG_AI_IS_ENABLE || ObjectUtils.isEmpty(REG_AI_URL)) { if (!REG_AI_IS_ENABLE || ObjectUtils.isEmpty(REG_AI_API)) {
return; return;
} }
log.info("[推送]AI问诊报告推送..."); log.info("[推送]AI问诊报告推送...");
@ -277,7 +277,7 @@ public class MessagePushConfig {
.add("url", url) .add("url", url)
.add("organizeName", ORGANIZENAME) .add("organizeName", ORGANIZENAME)
.build(); .build();
OkHttpHelper.post(REG_AI_URL, requestBody); OkHttpHelper.post(REG_AI_API, requestBody);
} catch (Exception e) { } catch (Exception e) {
log.warn("[推送]AI问诊报告推送通知错误-{}", e.getMessage()); log.warn("[推送]AI问诊报告推送通知错误-{}", e.getMessage());
} }
@ -293,7 +293,7 @@ public class MessagePushConfig {
public static void regObsDocument(MerchantEnum merchantEnum, Register reg) { public static void regObsDocument(MerchantEnum merchantEnum, Register reg) {
try { try {
if (!merchantEnum.equals(MerchantEnum.WX) if (!merchantEnum.equals(MerchantEnum.WX)
|| reg == null || ObjectUtils.isEmpty(OBS_DOCUMENT_URL)) { || reg == null || ObjectUtils.isEmpty(OBS_DOCUMENT_API)) {
return; return;
} }
@ -311,7 +311,7 @@ public class MessagePushConfig {
.add("organizeName", ORGANIZENAME) .add("organizeName", ORGANIZENAME)
.add("buttonName", "进入产科建档系统") .add("buttonName", "进入产科建档系统")
.build(); .build();
OkHttpHelper.post(OBS_DOCUMENT_URL, requestBody); OkHttpHelper.post(OBS_DOCUMENT_API, requestBody);
} catch (Exception e) { } catch (Exception e) {
log.warn("[推送]产科建档推送通知错误-{}", e.getMessage()); log.warn("[推送]产科建档推送通知错误-{}", e.getMessage());
} }
@ -324,7 +324,7 @@ public class MessagePushConfig {
public static void regCancelPush(MerchantEnum merchantEnum, Register reg) { public static void regCancelPush(MerchantEnum merchantEnum, Register reg) {
try { try {
if (!merchantEnum.equals(MerchantEnum.WX) 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; return;
} }
log.info("[推送]取消预约..."); log.info("[推送]取消预约...");
@ -350,7 +350,7 @@ public class MessagePushConfig {
String time = (ObjectUtils.isEmpty(begTime) || ObjectUtils.isEmpty(endTime)) ? "" : (" " + begTime + "-" + endTime); 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("openId", DesEncryptHelper.enCode(openid));
params.put("patientName", patient.getName() + " ID:" + patientId); params.put("patientName", patient.getName() + " ID:" + patientId);
params.put("deptName", deptName); params.put("deptName", deptName);
@ -370,7 +370,7 @@ public class MessagePushConfig {
*/ */
public static void recipePush(List<Recipe> recipeList, String treatNum, String patientId, String openid, String tip) { public static void recipePush(List<Recipe> recipeList, String treatNum, String patientId, String openid, String tip) {
try { try {
if (!RX_PAID_IS_ENABLE || ObjectUtils.isEmpty(RX_PAID_URL)) { if (!RX_PAID_IS_ENABLE || ObjectUtils.isEmpty(RX_PAID_API)) {
return; return;
} }
@ -394,7 +394,7 @@ public class MessagePushConfig {
return; return;
} }
OkHttpHelper.getAsync(RX_PAID_URL, params -> { OkHttpHelper.getAsync(RX_PAID_API, params -> {
params.put("openId", DesEncryptHelper.enCode(openid)); params.put("openId", DesEncryptHelper.enCode(openid));
params.put("patientName", patient.getName() + " ID:" + patientId); params.put("patientName", patient.getName() + " ID:" + patientId);
params.put("content", tip); params.put("content", tip);

@ -91,6 +91,7 @@ public class WXPayUtility {
.create(); .create();
private static final char[] SYMBOLS = private static final char[] SYMBOLS =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
private static final SecureRandom random = new SecureRandom(); private static final SecureRandom random = new SecureRandom();
/** /**

@ -1,18 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<config> <config>
<!-- 报告解读 --> <report name="报告解读">
<report>
<is_dev></is_dev> <is_dev></is_dev>
<partner_id></partner_id> <partner_id></partner_id>
<token></token> <token></token>
</report> </report>
<!-- 智能导诊 --> <ai_guidance name="智能导诊">
<ai_guidance>
<!-- 是否开启 --> <!-- 是否开启 -->
<is_enable>true</is_enable> <is_enable>true</is_enable>
<!-- 是否为分时段挂号(默认true) --> <!-- 是否为分时段挂号(默认true) -->
<is_split_time_reg>true</is_split_time_reg> <is_split_time_reg>false</is_split_time_reg>
<!-- 合作方ID --> <!-- 合作方ID -->
<partner_id>100000637</partner_id> <partner_id>100000637</partner_id>
<!-- 密钥token --> <!-- 密钥token -->
@ -25,6 +23,6 @@
<hosp_intro name="医院介绍">暂无介绍</hosp_intro> <hosp_intro name="医院介绍">暂无介绍</hosp_intro>
<hosp_level name="医院等级">二级甲等</hosp_level> <hosp_level name="医院等级">二级甲等</hosp_level>
<hosp_address name="医院地址">暂无地址</hosp_address> <hosp_address name="医院地址">暂无地址</hosp_address>
<hosp_tel name="联系方式">0871-67798120</hosp_tel> <hosp_tel name="联系方式"></hosp_tel>
</ai_guidance> </ai_guidance>
</config> </config>

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<config> <config>
<report name="报告解读"> <report name="报告解读">
<is_dev mame="是否为测试环境">true</is_dev>
<hosp_id name="医院ID">31737</hosp_id> <hosp_id name="医院ID">31737</hosp_id>
<partner_id name="合作方ID">20009251</partner_id> <partner_id name="合作方ID">20009250</partner_id>
<token name="密钥token">3bee9edc0a2f41ac911b9b714c854cad</token> <token name="密钥token">c4a39049d4b1c29ffaa9a312687fdcfc</token>
<!-- 测试环境 --> <!-- 测试环境 -->
<dev_partner_id>20009250</dev_partner_id> <dev_partner_id>20009250</dev_partner_id>
<dev_token>3bee9edc0a2f41ac911b9b714c854cad</dev_token> <dev_token>3bee9edc0a2f41ac911b9b714c854cad</dev_token>
@ -22,9 +21,9 @@
<!-- AI版:电子健康卡AppId(管理>开发商接入) | 旧版:合作方ID(腾讯提供)--> <!-- AI版:电子健康卡AppId(管理>开发商接入) | 旧版:合作方ID(腾讯提供)-->
<partner_id>34edf7cd14e646ae9c1bbca791b7b685</partner_id> <partner_id>34edf7cd14e646ae9c1bbca791b7b685</partner_id>
<!-- AI版:电子健康卡AppSecret(管理>开发商接入) | 旧版:Token(腾讯提供)--> <!-- AI版:电子健康卡AppSecret(管理>开发商接入) | 旧版:Token(腾讯提供)-->
<partner_secret >b26188e6142d43b88f01453853d52a0a</partner_secret> <partner_secret>b26188e6142d43b88f01453853d52a0a</partner_secret>
<!-- --> <!-- 测试密钥token -->
<dev_partner_secret>b26188e6142d43b88f01453853d52a0a</dev_partner_secret> <dev_partner_secret name="测试token">b26188e6142d43b88f01453853d52a0a</dev_partner_secret>
<branch_id>800002723</branch_id> <branch_id>800002723</branch_id>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<config>
<pay name="支付配置">
<url>http://127.0.0.1</url>
<application_id name="应用编号">1</application_id>
<merchant_id name="应用商户编号">1</merchant_id>
<public_key>MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD1eiOktZm8bUwjHA2bFlrULg9v/VAmBfUWb8/1+xyZH5eSa7itvAG2Kdzv7L59nRIspXyO6ZW+gGmofnX8CqI5ofLrpissgoqZadNfz5v/k2Q78YTBM8BEMwkrPwOsbFX62poPSKr4kZRHgMADJkgS6AhsaDNBLdH6uRE8R0H6lQIDAQAB</public_key>
<private_key>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==</private_key>
</pay>
</config>

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<config>
</config>

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<config> <config>
<xbd> <xbd>
<peis_url name="体检预约"></peis_url> <peis_url name="体检预约">http://200.200.200.71:5050/peisReserve</peis_url>
<pacs_cloud_url name="云胶片">http://192.168.0.183:3307/wx3307</pacs_cloud_url> <pacs_cloud_url name="云胶片">http://192.168.0.183:3307/wx3307</pacs_cloud_url>
<casebook_url name="病历复印">http://192.168.0.183:3307/wx3307</casebook_url> <casebook_url name="病历复印"></casebook_url>
</xbd> </xbd>
<rm_lis name="瑞美LIS"> <rm_lis name="瑞美LIS">

Loading…
Cancel
Save