1.新增金额转换异常处理

2、新增问诊处方退费业务逻辑和功能开关
3、支付相关日志统一调整
master_pay
王绍全 6 days ago
parent a31e168153
commit e3c066143e
  1. 54
      src/main/java/com/ynxbd/ali/helper/AliHelper.java
  2. 32
      src/main/java/com/ynxbd/bcm/config/BCMHelper.java
  3. 4
      src/main/java/com/ynxbd/common/TestA.java
  4. 2
      src/main/java/com/ynxbd/common/action/pay/AliPayAction.java
  5. 2
      src/main/java/com/ynxbd/common/action/pay/BcmPayAction.java
  6. 2
      src/main/java/com/ynxbd/common/action/pay/JYPayAction.java
  7. 58
      src/main/java/com/ynxbd/common/action/pay/PayAction.java
  8. 2
      src/main/java/com/ynxbd/common/action/pay/ThirdPartyPayAction.java
  9. 18
      src/main/java/com/ynxbd/common/action/xk/XKAction.java
  10. 7
      src/main/java/com/ynxbd/common/bean/pay/Order.java
  11. 2
      src/main/java/com/ynxbd/common/bean/xk/XKCostDetail.java
  12. 8
      src/main/java/com/ynxbd/common/dao/RxDao.java
  13. 2
      src/main/java/com/ynxbd/common/dao/his/HisXKDao.java
  14. 4
      src/main/java/com/ynxbd/common/his/HisConfig.java
  15. 5
      src/main/java/com/ynxbd/common/his/HisFactory.java
  16. 20
      src/main/java/com/ynxbd/common/service/MicroService.java
  17. 6
      src/main/java/com/ynxbd/common/service/PEISService.java
  18. 2
      src/main/java/com/ynxbd/common/service/PayMedRecordService.java
  19. 4
      src/main/java/com/ynxbd/common/service/PayService.java
  20. 2
      src/main/java/com/ynxbd/common/service/RegService.java
  21. 80
      src/main/java/com/ynxbd/common/service/RxService.java
  22. 33
      src/main/java/com/ynxbd/jy/helper/JYPayHelper.java
  23. 2
      src/main/java/com/ynxbd/wx/servlet/oldpay/PayNotifyServlet.java
  24. 109
      src/main/java/com/ynxbd/wx/wxfactory/WxPayHelper.java
  25. 2
      src/main/java/com/ynxbd/wx/wxfactory/medical/Client.java
  26. 8
      src/main/java/com/ynxbd/wx/wxfactory/medins/Client.java
  27. 2
      src/main/java/com/ynxbd/wx/wxfactory/payment/jsapi/Client.java
  28. 2
      src/main/resources/webservice.xml

@ -130,7 +130,7 @@ public class AliHelper {
user.setErrMsg(response.getMsg() + "|" + response.getSubMsg());
}
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【支付宝】获取用户信息-异常:", e);
}
return user;
}
@ -160,7 +160,7 @@ public class AliHelper {
log.info("[支付宝]认证失败,原因:{}, {}", response.msg, response.subMsg);
}
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【支付宝】获取授权访问令牌-异常:", e);
}
return user;
}
@ -199,7 +199,7 @@ public class AliHelper {
log.info("【支付宝】刷新授权访问令牌 调用失败,原因:{}, {}", response.msg, response.subMsg);
}
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【支付宝】刷新授权访问令牌-异常:", e);
}
return null;
}
@ -214,15 +214,15 @@ public class AliHelper {
* @param buyerId 买家的支付宝唯一用户号(2088开头的16位纯数字)
* @param notifyType 回调类型
*/
public static JSONObject createOrder(MerchantEnum merchantEnum, String subject, String outTradeNo, String totalAmount, String notifyType, String buyerId) {
log.info("【支付宝】创建交易 subject={}, outTradeNo={}, totalAmount={}, buyerId={}", subject, outTradeNo, totalAmount, buyerId);
public static JSONObject createOrder(MerchantEnum merchantEnum, String subject, String outTradeNo, BigDecimal totalAmount, String notifyType, String buyerId) {
log.info("【支付宝】创建预支付交易订单 subject={}, outTradeNo={}, totalAmount={}, buyerId={}", subject, outTradeNo, totalAmount, buyerId);
if (ObjectUtils.isEmpty(subject)
|| ObjectUtils.isEmpty(outTradeNo)
|| ObjectUtils.isEmpty(totalAmount)
|| ObjectUtils.isEmpty(buyerId)
|| ObjectUtils.isEmpty(notifyType)
|| merchantEnum == null) {
log.info("【支付宝】创建交易,参数缺失");
log.error("【支付宝】创建预支付交易订单-失败:参数缺失");
return null;
}
@ -236,10 +236,9 @@ public class AliHelper {
// 调用asyncNotify扩展方法,可以为每次API调用,设置独立的异步通知地址 此处设置的异步通知地址的优先级高于全局Config中配置的异步通知地址
.asyncNotify(WeChatConfig.getHttpsBaseURL() + merchantEnum.getNotifyUrl(outTradeNo, notifyType))
.optional("extend_params", extend_params)
.create(subject, outTradeNo, totalAmount, buyerId);
log.info("【支付宝】订单信息:{}", JsonHelper.toJsonString(response));
.create(subject, outTradeNo, totalAmount.toString(), buyerId);
log.info("【支付宝】创建预支付交易订单[{}]-响应数据:{}", outTradeNo, JsonHelper.toJsonString(response));
if (ResponseChecker.success(response)) {
JSONObject jsonObj = new JSONObject();
jsonObj.put("tradeNo", response.getTradeNo());
@ -248,10 +247,10 @@ public class AliHelper {
return jsonObj;
} else {
log.info("【支付宝】创建交易调用失败,原因:{}, {}", response.getMsg(), response.getSubMsg());
log.error("【支付宝】创建预支付交易订单[{}]-失败:{}, {}", outTradeNo, response.getMsg(), response.getSubMsg());
}
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【支付宝】创建预支付交易订单-异常:", e);
}
return null;
}
@ -298,9 +297,8 @@ public class AliHelper {
order.setOutTradeNo(response.outTradeNo);
order.setBizTradeNo(response.outTradeNo);
} catch (Exception e) {
log.info("【支付宝】[盒子支付]异常 {}", e.getMessage());
log.error("【支付宝】[盒子支付]-异常:", e);
order.setErrorMsg("网络异常或当前不支持支付宝");
ErrorHelper.println(e);
}
return order;
}
@ -357,8 +355,8 @@ public class AliHelper {
if (e.getMessage() != null && e.getMessage().contains("验签失败")) {
order.setErrorMsg("[支付宝]订单不存在或验签失败");
} else {
order.setErrorMsg("[支付宝]查询订单发生异常");
ErrorHelper.println(e);
log.error("【支付宝】查询订单-异常:", e);
order.setErrorMsg("[支付宝]查询订单-异常");
}
}
return order;
@ -405,10 +403,10 @@ public class AliHelper {
return bill;
} else {
throw new ServiceException("【支付宝】查询交易调用失败,原因:" + response.msg + ", " + response.subMsg);
throw new ServiceException("【支付宝】交易退款查询-失败-原因:" + response.msg + ", " + response.subMsg);
}
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【支付宝】交易退款查询-异常:", e);
throw new ServiceException(ResultEnum.INTERFACE_ALI_INVOKE_ERROR);
}
}
@ -515,7 +513,7 @@ public class AliHelper {
orderRefund.setErrorMsg("【支付宝】网络异常或当前不支持支付宝");
String refundResult = orderRefund.getRefundResult();
orderRefund.setRefundResult(StringUtils.isEmpty(refundResult) ? orderRefund.getErrorMsg() : refundResult);
ErrorHelper.println(e);
log.error("【支付宝】交易退款-异常:", e);
}
return orderRefund;
}
@ -542,7 +540,7 @@ public class AliHelper {
log.info("【支付宝】关闭交易调用失败,原因:{}, {}", response.msg, response.subMsg);
}
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【支付宝】关闭交易-异常:", e);
return false;
}
return true;
@ -565,10 +563,10 @@ public class AliHelper {
if (ResponseChecker.success(response)) {
return true;
} else {
log.info("【支付宝】撤销交易调用失败,原因:{}, {}", response.msg, response.subMsg);
log.error("【支付宝】撤销交易-失败,原因:{}, {}", response.msg, response.subMsg);
}
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【支付宝】撤销交易-异常:", e);
return false;
}
return true;
@ -594,13 +592,13 @@ public class AliHelper {
if (ResponseChecker.success(response)) {
return response.getBillDownloadUrl();
} else {
log.info("【支付宝】查询对账单下载地址调用失败,原因:{}, {}", response.msg, response.subMsg);
log.info("【支付宝】查询对账单下载地址-失败,原因:{}, {}", response.msg, response.subMsg);
}
} catch (Exception e) {
if (e.getMessage().contains("验签失败")) { // 没有交易
return "";
}
ErrorHelper.println(e);
log.error("【支付宝】查询对账单下载地址-异常:", e);
return null;
}
return null;
@ -621,7 +619,7 @@ public class AliHelper {
return flag;
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【支付宝】异步通知验签-异常:", e);
return false;
}
}
@ -641,17 +639,17 @@ public class AliHelper {
* @return
*/
public static boolean templateMessage(String toUserId, String fromId, String userTemplateId, String page, String data) {
log.info("【支付宝】模板消息推送");
System.out.println("【支付宝】模板消息推送...");
try {
AliConfig.initConfig();
AlipayOpenAppMiniTemplatemessageSendResponse response = Factory.Marketing.TemplateMessage().send(toUserId, fromId, null, null, null);
if (ResponseChecker.success(response)) {
return true;
} else {
log.info("【支付宝】模板消息推送失败,原因:{}, {}", response.msg, response.subMsg);
log.info("【支付宝】模板消息推送-失败,原因:{}, {}", response.msg, response.subMsg);
}
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【支付宝】模板消息推送-异常:", e);
return false;
}
return false;
@ -696,7 +694,7 @@ public class AliHelper {
}
}
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【支付宝】异常:", e);
throw new ServiceException(ResultEnum.INTERFACE_ALI_INVOKE_ERROR);
}
}

