diff --git a/pom.xml b/pom.xml index 8f477f3..d79ca18 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ UTF-8 1.8 1.8 - 6.3.0.2 + 6.7.0 2.14.1 1.2.83 @@ -63,7 +63,7 @@ ch.qos.logback logback-classic - 1.2.10 + 1.5.16 slf4j-api @@ -160,7 +160,7 @@ com.thoughtworks.xstream xstream - 1.4.20 + 1.4.21 @@ -311,7 +311,7 @@ com.alipay.sdk alipay-sdk-java - 4.35.9.ALL + 4.40.54.ALL fastjson @@ -381,7 +381,7 @@ cn.hutool hutool-captcha - 5.8.11 + 5.8.36 @@ -419,6 +419,7 @@ + com.alipay.sdk easysdk-kernel diff --git a/src/main/java/com/ynxbd/common/action/AccountsAction.java b/src/main/java/com/ynxbd/common/action/AccountsAction.java index b44336d..766cce7 100644 --- a/src/main/java/com/ynxbd/common/action/AccountsAction.java +++ b/src/main/java/com/ynxbd/common/action/AccountsAction.java @@ -24,6 +24,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Namespace; + import java.util.*; /** diff --git a/src/main/java/com/ynxbd/common/action/pay/MedicalAction.java b/src/main/java/com/ynxbd/common/action/pay/MedicalAction.java index efa7d86..924f2c8 100644 --- a/src/main/java/com/ynxbd/common/action/pay/MedicalAction.java +++ b/src/main/java/com/ynxbd/common/action/pay/MedicalAction.java @@ -17,7 +17,6 @@ import com.ynxbd.common.result.Result; import com.ynxbd.common.result.ResultEnum; import com.ynxbd.common.result.ServiceException; import com.ynxbd.common.service.MedicalService; -import com.ynxbd.common.service.PatientService; import com.ynxbd.common.service.params.RegParams; import com.ynxbd.wx.wxfactory.*; import com.ynxbd.wx.wxfactory.bean.*; @@ -240,7 +239,7 @@ public class MedicalAction extends BaseAction { Result result = MedicalService.refund(userInfo.getPayAuthNo(), chrgBchno.substring(1), outTradeNo, bankTransNo, tradeNo, mdUserId, cashFee, insuranceFee); String message = result.isSuccess() ? WxPayHelper.OK : result.getMessage(); - if (!recipeDao.updateRefundRByTradeNo(tradeNo, message)) { + if (!recipeDao.updateRefundByTradeNo(tradeNo, message)) { log.info("【医保】修改退费信息失败 [{}] outTradeNo={}, tradeNo={}", message, outTradeNo, tradeNo); } if (result.isSuccess()) { @@ -315,7 +314,7 @@ public class MedicalAction extends BaseAction { // } /** - * 回调通知 + * [医保支付]微信回调通知 */ @Action("payNotify") public Result payNotify() { @@ -335,8 +334,8 @@ public class MedicalAction extends BaseAction { String notifyType = notifyInfo.getAttach(); - log.info("【医保】[{}] 收到通知" + - " outTradeNo={}, bankTransNo={}, notifyType={}", notifyType, outTradeNo, bankTransNo, notifyType); + log.info("【医保】[{}] 收到通知 outTradeNo={}, bankTransNo={}, notifyType={}", + notifyType, outTradeNo, bankTransNo, notifyType); switch (PEnum.toEnum(notifyType)) { case RECIPE: @@ -345,7 +344,6 @@ public class MedicalAction extends BaseAction { case REG: // 挂号 MedicalService.regPay(MerchantEnum.WX, outTradeNo, bankTransNo, payDate, payTime, openid, payInfo); - break; case IN_HOSP: diff --git a/src/main/java/com/ynxbd/common/config/interceptor/MethodInterceptor.java b/src/main/java/com/ynxbd/common/config/interceptor/MethodInterceptor.java index 1504a5a..87ad24c 100644 --- a/src/main/java/com/ynxbd/common/config/interceptor/MethodInterceptor.java +++ b/src/main/java/com/ynxbd/common/config/interceptor/MethodInterceptor.java @@ -1,12 +1,11 @@ package com.ynxbd.common.config.interceptor; -import com.opensymphony.xwork2.ActionContext; -import com.opensymphony.xwork2.ActionInvocation; import com.ynxbd.common.helper.common.ErrorHelper; import com.ynxbd.common.helper.common.JsonHelper; import com.ynxbd.common.result.Result; -import com.ynxbd.common.result.struts2.BaseResult; import org.apache.commons.lang3.ObjectUtils; +import org.apache.struts2.ActionContext; +import org.apache.struts2.ActionInvocation; import org.apache.struts2.interceptor.ServletConfigInterceptor; import javax.servlet.http.HttpServletRequest; @@ -22,18 +21,19 @@ import java.util.List; /** * 方法拦截器 */ -public class MethodInterceptor extends ServletConfigInterceptor { +public class MethodInterceptor extends org.apache.struts2.interceptor.AbstractInterceptor { + @Override - public String intercept(ActionInvocation invocation) throws Exception { - Object action = invocation.getAction(); - ActionContext context = invocation.getInvocationContext(); + public String intercept(ActionInvocation actionInvocation) throws Exception { + Object action = actionInvocation.getAction(); + ActionContext context = actionInvocation.getInvocationContext(); HttpServletRequest request = context.getServletRequest(); if (action instanceof org.apache.struts2.action.ServletRequestAware) { ((org.apache.struts2.action.ServletRequestAware) action).withServletRequest(request); } - String methodName = invocation.getProxy().getMethod(); + String methodName = actionInvocation.getProxy().getMethod(); String initials; for (Method method : action.getClass().getDeclaredMethods()) { if (method.getName().equals(methodName)) { @@ -124,6 +124,11 @@ public class MethodInterceptor extends ServletConfigInterceptor { return "SUCCESS"; } +// @Override +// public String intercept(com.opensymphony.xwork2.ActionInvocation invocation) throws Exception { +// +// } + public void respJson(HttpServletResponse response, Object action, Object data) { if (action instanceof org.apache.struts2.action.ServletResponseAware) { @@ -147,4 +152,5 @@ public class MethodInterceptor extends ServletConfigInterceptor { e.printStackTrace(); } } + } diff --git a/src/main/java/com/ynxbd/common/dao/RecipeDao.java b/src/main/java/com/ynxbd/common/dao/RecipeDao.java index 1c6cf43..b298f5a 100644 --- a/src/main/java/com/ynxbd/common/dao/RecipeDao.java +++ b/src/main/java/com/ynxbd/common/dao/RecipeDao.java @@ -547,7 +547,7 @@ public class RecipeDao { * @param refundResult 退款信息 * @return 是否成功 */ - public boolean updateRefundRByTradeNo(String tradeNo, String refundResult) { + public boolean updateRefundByTradeNo(String tradeNo, String refundResult) { String sql = "update pay set refundResult=?, refundTime=now() where tradeNo=? and (refundResult is null or refundResult != 'OK')"; return DataBase.update(sql, ps -> { ps.setString(1, refundResult); diff --git a/src/main/java/com/ynxbd/common/result/struts2/BaseResult.java b/src/main/java/com/ynxbd/common/result/struts2/BaseResult.java index 82b157d..39dbe55 100644 --- a/src/main/java/com/ynxbd/common/result/struts2/BaseResult.java +++ b/src/main/java/com/ynxbd/common/result/struts2/BaseResult.java @@ -1,8 +1,8 @@ package com.ynxbd.common.result.struts2; -import com.opensymphony.xwork2.ActionInvocation; import com.ynxbd.common.helper.common.JsonHelper; import com.ynxbd.common.result.Result; +import org.apache.struts2.ActionInvocation; import org.apache.struts2.ServletActionContext; import javax.servlet.http.HttpServletResponse; @@ -11,10 +11,11 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; -public class BaseResult implements com.opensymphony.xwork2.Result { +public class BaseResult implements org.apache.struts2.result.Result { @Override - public void execute(ActionInvocation actionInvocation) { + public void execute(ActionInvocation actionInvocation) throws Exception { + } /** @@ -100,4 +101,5 @@ public class BaseResult implements com.opensymphony.xwork2.Result { } return null; } + } diff --git a/src/main/java/com/ynxbd/common/service/MedicalService.java b/src/main/java/com/ynxbd/common/service/MedicalService.java index 4b50168..20cdfb1 100644 --- a/src/main/java/com/ynxbd/common/service/MedicalService.java +++ b/src/main/java/com/ynxbd/common/service/MedicalService.java @@ -16,10 +16,13 @@ import com.ynxbd.common.result.ResultEnum; import com.ynxbd.common.result.ServiceException; import com.ynxbd.wx.config.WeChatConfig; import com.ynxbd.wx.wxfactory.WxMedicalHelper; +import com.ynxbd.wx.wxfactory.WxPayHelper; import com.ynxbd.wx.wxfactory.bean.MedicalInfo; import com.ynxbd.wx.wxfactory.bean.MedicalOrder; import com.ynxbd.wx.wxfactory.bean.MedicalUserInfo; import com.ynxbd.wx.wxfactory.bean.OrderTypeEnum; +import com.ynxbd.wx.wxfactory.medical.MdConfig; +import com.ynxbd.wx.wxfactory.medical.enums.MdRefundTypeEnum; import lombok.extern.slf4j.Slf4j; import java.math.BigDecimal; @@ -61,13 +64,13 @@ public class MedicalService { * @param recipeJson 处方json * @param totalFee 订单金额 */ - public static MedicalInfo recipeMdUploadFeeDetails(String qrCode, String openid, String patientId, String cardNo, String realName, String treatNum, String recipeJson, BigDecimal totalFee,String ybAttrib,String ybBZCode, String ybBZName) throws ServiceException { + public static MedicalInfo recipeMdUploadFeeDetails(String qrCode, String openid, String patientId, String cardNo, String realName, String treatNum, String recipeJson, BigDecimal totalFee, String ybAttrib, String ybBZCode, String ybBZName) throws ServiceException { MedicalUserInfo userInfo = WxMedicalHelper.getUserInfo(openid, qrCode, cardNo, realName); String payAuthNo = userInfo.getPayAuthNo(); log.info("[医保]上传明细:patientId={}, totalFee={}, cardNo={}, recipeJson={}", patientId, totalFee, cardNo, recipeJson); - JsonResult result = HisMedicalDao.recipeMdUploadFeeDetails(payAuthNo, cardNo, openid, patientId, treatNum, recipeJson, totalFee,ybAttrib,ybBZCode,ybBZName); + JsonResult result = HisMedicalDao.recipeMdUploadFeeDetails(payAuthNo, cardNo, openid, patientId, treatNum, recipeJson, totalFee, ybAttrib, ybBZCode, ybBZName); return mdPlaceOrder(payAuthNo, result); } @@ -294,7 +297,7 @@ public class MedicalService { */ public static boolean regPay(MerchantEnum merchantEnum, String outTradeNo, String bankTransNo, String payDate, String payTime, String openid, String payInfo) { if (outTradeNo == null || bankTransNo == null || payDate == null || payTime == null) { - log.info("【医保】HIS结算参数缺失 outTradeNo={}, bankTransNo={}, payDate={}, payTime={}", outTradeNo, bankTransNo, payDate, payTime); + log.info("[医保][挂号]HIS结算参数缺失 outTradeNo={}, bankTransNo={}, payDate={}, payTime={}", outTradeNo, bankTransNo, payDate, payTime); return false; } RegisterDao regDao = new RegisterDao(); @@ -306,12 +309,12 @@ public class MedicalService { Integer hisStatus = reg.getHisStatus(); Integer payStatus = reg.getPayStatus(); if (payStatus == null || hisStatus == null || payStatus == 0 || hisStatus == 0) { // 状态不明确 - log.info("{} [挂号]订单已支付 outTradeNo={}, bankTransNo={}", merchantEnum.NAME, outTradeNo, bankTransNo); + log.info("{}[医保][挂号]订单已支付 outTradeNo={}, bankTransNo={}", merchantEnum.NAME, outTradeNo, bankTransNo); return true; } if (!regDao.updateMerPaidByOutTradeNo(outTradeNo, payDate, payTime, bankTransNo)) { - log.info("【医保】[挂号]修改订单支付状态 outTradeNo={}, bankTransNo={}", outTradeNo, bankTransNo); + log.info("[医保][挂号]修改订单支付状态 outTradeNo={}, bankTransNo={}", outTradeNo, bankTransNo); return false; } @@ -325,7 +328,7 @@ public class MedicalService { BigDecimal cashFee = reg.getPayMoney(); // 现金 BigDecimal acctFee = reg.getAcctFee(); // 个账 if (mdUserId == null || tradeNo == null || chrgBchno == null || cashFee == null || acctFee == null) { - log.info("【医保】[挂号]HIS结算参数缺失 outTradeNo={}, bankTransNo={}, tradeNo={}, mdUserId={}, chrgBchno={}", outTradeNo, bankTransNo, tradeNo, mdUserId, chrgBchno); + log.info("[医保][挂号]HIS结算参数缺失 outTradeNo={}, bankTransNo={}, tradeNo={}, mdUserId={}, chrgBchno={}", outTradeNo, bankTransNo, tradeNo, mdUserId, chrgBchno); return false; } @@ -333,23 +336,40 @@ public class MedicalService { if (!jsonResult.success()) { String respCode = jsonResult.getCode(); String respMessage = jsonResult.getMessage(); - log.info("【医保】HIS结算失败 outTradeNo={}, bankTransNo={}, respCode={}, respMessage={}", outTradeNo, bankTransNo, respCode, respMessage); + log.info("[医保][挂号]HIS结算失败 outTradeNo={}, bankTransNo={}, respCode={}, respMessage={}", outTradeNo, bankTransNo, respCode, respMessage); if (!regDao.updateHisPaidFailByOutTradeNo(outTradeNo, respCode, respMessage)) { - log.info("【医保】[处方]更新HIS缴费失败信息异常 outTradeNo={}, code={}, message={}", outTradeNo, respCode, respMessage); + log.info("[医保][挂号]更新HIS缴费失败信息异常 outTradeNo={}, code={}, message={}", outTradeNo, respCode, respMessage); } if (jsonResult.isTimeout()) { // 调用超时-不退费 - log.info("【医保】HIS结算调用超时 outTradeNo={}, bankTransNo={}, tradeNo={}, mdUserId={}", outTradeNo, bankTransNo, tradeNo, mdUserId); + log.info("[医保][挂号]HIS结算调用超时 outTradeNo={}, bankTransNo={}, tradeNo={}, mdUserId={}", outTradeNo, bankTransNo, tradeNo, mdUserId); return false; } + if (MdConfig.IS_AUTO_REFUND) { + log.info("[医保][挂号]现金自动退费功能未开启 outTradeNo={}, bankTransNo={}, tradeNo={}", outTradeNo, bankTransNo, tradeNo); + return false; + } + + // 微信医保自动退费 + MedicalOrder order = WxMedicalHelper.refundCash(outTradeNo, ("R" + tradeNo), tradeNo, cashFee, "系统繁忙缴费失败,自动退费"); + boolean isOk = order.isOk(); + log.info("【微信】[医保][挂号]现金自动退费{} outTradeNo={}, bankTransNo={}, tradeNo={}", (isOk ? "成功" : "失败"), outTradeNo, bankTransNo, tradeNo); + if (isOk) { + String refundResult = order.isOk() ? WxPayHelper.OK : order.getMessage(); + if (!regDao.updateRefundByTradeNo(tradeNo, refundResult)) { + log.info("【微信】[医保][挂号]现金自动退费 修改数据库状态失败 tradeNo={}, refundResult={}", tradeNo, refundResult); + } + } else { + log.info("【微信】[医保][挂号]现金自动退费 失败:{}", order.getMessage()); + } return false; } - log.info("【医保】HIS结算成功 outTradeNo={}, bankTransNo={}", outTradeNo, bankTransNo); + log.info("[医保][挂号]HIS结算成功 outTradeNo={}, bankTransNo={}", outTradeNo, bankTransNo); // 成功处理 if (!regDao.updateHisPaidByOutTradeNo(outTradeNo)) { - log.error("【医保】挂号修改成功数据失败"); + log.error("[医保][挂号]修改成功数据失败"); } return true; } @@ -368,14 +388,14 @@ public class MedicalService { */ public static boolean recipePay(MerchantEnum merchantEnum, String outTradeNo, String bankTransNo, String payDate, String payTime, String openid, String payInfo) { if (outTradeNo == null || bankTransNo == null || payDate == null || payTime == null) { - log.info("【医保】HIS结算参数缺失 outTradeNo={}, bankTransNo={}, payDate={}, payTime={}", outTradeNo, bankTransNo, payDate, payTime); + log.info("[医保][处方]HIS结算参数缺失 outTradeNo={}, bankTransNo={}, payDate={}, payTime={}", outTradeNo, bankTransNo, payDate, payTime); return false; } RecipeDao recipeDao = new RecipeDao(); // 此处判断是否已经发起缴费,只要已存在数据库记录,说明已经发起了缴费请求,不能根据已经缴费成功,才取消本次缴费请求,因为请求可能已经延时,本次请求可能是重复提交的请求 if (PayService.hasUserOrderNo(outTradeNo, openid)) { - log.info("{}[处方]已发起缴费 outTradeNo={}", merchantEnum.NAME, outTradeNo); + log.info("{}[医保][处方]已发起缴费 outTradeNo={}", merchantEnum.NAME, outTradeNo); return false; } @@ -385,7 +405,7 @@ public class MedicalService { Recipe recipe = recipeDao.selectOneByOutTradeNo(outTradeNo); if (recipe == null) { - log.info("【医保】数据库中未查询到订单信息 outTradeNo={}, bankTransNo={}", outTradeNo, bankTransNo); + log.info("[医保][处方]数据库中未查询到订单信息 outTradeNo={}, bankTransNo={}", outTradeNo, bankTransNo); return false; } @@ -395,18 +415,18 @@ public class MedicalService { BigDecimal cashFee = recipe.getPayMoney(); // 现金 BigDecimal acctFee = recipe.getAcctFee(); // 个账 if (mdUserId == null || tradeNo == null || chrgBchno == null || cashFee == null || acctFee == null) { - log.info("【医保】HIS结算参数缺失 outTradeNo={}, bankTransNo={}, tradeNo={}, mdUserId={}, chrgBchno={}", outTradeNo, bankTransNo, tradeNo, mdUserId, chrgBchno); + log.info("[医保][处方]HIS结算参数缺失 outTradeNo={}, bankTransNo={}, tradeNo={}, mdUserId={}, chrgBchno={}", outTradeNo, bankTransNo, tradeNo, mdUserId, chrgBchno); return false; } Integer hisStatus = recipe.getHisStatus(); if (hisStatus != null && hisStatus == 0) { - log.info("{} [处方]已交过费, 结束本次缴费流程:outTradeNo={}, bankTransNo={}", merchantEnum.NAME, outTradeNo, bankTransNo); + log.info("{} [医保][处方]已交过费, 结束本次缴费流程:outTradeNo={}, bankTransNo={}", merchantEnum.NAME, outTradeNo, bankTransNo); return false; } if (recipeDao.updateMerPaidByTradeNo(tradeNo, bankTransNo)) { - log.info("{} [处方]更新商户信息成功 outTradeNo={}, bankTransNo={}", merchantEnum.NAME, outTradeNo, bankTransNo); + log.info("{} [医保][处方]更新商户信息成功 outTradeNo={}, bankTransNo={}", merchantEnum.NAME, outTradeNo, bankTransNo); } JsonResult jsonResult = HisMedicalDao.mdPay(mdUserId, payDate, payTime, tradeNo, bankTransNo, cashFee); @@ -414,26 +434,44 @@ public class MedicalService { if (!jsonResult.success()) { String respCode = jsonResult.getCode(); String respMessage = jsonResult.getMessage(); - log.info("【医保】HIS结算失败 outTradeNo={}, bankTransNo={}, respCode={}, respMessage={}", outTradeNo, bankTransNo, respCode, respMessage); + log.info("[医保][处方]HIS结算失败 outTradeNo={}, bankTransNo={}, respCode={}, respMessage={}", outTradeNo, bankTransNo, respCode, respMessage); if (!recipeDao.updateHisPaidFailByTradeNo(tradeNo, respCode, respMessage)) { - log.info("【医保】[处方]更新HIS缴费失败信息失败 tradeNo={}, code={}, message={}", tradeNo, respCode, respMessage); + log.info("[医保][处方]更新HIS缴费失败信息失败 tradeNo={}, code={}, message={}", tradeNo, respCode, respMessage); } if (jsonResult.isTimeout()) { // 调用超时-不退费 - log.info("【医保】HIS结算调用超时-不退费 outTradeNo={}, bankTransNo={}, tradeNo={}, mdUserId={}", outTradeNo, bankTransNo, tradeNo, mdUserId); + log.info("[医保][处方]HIS结算调用超时-不退费 outTradeNo={}, bankTransNo={}, tradeNo={}, mdUserId={}", outTradeNo, bankTransNo, tradeNo, mdUserId); return false; } + + if (MdConfig.IS_AUTO_REFUND) { + log.info("[医保][处方][现金自动退费]功能未开启 outTradeNo={}, bankTransNo={}, tradeNo={}", outTradeNo, bankTransNo, tradeNo); + return false; + } + + // 微信医保自动退费 + MedicalOrder order = WxMedicalHelper.refundCash(outTradeNo, ("R" + tradeNo), tradeNo, cashFee, "系统繁忙缴费失败,自动退费"); + boolean isOk = order.isOk(); + log.info("【微信】[医保][处方]现金自动退费 {} outTradeNo={}, bankTransNo={}, tradeNo={}", (isOk ? "成功" : "失败"), outTradeNo, bankTransNo, tradeNo); + if (isOk) { + String refundResult = order.isOk() ? WxPayHelper.OK : order.getMessage(); + if (!recipeDao.updateRefundByTradeNo(tradeNo, refundResult)) { + log.info("[医保][处方]现金自动退费 修改数据库状态失败 tradeNo={}, refundResult={}", tradeNo, refundResult); + } + } else { + log.info("【微信】[医保][处方]现金自动退费 失败:{}", order.getMessage()); + } return false; } String hisTransNo = jsonResult.getDataMapString("HISTransNo"); String invoiceTransNo = jsonResult.getDataMapString("InvoiceTransNo"); - log.info("【医保】HIS结算成功 outTradeNo={}, bankTransNo={}, hisTransNo={}, invoiceTransNo={}", outTradeNo, bankTransNo, hisTransNo, invoiceTransNo); + log.info("[医保][处方]HIS结算成功 outTradeNo={}, bankTransNo={}, hisTransNo={}, invoiceTransNo={}", outTradeNo, bankTransNo, hisTransNo, invoiceTransNo); // 成功处理 if (!recipeDao.updateHisPaidByTradeNo(tradeNo, hisTransNo, invoiceTransNo)) { - log.error("【医保】修改成功数据失败"); + log.error("[医保][处方]修改成功数据失败"); } return true; } diff --git a/src/main/java/com/ynxbd/common/service/RecipeService.java b/src/main/java/com/ynxbd/common/service/RecipeService.java index 868bb9d..4445816 100644 --- a/src/main/java/com/ynxbd/common/service/RecipeService.java +++ b/src/main/java/com/ynxbd/common/service/RecipeService.java @@ -555,7 +555,7 @@ public class RecipeService { outTradeNo, recipeId, recipeFee, refundDesc ); - if (!recipeDao.updateRefundRByTradeNo(tradeNo, refundInfo.getRefundResult())) { + if (!recipeDao.updateRefundByTradeNo(tradeNo, refundInfo.getRefundResult())) { log.info("{} [处方自动退款]更新退款返回结果失败:outTradeNo={}, recipeId={}", merchantEnum.NAME, outTradeNo, recipeId); } return true; @@ -662,7 +662,7 @@ public class RecipeService { } if (cashFee.compareTo(BigDecimal.ZERO) == 0) { - if (!recipeDao.updateRefundRByTradeNo(payOrdId, WxPayHelper.OK)) { + if (!recipeDao.updateRefundByTradeNo(payOrdId, WxPayHelper.OK)) { log.error("[医保]现金0修改数据库状态失败 payOrderId={}", payOrdId); return Result.error(ResultEnum.DATA_UPDATE_ERROR); } @@ -680,7 +680,7 @@ public class RecipeService { log.info("[医保]现金退费order={}", order); refundResult = order.isOk() ? WxPayHelper.OK : order.getMessage(); - if (!recipeDao.updateRefundRByTradeNo(payOrdId, refundResult)) { + if (!recipeDao.updateRefundByTradeNo(payOrdId, refundResult)) { log.error("[医保]现金退费修改数据库状态失败 payOrderId={}, refundResult={}", payOrdId, refundResult); } if (order.isOk()) { @@ -719,7 +719,7 @@ public class RecipeService { Order refundInfo = PayService.handRefund(recipe.getUpdateTime(), recipe.getUpdateTime(), recipe, recipe.getTotalFee(), refundUser, refundDesc, orderType.CODE, recipeList.size(), sys, () -> recipeDao.updateRefundByRecipeId(outTradeNo, recipeId)); - if (!recipeDao.updateRefundRByTradeNo(tradeNo, refundInfo.getRefundResult())) { + if (!recipeDao.updateRefundByTradeNo(tradeNo, refundInfo.getRefundResult())) { log.info("[处方]退费成功,更新状态失败:outTradeNo={}, {}", outTradeNo, refundInfo); } else { if ("0".equals(recipe.getRefundResult())) { diff --git a/src/main/java/com/ynxbd/wx/wxfactory/WxMedicalHelper.java b/src/main/java/com/ynxbd/wx/wxfactory/WxMedicalHelper.java index fdb2e09..6df9f6b 100644 --- a/src/main/java/com/ynxbd/wx/wxfactory/WxMedicalHelper.java +++ b/src/main/java/com/ynxbd/wx/wxfactory/WxMedicalHelper.java @@ -10,6 +10,7 @@ import com.ynxbd.wx.wxfactory.base.auth.models.RespAccessToken; import com.ynxbd.wx.wxfactory.base.auth.models.RespJsapiTicket; import com.ynxbd.wx.wxfactory.bean.*; import com.ynxbd.wx.wxfactory.medical.MdConfig; +import com.ynxbd.wx.wxfactory.medical.enums.MdRefundTypeEnum; import com.ynxbd.wx.wxfactory.utils.WxSignHelper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; @@ -236,9 +237,8 @@ public class WxMedicalHelper { } - /** - * [医保]获取授权链接 + * [医保]退费 */ public static MedicalOrder refund(String outTradeNo, String outRefundNo, String payOrdId, BigDecimal cashFee, String reason) { return WxFactory.Medical.Common().refund( @@ -250,6 +250,25 @@ public class WxMedicalHelper { outRefundNo, payOrdId, cashFee, + null, + reason + ); + } + + /** + * [医保]退现金部分 + */ + public static MedicalOrder refundCash(String outTradeNo, String outRefundNo, String payOrdId, BigDecimal cashFee, String reason) { + return WxFactory.Medical.Common().refund( + WxCacheHelper.getAccessToken(), + MdConfig.MD_APP_ID, + WeChatConfig.MCH_ID, + MdConfig.PAY_KEY, + outTradeNo, + outRefundNo, + payOrdId, + cashFee, + MdRefundTypeEnum.CASH_ONLY, reason ); } diff --git a/src/main/java/com/ynxbd/wx/wxfactory/medical/Client.java b/src/main/java/com/ynxbd/wx/wxfactory/medical/Client.java index 6256651..3c31871 100644 --- a/src/main/java/com/ynxbd/wx/wxfactory/medical/Client.java +++ b/src/main/java/com/ynxbd/wx/wxfactory/medical/Client.java @@ -9,6 +9,7 @@ import com.ynxbd.common.helper.http.OkHttpHelper; import com.ynxbd.common.result.JsonResult; import com.ynxbd.wx.wxfactory.WxFactory; import com.ynxbd.wx.wxfactory.bean.*; +import com.ynxbd.wx.wxfactory.medical.enums.MdRefundTypeEnum; import com.ynxbd.wx.wxfactory.utils.WxRequestHelper; import com.ynxbd.wx.wxfactory.utils.WxSignHelper; import lombok.NoArgsConstructor; @@ -31,12 +32,11 @@ public class Client { * @param url url */ public String getAuthUrl(String url) { - log.info("[医保]免密授权地址-{}",MdConfig.getConfigUrl(url)); + log.info("[医保]免密授权地址-{}", MdConfig.getConfigUrl(url)); return MdConfig.getConfigUrl(url); } - /** * 微信医保下单 * @@ -118,8 +118,8 @@ public class Client { //========================================================== params.put("hospital_name", hospitalName); // - if(MdConfig.IS_DEV){ - params.put("use_sandbox",1); + if (MdConfig.IS_DEV) { + params.put("use_sandbox", 1); } //========================================================= @@ -187,11 +187,11 @@ public class Client { * @param mdPayKey mdPayKey * @param outTradeNo 订单号 * @param outRefundNo 退费订单号 - * @param payOrdId 医保订单号 + * @param payOrdId 医保订单号|对应处方上传的出参单号 * @param cashFee 退费现金 * @param reason 退费原因 */ - public MedicalOrder refund(String accessToken, String appId, String mchId, String mdPayKey, String outTradeNo, String outRefundNo, String payOrdId, BigDecimal cashFee, String reason) { + public MedicalOrder refund(String accessToken, String appId, String mchId, String mdPayKey, String outTradeNo, String outRefundNo, String payOrdId, BigDecimal cashFee, MdRefundTypeEnum mdRefundTypeEnum, String reason) { if (reason == null) { reason = "申请退款"; } @@ -205,32 +205,27 @@ public class Client { params.put("mch_id", mchId); // 二选一 params.put("hosp_out_trade_no", outTradeNo); // 第三方服务商订单号 outTradeNo - // params.put("med_trans_id", medTransId); // 微信生成的医疗订单号 + // params.put("med_trans_id", medTransId); // 微信生成的医疗订单号 params.put("hosp_out_refund_no", outRefundNo); // 退费订单号 params.put("nonce_str", UUID.randomUUID().toString().replaceAll("-", "")); - JSONObject requestContent = new JSONObject(); requestContent.put("ref_reason", finalReason); requestContent.put("payOrdId", payOrdId); params.put("request_content", JSON.toJSONString(requestContent)); -// /** -// * 1、不填则全退,CASH_ONLY则只退现金部分; -// * 2、INS_ONLY:为全额退医保部分(统筹+个账),如果订单已经单独退了统筹部分则不再支持医保部分全额退款; -// * 3、INS_PLAN_PART:为只退医保统筹部分,当前统筹部分仅支持一次性退款; -// * 4、INS_INDIVIDUAL_PART:为只退医保个账部分,个账部分支持多次退款。 -// * 现金跟医保可以分开退款,医保部分统筹和个账部分也可以分开退,需要填写不同的hosp_out_refund_no参数 -// */ -// params.put("part_refund_type", "INS_ONLY"); // 部分退款 + // /** // * 不填默认全退,填写金额时则指定金额不能为0;该参数只在part_refund_type为INS_INDIVIDUAL_PART生效 // */ // params.put("ins_refund_fee", new BigDecimal(refundFee).movePointRight(2)); // 个账部分退款 - params.put("cash_refund_fee", cashFee.movePointRight(2).intValue()); // 现金退款 + if (mdRefundTypeEnum != null) { + params.put("part_refund_type", mdRefundTypeEnum.CODE); // 只退现金部分 + } + params.put("cash_refund_fee", cashFee.movePointRight(2).intValue()); // 现金退款 // 医保退款必须------------------------------------------------ params.put("cancel_bill_no", outRefundNo); // 撤销单据号 @@ -322,7 +317,7 @@ public class Client { * @return 用户信息 */ public MedicalUserInfo getUserInfo(String reqUrl, String openid, String qrcode) { - log.info("[医保]用户授权地址-{}",reqUrl); + log.info("[医保]用户授权地址-{}", reqUrl); MedicalUserInfo info = new MedicalUserInfo(); String timestamp = Long.toString(System.currentTimeMillis()); diff --git a/src/main/java/com/ynxbd/wx/wxfactory/medical/MdConfig.java b/src/main/java/com/ynxbd/wx/wxfactory/medical/MdConfig.java index 72ea543..42b8642 100644 --- a/src/main/java/com/ynxbd/wx/wxfactory/medical/MdConfig.java +++ b/src/main/java/com/ynxbd/wx/wxfactory/medical/MdConfig.java @@ -34,6 +34,7 @@ public class MdConfig { public static final String MD_APP_SECRET; public static boolean IS_DEV = true; + public static boolean IS_AUTO_REFUND = true; static { ProperHelper config = new ProperHelper().read("medical.properties"); @@ -42,6 +43,8 @@ public class MdConfig { config.setIsEnable(IS_ENABLE); IS_DEV = config.getBoolean("medical.is_dev", true); + IS_AUTO_REFUND = config.getBoolean("medical.is_auto_refund", false); + CHANNEL = config.getString("medical.channel"); ORG_NO = config.getString("medical.org_no"); ORG_APP_ID = config.getString("medical.org_app_id"); diff --git a/src/main/java/com/ynxbd/wx/wxfactory/medical/enums/MdRefundTypeEnum.java b/src/main/java/com/ynxbd/wx/wxfactory/medical/enums/MdRefundTypeEnum.java new file mode 100644 index 0000000..8633eea --- /dev/null +++ b/src/main/java/com/ynxbd/wx/wxfactory/medical/enums/MdRefundTypeEnum.java @@ -0,0 +1,36 @@ +package com.ynxbd.wx.wxfactory.medical.enums; + +import lombok.ToString; +import org.apache.commons.lang3.ObjectUtils; + +@ToString +public enum MdRefundTypeEnum { + + // 不填则全退|备注:现金跟医保可以分开退款,医保部分统筹和个账部分也可以分开退,需要填写不同的hosp_out_refund_no参数 + CASH_ONLY("CASH_ONLY", "只退现金部分"), + INS_ONLY("INS_ONLY", "为全额退医保部分(统筹+个账),如果订单已经单独退了统筹部分则不再支持医保部分全额退款"), + INS_PLAN_PART("INS_PLAN_PART", "为只退医保统筹部分,当前统筹部分仅支持一次性退款"), + INS_INDIVIDUAL_PART("INS_INDIVIDUAL_PART", "为只退医保个账部分,个账部分支持多次退款"), + ; + + public final String CODE; + public final String NAME; + + MdRefundTypeEnum(String CODE, String NAME) { + this.CODE = CODE; + this.NAME = NAME; + } + + + public static MdRefundTypeEnum findEnum(Integer code) { + if (ObjectUtils.isEmpty(code)) { + return null; + } + for (MdRefundTypeEnum item : MdRefundTypeEnum.values()) { + if (item.CODE.equals(code)) { + return item; + } + } + return null; + } +} diff --git a/src/main/resources/medical.properties b/src/main/resources/medical.properties index 29c9713..2ed0786 100644 --- a/src/main/resources/medical.properties +++ b/src/main/resources/medical.properties @@ -1,32 +1,33 @@ -# 医保配置 +# \u533B\u4FDD\u914D\u7F6E medical.is_dev=true medical.is_enable=true +medical.is_auto_refund=true -# 只有订阅号的医院或只想用订阅号的医院 申请一个空服务号 空服务号配置微信公众号(服务号)appId +# \u53EA\u6709\u8BA2\u9605\u53F7\u7684\u533B\u9662\u6216\u53EA\u60F3\u7528\u8BA2\u9605\u53F7\u7684\u533B\u9662 \u7533\u8BF7\u4E00\u4E2A\u7A7A\u670D\u52A1\u53F7 \u7A7A\u670D\u52A1\u53F7\u914D\u7F6E\u5FAE\u4FE1\u516C\u4F17\u53F7\uFF08\u670D\u52A1\u53F7\uFF09appId medical.md_app_id=wx73fc2dbf84a43dce medical.md_app_secret=06ba8338f3db206d0be3019ff29ed431 -# 城市编码(腾讯提供) +# \u57CE\u5E02\u7F16\u7801\uFF08\u817E\u8BAF\u63D0\u4F9B\uFF09 medical.city_code=530700 -# 医院名称 -medical.hospital_name=\u4e91\u5357\u7701\u7b2c\u4e09\u4eba\u6c11\u533b\u9662 -# 医保(1.excel文档)---------------------------------------------------------------------------------- -# 定点医药机构编码 +# \u533B\u9662\u540D\u79F0 +medical.hospital_name=\u4E91\u5357\u7701\u7B2C\u4E09\u4EBA\u6C11\u533B\u9662 +# \u533B\u4FDD\uFF081.excel\u6587\u6863\uFF09---------------------------------------------------------------------------------- +# \u5B9A\u70B9\u533B\u836F\u673A\u6784\u7F16\u7801 medical.org_no=H53011200807 -# 定点医药机构小程序/h5应用id(正式环境:渠道编号) +# \u5B9A\u70B9\u533B\u836F\u673A\u6784\u5C0F\u7A0B\u5E8F/h5\u5E94\u7528id\uFF08\u6B63\u5F0F\u73AF\u5883\uFF1A\u6E20\u9053\u7F16\u53F7\uFF09 medical.org_app_id=1GUMNBHQ70MU3F60C80A00008DB89259 -# 定点医药机构渠道认证编码 +# \u5B9A\u70B9\u533B\u836F\u673A\u6784\u6E20\u9053\u8BA4\u8BC1\u7F16\u7801 medical.org_chnl_crtf_codg=BqK1kMStlhVDgN2uHf4EsLK/F2LjZPYJ81nK2eYQqxtlXTierXl8479LHWGrW1Rd -# 免密授权(2.联系腾讯-->邮件提供(需提供给腾讯负责人:1.医院正式域名、2.公众号appid、3.免密授权ip白名单))---------- -# 合作方id +# \u514D\u5BC6\u6388\u6743\uFF082.\u8054\u7CFB\u817E\u8BAF-->\u90AE\u4EF6\u63D0\u4F9B\uFF08\u9700\u63D0\u4F9B\u7ED9\u817E\u8BAF\u8D1F\u8D23\u4EBA\uFF1A1.\u533B\u9662\u6B63\u5F0F\u57DF\u540D\u30012.\u516C\u4F17\u53F7appid\u30013.\u514D\u5BC6\u6388\u6743ip\u767D\u540D\u5355\uFF09\uFF09---------- +# \u5408\u4F5C\u65B9id medical.partner_id=50003409 -# 测试密钥 +# \u6D4B\u8BD5\u5BC6\u94A5 medical.dev_partner_secret=af01101467007e28fe3a0b0caf0fb54a -# 正式密钥 +# \u6B63\u5F0F\u5BC6\u94A5 medical.partner_secret=f92df3128382757425ba4c5ca166688f -# 渠道号 +# \u6E20\u9053\u53F7 medical.channel=aaghgf2i4ddgrokh247fgo7n -# 医保支付签名key(3.公众号-->城市服务-->医保支付功能开通后-->邮件提供)---------------------------------------- +# \u533B\u4FDD\u652F\u4ED8\u7B7E\u540Dkey\uFF083.\u516C\u4F17\u53F7-->\u57CE\u5E02\u670D\u52A1-->\u533B\u4FDD\u652F\u4ED8\u529F\u80FD\u5F00\u901A\u540E-->\u90AE\u4EF6\u63D0\u4F9B\uFF09---------------------------------------- medical.pay_key=9baafa056ad046ebf4fafc2b80c17df6 \ No newline at end of file