From a2420d61fdcc30b706c3edaa015a0351b14f6f36 Mon Sep 17 00:00:00 2001 From: sangchengzhi <2305486879@qq.com> Date: Thu, 22 Jan 2026 10:41:24 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=97=85=E6=A1=88=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=8E=A5=E5=8F=A3=EF=BC=8C=E4=BF=AE=E6=94=B9=E9=80=80?= =?UTF-8?q?=E8=B4=B9=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/guahao/api/task/GuahaoTask.java | 5 + .../walkinto/controller/ApiPayController.java | 22 +- .../api/walkinto/service/WxPayService.java | 219 +++++++++++++++++- .../java/com/guahao/common/util/XmlUtil.java | 13 +- .../reserve/controller/BingAnController.java | 47 +++- .../h5/reserve/mapper/BinganMapper.java | 7 + .../h5/reserve/service/BinganService.java | 6 + .../h5/reserve/service/BinganServiceImpl.java | 16 ++ .../h5/reserve/service/Reserve8Service.java | 2 +- .../com/guahao/h5/reserve/vo/BingAnVO.java | 1 + .../mybatis/mapper/reserve/BinganMapper.xml | 12 + 11 files changed, 333 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/guahao/api/task/GuahaoTask.java b/src/main/java/com/guahao/api/task/GuahaoTask.java index 95e2c34..84787b8 100644 --- a/src/main/java/com/guahao/api/task/GuahaoTask.java +++ b/src/main/java/com/guahao/api/task/GuahaoTask.java @@ -80,6 +80,11 @@ public class GuahaoTask { } else { cancelSuccess = true; log.info("退号成功"); + if (vo.getZfamount().equals("0.00")){ + log.info("0元挂号,跳过退费处理"); + refundSuccess = true; + return; + } // 2. 执行退费 Map refundResult = reserve8Service.MOP_BillsPayedRefund(vo); diff --git a/src/main/java/com/guahao/api/walkinto/controller/ApiPayController.java b/src/main/java/com/guahao/api/walkinto/controller/ApiPayController.java index 3d10d3f..b17452d 100644 --- a/src/main/java/com/guahao/api/walkinto/controller/ApiPayController.java +++ b/src/main/java/com/guahao/api/walkinto/controller/ApiPayController.java @@ -153,6 +153,23 @@ public class ApiPayController { return wxPayService.buildFailResponse("处理异常"); } } + /** + * 微信退款回调通知接口 + * + * @return + */ + @PostMapping("/wxRefund/notify2") + @WebLog(description = "wxRefundNotify2") + public String wxRefundNotify2(@RequestBody String xmlStr, HttpServletResponse response, HttpServletRequest request) { + try { + String result = wxPayService.handleWxRefundNotify2(xmlStr); + return result; + } catch (Exception e) { + logger.error("微信支付回调处理异常", e); + // 返回失败,微信会重试 + return wxPayService.buildFailResponse("处理异常"); + } + } /** * 查询微信订单状态 @@ -184,13 +201,14 @@ public class ApiPayController { @PostMapping("/wxpay/refundOrder") @WebLog(description = "refundOrder") public Object refundOrder(@RequestParam("powertranid") String powertranid, - @RequestParam("money") String money + @RequestParam("money") String money, + @RequestParam("type") String type ) { String paramTip = ""; try { paramTip = String.format(" >>> requestObj:%s", JSONUtil.toJsonStr(powertranid)); - Map map = wxPayService.refundOrder(powertranid,money); + Map map = wxPayService.refundOrder(powertranid,money,type); return ResponseResult.success(map); } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/java/com/guahao/api/walkinto/service/WxPayService.java b/src/main/java/com/guahao/api/walkinto/service/WxPayService.java index 0af7708..9119c11 100644 --- a/src/main/java/com/guahao/api/walkinto/service/WxPayService.java +++ b/src/main/java/com/guahao/api/walkinto/service/WxPayService.java @@ -187,7 +187,7 @@ public class WxPayService { txSendMsg.SendNotifyYJJ(uo,openid); }else { //写入his失败,执行退款处理 - refundOrder(uo.getCode(),AmountUtil.doubleToStr(uo.getMoney())); + refundOrder(uo.getCode(),AmountUtil.doubleToStr(uo.getMoney()),"微信"); } } @@ -424,7 +424,7 @@ public class WxPayService { } else { log.error("挂号确认失败,将自动退款: " + mapConfirm.get("errormsg")); // 可以考虑发起退款 - refundOrder(outTradeNo, String.valueOf(reserveVo.getZfamount())); + refundOrder(outTradeNo, String.valueOf(reserveVo.getZfamount()),"微信"); } } else { log.warn("未找到对应订单: " + outTradeNo); @@ -541,7 +541,7 @@ public class WxPayService { } } - public Map refundOrder(String powertranid,String amount) { + public Map refundOrder(String powertranid,String amount,String type) { Map data = new HashMap<>(); data.put("appid", wxPayConfig.getAppId()); data.put("mch_id", wxPayConfig.getMchId()); @@ -553,7 +553,11 @@ public class WxPayService { String money = WxPayDUtil.yuanToFee(amount); data.put("total_fee", money); data.put("refund_fee", money); - data.put("notify_url", "https://nxwj.btlsoln.com/nxgzh/pay/wxRefund/notify"); + if (type.equals("微信")){ + data.put("notify_url", "https://nxwj.btlsoln.com/nxgzh/pay/wxRefund/notify"); + } else if (type.equals("全部")) { + data.put("notify_url", "https://nxwj.btlsoln.com/nxgzh/pay/wxRefund/notify2"); + } data.put("op_user_id", wxPayConfig.getMchId()); // 操作员 = 商户号 CloseableHttpClient client = null; @@ -721,6 +725,7 @@ public class WxPayService { Reserve8Vo vo = new Reserve8Vo(); vo.setOrderno(outTradeNo); List reserveList = reserve8Mapper.getReserveList(vo); + // HisRefundVo refundVo = new HisRefundVo(); if (reserveList.isEmpty()){ if (outTradeNo.substring(0, 2).equals("YC")){ //业务处理逻辑...... @@ -733,11 +738,12 @@ public class WxPayService { userOrderMapper.SelectUserOrderByCode(outTradeNo,3); + InterfaceCount interfaceCount = new InterfaceCount(); interfaceCount.setUserId(Integer.toString(uo.getUser_id())); interfaceCount.setInterfaceIdentification("YCTF"); interfaceCountService.updateInterfaceConut(interfaceCount); - return ""; + }else if (outTradeNo.substring(0, 2).equals("MZ")){ HsjcVo hsjcvo = new HsjcVo(); hsjcvo.setOrderno(outTradeNo); @@ -745,22 +751,50 @@ public class WxPayService { hsjcvo = list.get(0); hsjcMapper.updateByOutTradeNo(outTradeNo,5); + // refundVo.setPatientid(hsjcvo.getPatientid()); + // refundVo.setBillsmsg(hsjcvo.getReferno()); + // refundVo.setPaynature("1"); + // refundVo.setPaytype("微信"); + // refundVo.setPowertranid(outTradeNo); + // refundVo.setZfamount(hsjcvo.getZfamount()); + // refundVo.setYbzhamount("0.00"); + // refundVo.setYbtcamount("0.00"); + // refundVo.setHisopernum("WX"); InterfaceCount interfaceCount = new InterfaceCount(); interfaceCount.setUserId(Integer.toString(hsjcvo.getUserId())); interfaceCount.setInterfaceIdentification("MZTF"); interfaceCountService.updateInterfaceConut(interfaceCount); - return ""; - }else if (outTradeNo.substring(0, 2).equals("BA")){ + }else if (outTradeNo.substring(0, 2).equals("BA")){ + BingAnVO bingAnVO = binganMapper.selectByOrderNo(outTradeNo); // 手动病案退款 binganMapper.updateByOrderNoAndStatus(outTradeNo); - // InterfaceCount interfaceCount = new InterfaceCount(); - // interfaceCount.setUserId(Integer.toString(hsjcvo.getUserId())); - // interfaceCount.setInterfaceIdentification("BATF"); - // interfaceCountService.updateInterfaceConut(interfaceCount); - return ""; + + // refundVo.setPatientid(bingAnVO.getPatientId()); + // refundVo.setBillsmsg(bingAnVO.getReptno()); + // refundVo.setPaynature("1"); + // refundVo.setPaytype("微信"); + // refundVo.setPowertranid(outTradeNo); + // refundVo.setZfamount(bingAnVO.getAmount().toPlainString()); + // refundVo.setYbzhamount("0.00"); + // refundVo.setYbtcamount("0.00"); + // refundVo.setHisopernum("WX"); + + InterfaceCount interfaceCount = new InterfaceCount(); + interfaceCount.setUserId(bingAnVO.getPatientId()); + interfaceCount.setInterfaceIdentification("BATF"); + interfaceCountService.updateInterfaceConut(interfaceCount); + } + // // his退费 + // String strXML = XmlUtil.getBillsPayedRefund(refundVo); + // log.debug("His退费MOP_BillsPayedRefund req:" + strXML); + // // 发送soap请求 + // String respXml = SoapUtil.soapMethod(strXML); + // log.debug("His退费MOP_BillsPayedRefund res:" + respXml); + + return ""; } Reserve8Vo reserveVo = reserveList.get(0); // 4. 冪等处理 @@ -905,6 +939,167 @@ public class WxPayService { } + public String handleWxRefundNotify2(String xmlData) { + log.info("进入退款回调"); + try { + // 1. 解析外层 XML + log.info("微信退款回调通知 XML: " + xmlData); + WxPayUtil wxPayUtil = new WxPayUtil(); + Map notifyMap = wxPayUtil.xmlToMap(xmlData); + + String returnCode = notifyMap.get("return_code"); + if (!"SUCCESS".equals(returnCode)) { + log.warn("微信通知失败: return_code={}", returnCode); + return ""; + } + + String reqInfo = notifyMap.get("req_info"); + if (reqInfo == null || reqInfo.isEmpty()) { + log.warn("req_info 为空"); + return ""; + } + + // 2. 解密 req_info(使用 APIv2 key) + String apiKey = wxPayConfig.getApiKey(); // 确保这是 32 位的 API 密钥 + String decryptData; + try { + decryptData = decryptReqInfo(reqInfo,apiKey); + } catch (Exception e) { + log.error("解密 req_info 失败", e); + return ""; + } + + log.info("解密后的退款数据: " + decryptData); + + // 3. 解析明文 XML + Map refundResult = wxPayUtil.xmlToMap(decryptData); + + String outTradeNo = refundResult.get("out_trade_no"); + String outRefundNo = refundResult.get("out_refund_no"); + String refundStatus = refundResult.get("refund_status"); // SUCCESS / FAIL / PROCESSING + + log.info("退款结果: out_trade_no={}, out_refund_no={}, status={}", outTradeNo, outRefundNo, refundStatus); + + // + // if (refundService.isAlreadyProcessed(outRefundNo)) { + // log.info("退款单 {} 已处理,跳过", outRefundNo); + // return ""; + // } + + + // 5. 处理业务逻辑 + if ("SUCCESS".equals(refundStatus)) { + Reserve8Vo vo = new Reserve8Vo(); + vo.setOrderno(outTradeNo); + List reserveList = reserve8Mapper.getReserveList(vo); + HisRefundVo refundVo = new HisRefundVo(); + if (reserveList.isEmpty()){ + if (outTradeNo.substring(0, 2).equals("YC")){ + //业务处理逻辑...... + Example example = new Example(UserOrder.class); + Example.Criteria criteria = example.createCriteria(); + criteria.andEqualTo("code", outTradeNo); + + List list = userOrderMapper.selectByExample(example); + UserOrder uo = list.get(0); + + userOrderMapper.SelectUserOrderByCode(outTradeNo,3); + // refundVo.setPatientid(uo.getCard_no()); + // refundVo.setBillsmsg(); + + + InterfaceCount interfaceCount = new InterfaceCount(); + interfaceCount.setUserId(Integer.toString(uo.getUser_id())); + interfaceCount.setInterfaceIdentification("YCTF"); + interfaceCountService.updateInterfaceConut(interfaceCount); + + }else if (outTradeNo.substring(0, 2).equals("MZ")){ + HsjcVo hsjcvo = new HsjcVo(); + hsjcvo.setOrderno(outTradeNo); + List list = hsjcMapper.getMzjfListByFlow(hsjcvo); + hsjcvo = list.get(0); + + hsjcMapper.updateByOutTradeNo(outTradeNo,5); + refundVo.setPatientid(hsjcvo.getPatientid()); + refundVo.setBillsmsg(hsjcvo.getReferno()); + refundVo.setPaynature("1"); + refundVo.setPaytype("微信"); + refundVo.setPowertranid(outTradeNo); + refundVo.setZfamount(hsjcvo.getZfamount()); + refundVo.setYbzhamount("0.00"); + refundVo.setYbtcamount("0.00"); + refundVo.setHisopernum("WX"); + + InterfaceCount interfaceCount = new InterfaceCount(); + interfaceCount.setUserId(Integer.toString(hsjcvo.getUserId())); + interfaceCount.setInterfaceIdentification("MZTF"); + interfaceCountService.updateInterfaceConut(interfaceCount); + + }else if (outTradeNo.substring(0, 2).equals("BA")){ + BingAnVO bingAnVO = binganMapper.selectByOrderNo(outTradeNo); + // 手动病案退款 + binganMapper.updateByOrderNoAndStatus(outTradeNo); + + refundVo.setPatientid(bingAnVO.getPatientId()); + refundVo.setBillsmsg(bingAnVO.getReptno()); + refundVo.setPaynature("1"); + refundVo.setPaytype("微信"); + refundVo.setPowertranid(outTradeNo); + refundVo.setZfamount(bingAnVO.getAmount().toPlainString()); + refundVo.setYbzhamount("0.00"); + refundVo.setYbtcamount("0.00"); + refundVo.setHisopernum("WX"); + + InterfaceCount interfaceCount = new InterfaceCount(); + interfaceCount.setUserId(bingAnVO.getPatientId()); + interfaceCount.setInterfaceIdentification("BATF"); + interfaceCountService.updateInterfaceConut(interfaceCount); + + } + // his退费 + String strXML = XmlUtil.getBillsPayedRefund(refundVo); + log.debug("His退费MOP_BillsPayedRefund req:" + strXML); + // 发送soap请求 + String respXml = SoapUtil.soapMethod(strXML); + log.debug("His退费MOP_BillsPayedRefund res:" + respXml); + + return ""; + } + Reserve8Vo reserveVo = reserveList.get(0); + // 4. 冪等处理 + if (reserveVo.getAppStatus() != null && reserveVo.getAppStatus().intValue() == 1) { + // 处理逻辑 + return ""; + } + + + if (!reserveList.isEmpty()) { + // 更新状态:1 已退费 + reserve8Mapper.opAppPayAppoint(outTradeNo, "Y", 1,""); + + // 统计 + InterfaceCount interfaceCount = new InterfaceCount(); + interfaceCount.setUserId(Integer.toString(reserveVo.getUserId())); + interfaceCount.setInterfaceIdentification("TH"); + interfaceCountService.updateInterfaceConut(interfaceCount); + + log.info("退款成功,订单 {} 已更新", outTradeNo); + } else { + log.warn("未找到订单: {}", outTradeNo); + } + } else { + log.warn("退款未成功: {}", refundStatus); + } + + // 6. 返回成功 + return ""; + + } catch (Exception e) { + log.error("处理退款回调异常", e); + // ❗❗❗ 重要:返回 FAIL,让微信重试! + return ""; + } + } } diff --git a/src/main/java/com/guahao/common/util/XmlUtil.java b/src/main/java/com/guahao/common/util/XmlUtil.java index fb3d323..4223620 100644 --- a/src/main/java/com/guahao/common/util/XmlUtil.java +++ b/src/main/java/com/guahao/common/util/XmlUtil.java @@ -2219,7 +2219,18 @@ public class XmlUtil { str.append(vo.getPages()); str.append(""); str.append(""); - str.append(vo.getAmount()); + // 安全的数值减法运算,处理可能的空值和精度问题 + BigDecimal amount = vo.getAmount(); + BigDecimal selectAmount = vo.getSelectAmount(); + BigDecimal result = BigDecimal.ZERO; + if (amount != null && selectAmount != null) { + result = amount.subtract(selectAmount); + } else if (amount != null) { + result = amount; + } else if (selectAmount != null) { + result = selectAmount.negate(); + } + str.append(result); str.append(""); str.append(""); str.append("]]>"); diff --git a/src/main/java/com/guahao/h5/reserve/controller/BingAnController.java b/src/main/java/com/guahao/h5/reserve/controller/BingAnController.java index fc395a9..a061ac3 100644 --- a/src/main/java/com/guahao/h5/reserve/controller/BingAnController.java +++ b/src/main/java/com/guahao/h5/reserve/controller/BingAnController.java @@ -65,7 +65,7 @@ public class BingAnController { } } @RequestMapping(value = "/apiGetBAList", method = RequestMethod.POST) - @WebLog(description = "apiGetBAList") + @WebLog(description = "查询病案信息通过userId") public Object apiGetBAList(Integer userId,String token) { try { int retToken = getUserToken(userId,token); @@ -80,6 +80,51 @@ public class BingAnController { return ResponseResult.sysError(e.getLocalizedMessage()); } } + @RequestMapping(value = "/apiGetBAList2", method = RequestMethod.POST) + @WebLog(description = "查询病案信息通过patientId或者住院号") + public Object apiGetBAList2(Integer userId,String token,String patientId,String hosNum) { + try { + int retToken = getUserToken(userId,token); + if (retToken != 0) { + List list = null; + if (patientId != null && !patientId.isEmpty()) { + // 处理 patientId 相关逻辑 + log.info("通过patientId查询病案"); + list = binganService.apiGetBAListByPatientId(patientId); + } else if (hosNum != null && !hosNum.isEmpty()) { + // 处理 hosNum 相关逻辑 + log.info("通过住院号查询病案"); + list = binganService.apiGetBAListByHosNum(hosNum); + } + + return ResponseResult.success(list); + } else { + return ResponseResult.sysLoginError(); + } + } catch (Exception e) { + return ResponseResult.sysError(e.getLocalizedMessage()); + } + } + @RequestMapping(value = "/apiUpdateBA", method = RequestMethod.POST) + @WebLog(description = "更新病案份数") + public Object apiUpdateBA(Integer userId,String token,BingAnVO vo ) { + try { + int retToken = getUserToken(userId,token); + if (retToken != 0) { + log.info("更新病案份数,vo:{}",vo); + int i = binganService.apiUpdateBA(vo); + if (i == 1){ + return ResponseResult.success(); + }else { + return ResponseResult.sysError("更新失败"); + } + } else { + return ResponseResult.sysLoginError(); + } + } catch (Exception e) { + return ResponseResult.sysError(e.getLocalizedMessage()); + } + } @RequestMapping(value = "/apiDeleteApplication", method = RequestMethod.POST) @WebLog(description = "apiDeleteApplication") public Object apiDeleteApplication(Integer id,Integer userId,String token) { diff --git a/src/main/java/com/guahao/h5/reserve/mapper/BinganMapper.java b/src/main/java/com/guahao/h5/reserve/mapper/BinganMapper.java index aa0134e..5177425 100644 --- a/src/main/java/com/guahao/h5/reserve/mapper/BinganMapper.java +++ b/src/main/java/com/guahao/h5/reserve/mapper/BinganMapper.java @@ -4,6 +4,7 @@ import com.guahao.h5.reserve.vo.BingAnVO; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import java.math.BigDecimal; import java.util.List; @Mapper @@ -29,4 +30,10 @@ public interface BinganMapper { void updateById(String payOrderNo, Integer id); void updateByOrderNoAndStatus(String orderno); + + int updateByCopies(Integer id, Integer copies, BigDecimal amount); + + List selectListByPatientId(String patientId); + + List selectListByHosNum(String hosNum); } diff --git a/src/main/java/com/guahao/h5/reserve/service/BinganService.java b/src/main/java/com/guahao/h5/reserve/service/BinganService.java index 5c3df6c..85b6790 100644 --- a/src/main/java/com/guahao/h5/reserve/service/BinganService.java +++ b/src/main/java/com/guahao/h5/reserve/service/BinganService.java @@ -18,4 +18,10 @@ public interface BinganService { Integer apiDeleteApplication(Integer id); Map apiBAPay(BingAnPayVO vo, HttpServletRequest request); + + int apiUpdateBA(BingAnVO vo); + + List apiGetBAListByPatientId(String patientId); + + List apiGetBAListByHosNum(String hosNum); } diff --git a/src/main/java/com/guahao/h5/reserve/service/BinganServiceImpl.java b/src/main/java/com/guahao/h5/reserve/service/BinganServiceImpl.java index ef71c1e..69f6cd8 100644 --- a/src/main/java/com/guahao/h5/reserve/service/BinganServiceImpl.java +++ b/src/main/java/com/guahao/h5/reserve/service/BinganServiceImpl.java @@ -250,4 +250,20 @@ public class BinganServiceImpl implements BinganService { throw new RuntimeException(e); } } + + @Override + public int apiUpdateBA(BingAnVO vo) { + + return binganMapper.updateByCopies(vo.getId(),vo.getCopies(),vo.getAmount()); + } + + @Override + public List apiGetBAListByPatientId(String patientId) { + return binganMapper.selectListByPatientId(patientId); + } + + @Override + public List apiGetBAListByHosNum(String hosNum) { + return binganMapper.selectListByHosNum(hosNum); + } } diff --git a/src/main/java/com/guahao/h5/reserve/service/Reserve8Service.java b/src/main/java/com/guahao/h5/reserve/service/Reserve8Service.java index 4675a0e..7e44bf8 100644 --- a/src/main/java/com/guahao/h5/reserve/service/Reserve8Service.java +++ b/src/main/java/com/guahao/h5/reserve/service/Reserve8Service.java @@ -379,7 +379,7 @@ public class Reserve8Service { } else if (vo.getHisopernum().equals("wx") || vo.getHisopernum().equals("GZH")) { log.debug("微信退款"); vo.setPowertranid(vo3.getOrderno()); - Map stringStringMap = wxPayService.refundOrder(vo.getPowertranid(), vo.getZfamount()); + Map stringStringMap = wxPayService.refundOrder(vo.getPowertranid(), vo.getZfamount(),"微信"); Map objectMap = convertStringMapToObjectMap(stringStringMap); if ("SUCCESS".equals(objectMap.get("return_code")) && "SUCCESS".equals(objectMap.get("result_code"))) { diff --git a/src/main/java/com/guahao/h5/reserve/vo/BingAnVO.java b/src/main/java/com/guahao/h5/reserve/vo/BingAnVO.java index c7c8dca..64483ed 100644 --- a/src/main/java/com/guahao/h5/reserve/vo/BingAnVO.java +++ b/src/main/java/com/guahao/h5/reserve/vo/BingAnVO.java @@ -47,6 +47,7 @@ public class BingAnVO { private MultipartFile powerOfAttorneyFile;// 授权委托书(对应前端的powerOfAttorneyFile) private BigDecimal selectAmount; //查询费 private Integer pages; //页数 + private Integer copies; // 打印份数 private BigDecimal amount; //需支付金额 private Integer status; //支付状态 private Integer send; //领取状态 diff --git a/src/main/resources/mybatis/mapper/reserve/BinganMapper.xml b/src/main/resources/mybatis/mapper/reserve/BinganMapper.xml index 13f1aca..ae2185a 100644 --- a/src/main/resources/mybatis/mapper/reserve/BinganMapper.xml +++ b/src/main/resources/mybatis/mapper/reserve/BinganMapper.xml @@ -44,6 +44,12 @@ SET status = 0 WHERE orderno = #{orderno} + + UPDATE express + SET copies = #{copies}, + amount = #{amount} + WHERE id = #{id} + SELECT * FROM express WHERE user_id = #{userId} and status = #{status} and deleted = 0 and orderno IS NOT NULL; + + \ No newline at end of file