package thyyxxk.wxservice_server.service; import com.alibaba.fastjson.JSONObject; import com.wechat.pay.java.core.util.GsonUtil; import com.wechat.pay.java.service.payments.jsapi.model.*; import com.wechat.pay.java.service.payments.model.Transaction; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import thyyxxk.wxservice_server.config.exception.ExceptionEnum; import thyyxxk.wxservice_server.constant.OrderType; import thyyxxk.wxservice_server.constant.medins.Insutype; import thyyxxk.wxservice_server.constant.medins.MedType; import thyyxxk.wxservice_server.dao.WxApiDao; import thyyxxk.wxservice_server.entity.ResultVo; import thyyxxk.wxservice_server.entity.appointment.DoctorInfo; import thyyxxk.wxservice_server.entity.paymzfee.MedinsPresettle; import thyyxxk.wxservice_server.entity.wxapi.JsApiSHA1; import thyyxxk.wxservice_server.entity.wxapi.GenMzPayQrcodeParam; import thyyxxk.wxservice_server.entity.wxapi.WxPayOrder; import thyyxxk.wxservice_server.entity.wxapi.WxPyQrcdPrm; import thyyxxk.wxservice_server.factory.wechatpay.WeChatPayService; import thyyxxk.wxservice_server.factory.wechatpay.model.NativePayResponse; import thyyxxk.wxservice_server.factory.wechatpay.model.WechatPayGlobalRequest; import thyyxxk.wxservice_server.utils.*; import java.math.BigDecimal; import java.util.*; import java.util.concurrent.TimeUnit; /** * @author dj */ @Slf4j @Service public class WxApiService { private final WxApiDao dao; private final SavePayResultService savePayResultService; @Autowired public WxApiService(WxApiDao dao, SavePayResultService savePayResultService) { this.dao = dao; this.savePayResultService = savePayResultService; } public ResultVo getJsapiSHA1Sign(JsApiSHA1 data) throws Exception { data.setAppId(PropertiesUtil.getLocalProperty("appId")); data.setTicket(PropertiesUtil.getLocalProperty("ticket")); data.setNoncestr(SnowFlakeId.instance().nextId()); data.setTimestamp(String.valueOf(System.currentTimeMillis() / 1000)); String toSign = "jsapi_ticket=" + data.getTicket() + "&noncestr=" + data.getNoncestr() + "×tamp=" + data.getTimestamp() + "&url=" + data.getUrl(); data.setSignature(WxPaySignUtil.sha1Encode(toSign)); log.info("获取wxJsApi签名:{}", data); return ResultVoUtil.success(data); } public ResultVo createPayOrder(WxPayOrder order) { WxPayOrder existOrder = getExistOrder(order); if (null != existOrder) { if (existOrder.getTradeState() == Transaction.TradeStateEnum.SUCCESS) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "您已支付过一笔相同金额的订单,请勿重复支付。"); } if (StringUtil.notBlank(existOrder.getPrepayId()) && existOrder.getTradeState() == Transaction.TradeStateEnum.NOTPAY && DateUtil.orderValid(existOrder.getCreateDatetime())) { return ResultVoUtil.success(existOrder); } if (null == order.getYjReqNo()) { order.setYjReqNo(existOrder.getYjReqNo()); } } int payAmt = DecimalTool.moneyYuanToFen(order.getCashpayAmt()); order.setOpenid(TokenUtil.getInstance().getUserOpenid()); order.setTradeNo(SnowFlakeId.instance().nextId()); order.setMchId(PropertiesUtil.getLocalProperty("mchId")); if (payAmt == 0) { order.setPrepayId("PREPARED"); order.setTimeStamp(String.valueOf(System.currentTimeMillis())); order.setSerialNo(SnowFlakeId.instance().nextId()); } else { WechatPayGlobalRequest request = new WechatPayGlobalRequest.Builder() .openid(order.getOpenid()).description(order.getBody()) .outTradeNo(order.getTradeNo()).totalAmount(payAmt).build(); PrepayWithRequestPaymentResponse response = new WeChatPayService().jsApiPrepay(request); order.setAppId(response.getAppId()); order.setPrepayId(response.getPackageVal()); order.setTimeStamp(response.getTimeStamp()); order.setSerialNo(response.getNonceStr()); order.setSignType(response.getSignType()); order.setPaySign(response.getPaySign()); } if (null == order.getFundpayAmt()) { order.setFundpayAmt(BigDecimal.ZERO); } if (null == order.getAcctpayAmt()) { order.setAcctpayAmt(BigDecimal.ZERO); } if (null == order.getCouponAmt()) { order.setCouponAmt(BigDecimal.ZERO); } BigDecimal discount = order.getFundpayAmt().add(order.getAcctpayAmt()) .add(order.getCouponAmt()); BigDecimal cashpayAmt = order.getTotalFee().subtract(discount); if (cashpayAmt.compareTo(BigDecimal.ZERO) < 0) { cashpayAmt = BigDecimal.ZERO; } order.setCashpayAmt(cashpayAmt); order.setPatientName(dao.selectPatientName(order.getPatientId())); order.setCreateDatetime(new Date()); order.setTradeState(Transaction.TradeStateEnum.NOTPAY); dao.insertNewOrder(order); return ResultVoUtil.success(order); } private WxPayOrder getExistOrder(WxPayOrder order) { if (order.getOrderType() == OrderType.CLINIC_REGISTER.getCode() || order.getOrderType() == OrderType.REGISTRATION.getCode()) { return dao.selectSameGhOrder(order.getPatientId(), order.getMzyRequestId(), order.getCashpayAmt()); } else if (order.getOrderType() == OrderType.OUTPATIENT.getCode()) { return dao.selectSameMzPayOrder(order.getHisOrdNum(), order.getCashpayAmt()); } return null; } public ResultVo queryOrderStateOnly(String tradeNo) { WechatPayGlobalRequest request = new WechatPayGlobalRequest.Builder() .outTradeNo(tradeNo).build(); Transaction transaction = new WeChatPayService().queryOrderState(request); JSONObject response = JSONObject.parseObject(GsonUtil.toJson(transaction)); return ResultVoUtil.success(response); } public String queryOrderState(String tradeNo) { try { while (TradeVectorUtil.tradeNoBeingQuery(tradeNo) || TradeVectorUtil.tradeNoBeingRefund(tradeNo)) { log.info("订单号:{} 正在查询状态中,进入等待区。", tradeNo); TimeUnit.SECONDS.sleep(3); } TradeVectorUtil.addBeingQuery(tradeNo); WxPayOrder order = dao.selectOrderByTradeNo(tradeNo); OrderType orderType = OrderType.get(order.getOrderType()); int hasSaved = 0; if (orderType == OrderType.REGISTRATION || orderType == OrderType.CLINIC_REGISTER) { hasSaved = dao.alreadyPaidRegisterFee(order.getTradeNo()); } else if (orderType == OrderType.OUTPATIENT) { hasSaved = dao.alreadyPayed(order.getTradeNo()); } if (hasSaved == 1) { dao.updateSuccessHisStatus(tradeNo); if (orderType == OrderType.REGISTRATION) { log.info("订单号:{} 的挂号信息已保存,无需再次查询订单状态。", order.getTradeNo()); return DateUtil.formatDatetime(order.getPayDatetime()); } log.info("订单号:{} 的门诊缴费信息已保存,无需再次查询订单状态。", order.getTradeNo()); return DateUtil.formatDatetime(order.getPayDatetime()); } Transaction transaction; if (order.getCashpayAmt().compareTo(BigDecimal.ZERO) == 0) { transaction = new Transaction(); transaction.setTradeState(Transaction.TradeStateEnum.SUCCESS); transaction.setSuccessTime(DateUtil.formatDatetime(new Date())); } else { WechatPayGlobalRequest request = new WechatPayGlobalRequest.Builder() .outTradeNo(tradeNo).build(); transaction = new WeChatPayService().queryOrderState(request); } Transaction.TradeStateEnum tradeState = transaction.getTradeState(); if (tradeState == Transaction.TradeStateEnum.SUCCESS) { String successTime = transaction.getSuccessTime() .split("\\+")[0].replace("T", " "); dao.updatePayStatusAndPayTime(tradeNo, tradeState, successTime); switch (orderType) { case CLINIC_REGISTER: return savePayResultService.saveClinicRegister(order, successTime); case REGISTRATION: return savePayResultService.saveAppointment(order, successTime); case OUTPATIENT: return savePayResultService.saveMzChargeInfo(order, successTime); case INPATIENT_PRE_PAY: return savePayResultService.saveZyYjjInfo(order, successTime); case SELF_HELP_MACHINE: case INSPECTIONS: return "订单已支付。"; default: return "ERROR:未识别到的订单类型,请联系服务中心。"; } } dao.updatePayStatusAndQueryTimes(tradeNo, tradeState); return "ERROR:" + transaction.getTradeStateDesc(); } catch (Exception e) { log.error("查询订单状态出错:", e); return "ERROR:服务器错误,请联系管理员处理。【订单号:" + tradeNo + "】"; } finally { TradeVectorUtil.removeBeingQuery(tradeNo); } } public ResultVo generateMzGuideBillPayQrcode(GenMzPayQrcodeParam param) { WechatPayGlobalRequest request = new WechatPayGlobalRequest.Builder() .totalAmount(param.getTotalAmt()).description("湖南泰和医院-门诊缴费").build(); NativePayResponse response = new WeChatPayService().nativePrepay(request); long timesStamp = System.currentTimeMillis() / 1000; WxPayOrder order = new WxPayOrder(); order.setAppId(PropertiesUtil.getLocalProperty("appId")); order.setBody("门诊缴费"); order.setOpenid(""); order.setPatientId(param.getPatientId()); order.setPatientName(dao.selectPatientName(param.getPatientId())); order.setMchId(PropertiesUtil.getLocalProperty("mchId")); order.setTimeStamp(String.valueOf(timesStamp)); order.setTradeNo(response.getTradeNo()); order.setCreateDatetime(new Date()); order.setTradeState(Transaction.TradeStateEnum.NOTPAY); order.setSerialNo(SnowFlakeId.instance().nextId()); order.setOrderType(OrderType.OUTPATIENT.getCode()); order.setHisOrdNum(param.getHisOrdNum()); // MedinsPresettle presettle = getFundPayAmt(param.getHisOrdNum()); order.setFundpayAmt(BigDecimal.ZERO); order.setAcctpayAmt(BigDecimal.ZERO); order.setCashpayAmt(DecimalTool.moneyFenToYuan(param.getTotalAmt())); order.setCouponAmt(BigDecimal.ZERO); order.setTotalFee(order.getCashpayAmt()); dao.insertNewOrder(order); return ResultVoUtil.success(response.getCodeUrl()); } public ResultVo> getWxPayQrcode(WxPyQrcdPrm param) { String patName = dao.selectPatientName(param.getPatientId()); if (null == patName) { return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有找到患者信息,请检查patientId是否正确!"); } WxPayOrder order = new WxPayOrder(); if (param.getOrderType() == OrderType.INPATIENT_PRE_PAY.getCode()) { if (StringUtil.isBlank(param.getInpatientNo())) { return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "费用类型为住院预交金时,住院号不能为空!"); } if (null == param.getAdmissTimes()) { return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "费用类型为住院预交金时,住院次数不能为空!"); } order.setInpatientNo(param.getInpatientNo()); order.setAdmissTimes(param.getAdmissTimes()); } WechatPayGlobalRequest request = new WechatPayGlobalRequest.Builder() .totalAmount(param.getTotalAmt()).description(param.getDescription()).build(); NativePayResponse response = new WeChatPayService().nativePrepay(request); long timesStamp = System.currentTimeMillis() / 1000; String orderTypeName = OrderType.get(param.getOrderType()).getLabel(); order.setAppId(PropertiesUtil.getLocalProperty("appId")); order.setBody(orderTypeName); order.setOpenid(""); order.setTotalFee(DecimalTool.moneyFenToYuan(param.getTotalAmt())); order.setPatientId(param.getPatientId()); order.setPatientName(patName); order.setMchId(PropertiesUtil.getLocalProperty("mchId")); order.setTimeStamp(String.valueOf(timesStamp)); order.setTradeNo(response.getTradeNo()); order.setCreateDatetime(new Date()); order.setTradeState(Transaction.TradeStateEnum.NOTPAY); order.setSerialNo(SnowFlakeId.instance().nextId()); order.setOrderType(param.getOrderType()); order.setFundpayAmt(BigDecimal.ZERO); order.setAcctpayAmt(BigDecimal.ZERO); order.setCouponAmt(BigDecimal.ZERO); order.setCashpayAmt(order.getTotalFee()); dao.insertNewOrder(order); Map map = new HashMap<>(); map.put("qrcodeUrl", response.getCodeUrl()); map.put("tradeNo", response.getTradeNo()); map.put("serialNo", order.getSerialNo()); return ResultVoUtil.success(map); } private MedinsPresettle getFundPayAmt(String hisOrdNum) { String[] hisOrdNumSplitArray = hisOrdNum.split("_"); String patNo = hisOrdNumSplitArray[0]; int times = Integer.parseInt(hisOrdNumSplitArray[1]); MedinsPresettle presettle = dao.selectSettleinfo(patNo, times); if (null == presettle) { presettle = dao.selectMedinsPresettle2(patNo, times); } if (null == presettle) { presettle = new MedinsPresettle(); presettle.setFundPaySumamt(BigDecimal.ZERO); presettle.setAcctPay(BigDecimal.ZERO); } return presettle; } public String closeWxOrder(WxPayOrder order) { String tradeNo = order.getTradeNo(); if (StringUtil.isBlank(tradeNo)) { return "参数错误:[tradeNo]不能为空!"; } Transaction.TradeStateEnum tradeState = dao.selectOrderStatus(tradeNo); if (null == tradeState) { return "订单不存在。"; } if (tradeState == Transaction.TradeStateEnum.SUCCESS) { return "订单已支付,无法关闭。"; } if (tradeState == Transaction.TradeStateEnum.CLOSED) { return "SUCCESS"; } WechatPayGlobalRequest request = new WechatPayGlobalRequest.Builder() .outTradeNo(tradeNo).build(); new WeChatPayService().closeOrder(request); dao.updatePayStatusOnly(tradeNo, Transaction.TradeStateEnum.CLOSED); return "SUCCESS"; } public void closeUnpaidWxOrder(String hisOrdNum) { List tradeNos = dao.selectTradeNoByHisOrdNum(hisOrdNum); for (String tradeNo : tradeNos) { WechatPayGlobalRequest request = new WechatPayGlobalRequest.Builder() .outTradeNo(tradeNo).build(); new WeChatPayService().closeOrder(request); dao.updatePayStatusOnly(tradeNo, Transaction.TradeStateEnum.CLOSED); } } public ResultVo getDoctorInfo(String doctorCode) { DoctorInfo doctorInfo = dao.selectDoctorInfo(doctorCode); if (null == doctorInfo) { return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "未找到医生信息!"); } return ResultVoUtil.success(doctorInfo); } public String saveInpatientPrepay(String tradeNo) { WxPayOrder order = dao.selectOrderByTradeNo(tradeNo); if (null == order) { return "ERROR:没有找到订单号【" + tradeNo + "】对应的订单。"; } if (StringUtil.isBlank(order.getInpatientNo()) || null == order.getAdmissTimes()) { return "ERROR:预交金订单的住院号和住院次数不能为空。"; } return savePayResultService.saveZyYjjInfo(order, DateUtil.formatDatetime(order.getPayDatetime())); } }