@ -8,7 +8,6 @@ import com.ynxbd.common.bean.enums.MerchantEnum;
import com.ynxbd.common.bean.pay.Order;
import com.ynxbd.common.bean.pay.PayResult;
import com.ynxbd.common.helper.common.DateHelper;
import com.ynxbd.common.helper.common.ErrorHelper;
import com.ynxbd.common.helper.common.JsonHelper;
import com.ynxbd.common.helper.common.RepeatKeyHelper;
import com.ynxbd.common.result.ResultEnum;
@ -111,14 +110,19 @@ public class BCMHelper {
throw new ServiceException(((ServiceException) e).getResultEnum(), e.getMessage());
}
ErrorHelper.println(e);
log.error("【交行】支付通知-异常:", e);
throw new ServiceException(String.format("【交行】支付通知异常:[%s]", e.getMessage()));
}
}
public static JSONObject createOrder(MerchantEnum merchantEnum, String title, String outTradeNo, String totalFee, String notifyType) {
public static JSONObject createOrder(MerchantEnum merchantEnum, String title, String outTradeNo, BigDecimal totalFee, String notifyType) {
try {
if (merchantEnum == null || ObjectUtils.isEmpty(outTradeNo) || totalFee == null) {
log.error("【交行】创建预支付交易订单失败:参数缺失");
return null;
}
DefaultBocomClient client = BCMConfig.createClient();
MPNG210003RequestV1 clientRequest = new MPNG210003RequestV1();
@ -142,7 +146,7 @@ public class BCMHelper {
// 回调地址
reqBody.setNotifyUrl(WeChatConfig.getBaseURL() + merchantEnum.getNotifyUrl(null, notifyType));
reqBody.setPayMerTranNo(outTradeNo); // 商户订单号
reqBody.setTotalAmount(totalFee); // 订单总金额
reqBody.setTotalAmount(totalFee.toString()); // 订单总金额
reqBody.setTranContent(title); // 交易内容
reqBody.setLocation(ONLINE);
reqBody.setCurrency(CNY);
@ -175,38 +179,38 @@ public class BCMHelper {
clientRequest.setBizContent(bizContent);
MPNG210003ResponseV1 clientResponse = client.execute(clientRequest, UUID.randomUUID().toString().replace("-", ""));
log.info("【交行】下单 outTradeNo={}, resp={}", outTradeNo, JsonHelper.toJsonString(clientResponse));
log.info("【交行】创建预支付交易订单[{}]-响应数据:{}", outTradeNo, JsonHelper.toJsonString(clientResponse));
if (clientResponse == null) {
log.info("【交行】下单失败 outTradeNo={}", outTradeNo);
log.error("【交行】创建预支付交易订单[{}]-失败:响应数据为空", outTradeNo);
return null;
}
if (!clientResponse.isSuccess()) {
log.info("【交行】下单失败 outTradeNo={}, resp={}", outTradeNo, JsonHelper.toJsonString(clientResponse));
log.error("【交行】创建预支付交易订单[{}]-失败:resp={}", outTradeNo, JsonHelper.toJsonString(clientResponse));
return null;
}
// head
MPNG210003ResponseV1.RspHead rspHead = clientResponse.getRspHead();
if (rspHead == null) {
log.info("【交行】下单失败 outTradeNo={}, rspHead={}", outTradeNo, JsonHelper.toJsonString(rspHead));
log.error("【交行】创建预支付交易订单[{}]-失败:响应数据head为空", outTradeNo);
return null;
}
if (!RESP_STATUS_S.equals(rspHead.getResponseStatus())) {
log.info("【交行】下单失败 outTradeNo={}, code={}, message={}", outTradeNo, rspHead.getResponseCode(), rspHead.getResponseMsg());
log.error("【交行】创建预支付交易订单[{}]-失败: code={}, message={}", outTradeNo, rspHead.getResponseCode(), rspHead.getResponseMsg());
return null;
}
// body
MPNG210003ResponseV1.RspBody rspBody = clientResponse.getRspBody();
if (rspBody == null) {
log.info("【交行】下单失败 outTradeNo={}, rspBody={}", outTradeNo, JsonHelper.toJsonString(rspBody));
log.error("【交行】创建预支付交易订单[{}]-失败:响应数据body为空", outTradeNo);
return null;
}
String payUrl = rspBody.getRedirectUrl();
if (ObjectUtils.isEmpty(payUrl)) {
log.info("【交行】下单失败 outTradeNo={}, rspBody={}", outTradeNo, JsonHelper.toJsonString(rspBody));
log.error("【交行】创建预支付交易订单[{}]-失败:返回下单链接为空 body={}", outTradeNo, JsonHelper.toJsonString(rspBody));
return null;
}
JSONObject jsonObj = new JSONObject();
@ -216,7 +220,7 @@ public class BCMHelper {
jsonObj.put("type", MerchantEnum.BCM.CODE);
return jsonObj;
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【交行】创建预支付交易订单[{}]-异常:", outTradeNo, e);
}
return null;
}
@ -331,7 +335,7 @@ public class BCMHelper {
}
return order;
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【交行】查询订单-异常:", e);
order.setErrorMsg("【交行】" + e.getMessage());
return order;
}
@ -424,7 +428,7 @@ public class BCMHelper {
order.setSuccess(true); // 操作成功标识
return order;
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【交行】交易退款-异常:", e);
order.setErrorMsg("【交行】" + e.getMessage());
return order;
}

@ -137,7 +137,9 @@ public class TestA {
public static void main(String[] args) {
System.out.println(DateHelper.dateFormatDate("20260831100304", DateHelper.DateEnum.yyyyMMddHHmmss, DateHelper.DateEnum.yyyy_MM_dd_HH_mm_ss));
System.out.println(new BigDecimal("0.101").movePointRight(2).intValueExact());
System.out.println(new BigDecimal("0.100").movePointRight(2).toString());
// System.out.println(DateHelper.dateFormatDate("20260831100304", DateHelper.DateEnum.yyyyMMddHHmmss, DateHelper.DateEnum.yyyy_MM_dd_HH_mm_ss));
// XKChargeOrRefund info = new XKChargeOrRefund();
// info.setVisitNo("111");
// OkHttpHelper.postAsync("http://127.0.0.1:9090/micro/xk/rxChargeOrRefund", map -> {

@ -60,7 +60,7 @@ public class AliPayAction extends BaseAction {
switch (PEnum.findEnum(notifyType)) {
case RECIPE:
new RxService().hisRxListPay(MerchantEnum.ALI, totalFee.toString(), openid, outTradeNo, bankTransNo, null, payDate, payTime, payInfo);
new RxService().hisRxListPay(MerchantEnum.ALI, totalFee, openid, outTradeNo, bankTransNo, null, payDate, payTime, payInfo);
break;
case REG: // 挂号

@ -52,7 +52,7 @@ public class BcmPayAction extends BaseAction {
switch (PEnum.findEnum(notifyType)) {
case RECIPE:
openid = new RxService().queryOpenIdByOutTradeNo(outTradeNo);
new RxService().hisRxListPay(MerchantEnum.BCM, totalFee.toString(), openid, outTradeNo, bankTransNo, bankMerchantNo, payDate, payTime, payInfo);
new RxService().hisRxListPay(MerchantEnum.BCM, totalFee, openid, outTradeNo, bankTransNo, bankMerchantNo, payDate, payTime, payInfo);
break;
case REG: // 挂号

@ -56,7 +56,7 @@ public class JYPayAction extends BaseAction {
// jyOrder.businessTypeEnum = JYBusinessTypeEnum.B102;
//
// req.setJyOrder(jyOrder);
JSONObject prepay = JYPayHelper.createOrder(MerchantEnum.JY, title, merOrderNum, totalFee.toString(), PEnum.REG, ip, payOpenId, openid, req);
JSONObject prepay = JYPayHelper.createOrder(MerchantEnum.JY, title, merOrderNum, totalFee, PEnum.REG, ip, payOpenId, openid, req);
if (prepay == null) {
return Result.error(ResultEnum.PAY_ERROR_ORDER); // 下单异常
}

@ -92,7 +92,7 @@ public class PayAction extends BaseAction {
* @param awaitSecond 待秒数,0继续执行不等待(不传或null 为0)
*/
@Action("recipePay")
public Result recipePay(boolean isPrepay, String payCode, String payOpenId, String openid, String patientId, String treatNum, String totalFee, String recipeJson, String payWay, Integer rxType, Integer awaitSecond) {
public Result recipePay(boolean isPrepay, String payCode, String payOpenId, String openid, String patientId, String treatNum, BigDecimal totalFee, String recipeJson, String payWay, Integer rxType, Integer awaitSecond) {
try {
MerchantEnum merchantEnum = MerchantEnum.findEnumByCode(payCode);
if (merchantEnum == null) { // 支付方式异常
@ -151,7 +151,7 @@ public class PayAction extends BaseAction {
* * @param payCode 退款支付方式 { ali:支付宝;wx:微信 }
*/
@Action("inHospDepositPay")
public Result inHospDepositPay(String payCode, String payOpenId, String openid, String patientId, String patientName, String treatNum, String payMoney, String payWay) {
public Result inHospDepositPay(String payCode, String payOpenId, String openid, String patientId, String patientName, String treatNum, BigDecimal payMoney, String payWay) {
Result result = PayService.isPaymentPermittedByTime();
if (result != null) {
return result;
@ -187,8 +187,8 @@ public class PayAction extends BaseAction {
order.setPatientId(patientId);
order.setPatientName(patientName);
order.setTreatNum(treatNum);
order.setPayMoney(new BigDecimal(payMoney));
order.setTotalFee(new BigDecimal(payMoney));
order.setPayMoney(payMoney);
order.setTotalFee(payMoney);
order.setPayWay(payWay);
order.setPayOpenId(payOpenId);
order.setPayMchCode(merchantEnum.CODE);
@ -811,12 +811,13 @@ public class PayAction extends BaseAction {
return Result.error(ResultEnum.PARAM_IS_DEFECT);
}
if (new BigDecimal(totalFee).compareTo(BigDecimal.ZERO) == 0) { // 0 元处理
BigDecimal orderTotalFee = new BigDecimal(totalFee);
if (orderTotalFee.compareTo(BigDecimal.ZERO) == 0) { // 0 元处理
return Result.error(ResultEnum.PAY_MONEY_IS_ZERO);
}
String ip = HttpHelper.getIpAddress(request);
JSONObject respJson = PayService.createOrder(merchantEnum, pEnum, payOpenId, openId, patientId, totalFee, bizTradeNo, ip, body);
JSONObject respJson = PayService.createOrder(merchantEnum, pEnum, payOpenId, openId, patientId, orderTotalFee, bizTradeNo, ip, body);
if (respJson == null) {
return Result.error(ResultEnum.PAY_ERROR);
}
@ -824,42 +825,6 @@ public class PayAction extends BaseAction {
}
/**
* [在线问诊]退费
*
* @param payCode
* @param outTradeNo
* @param totalFee
* @param bankTransNo
* @param openid
* @param patientId
* @param refundDesc
* @return
*/
@Action("refundOLOrder")
public Result refundOLOrder(String payCode, String outTradeNo, String totalFee, String bankTransNo, String openid, String patientId, String refundDesc) {
MerchantEnum merchantEnum = MerchantEnum.findEnumByCode(payCode);
if (merchantEnum == null) {
return Result.error(ResultEnum.PAY_TYPE_NOT_SUPPORT);
}
bankTransNo = AesMicroHelper.decode(bankTransNo);
outTradeNo = AesMicroHelper.decode(outTradeNo);
totalFee = AesMicroHelper.decode(totalFee);
openid = AesMicroHelper.decode(openid);
log.info("[问诊]退费 outTradeNo={}, bankTransNo={}, totalFee={}, openid={}, patientId={}", outTradeNo, bankTransNo, totalFee, openid, patientId);
if (outTradeNo == null || bankTransNo == null || openid == null || totalFee == null) {
return Result.error(ResultEnum.PARAM_IS_BLANK);
}
BigDecimal totalFeeDecimal = new BigDecimal(totalFee);
String outRefundNo = HisFactory.getHisTradeNo(bankTransNo, PEnum.OL_REG);
Order orderRefund = PayService.refund(merchantEnum, outTradeNo, outRefundNo, totalFeeDecimal, totalFeeDecimal, refundDesc, new Date(), openid, patientId, null);
if (orderRefund.isSuccess()) {
return Result.success(AesMicroHelper.encode(outRefundNo));
}
return Result.error(orderRefund.getErrorMsg());
}
/**
* [扫码支付]支付
*/
@ -888,7 +853,7 @@ public class PayAction extends BaseAction {
String ip = request.getRemoteAddr();
//
if (isWeb) {
JSONObject order = WxPayHelper.createOrder(MerchantEnum.WX, title, totalFee.toString(), outTradeNo, PEnum.OUT_COLLECT.CODE, ip, openid, null);
JSONObject order = WxPayHelper.createOrder(MerchantEnum.WX, title, totalFee, outTradeNo, PEnum.OUT_COLLECT.CODE, ip, openid, null);
return Result.success(order);
}
@ -929,7 +894,8 @@ public class PayAction extends BaseAction {
return Result.error(ResultEnum.PARAM_IS_DEFECT);
}
if (new BigDecimal(totalFee).compareTo(BigDecimal.ZERO) == 0) {
BigDecimal orderTotalFee = new BigDecimal(totalFee);
if (orderTotalFee.compareTo(BigDecimal.ZERO) == 0) {
return Result.error(ResultEnum.PAY_MONEY_IS_ZERO);
}
@ -942,12 +908,12 @@ public class PayAction extends BaseAction {
String bizTradeNo = merchantEnum.createBizTradeNo();
String ip = request.getRemoteAddr();
String body = "体检预约 患者:" + patientId + "\n体检号:" + treatNum + "\n订单号:" + noticeOrderNo;
JSONObject respJson = PayService.createOrder(merchantEnum, PEnum.PEIS_RESERVE, payOpenId, openId, patientId, totalFee, bizTradeNo, ip, body);
JSONObject respJson = PayService.createOrder(merchantEnum, PEnum.PEIS_RESERVE, payOpenId, openId, patientId, orderTotalFee, bizTradeNo, ip, body);
if (respJson == null) {
return Result.error(ResultEnum.PAY_ERROR);
}
if (!peisService.savePEISOrder(merchantEnum, payOpenId, openId, patientId, treatNum, totalFee, noticeOrderNo, new ApiPrepayResp(respJson))) {
if (!peisService.savePEISOrder(merchantEnum, payOpenId, openId, patientId, treatNum, orderTotalFee, noticeOrderNo, new ApiPrepayResp(respJson))) {
log.info("{} [体检预约]订单信息保存失败 patientId={}, noticeOrderNo={}", merchantEnum.NAME, patientId, noticeOrderNo);
return Result.error(ResultEnum.SPECIFIED_QUESTIONED_USER_NOT_EXIST);
}

@ -68,7 +68,7 @@ public class ThirdPartyPayAction extends BaseAction {
String ip = request.getRemoteAddr();
String body = "扫码挂号" + date + " 患者:" + patientId;
JSONObject respJson = PayService.createOrder(merchantEnum, PEnum.TPP_QR_REG, payOpenId, openid, patientId, money.toString(), bizTradeNo, ip, body);
JSONObject respJson = PayService.createOrder(merchantEnum, PEnum.TPP_QR_REG, payOpenId, openid, patientId, money, bizTradeNo, ip, body);
if (respJson == null) {
return Result.error(ResultEnum.PAY_ERROR); // 支付异常
}

@ -1,5 +1,6 @@
package com.ynxbd.common.action.xk;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.ynxbd.common.action.base.BaseAction;
import com.ynxbd.common.bean.his.HisTreat;
@ -9,6 +10,8 @@ import com.ynxbd.common.dao.his.HisXKDao;
import com.ynxbd.common.result.JsonResult;
import com.ynxbd.common.result.Result;
import com.ynxbd.common.result.ResultEnum;
import com.ynxbd.common.service.RxService;
import com.ynxbd.wx.config.WeChatConfig;
import com.ynxbd.wx.wxfactory.AesWxHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
@ -134,14 +137,17 @@ public class XKAction extends BaseAction {
/**
* [问诊]删除处方
* [问诊]撤销处方
*/
@Action("delRx")
public Result delRx(@AesDecode String treatNum, @AesDecode String rxCode, @AesDecode String doctCode) {
log.info("[问诊]删除处方 treatNum={}, rxCode={}, doctCode={}", treatNum, rxCode, doctCode);
@Action("cancelOLRx")
public Result cancelOLRx(@AesDecode String treatNum, @AesDecode String rxCode, @AesDecode String doctCode) {
try {
new HisXKDao().delRx(treatNum, rxCode, doctCode);
return Result.success();
log.info("[问诊]撤销处方 treatNum={}, rxCode={}, doctCode={}", treatNum, rxCode, doctCode);
if (StrUtil.hasBlank(treatNum, rxCode, doctCode)) {
return Result.error(ResultEnum.PARAM_IS_DEFECT);
}
new HisXKDao().cancelHisRx(treatNum, rxCode, doctCode);
return new RxService().refundOLRx(treatNum, rxCode);
} catch (Exception e) {
return Result.error(e);
}

@ -244,4 +244,11 @@ public class Order implements Serializable {
public boolean hasErrorMsg() {
return !ObjectUtils.isEmpty(errorMsg) || !ObjectUtils.isEmpty(errorCode);
}
public String resolvePayOpenId(){
if (ObjectUtils.isEmpty(this.payOpenId)) {
return this.openid;
}
return this.payOpenId;
}
}

@ -28,7 +28,7 @@ public class XKCostDetail {
*/
private String projName;
/**
* 收费/退费标志
* 收费/退费标志[1、收费,2、退费]
*/
private String chargeRefundCode;
/**

@ -594,4 +594,12 @@ public class RxDao {
}
return dataList.get(0);
}
public List<Recipe> selectRxPaidByTreatNumAndRxCode(String treatNum, String rxCode) {
String sql = "select * from pay where updateTime >= DATE_SUB(CurDate(), INTERVAL 30 DAY) and treatNum= ? and recipeId=? and payStatus = 0";
return DataBase.select(sql, Recipe.class, ps -> {
ps.setString(1, treatNum);
ps.setString(2, rxCode);
});
}
}

@ -148,7 +148,7 @@ public class HisXKDao {
return jsonResult;
}
public JsonResult delRx(String treatNum, String rxCode, String doctCode) throws ServiceException {
public JsonResult cancelHisRx(String treatNum, String rxCode, String doctCode) throws ServiceException {
JsonResult jsonResult = HisFactory.His().getJsonResult(HisEnum.HIS_XK_RX_DEL, params -> {
params.put("MZNum", treatNum);
params.put("CFNum", rxCode);

@ -42,6 +42,8 @@ public class HisConfig {
// 开启预结算(第1开关)(如果HIS未限制-则存在直接入库风险!!!!!!!!!!!!!!!!!!)
public static final boolean IS_RX_PREPAY;
// 是否撤销处方时退费-[def:false]
public static final boolean IS_CANCEL_RX_REFUND;
static {
XmlConfigHelper config = new XmlConfigHelper().read("webservice.xml", "his");
@ -51,7 +53,7 @@ public class HisConfig {
IS_ALI_MER = config.getBoolean("is_ali_mer", false);
IS_REQ_CDATA = config.getBoolean("is_req_cdata", false);
IS_RX_PREPAY = config.getBoolean("is_rx_prepay", false);
IS_CANCEL_RX_REFUND = config.getBoolean("is_cancel_rx_refund", false);
String url = config.getString("url");
if (url == null) {

@ -79,6 +79,11 @@ public class HisFactory {
return prefix + pEnum.ORDER_CODE.toUpperCase() + "001";
}
public static String getOutRefundNo(String prefix, PEnum pEnum) {
String tradeNo = getHisTradeNo(prefix, pEnum);
return ObjectUtils.isEmpty(tradeNo) ? null : "R" + tradeNo;
}
/**
* 字符串集转xml

@ -40,16 +40,26 @@ public class MicroService {
}
public void uploadRxFee(List<Recipe> rxList, String outTradeNo, boolean isNotFailRx, BigDecimal totalFee, boolean isMedIns) {
/**
* 监管平台,处方缴费数据上报
*
* @param isRefund 是否为退费
* @param rxList 处方集
* @param outTradeNo 商户订单号
* @param isNotFailRx 是否有异常处方
* @param totalFee 订单金额
* @param isMedIns 是否为医保缴费
*/
public void uploadRxFee(boolean isRefund, List<Recipe> rxList, String outTradeNo, boolean isNotFailRx, BigDecimal totalFee, boolean isMedIns) {
try {
if (rxList.isEmpty()) {
log.warn("[监管平台]缴费处方数量为0 outTradeNo={}", outTradeNo);
log.warn("[监管平台]订单处方数量为0不上报 outTradeNo={}", outTradeNo);
return;
}
List<Recipe> olRxList = rxList.stream().filter(Recipe::hasOLRx).collect(Collectors.toList());
if (olRxList.size() != rxList.size()) {
log.warn("[监管平台]缴费处方互联网处方数量和订单的处方数量不一致 outTradeNo={}", outTradeNo);
log.warn("[监管平台]订单处方数量和互联网处方数量不一致 outTradeNo={}", outTradeNo);
}
Recipe rx = rxList.get(0);
@ -64,7 +74,7 @@ public class MicroService {
String deptName = rx.getDeptName();
String bankTransNo = rx.getBankTransNo();
if (StrUtil.hasBlank(openId, patientId, treatNum, deptCode, deptName, bankTransNo)) {
log.warn("[监管平台]查询HIS患者信息失败 openId={}, patientId={}, treatNum={}, deptCode={}, deptName={}, bankTransNo={}", openId, patientId, treatNum, deptCode, deptName, bankTransNo);
log.warn("[监管平台]处方数据上报-参数缺失 openId={}, patientId={}, treatNum={}, deptCode={}, deptName={}, bankTransNo={}", openId, patientId, treatNum, deptCode, deptName, bankTransNo);
return;
}
@ -83,7 +93,7 @@ public class MicroService {
String sex = patient.getSex();
final String chargeRefundCode = "1";
final String chargeRefundCode = isRefund ? "2" : "1"; // [1、收费,2、退费]
List<XKCostDetail> items = new ArrayList<>();
for (Recipe item : rxList) {
XKCostDetail detail = new XKCostDetail();

@ -65,7 +65,7 @@ public class PEISService {
* @param noticeOrderNo 体检订单号
* @return bool
*/
public boolean savePEISOrder(MerchantEnum merchantEnum, String payOpenId, String openId, String patientId, String treatNum, String totalFee, String noticeOrderNo, ApiPrepayResp prepayResp) {
public boolean savePEISOrder(MerchantEnum merchantEnum, String payOpenId, String openId, String patientId, String treatNum, BigDecimal totalFee, String noticeOrderNo, ApiPrepayResp prepayResp) {
String outTradeNo = prepayResp.findOutTradeNo();
String bizTradeNo = prepayResp.findBizTradeNo();
String mixTradeNo = prepayResp.findMixTradeNo();
@ -89,8 +89,8 @@ public class PEISService {
order.setMixTradeNo(mixTradeNo);
order.setNoticeOrderNo(noticeOrderNo);
order.setTotalFee(new BigDecimal(totalFee));
order.setPayMoney(new BigDecimal(totalFee));
order.setTotalFee(totalFee);
order.setPayMoney(totalFee);
order.setPayStatus(-1);
order.setNoticeStatus(-1);
return new PEISDao().insert(order);

@ -44,7 +44,7 @@ public class PayMedRecordService {
}
String body = "病历复印 住院号:" + treatNum;
JSONObject respJson = PayService.createOrder(merchantEnum, PEnum.MED_RECORD, payOpenId, openId, patientId, totalFee.toString(), bizTradeNo, ip, body);
JSONObject respJson = PayService.createOrder(merchantEnum, PEnum.MED_RECORD, payOpenId, openId, patientId, totalFee, bizTradeNo, ip, body);
if (respJson == null) {
return Result.error(ResultEnum.PAY_ERROR);
}

@ -66,7 +66,7 @@ public class PayService {
switch (PEnum.findEnum(notifyType)) {
case RECIPE:
new RxService().hisRxListPay(mchEnum, totalFee.toString(), openid, outTradeNo, bankTransNo, null, payDate, payTime, payInfo);
new RxService().hisRxListPay(mchEnum, totalFee, openid, outTradeNo, bankTransNo, null, payDate, payTime, payInfo);
break;
case REG: // 挂号
@ -549,7 +549,7 @@ public class PayService {
/**
* 唤起支付-创建订单
*/
public static JSONObject createOrder(MerchantEnum merchantEnum, PEnum pEnum, String payOpenId, String msgOpenId, String patientId, String totalFee, String bizTradeNo, String ip, String title) {
public static JSONObject createOrder(MerchantEnum merchantEnum, PEnum pEnum, String payOpenId, String msgOpenId, String patientId, BigDecimal totalFee, String bizTradeNo, String ip, String title) {
if (merchantEnum == null || ObjectUtils.isEmpty(pEnum) || pEnum.CODE == null) {
return null;
}

@ -844,7 +844,7 @@ public class RegService {
}
}
JSONObject respJson = PayService.createOrder(merchantEnum, PEnum.REG, payOpenId, openid, patientId, totalFee.toString(), bizTradeNo, ip, body);
JSONObject respJson = PayService.createOrder(merchantEnum, PEnum.REG, payOpenId, openid, patientId, totalFee, bizTradeNo, ip, body);
if (respJson == null) {
return Result.error(ResultEnum.PAY_ERROR); // 支付异常
}

@ -7,15 +7,14 @@ import com.ynxbd.common.bean.enums.MerchantEnum;
import com.ynxbd.common.bean.pay.ApiPrepayResp;
import com.ynxbd.common.bean.pay.Order;
import com.ynxbd.common.bean.pay.Recipe;
import com.ynxbd.common.config.interceptor.AesDecode;
import com.ynxbd.common.dao.RxDao;
import com.ynxbd.common.dao.RefundDao;
import com.ynxbd.common.dao.SelfHelpDao;
import com.ynxbd.common.dao.his.HisAccountDao;
import com.ynxbd.common.dao.his.HisRecipeDao;
import com.ynxbd.common.helper.common.DateHelper;
import com.ynxbd.common.helper.common.ErrorHelper;
import com.ynxbd.common.helper.common.JsonHelper;
import com.ynxbd.common.helper.common.QuickDrugDispenseHelper;
import com.ynxbd.common.helper.common.*;
import com.ynxbd.common.his.HisConfig;
import com.ynxbd.common.his.HisFactory;
import com.ynxbd.common.result.JsonResult;
import com.ynxbd.common.result.Result;
@ -31,6 +30,7 @@ import com.ynxbd.wx.wxfactory.WxPayHelper;
import com.ynxbd.wx.wxfactory.medical.models.WxMedOrder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.struts2.convention.annotation.Action;
import java.math.BigDecimal;
import java.util.*;
@ -93,7 +93,7 @@ public class RxService {
* @param treatNum 门诊号
* @return 是否完成操作
*/
public Result medInsPrepay(MerchantEnum merchantEnum, String payOpenId, String openid, String patientId, String treatNum, String totalFee, String recipeJson, String payWay, Integer rxType, Integer awaitSecond, boolean isHttps) {
public Result medInsPrepay(MerchantEnum merchantEnum, String payOpenId, String openid, String patientId, String treatNum, BigDecimal totalFee, String recipeJson, String payWay, Integer rxType, Integer awaitSecond, boolean isHttps) {
try {
Result result = PayService.isPaymentPermittedByTime();
if (result != null) {
@ -123,7 +123,7 @@ public class RxService {
}
// 金额为0的处方不进行回调通知
if ("0".equals(totalFee)) {
if (BigDecimal.ZERO.compareTo(totalFee) == 0) {
String bizTradeNo = merchantEnum.createBizTradeNo();
// 订单信息预存
if (!rxService.saveRxData(merchantEnum, payOpenId, openid, recipeJson, payWay, rxType, patientId, treatNum, totalFee, new ApiPrepayResp(bizTradeNo))) {
@ -226,7 +226,7 @@ public class RxService {
* @param treatNum 门诊号
* @return 是否完成操作
*/
public boolean saveRxData(MerchantEnum merchantEnum, String payOpenId, String openid, String recipeJson, String payWay, Integer rxType, String patientId, String treatNum, String totalFee, ApiPrepayResp prepayResp) throws ServiceException {
public boolean saveRxData(MerchantEnum merchantEnum, String payOpenId, String openid, String recipeJson, String payWay, Integer rxType, String patientId, String treatNum, BigDecimal totalFee, ApiPrepayResp prepayResp) throws ServiceException {
log.info("{}[处方支付]预存信息 patientId={}, treatNum={}, rxType={}, recipeJson={}", merchantEnum.NAME, patientId, treatNum, rxType, recipeJson);
List<Recipe> rxList = JsonHelper.parseArray(recipeJson, Recipe.class);
if (rxList == null || rxList.isEmpty()) {
@ -260,7 +260,7 @@ public class RxService {
rxItem.setRxType(rxType);
// recipe.setTradeNo(CodeHelper.getHisTradeNo()); // 本次his交易流水号
rxItem.setTradeNo(null); // 本次his交易流水号
rxItem.setTotalFee(new BigDecimal(totalFee));
rxItem.setTotalFee(totalFee);
rxItem.setPayMoney(rxItem.getRecipeFee());
rxItem.setHisStatus(-1);
rxItem.setPayStatus(-1);
@ -286,7 +286,7 @@ public class RxService {
* @param payTime 支付时间
* @return 是否完成操作
*/
public boolean hisRxListPay(MerchantEnum merchantEnum, String totalFee, String openid, String outTradeNo, String bankTransNo, String bankMerchantNo, String payDate, String payTime, String payInfo) {
public boolean hisRxListPay(MerchantEnum merchantEnum, BigDecimal totalFee, String openid, String outTradeNo, String bankTransNo, String bankMerchantNo, String payDate, String payTime, String payInfo) {
RxDao rxDao = new RxDao();
// 此处判断是否已经发起缴费,只要已存在数据库记录,说明已经发起了缴费请求,不能根据已经缴费成功,才取消本次缴费请求,因为请求可能已经延时,本次请求可能是重复提交的请求
@ -319,9 +319,9 @@ public class RxService {
rxTotalFee = rxTotalFee.add(recipe.getPayMoney());
}
log.info("{} [处方]金额计算{} outTradeNo={}, bankTransNo={}, rxTotalFee={}, totalFee={}", merchantEnum.NAME, (rxTotalFee.compareTo(new BigDecimal(totalFee)) == 0 ? "" : "异常"), outTradeNo, bankTransNo, rxTotalFee, totalFee);
if (rxTotalFee.compareTo(new BigDecimal(totalFee)) > 0) { // 支付的金额不足
log.info("{} [处方]缴费金额异常 outTradeNo={}, bankTransNo={}, rxTotalFee={}, totalFee={}", merchantEnum.NAME, outTradeNo, bankTransNo, rxTotalFee, totalFee);
log.info("{} [处方]金额计算{} outTradeNo={}, bankTransNo={}, rxTotalFee={}, totalFee={}", merchantEnum.NAME, (rxTotalFee.compareTo(totalFee) == 0 ? "" : "异常"), outTradeNo, bankTransNo, rxTotalFee, totalFee);
if (rxTotalFee.compareTo(totalFee) > 0) { // 支付的金额不匹配
log.error("{} [处方]缴费金额异常 outTradeNo={}, bankTransNo={}, rxTotalFee={}, totalFee={}", merchantEnum.NAME, outTradeNo, bankTransNo, rxTotalFee, totalFee);
return false;
}
@ -358,12 +358,12 @@ public class RxService {
long endTime = System.currentTimeMillis(); // 结束时间
log.info("{} [处方]请求HIS结束 耗时:{} outTradeNo={}, bankTransNo={}", merchantEnum.NAME, ((endTime - begTime) / 1000) + "s(" + (endTime - begTime) + "ms)", outTradeNo, bankTransNo);
if ("0".equals(totalFee)) { // 总金额为0不进行退费处理
if (BigDecimal.ZERO.compareTo(totalFee) == 0) { // 总金额为0不进行退费处理
return true;
}
if (MerchantEnum.JY.equals(merchantEnum)) {
new MicroService().uploadRxFee(rxList, outTradeNo, failedList.isEmpty(), new BigDecimal(totalFee), false);
new MicroService().uploadRxFee(false, rxList, outTradeNo, failedList.isEmpty(), totalFee, false);
return true;
}
@ -384,7 +384,7 @@ public class RxService {
refundDesc = "缴费失败 处方号:" + failedRecipeId + "\n原因:[" + errorCode + "]" + errorMsg;
try {
// 自动退费
rxAutoRefund(merchantEnum, openid, patientId, outTradeNo, failed.getTradeNo(), failedRecipeId, failed.getPayMoney(), new BigDecimal(totalFee), failed.getUpdateTime(), errorCode, errorMsg, refundDesc);
rxAutoRefund(merchantEnum, openid, patientId, outTradeNo, failed.getTradeNo(), failedRecipeId, failed.getPayMoney(), totalFee, failed.getUpdateTime(), errorCode, errorMsg, refundDesc);
} catch (Exception e) {
ErrorHelper.println(e);
}
@ -1109,4 +1109,54 @@ public class RxService {
Recipe order = rxList.get(0);
return order.getOpenid();
}
public List<Recipe> selectRxPaidByTreatNumAndRxCode(String treatNum, String rxCode) {
return new RxDao().selectRxPaidByTreatNumAndRxCode(treatNum, rxCode);
}
public Result refundOLRx(String treatNum, String rxCode) {
if (!HisConfig.IS_CANCEL_RX_REFUND) {
return Result.success();
}
log.info("[问诊-处方]退费-入参 treatNum={}, rxCode={}", treatNum, rxCode);
List<Recipe> rxList = new RxService().selectRxPaidByTreatNumAndRxCode(treatNum, rxCode);
if (rxList.isEmpty()) {
return Result.error(ResultEnum.PAY_ORDER_NOT_FOUND);
}
if (rxList.size() > 1) {
return Result.error("存在多笔订单禁止退费");
}
Recipe recipe = rxList.get(0);
String outTradeNo = recipe.getOutTradeNo();
String bizTradeNo = recipe.getBizTradeNo();
String bankTransNo = recipe.getBankTransNo();
String tradeNo = recipe.getTradeNo();
BigDecimal payMoney = recipe.getPayMoney();
BigDecimal totalFee = recipe.getTotalFee();
String payOpenId = recipe.resolvePayOpenId();
String patientId = recipe.getPatientId();
log.info("[问诊-处方]退费 bizTradeNo={}, outTradeNo={}, bankTransNo={}, tradeNo={}, totalFee={}, payOpenId={}, patientId={}", bizTradeNo, outTradeNo, bankTransNo, tradeNo, totalFee, payOpenId, patientId);
if (bizTradeNo == null || outTradeNo == null || bankTransNo == null || tradeNo == null || payOpenId == null || totalFee == null) {
return Result.error(ResultEnum.PARAM_IS_BLANK);
}
MerchantEnum merchantEnum = MerchantEnum.findEnumByOutTradeNo(bizTradeNo);
if (merchantEnum == null) {
return Result.error(ResultEnum.PAY_TYPE_NOT_SUPPORT);
}
String outRefundNo = ("R" + tradeNo);
Order orderRefund = PayService.refund(merchantEnum, outTradeNo, outRefundNo, payMoney, totalFee, "处方撤销", new Date(), payOpenId, patientId, null);
if (!new RxDao().updateRefundByTradeNo(tradeNo, orderRefund.getRefundResult())) {
log.info("{} [问诊处方退费]更新退款返回结果失败:bizTradeNo={}, outTradeNo={}", merchantEnum.NAME, bizTradeNo, outTradeNo);
}
if (!orderRefund.isSuccess()) {
return Result.error(ResultEnum.PAY_ERROR_REFUND);
}
new MicroService().uploadRxFee(true, rxList, outTradeNo, false, totalFee, false);
return Result.success();
}
}

@ -57,38 +57,45 @@ public class JYPayHelper {
* @param merchantEnum 枚举
* @param title 商品标题
* @param totalFee 订单金额
* @param merOrderNum 应用商户订单号
* @param bizTradeNo 应用商户订单号
* @param pEnum 业务类型
* @param ip ip地址
* @param payOpenId 用于下单的openId
* @param msgOpenId 用于推送的openId
* @return 成功返回 json, 否则返回null
*/
public static JSONObject createOrder(MerchantEnum merchantEnum, String title, String merOrderNum, String totalFee, PEnum pEnum, String ip, String payOpenId, String msgOpenId, ReqOrder reqOrder) {
public static JSONObject createOrder(MerchantEnum merchantEnum, String title, String bizTradeNo, BigDecimal totalFee, PEnum pEnum, String ip, String payOpenId, String msgOpenId, ReqOrder reqOrder) {
try {
String notifyType = pEnum.CODE;
JYPSEnum jyEnum = JYPSEnum.findEnum(pEnum);
if (ObjectUtils.isEmpty(payOpenId) || ObjectUtils.isEmpty(merOrderNum)
if (ObjectUtils.isEmpty(payOpenId) || ObjectUtils.isEmpty(bizTradeNo)
|| merchantEnum == null || totalFee == null || notifyType == null) {
log.error("【京硕】预下单参数缺失");
log.error("【京硕】创建预支付交易订单-失败:参数缺失");
return null;
}
int orderAmt = new BigDecimal(totalFee).movePointRight(2).intValue(); // 金额转换=>单位分
if (orderAmt == 0) {
log.error("【京硕】订单金额转换异常,或金额为0");
int orderAmt;
try {
orderAmt = totalFee.movePointRight(2).intValueExact(); // 金额转换=>单位分
if (orderAmt == 0) {
log.error("【京硕】创建预支付交易订单-金额转换异常或金额为0");
return null;
}
} catch (Exception e) {
log.error("【微信】创建预支付交易订单-失败:金额转换异常:", e);
return null;
}
log.info("【京硕】预下单 {},{},{},{},{}", title, merOrderNum, totalFee, ip, merchantEnum.NOTIFY_URL);
log.info("【京硕】创建预支付交易订单[{}] {},{},{},{}", bizTradeNo, title, totalFee, ip, merchantEnum.NOTIFY_URL);
Map<String, String> params = new HashMap<>();
params.put("openId", payOpenId);
params.put("hospitalId", JYPayConfig.HOSP_ID); // 医院ID
params.put("applicationId", JYPayConfig.APPLICATION_ID);
params.put("merchantId", JYPayConfig.MERCHANT_ID);
params.put("merOrderNum", merOrderNum); // 商户订单号
params.put("merOrderNum", bizTradeNo); // 商户订单号
params.put("hisOrderNum", null); // HIS订单号:可以为发票号[该接口若不传,在业务完成后调用2.1.6接口]
params.put("hisTransNum", null); // HIS流水号:可以为发票号[该接口若不传,在业务完成后调用2.1.6接口]
// 金额
@ -138,16 +145,16 @@ public class JYPayHelper {
}
params.put("signValue", signValue); // 数字签名:由接入方生成的签名,支付平台根据该字段对入参进行验签;签名生成规则参考4加签验签规则
log.info("【京硕】预下单-入参-{}", JSONObject.toJSONString(params));
log.info("【京硕】创建预支付交易订单[{}]-入参:{}", bizTradeNo, JSONObject.toJSONString(params));
JYResult result = createRequest("/qy_iips_pay/paycore/prePayOrder", params);
log.info("【京硕】预下单-响应-{}", JsonHelper.toJsonString(result));
log.info("【京硕】创建预支付交易订单[{}]-响应数据:{}", bizTradeNo, JsonHelper.toJsonString(result));
if (!result.isSuccess()) {
log.error("【京硕】预下单-失败:{}", result.getMessage());
log.error("【京硕】创建预支付交易订单[{}]-失败:{}", bizTradeNo, result.getMessage());
return null;
}
return result.toWxPrepayJson();
} catch (Exception e) {
log.error("【京硕】预下单-异常:", e);
log.error("【京硕】创建预支付交易订单[{}]-异常:", bizTradeNo, e);
}
return null;
}

@ -51,7 +51,7 @@ public class PayNotifyServlet extends HttpServlet {
String payTime = info.getPayTime();
// 和HIS交互
new RxService().hisRxListPay(MerchantEnum.WX, totalFee.toString(), openid, outTradeNo, bankTransNo, null, payDate, payTime, payInfo);
new RxService().hisRxListPay(MerchantEnum.WX, totalFee, openid, outTradeNo, bankTransNo, null, payDate, payTime, payInfo);
} catch (ServiceException e) {
Result.respXml(response, notify.resp(e)); // 收到请求-解析成功

@ -71,7 +71,7 @@ public class WxPayHelper {
}
}
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【微信】初始化加载证书-异常:", e);
}
}
@ -141,7 +141,7 @@ public class WxPayHelper {
if (e instanceof ServiceException) {
throw e;
}
ErrorHelper.println(e);
log.error("【微信】支付通知异常:", e);
throw new ServiceException(String.format("【微信】支付通知异常:[%s]", e.getMessage()));
}
}
@ -160,20 +160,23 @@ public class WxPayHelper {
* @param msgOpenId 用于推送的openId
* @return 成功返回 json, 否则返回null
*/
public static JSONObject createOrder(MerchantEnum merchantEnum, String title, String totalFee, String outTradeNo, String notifyType, String ip, String payOpenId, String msgOpenId) {
public static JSONObject createOrder(MerchantEnum merchantEnum, String title, BigDecimal totalFee, String outTradeNo, String notifyType, String ip, String payOpenId, String msgOpenId) {
try {
if (ObjectUtils.isEmpty(payOpenId) || ObjectUtils.isEmpty(outTradeNo)
|| merchantEnum == null || totalFee == null || notifyType == null) {
log.info("【微信】下单参数缺失");
log.error("【微信】创建预支付交易订单-失败:参数缺失");
return null;
}
String cents;
int cents;
try {
cents = new BigDecimal(totalFee).movePointRight(2).toString(); // 金额转换=>单位分
cents = totalFee.movePointRight(2).intValueExact(); // 金额转换=>单位分
if (cents == 0) {
log.error("【微信】创建预支付交易订单-金额转换异常或金额为0");
return null;
}
} catch (Exception e) {
ErrorHelper.println(e);
log.info("【微信】统一下单金额转换异常");
log.error("【微信】创建预支付交易订单-失败:金额转换异常:", e);
return null;
}
@ -190,20 +193,20 @@ public class WxPayHelper {
unifiedorder.setOut_trade_no(outTradeNo);
unifiedorder.setBody(title);
unifiedorder.setTotal_fee(cents); // 金额分
unifiedorder.setTotal_fee(Integer.toString(cents)); // 金额分
unifiedorder.setSpbill_create_ip(ip);
unifiedorder.setNotify_url(WeChatConfig.getBaseURL() + merchantEnum.NOTIFY_URL);
unifiedorder.setTrade_type("JSAPI");
// 额外参数
unifiedorder.setAttach(notifyType);
log.info("【微信】统一下单 {},{},{},{},{},{},{},{}", appId, mchId, nonce, title, outTradeNo, totalFee, ip, merchantEnum.NOTIFY_URL);
log.info("【微信】创建预支付交易订单[{}] {},{},{},{},{},{},{}", outTradeNo, appId, mchId, nonce, title, totalFee, ip, merchantEnum.NOTIFY_URL);
// 微信统一下单
UnifiedorderResult unifiedorderResult = PayMchAPI.payUnifiedorder(unifiedorder, mchKey);
log.info("【微信】统一下单返回:{}", JsonHelper.toJsonString(unifiedorderResult));
log.info("【微信】创建预支付交易订单[{}]-响应数据:{}", outTradeNo, JsonHelper.toJsonString(unifiedorderResult));
if (unifiedorderResult == null) {
log.info("【微信】统一下单失败");
log.error("【微信】创建预支付交易订单[{}]-失败:响应数据为空", outTradeNo);
return null;
}
@ -211,7 +214,7 @@ public class WxPayHelper {
// 下单是否成功
Boolean sign_status = unifiedorderResult.getSign_status();
if (!SUCCESS.equals(result_code) || sign_status == null || !sign_status) {
log.info("【微信】统一下单返回异常信息:sign_status={}, err_code=[ {} ], err_code_des=[ {} ]", sign_status, unifiedorderResult.getErr_code(), unifiedorderResult.getErr_code_des());
log.error("【微信】创建预支付交易订单[{}]-失败-返回错误信息:sign_status={}, err_code=[ {} ], err_code_des=[ {} ]", outTradeNo, sign_status, unifiedorderResult.getErr_code(), unifiedorderResult.getErr_code_des());
return null;
}
String json = weixin.popular.util.PayUtil.generateMchPayJsRequestJson(unifiedorderResult.getPrepay_id(), appId, mchKey);
@ -222,7 +225,7 @@ public class WxPayHelper {
return respJson;
}
} catch (Exception e) {
log.error("【微信】统一下单异常信息:{} - ", e.getMessage(), e);
log.error("【微信】创建预支付交易订单[{}]-失败-异常信息:{} - ", outTradeNo, e.getMessage(), e);
}
return null;
}
@ -243,19 +246,23 @@ public class WxPayHelper {
try {
log.info("【微信】退款开始 outTradeNo={}, refundMoney={}, totalFee={}", outTradeNo, refundMoney, totalFee);
int feeCents = refundMoney.movePointRight(2).intValue(); // 单位分
int totalFeeCents = totalFee.movePointRight(2).intValue();
if (feeCents == 0 || totalFeeCents == 0) {
order.setErrorMsg(ResultEnum.REFUND_MONEY_IS_ZERO.message);
return order;
int refundFeeCents, totalFeeCents;
try {
refundFeeCents = refundMoney.movePointRight(2).intValueExact(); // 单位分
totalFeeCents = totalFee.movePointRight(2).intValueExact();
if (refundFeeCents == 0 || totalFeeCents == 0) {
order.setErrorMsg(ResultEnum.REFUND_MONEY_IS_ZERO.message);
return order;
}
} catch (Exception e) {
log.error("【微信】退款-失败:金额转换异常:", e);
return null;
}
if (merchantEnum == null) {
merchantEnum = MerchantEnum.WX;
}
SecapiPayRefund refund = new SecapiPayRefund();
refund.setAppid(merchantEnum.APP_ID);
refund.setMch_id(WeChatConfig.MCH_ID);
@ -263,7 +270,7 @@ public class WxPayHelper {
refund.setSign_type("MD5");
refund.setOut_trade_no(outTradeNo);
refund.setOut_refund_no(outRefundNo);
refund.setRefund_fee(feeCents);
refund.setRefund_fee(refundFeeCents);
refund.setTotal_fee(totalFeeCents);
refund.setRefund_fee_type("CNY");
refund.setRefund_account("REFUND_SOURCE_UNSETTLED_FUNDS");
@ -312,7 +319,7 @@ public class WxPayHelper {
order.setSuccess(true);
return order;
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【微信】退款异常:", e);
order.setErrorMsg(ResultEnum.INTERFACE_WX_INVOKE_ERROR.message);
String refundResult = order.getRefundResult();
order.setRefundResult(ObjectUtils.isEmpty(refundResult) ? order.getErrorMsg() : refundResult);
@ -339,9 +346,18 @@ public class WxPayHelper {
return order;
}
int totalFeeCents;
try {
totalFeeCents = totalFee.movePointRight(2).intValue();
int totalFeeCents;
try {
totalFeeCents = totalFee.movePointRight(2).intValueExact();
if (totalFeeCents == 0) {
log.error("【微信】[盒子支付]-金额转换异常或金额为0");
return null;
}
} catch (Exception e) {
log.error("【微信】[盒子支付]-失败:金额转换异常:", e);
return null;
}
String appId = WeChatConfig.APP_ID;
String mchId = WeChatConfig.MCH_ID;
@ -432,9 +448,8 @@ public class WxPayHelper {
log.info("【微信】[扫码盒子]免密支付-耗时:[{}] [{}]", ((System.currentTimeMillis() - begTime) + "ms"), outTradeNo);
return wxOrder;
} catch (Exception e) {
log.info("【微信】[盒子支付]异常 {}", e.getMessage());
log.error("【微信】[盒子支付]异常:", e);
order.setErrorMsg("网络异常或当前不支持微信支付");
ErrorHelper.println(e);
}
return order;
}
@ -488,7 +503,7 @@ public class WxPayHelper {
return wxOrder;
}
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【微信】[盒子支付]等待扫码支付异常:", e);
}
}
return null;
@ -544,7 +559,7 @@ public class WxPayHelper {
order.setSuccess(true); // 订单支付成功(判断条件)
}
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【微信】撤销订单异常:", e);
order.setErrorMsg("异常信息:" + e.getMessage());
}
return order;
@ -650,7 +665,7 @@ public class WxPayHelper {
}
List<RefundqueryResultItem> refundOrderList = wxResult.getRefundqueryResultItems();
if (refundOrderList == null || refundOrderList.size() == 0) {
if (refundOrderList == null || refundOrderList.isEmpty()) {
return billList;
}
BigDecimal totalFee = new BigDecimal(wxResult.getTotal_fee()).movePointLeft(2);
@ -763,7 +778,7 @@ public class WxPayHelper {
order.setTotalFee(new BigDecimal(totalFee).movePointLeft(2));
}
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【微信】查询订单-异常:", e);
order.setErrorMsg("异常信息:" + e.getMessage());
}
return order;
@ -831,7 +846,7 @@ public class WxPayHelper {
order.setTotalFee(new BigDecimal(totalFee).movePointLeft(2));
}
} catch (Exception e) {
ErrorHelper.println(e);
log.error("【微信】查询订单-异常:", e);
order.setErrorMsg("异常信息:" + e.getMessage());
}
return order;
@ -1210,17 +1225,20 @@ public class WxPayHelper {
public static WxNativePayResult createNativeOrder(String notifyUrl, String title, BigDecimal totalFee, String outTradeNo, String notifyType, String ip) {
try {
if (ObjectUtils.isEmpty(outTradeNo) || ObjectUtils.isEmpty(notifyUrl) || totalFee == null || notifyType == null) {
log.info("Native下单参数缺失");
log.error("【微信】[Native下单]参数缺失");
return null;
}
// 金额转换
String cents;
int cents;
try {
cents = totalFee.movePointRight(2).toString(); // 单位分
cents = totalFee.movePointRight(2).intValueExact(); // 单位分
if (cents == 0) {
log.error("【微信】[Native下单]-金额转换异常或金额为0");
return null;
}
} catch (Exception e) {
ErrorHelper.println(e);
log.info("【微信】Native统一下单金额转换异常");
log.error("【微信】[Native下单]金额转换异常:", e);
return null;
}
@ -1236,20 +1254,19 @@ public class WxPayHelper {
unifiedorder.setOut_trade_no(outTradeNo);
unifiedorder.setBody(title);
unifiedorder.setTotal_fee(cents); // 金额分
unifiedorder.setTotal_fee(Integer.toString(cents)); // 金额分
unifiedorder.setSpbill_create_ip(ip);
unifiedorder.setNotify_url(WeChatConfig.getBaseURL() + notifyUrl);
unifiedorder.setTrade_type("NATIVE");
// 额外参数
unifiedorder.setAttach(notifyType);
log.info("【微信】Native下单 {},{},{},{},{},{},{},{}", appId, mchId, nonce, title, outTradeNo, totalFee, ip, notifyUrl);
log.info("【微信】[Native下单] {},{},{},{},{},{},{},{}", appId, mchId, nonce, title, outTradeNo, totalFee, ip, notifyUrl);
// 微信统一下单
UnifiedorderResult unifiedorderResult = PayMchAPI.payUnifiedorder(unifiedorder, mchKey);
log.info("【微信】Native统一下单返回:{}", JsonHelper.toJsonString(unifiedorderResult));
log.info("【微信】[Native下单]返回:{}", JsonHelper.toJsonString(unifiedorderResult));
if (unifiedorderResult == null) {
log.info("【微信】Native统一下单失败");
log.error("【微信】[Native下单]失败");
return null;
}
@ -1257,13 +1274,14 @@ public class WxPayHelper {
// 下单是否成功
Boolean sign_status = unifiedorderResult.getSign_status();
if (!SUCCESS.equals(result_code) || sign_status == null || !sign_status) {
log.info("【微信】Native统一下单返回异常信息:sign_status={}, err_code=[ {} ], err_code_des=[ {} ]", sign_status, unifiedorderResult.getErr_code(), unifiedorderResult.getErr_code_des());
log.error("【微信】[Native下单]返回异常信息:sign_status={}, err_code=[ {} ], err_code_des=[ {} ]", sign_status, unifiedorderResult.getErr_code(), unifiedorderResult.getErr_code_des());
return null;
}
String codeUrl = unifiedorderResult.getCode_url();
String prepayId = unifiedorderResult.getPrepay_id();
log.info("微信】Native统一下单 返回 codeUrl={}, prepayId={}", codeUrl, prepayId);
log.info("微信】[Native下单] codeUrl={}, prepayId={}", codeUrl, prepayId);
if (ObjectUtils.isEmpty(codeUrl) || ObjectUtils.isEmpty(prepayId)) {
log.error("微信】[Native下单]-失败:响应数据缺失 codeUrl={}, prepayId={}", codeUrl, prepayId);
return null;
}
WxNativePayResult wxNativePayResult = new WxNativePayResult();
@ -1271,8 +1289,7 @@ public class WxPayHelper {
wxNativePayResult.setPrepayId(prepayId);
return wxNativePayResult;
} catch (Exception e) {
log.error("【微信】统一下单异常信息:{}", e.getMessage());
ErrorHelper.println(e);
log.error("【微信】统一下单异常信息:", e);
}
return null;
}

@ -94,7 +94,7 @@ public class Client {
BigDecimal finalCashFee = cashFee;
JsonResult jsonResult = WxRequestHelper.postMdXml(("https://api.weixin.qq.com/payinsurance/unifiedorder?access_token=" + accessToken), params -> {
params.put("insurance_fee", insuranceFee.movePointRight(2)); // 医保支付金额(分)
params.put("total_fee", totalFee.movePointRight(2)); // 总金额(分)
params.put("total_fee", totalFee.movePointRight(2).intValueExact()); // 总金额(分)
params.put("cash_fee", finalCashFee.movePointRight(2)); // 现金需要支付的金额 { 单位为分>=0 线上预结算模式金额填0; 线下预结算模式填实际自费金额 }
params.put("pay_type", payType); // 支付方式-医保 (1:现金 2:医保 3:现金+医保)

@ -113,11 +113,11 @@ public class Client {
request.medInsOrderCreateTime = LocalDateTime.now().toString(); // 【医保下单时间】 医院向医保中台下单的时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE。纯医保支付或医保自费混合支付时该字段必填,纯自费支付时禁止填写。
// 费用信息
request.totalFee = totalFee.movePointRight(2).longValue();
long medInsCashFee = cashFee.movePointRight(2).longValue();
request.totalFee = totalFee.movePointRight(2).longValueExact();
long medInsCashFee = cashFee.movePointRight(2).longValueExact();
if (!IS_PURE_SELF_PAID) { // 不是纯自费
request.medInsGovFee = medInsGovFee.movePointRight(2).longValue(); // 【医保统筹支付金额】纯医保支付或医保自费混合支付时该字段必填,纯自费支付时禁止填写。
request.medInsSelfFee = medInsSelfFee.movePointRight(2).longValue(); // 【医保个账支付金额】纯医保支付或医保自费混合支付时该字段必填,纯自费支付时禁止填写。
request.medInsGovFee = medInsGovFee.movePointRight(2).longValueExact(); // 【医保统筹支付金额】纯医保支付或医保自费混合支付时该字段必填,纯自费支付时禁止填写。
request.medInsSelfFee = medInsSelfFee.movePointRight(2).longValueExact(); // 【医保个账支付金额】纯医保支付或医保自费混合支付时该字段必填,纯自费支付时禁止填写。
request.medInsOtherFee = 0L; // 【医保其他支付金额】纯医保支付或医保自费混合支付时该字段必填,纯自费支付时禁止填写。
request.medInsCashFee = medInsCashFee; // 【需要自费的金额】纯医保支付或医保自费混合支付时该字段必填,纯自费支付时禁止填写。
}

@ -33,7 +33,7 @@ public class Client {
subOrdersItem0.mchid = mchId;
subOrdersItem0.outTradeNo = outTradeNo;
subOrdersItem0.amount = new UnionAPIv3JsapiPrepay.UnionAmountInfo();
subOrdersItem0.amount.totalAmount = totalFee.movePointRight(2).longValue(); // 商品单的金额,整型,单位为分
subOrdersItem0.amount.totalAmount = totalFee.movePointRight(2).longValueExact(); // 商品单的金额,整型,单位为分
subOrdersItem0.amount.currency = "CNY";
subOrdersItem0.attach = attach;
subOrdersItem0.description = description; // 商品信息描述

@ -1 +1 @@
<?xml version="1.0" encoding="UTF-8"?> <config> <his> <is_req_cdata name="州傣医使用-[def:false]">false</is_req_cdata> <!-- 处方预结算(第2开关)(注意该配置需联系his开发者确认支持才能开启,否则存在风险!) --> <is_rx_prepay name="处方预结算[风险][def:false]">false</is_rx_prepay> <!-- 开关配置 --> <is_ali_mer name="HIS是否开启支付宝分开对账-[def:false]">false</is_ali_mer> <is_log_resp name="是否强制打印响应xml数据-[def:false]">false</is_log_resp> <is_push_msg name="是否传递openid给His推送消息-[def:false]">false</is_push_msg> <!-- 医保 --> <wx_med_url name="[微信医保]">127.0.0.1:8888</wx_med_url> <ali_med_url name="[支付宝医保]">127.0.0.1:8888</ali_med_url> <dev_med_openid_s name="[医保测试openid多个用英文逗号隔开]">1</dev_med_openid_s> <!-- HIS --> <dev_url name="[测试环境]">200.200.200.60:7777</dev_url> <!-- <url name="[正式环境]">200.200.200.60:7777</url> --> <!-- <url name="德宏中医">200.200.200.60:7777</url>--> <url name="红河州第一人民医院">10.20.10.6:8888</url> </his> </config>
<?xml version="1.0" encoding="UTF-8"?> <config> <his> <is_req_cdata name="州傣医使用-[def:false]">false</is_req_cdata> <!-- 处方预结算(第2开关)(注意该配置需联系his开发者确认支持才能开启,否则存在风险!) --> <is_rx_prepay name="处方预结算[风险][def:false]">false</is_rx_prepay> <!-- 开关配置 --> <is_ali_mer name="HIS是否开启支付宝分开对账-[def:false]">false</is_ali_mer> <is_log_resp name="是否强制打印响应xml数据-[def:false]">false</is_log_resp> <is_push_msg name="是否传递openid给His推送消息-[def:false]">false</is_push_msg> <is_cancel_rx_refund name="是否撤销处方时退费-[def:false]">false</is_cancel_rx_refund> <!-- 医保 --> <wx_med_url name="[微信医保]">127.0.0.1:8888</wx_med_url> <ali_med_url name="[支付宝医保]">127.0.0.1:8888</ali_med_url> <dev_med_openid_s name="[医保测试openid多个用英文逗号隔开]">1</dev_med_openid_s> <!-- HIS --> <dev_url name="[测试环境]">200.200.200.60:7777</dev_url> <!-- <url name="[正式环境]">200.200.200.60:7777</url> --> <!-- <url name="德宏中医">200.200.200.60:7777</url>--> <url name="红河州第一人民医院">10.20.10.6:8888</url> </his> </config>
Loading…
Cancel
Save