package com.ynxbd.common.service; import com.alibaba.fastjson.JSONObject; import com.ynxbd.common.action.pay.PEnum; import com.ynxbd.common.action.pay.SelfHelpCount; import com.ynxbd.common.bean.ConfigSelfHelp; import com.ynxbd.common.bean.StandardPrice; import com.ynxbd.common.bean.enums.MerchantEnum; import com.ynxbd.common.bean.pay.Order; import com.ynxbd.common.bean.pay.Recipe; import com.ynxbd.common.dao.RecipeDao; 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.*; import com.ynxbd.common.helper.his.HisHelper; import com.ynxbd.common.result.JsonResult; import com.ynxbd.common.result.Result; import com.ynxbd.common.result.ResultEnum; import com.ynxbd.common.result.ServiceException; import com.ynxbd.common.service.cache.PayCache; import com.ynxbd.wx.config.MeTechnologyReConfig; import com.ynxbd.wx.utils.DateGenerate; import com.ynxbd.wx.wxfactory.WxMedicalHelper; import com.ynxbd.wx.wxfactory.WxPayHelper; import com.ynxbd.wx.wxfactory.bean.MedicalOrder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; import java.math.BigDecimal; import java.util.*; /** * 支付业务层 * * @Author wsq * @Date 2021/3/4 10:41 * @Copyright @ 2020 云南新八达科技有限公司 All rights reserved. */ @Slf4j public class RecipeService { /** * 是否在指定时间内重复支付 * * @return 是否完成操作 */ public Long isRepeatPay(String treatNum, Integer second) { log.info("[处方]是否重复支付 treatNum={}, second={}", treatNum, second); if (treatNum == null || second == null) { return null; } try { List orderList = new RecipeDao().selectByTreatNum(treatNum); int size = orderList.size(); if (size == 0) { return null; } second += size; Order order = orderList.get(0); log.info("[处方]在指定时间内重复支付 recipe={}", order); Date updateTime = order.getUpdateTime(); if (updateTime == null) { return null; } long curTime = new Date().getTime(); long time = ((curTime - updateTime.getTime()) / 1000); if (time < second) { return second - time; } return null; } catch (Exception e) { ErrorHelper.println(e); } return null; } /** * 处方订单信息预存 * * @param recipeJson 处方单json数据 * @param patientId 患者id * @param treatNum 门诊号 * @return 是否完成操作 */ public Result recipeHand(MerchantEnum merchantEnum, String openid, String patientId, String treatNum, String totalFee, String recipeJson, String payWay, Integer awaitSecond) { Result result = PayService.isNoPay(); if (result != null) { return result; } if (merchantEnum == null) { // 支付方式异常 return Result.error(ResultEnum.PAY_TYPE_ERROR); } log.info("{}[处方预支付]参数 openid={}, patientId={}, treatNum={}, totalFee={}, awaitSecond={}, payWay={}", merchantEnum.NAME, openid, patientId, treatNum, totalFee, awaitSecond, payWay); if (openid == null || patientId == null || treatNum == null || totalFee == null || recipeJson == null) { return Result.error(ResultEnum.PARAM_IS_DEFECT); } RecipeService recipeService = new RecipeService(); if (awaitSecond == null) { awaitSecond = 0; } if (awaitSecond != 0) { Long second = recipeService.isRepeatPay(treatNum, awaitSecond); if (second != null) { // 是否 awaitSecond s内重复支付 log.info("[处方] 下单等待 {} s 确定", second); return Result.error(ResultEnum.PAY_AWAIT, second); } } // 金额为0的处方不进行回调通知 if ("0".equals(totalFee)) { String outTradeNo = CodeHelper.getOutTradeNo(merchantEnum); // 订单信息预存 if (!recipeService.isSaveRecipeInfo(recipeJson, payWay, openid, patientId, treatNum, outTradeNo, totalFee)) { log.info("{} [处方支付]预存支付信息失败 patientId={}", merchantEnum.NAME, patientId); return Result.error(ResultEnum.SPECIFIED_QUESTIONED_USER_NOT_EXIST); } String payDate = DateHelper.getCurDate(); String payTime = DateHelper.getCurTime(); String bankTransNo = outTradeNo.substring(merchantEnum.CODE.length()); recipeService.recipeListPay(merchantEnum, totalFee, openid, outTradeNo, bankTransNo, null, payDate, payTime, null); Map map = new HashMap<>(); map.put("totalFee", 0); return Result.success(map); } // 医保支付 JSONObject mdRespJson = PayService.goMedical(merchantEnum, PEnum.RECIPE); if (mdRespJson != null) { return Result.success(mdRespJson); } return Result.success(); } /** * 处方订单信息预存 * * @param recipeJson 处方单json数据 * @param patientId 患者id * @param treatNum 门诊号 * @return 是否完成操作 */ public List hisRecipePrepay(String recipeJson, String patientId, String treatNum) { log.info("[处方]预结算 patientId={}, treatNum={}, recipeJson={}", patientId, treatNum, recipeJson); List respList = new ArrayList<>(); List recipeList = JsonHelper.parseArray(recipeJson, Recipe.class); if (recipeList == null || recipeList.size() == 0) { log.info("[处方]预结算勾选处方数量为0 或 数据转换失败"); return respList; } List recipeIds; String curDate = DateHelper.getCurDate(); String curTime = DateHelper.getCurTime(); String recipeId, feeId, feeInfo; JsonResult response; Recipe addInfo; for (Recipe recipe : recipeList) { recipeId = recipe.getRecipeId(); if (ObjectUtils.isEmpty(recipeId) || ObjectUtils.isEmpty(recipe.getRecipeFee())) { continue; } recipeIds = new ArrayList<>(); recipeIds.add(recipe.getRecipeId()); response = HisRecipeDao.prepay( patientId, treatNum, recipeIds, recipe.getRecipeFee().toString(), curDate, curTime, "app", MerchantEnum.WX); log.info("[处方]预结算 resp={}", response); if (response.success()) { feeId = response.getDataMapString("FeeID"); feeInfo = response.getDataMapString("FeeInfo"); log.info("[处方]预结算成功 treatNum={}, recipeId={}, feeId={}, feeInfo={}", treatNum, recipeId, feeId, feeInfo); if (feeId != null && feeInfo != null) { addInfo = new Recipe(); addInfo.setTreatNum(treatNum); addInfo.setRecipeId(recipeId); addInfo.setFeeId(feeId); addInfo.setFeeInfo(feeInfo); respList.add(addInfo); } } } return respList; } /** * 处方订单信息预存 * * @param recipeJson 处方单json数据 * @param payWay 支付方式 0:公众号内;1:扫码支付 * @param openid openid * @param patientId 患者id * @param treatNum 门诊号 * @param outTradeNo 订单号 * @return 是否完成操作 */ public boolean isSaveRecipeInfo(String recipeJson, String payWay, String openid, String patientId, String treatNum, String outTradeNo, String totalFee) { log.info("[处方支付]预存信息 patientId={}, treatNum={}, recipeJson={}", patientId, treatNum, recipeJson); List recipeList = JsonHelper.parseArray(recipeJson, Recipe.class); if (recipeList == null || recipeList.size() == 0) { log.info("[处方支付]勾选处方数量为0 或 数据转换失败"); return false; } RecipeDao recipeDao = new RecipeDao(); // 0:公众号内支付,1:扫码支付 payWay = payWay == null ? "0" : payWay; for (Recipe recipe : recipeList) { if (ObjectUtils.isEmpty(recipe.getRecipeId()) || ObjectUtils.isEmpty(recipe.getRecipeFee())) { return false; } recipe.setOpenid(openid); recipe.setPatientId(patientId); recipe.setTreatNum(treatNum); recipe.setOutTradeNo(outTradeNo); recipe.setPayWay(payWay); // recipe.setTradeNo(CodeHelper.getHisTradeNo()); // 本次his交易流水号 recipe.setTradeNo(null); // 本次his交易流水号 recipe.setTotalFee(new BigDecimal(totalFee)); recipe.setPayMoney(recipe.getRecipeFee()); recipe.setHisStatus(-1); recipe.setPayStatus(-1); if(treatNum.contains("P-")){ recipe.setOrderType("PEIS"); } } boolean isResult; if (recipeList.size() == 1) { // 单个处方 isResult = recipeDao.insert(recipeList.get(0)); } else { // 多个处方 isResult = recipeDao.insertBatch(recipeList) == recipeList.size(); } log.info("[处方]信息预存{}, patientId={}, treatNum={}", (isResult ? "成功" : "失败"), patientId, treatNum); return isResult; } /** * 处方多张支付 * * @param totalFee 总金额 * @param openid openid * @param outTradeNo 订单号 * @param bankTransNo 交易流水号 * @param payDate 支付日期 * @param payTime 支付时间 * @return 是否完成操作 */ public boolean recipeListPay(MerchantEnum merchantEnum, String totalFee, String openid, String outTradeNo, String bankTransNo, String bankMerchantNo, String payDate, String payTime, String payInfo) { RecipeDao recipeDao = new RecipeDao(); // 此处判断是否已经发起缴费,只要已存在数据库记录,说明已经发起了缴费请求,不能根据已经缴费成功,才取消本次缴费请求,因为请求可能已经延时,本次请求可能是重复提交的请求 if (PayService.hasUserOrderNo(outTradeNo, openid)) { log.info("{} [处方]已发起缴费 outTradeNo={}", merchantEnum.NAME, outTradeNo); return false; } if (recipeDao.isHisPaidByOutTradeNo(outTradeNo)) { log.info("{} [处方]已交过费, 退出本次缴费成功通知处理流程:outTradeNo={}, bankTransNo={}", merchantEnum.NAME, outTradeNo, bankTransNo); return false; } if (payInfo != null) { PayService.saveOrderNo(PEnum.RECIPE, outTradeNo, openid, payInfo, null); } List recipeList = recipeDao.selectListByOutTradeNo(outTradeNo); if (!recipeDao.updateNotifyPaid(outTradeNo, bankTransNo, bankMerchantNo, recipeList)) { log.info("{} [处方]更新商户信息失败(1) outTradeNo={}, bankTransNo={}", merchantEnum.NAME, outTradeNo, bankTransNo); if (!recipeDao.updateNotifyPaid(outTradeNo, bankTransNo, bankMerchantNo, recipeList)) { log.info("{} [处方]更新商户信息失败(2) outTradeNo={}, bankTransNo={}", merchantEnum.NAME, outTradeNo, bankTransNo); return false; } } List failedList = new ArrayList<>(); // HIS缴费失败的处方单 long begTime = System.currentTimeMillis(); // 开始时间 // HIS缴费 String patientId = null; Recipe recipeInfo; for (Recipe recipeItem : recipeList) { patientId = recipeItem.getPatientId(); recipeItem.setBankTransNo(bankTransNo); // HIS处方缴费 recipeInfo = recipeSinglePay(recipeItem, payDate, payTime, merchantEnum); // 调用失败的处方 if (recipeInfo.isRefund()) { failedList.add(recipeInfo); } // 如果是体检支付就只调用一次his结算 if(recipeItem.getTreatNum().contains("P-")){ // 体检缴费失败的所有费用进行退回 if (recipeInfo.isRefund()) { failedList = recipeList; } break; } } 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不进行退费处理 return true; } // 处理his缴费失败的处方 String failedRecipeId, errorCode, errorMsg, refundDesc; // 调用超时处方 List outTimeList = new ArrayList<>(); for (Recipe failed : failedList) { failedRecipeId = failed.getRecipeId(); errorCode = failed.getErrorCode(); errorMsg = failed.getErrorMsg(); if ("500".equals(errorCode)) { // 500 log.info("[处方]HIS请求超时,不退费 outTradeNo={}, tradeNo={}", outTradeNo, failed.getTradeNo()); outTimeList.add(failed); PayCache.putRecipeCache(failed.getTradeNo(), failed); } else { refundDesc = "缴费失败 处方号:" + failedRecipeId + "\n原因:[" + errorCode + "]" + errorMsg; try { // 自动退费 recipeAutoRefund(merchantEnum, openid, patientId, outTradeNo, failed.getTradeNo(), failedRecipeId, failed.getPayMoney(), new BigDecimal(totalFee), failed.getUpdateTime(), errorCode, errorMsg, refundDesc); } catch (Exception e) { ErrorHelper.println(e); } } } String tip = String.format("共计缴费处方单数:%s,失败数:%s,超时数:%s", recipeList.size(), (failedList.size() - outTimeList.size()), outTimeList.size()); log.info("{} [处方]{}", merchantEnum.NAME, tip); MeTechnologyReConfig.reserveRun(patientId); //天助医技预约 HCodeService.payNotifyReportHISData(openid, patientId); return true; } /** * 单张处方支付 * * @param recipe 支付信息 * @param payDate 支付日期 * @param payTime 支付时间 * @return order */ public Recipe recipeSinglePay(Recipe recipe, String payDate, String payTime, MerchantEnum merchantEnum) { Recipe order = new Recipe(); String openid = recipe.getOpenid(); String patientId = recipe.getPatientId(); String bankTransNo = recipe.getBankTransNo(); BigDecimal recipeFee = recipe.getPayMoney(); BigDecimal totalFee = recipe.getTotalFee(); order.setUpdateTime(recipe.getUpdateTime()); String tradeNo = recipe.getTradeNo(); String recipeId = recipe.getRecipeId(); order.setBankTransNo(bankTransNo); if (recipeFee == null) { order.setErrorMsg(String.format("[处方]金额为异常 recipeId=%s, tradeNo=%s", recipeId, tradeNo)); return order; } List recipeIds = new ArrayList<>(); recipeIds.add(recipeId); RecipeDao recipeDao = new RecipeDao(); String outTradeNo = recipe.getOutTradeNo(); String treatNum = recipe.getTreatNum(); JsonResult response = HisRecipeDao.payInvoice( openid, patientId, treatNum, recipeIds, recipeFee.toString(), totalFee.toString(), payDate, payTime, tradeNo, "app", bankTransNo, merchantEnum, recipe.getFeeId(), recipe.getFeeInfo()); String respCode = response.getCode(); String respMessage = response.getMessage(); if (!response.success()) { order.setErrorMsg(response.getMessage()); order.setErrorCode(response.getCode()); String errorMsg = recipe.getErrorMsg(); if (!ObjectUtils.isEmpty(errorMsg)) { respMessage = respMessage + "|" + errorMsg; } if (!recipeDao.updateHisPaidFailByTradeNo(tradeNo, respCode, respMessage)) { log.info("[处方]更新HIS缴费失败信息失败 tradeNo={}, code={}, message={}", tradeNo, respCode, respMessage); } if (recipeFee.compareTo(BigDecimal.ZERO) == 0) { log.info("[处方]HIS缴费失败,0元处方不退费,HIS返回:[{}] [{}]", respCode, respMessage); return order; } order.setRefund(true); // 需要退费 order.setTradeNo(tradeNo); order.setOutTradeNo(outTradeNo); order.setRecipeId(recipeId); order.setPayMoney(recipeFee); return order; } String drugInfo = response.getDataMapString("DrugInfo"); String hisTransNo = response.getDataMapString("HISTransNo"); String invoiceTransNo = response.getDataMapString("InvoiceTransNo"); log.info("[处方]HIS缴费成功, 更新支付信息:hisTransNo={}, invoiceTransNo={}, drugInfo={}", hisTransNo, invoiceTransNo, drugInfo); if (!ObjectUtils.isEmpty(drugInfo) && !ObjectUtils.isEmpty(invoiceTransNo)) { log.info("[处方]调用快速发药 invoiceTransNo={}, drugInfo={}", invoiceTransNo, drugInfo); QuickDrugDispenseHelper.quickDrug(drugInfo, invoiceTransNo); } // 更新支付信息 if (!recipeDao.updateHisPaidByTradeNo(tradeNo, hisTransNo, invoiceTransNo)) { log.info("[处方]更新HIS返回数据失败 outTradeNo={}, tradeNo={}, recipeId={}", outTradeNo, tradeNo, recipeId); } // 如果是体检支付就更新所有处方 if(treatNum.contains("P-")){ // 更新支付信息 if (!recipeDao.updateHisPaidByBankTransNo(bankTransNo, hisTransNo, invoiceTransNo)) { log.info("[处方]更新体检缴费HIS返回数据失败 outTradeNo={}, bankTransNo={}, recipeId={}", outTradeNo, bankTransNo, recipeId); } } if (new SelfHelpDao().updateNotice(treatNum)) { log.info("[自助开单]通知状态修改成功 treatNum={}", treatNum); } return order; } /** * 处方自动退费 * * @param openid openid * @param patientId 患者id * @param outTradeNo 商户单号 * @param tradeNo HIS交易流水号 * @param recipeId 退款处方id * @param recipeFee 退款处方金额 * @param totalFee 退款总金额 * @param refundDesc 退费说明 * @return 是否成功 */ public boolean recipeAutoRefund(MerchantEnum merchantEnum, String openid, String patientId, String outTradeNo, String tradeNo, String recipeId, BigDecimal recipeFee, BigDecimal totalFee, Date tradeDate, String respCode, String respMessage, String refundDesc) { if (recipeFee == null || totalFee == null || ObjectUtils.isEmpty(outTradeNo) || ObjectUtils.isEmpty(recipeId) || ObjectUtils.isEmpty(tradeNo)) { log.info("[处方自动退款]参数缺失:outTradeNo={}, recipeId={}, tradeNo={}, fee={}, payMoney={}", outTradeNo, recipeId, tradeNo, recipeFee, totalFee); return false; } if ("500".equals(respCode)) { // 超时or异常不退费 log.info("[处方]HIS请求超时,不退费 outTradeNo={}, tradeNo={}", outTradeNo, tradeNo); return false; } RecipeDao recipeDao = new RecipeDao(); HisAccountDao hisAccountDao = new HisAccountDao(); if (recipeDao.isHisPaidByRecipeId(outTradeNo, recipeId)) { log.info("[处方自动退款]数据库中已缴费成功,不退费:outTradeNo={}, tradeNo={}, recipeId={}", outTradeNo, tradeNo, recipeId); return false; } String begDate = DateGenerate.getNextDay(DateGenerate.getStringDateShort(), "-7"); String endDate = DateGenerate.getNextDay(DateGenerate.getStringDateShort(), "7"); String paidTip = hisAccountDao.isPaid(begDate, endDate, tradeNo); if (paidTip != null) { log.info("[处方自动退款]{}-不退费:outTradeNo={}, tradeNo={}, recipeId={}", paidTip, outTradeNo, tradeNo, recipeId); return false; } try { log.info("[处方退款]第1次等待8s"); Thread.sleep(8000); if (recipeDao.isHisPaidByRecipeId(outTradeNo, recipeId)) { log.info("[处方自动退款]数据库中已缴费成功 outTradeNo={}, tradeNo={}, recipeId={}", outTradeNo, tradeNo, recipeId); return false; } paidTip = hisAccountDao.isPaid(begDate, endDate, tradeNo); if (paidTip != null) { log.info("[处方自动退款]{}-不退费:outTradeNo={}, tradeNo={}, recipeId={}", paidTip, outTradeNo, tradeNo, recipeId); return false; } } catch (Exception e) { ErrorHelper.println(e); } // 更新退款状态失败,不退费!!! if (!recipeDao.updateRefundByRecipeId(outTradeNo, recipeId)) { log.info("{} [处方自动退款]更新退款状态失败-不退费", merchantEnum.NAME); return false; } Order refundInfo = PayService.refund(merchantEnum, outTradeNo, tradeNo, recipeFee, totalFee, refundDesc, tradeDate, openid, patientId, null); boolean isResult = refundInfo.isSuccess(); log.info("{} [处方自动退款]申请{} outTradeNo={}, recipeId={}, recipeFee={}, HIS返回:{}", merchantEnum.NAME, (isResult ? "成功" : "失败"), outTradeNo, recipeId, recipeFee, refundDesc ); if (!recipeDao.updateRefundRByTradeNo(tradeNo, refundInfo.getRefundResult())) { log.info("{} [处方自动退款]更新退款返回结果失败:outTradeNo={}, recipeId={}", merchantEnum.NAME, outTradeNo, recipeId); } return true; } /** * His系统处方手动退费 * * @param invoiceTransNo 发票流水号 * @param refundUser 退款人 * @param refundDesc 退款描述 * @return 是否成功 */ public synchronized boolean hisRefund(String invoiceTransNo, String patientId, String refundUser, String refundDesc, BigDecimal refundMoney, PEnum pEnum) throws ServiceException { RecipeDao recipeDao = new RecipeDao(); Recipe recipe = recipeDao.selectRefundByInvoiceTransNo(invoiceTransNo, patientId); if (recipe == null) { log.info("[HIS处方退费]没有查询到可退款的记录, 不退费 invoiceTransNo={}", invoiceTransNo); throw new ServiceException(ResultEnum.DATA_NOT_FOUND); } String authCode = recipe.getAuthCode(); if (ObjectUtils.isEmpty(authCode)) { log.info("[HIS处方退费]失败,条码为空 authCode={}", authCode); throw new ServiceException("条码为空"); } MerchantEnum merchantEnum = MerchantEnum.getMerchantEnumByAuthCode(authCode); if (merchantEnum == null) { log.info("[HIS处方退费]失败,支付方式异常 authCode={}", authCode); throw new ServiceException(ResultEnum.PAY_TYPE_ERROR); } if (ObjectUtils.isEmpty(refundDesc)) { refundDesc = "HIS手动退费"; } String bankTransNo = recipe.getBankTransNo(); String outTradeNo = recipe.getOutTradeNo(); BigDecimal dbPayMoney = recipe.getPayMoney(); if (refundMoney.compareTo(dbPayMoney) != 0) { log.info("[HIS挂号退费]金额符合禁止退费 invoiceTransNo={}, payMoney={}", invoiceTransNo, dbPayMoney); throw new ServiceException(ResultEnum.REFUND_MONEY_ERROR); } String outRefundNo = HisHelper.getHisTradeNo(bankTransNo, pEnum); Order orderRefund = PayService.refund(merchantEnum, outTradeNo, outRefundNo, refundMoney, recipe.getTotalFee(), refundDesc, recipe.getUpdateTime(), recipe.getOpenid(), recipe.getPatientId(), null); boolean isResult = orderRefund.isSuccess(); log.info("{} [HIS处方退费]申请{} outTradeNo={}, outRefundNo={}, invoiceTransNo={}, refundMoney={}, payMoney={}", merchantEnum.NAME, (isResult ? "成功" : "失败"), outTradeNo, outRefundNo, invoiceTransNo, refundMoney, dbPayMoney ); if (!isResult) { throw new ServiceException(ResultEnum.PAY_ERROR_REFUND); } String refundResult = orderRefund.getRefundResult(); if (!recipeDao.updateRefundByInvoiceTransNo(outTradeNo, outRefundNo, invoiceTransNo, refundResult)) { log.info("{} [HIS处方退费]更新退款结果失败 outTradeNo={}, outRefundNo={}, invoiceTransNo={}, refundResult={}", merchantEnum.NAME, outTradeNo, outRefundNo, invoiceTransNo, refundResult); } recipe.setRefundUser(refundUser); recipe.setRefundMoney(refundMoney); recipe.setRefundResult(refundResult); recipe.setRefundTable(pEnum.CODE); recipe.setTradeNo(outRefundNo); if (!new RefundDao().insert(recipe, refundDesc, "HIS")) { log.info("{} [HIS处方退费]退费信息新增失败 outTradeNo={}, outRefundNo={}, invoiceTransNo={}, refundResult={}", merchantEnum.NAME, outTradeNo, outRefundNo, invoiceTransNo, refundResult); } return true; } /** * His系统处方手动退费 * * @param reason 退费原因 * @return 是否成功 */ public Result mdCashRefund(String payOrdId, String reason) { RecipeDao recipeDao = new RecipeDao(); Recipe recipe = recipeDao.selectByTradeNo(payOrdId); if (recipe == null) { return Result.error(ResultEnum.DATA_NOT_FOUND); } Integer payStatus = recipe.getPayStatus(); if (payStatus == null || payStatus != 0) { log.info("【医保】退费参数缺失 payOrdId={}, payStatus={}", payOrdId, payStatus); return Result.error(ResultEnum.PAY_ORDER_PARAMS_IS_DEFECT); } String refundResult = recipe.getRefundResult(); if (WxPayHelper.OK.equals(refundResult)) { return Result.error(ResultEnum.REFUND_IS_REPEAT); // 退费重复申请 } String outTradeNo = recipe.getOutTradeNo(); BigDecimal cashFee = recipe.getPayMoney(); if (cashFee == null) { return Result.error(ResultEnum.REFUND_CASH_IS_NULL); } if (cashFee.compareTo(BigDecimal.ZERO) == 0) { if (!recipeDao.updateRefundRByTradeNo(payOrdId, WxPayHelper.OK)) { log.error("[医保]现金0修改数据库状态失败 payOrderId={}", payOrdId); return Result.error(ResultEnum.DATA_UPDATE_ERROR); } Map map = new HashMap<>(); map.put("transNo", recipe.getTradeNo()); map.put("payWay", recipe.getPayWay()); map.put("bankTransNo", recipe.getBankTransNo()); map.put("payMoney", cashFee); return Result.success(map); } MedicalOrder order = WxMedicalHelper.refund(outTradeNo, ("R" + payOrdId), payOrdId, cashFee, reason); log.info("[医保]现金退费order={}", order); refundResult = order.isOk() ? WxPayHelper.OK : order.getMessage(); if (!recipeDao.updateRefundRByTradeNo(payOrdId, refundResult)) { log.error("[医保]现金退费修改数据库状态失败 payOrderId={}, refundResult={}", payOrdId, refundResult); } if (order.isOk()) { Map map = new HashMap<>(); map.put("transNo", recipe.getTradeNo()); map.put("payWay", recipe.getPayWay()); map.put("bankTransNo", recipe.getBankTransNo()); map.put("payMoney", cashFee); return Result.success(map); } return Result.error(refundResult); } /** * 处方手动退费 * * @param refundUser 退款人 * @param refundDesc 退款描述 * @return 是否成功 */ public synchronized boolean isHandRefund(String tradeNo, String refundUser, String refundDesc, PEnum orderType, String sys) throws ServiceException { RecipeDao recipeDao = new RecipeDao(); Recipe recipe = recipeDao.selectRefundByTradeNo(tradeNo); if (recipe == null) { throw new ServiceException(ResultEnum.DATA_NOT_FOUND); } String outTradeNo = recipe.getOutTradeNo(); if (outTradeNo == null) { throw new ServiceException(ResultEnum.DATA_IS_WRONG); } List recipeList = recipeDao.selectListByOutTradeNo(outTradeNo); String recipeId = recipe.getRecipeId(); 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())) { log.info("[处方]退费成功,更新状态失败:outTradeNo={}, {}", outTradeNo, refundInfo); } else { if ("0".equals(recipe.getRefundResult())) { throw new ServiceException(ResultEnum.REFUND_STATUS_ERROR_UPDATE_STATUS_SUCCESS); } } return true; } /** * 处方手动退费 * * @return 是否成功 */ public Recipe recipeJsonToInfo(String treatNum, String recipeJson) { log.info("[处方支付]预存信息 treatNum={} recipeJson={}", treatNum, recipeJson); List recipeList = JsonHelper.parseArray(recipeJson, Recipe.class); if (recipeList == null || recipeList.size() == 0) { log.info("[处方支付]勾选处方数量为0 或 数据转换失败"); return null; } Recipe recipeInfo = new Recipe(); List> objects = new ArrayList<>(); Map recipeItem; boolean isFlag = false; for (Recipe recipe : recipeList) { if (!isFlag) { recipeInfo.setDeptCode(recipe.getDeptCode()); recipeInfo.setDeptName(recipe.getDeptName()); recipeInfo.setReqDeptCode(recipe.getReqDeptCode()); recipeInfo.setReqDeptName(recipe.getReqDeptName()); } recipeItem = new HashMap<>(); recipeItem.put("id", recipe.getRecipeId()); recipeItem.put("fee", recipe.getRecipeFee()); objects.add(recipeItem); isFlag = true; } recipeInfo.setRecipeJson(JsonHelper.toJsonString(objects)); return recipeInfo; } /** * 自助申请单预交费判断 */ public synchronized void selfHelpPrepay(String code, String treatNum) throws ServiceException { SelfHelpDao selfHelpDao = new SelfHelpDao(); ConfigSelfHelp config = selfHelpDao.selectConfigByCode(code); if (config != null && config.getEveryDayNum() != null) { SelfHelpCount countBean = selfHelpDao.selectTodayCountBean(code); int endTotal = countBean.getEndTotal(); // 已确认支付完成的数量 int payTotal = countBean.getPayTotal(); // 5分钟内点了支付按钮的用户数量 Integer everyDayNum = config.getEveryDayNum(); // 每日限制数量 if (endTotal >= everyDayNum) { // 超过数量限制 throw new ServiceException(ResultEnum.SELF_HELP_EXCEED_MAX); } // 600 - 597 - 3 = 2 if ((everyDayNum - endTotal - payTotal) > 0) { log.info("[1]endTotal={}, payTotal={}", endTotal, payTotal); if (!selfHelpDao.updatePrepay(treatNum)) { // 修改失败 | 或没有找到数据 throw new ServiceException(ResultEnum.SELF_HELP_EXCEED_MAX); } } else { log.info("[2]endTotal={}, payTotal={}", endTotal, payTotal); if (selfHelpDao.selectPrepayByTreatNum(treatNum) == null) { // 不在五分钟范围内 throw new ServiceException(ResultEnum.SELF_HELP_EXCEED_MAX); } } } } // public static void main(String[] args) throws InterruptedException { // RecipeService recipeService = new RecipeService(); // Thread thread = new Thread(() -> { // Pay one = recipeService.handRefund(PayTypeEnum.WX, "test", "test", "WX4596f62262eb4e2fa535d9c6d59d", "10552830", "recipe"); // System.out.println(one); // }); // thread.start(); // // Pay two = recipeService.handRefund(PayTypeEnum.WX, "test", "test", "WX4596f62262eb4e2fa535d9c6d59d", "10552830", "recipe"); // thread.join(); // System.out.println(two); // } // /** // * 扫码获取二维码中的信息 // * // * @param request 请求 // * @return 支付信息 // */ // public Pay getQRPayInfo(HttpServletRequest request) { // Pay pay = new Pay(); // InputStream in = null; // BufferedReader reader = null; // try { // StringBuilder sb = new StringBuilder(); // in = request.getInputStream(); // reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); // String len; // while ((len = reader.readLine()) != null) { // sb.append(len); // } // // // 解析xml成map // Map map = XMLConverUtil.convertToMap(sb.toString()); // // // 验证请求签名 // if (!map.get("sign").equals(SignatureUtil.generateSign(map, WeChatConfig.getMchKey()))) { // log.info("收到扫码支付请求:签名无效!"); // return null; // } // // String product_id = map.get("product_id"); // log.info("收到扫码支付请求:product_id=" + product_id + ", open_id=" + map.get("openid")); // if (!product_id.contains("XBD")) { // log.info("扫码支付:不合规则的字符串,不允许支付!product_id=" + product_id); // return null; // } // // String[] array = product_id.split("XBD"); // if (array.length < 5) { // log.info("扫码支付:参数少于5个,不允许支付!product_id=" + product_id); // return null; // } // // String patientId = array[0]; // String mzNum = array[1]; // 门诊号 // String recipeId = array[2]; // String payMoney = array[3]; // String recipeType = array[4]; // 1:处方单,2:申请单 // // log.info("多处方扫码支付:patientId=" + patientId); // if (patientId.equals("") || mzNum.equals("") || payMoney.equals("")) { // log.info("扫码支付:参数中有空值,不允许支付!product_id=" + product_id); // return null; // } // // Map recipeMap = new HashMap<>(); // recipeMap.put("id", recipeId); // String recipeJson = JSON.toJSONString(recipeMap); // // pay.setPatientId(patientId); // pay.setTreatNum(mzNum); // pay.setRecipeId(recipeId); //// pay.setPayMoney(payMoney); // pay.setRecipeType(recipeType); // pay.setRecipeJson(recipeJson); // // } catch (Exception e) { // e.printStackTrace(); // ErrorHelper.println(e); // } finally { // try { // if (reader != null) reader.close(); // // if (in != null) in.close(); // // } catch (Exception e) { // e.printStackTrace(); // ErrorHelper.println(e); // } // } // return pay; // } // // // /** // * 退款 // * // * @param tradeNo tradeNo // * @param fee 单次金额 // * @return 是否退款成功 // */ // public boolean old_recipe_refund(String tradeNo, String recipeId, int totalFee, int fee, String desc) { // String clazzPath = Objects.requireNonNull(RecipeService.class.getClassLoader().getResource("")).getPath(); // if (clazzPath == null) { // log.error("【微信】证书路径为空"); // return false; // // } // // String filePath = clazzPath + "apiclient_cert.p12"; // LocalHttpClient.initMchKeyStore(WeChatConfig.getMchId(), filePath); // SecapiPayRefund refund = new SecapiPayRefund(); // refund.setAppid(WeChatConfig.getAppId()); // refund.setMch_id(WeChatConfig.getMchId()); // refund.setNonce_str(UUID.randomUUID().toString().replace("-", "")); // refund.setSign_type("MD5"); // refund.setOut_trade_no(tradeNo); // refund.setOut_refund_no(UUID.randomUUID().toString().replace("-", "")); // refund.setTotal_fee(totalFee); // refund.setRefund_fee(fee); // refund.setRefund_fee_type("CNY"); // refund.setRefund_account("REFUND_SOURCE_UNSETTLED_FUNDS"); // if (desc.length() > 80) // desc = desc.substring(0, 80); // refund.setRefund_desc(desc); // SecapiPayRefundResult refundResult = PayMchAPI.secapiPayRefund(refund, WeChatConfig.getMchKey()); // // if (!"SUCCESS".equals(refundResult.getReturn_code())) { // log.info("【微信】退款失败"); // return false; // } // String refundMsg = refundResult.getReturn_msg(); // log.info("退款申请结果:tradeNo={}, refundMsg={}", tradeNo, refundMsg); // // return new RecipeDao().updateRefundResult(refundMsg, tradeNo, recipeId); // } /** * 标准物价查询 * * @param pageNum 页码 * @param pageSize 每页数量 * @param pyCode 拼音码 * @param type 类型 {1:检查治疗; 2:药品材料; 99:全部} * @param groupFlag 组套标识 { 0:不含组套; 1:包含组套 } * @return 结果 */ public Result getStandardPrice(Integer pageNum, Integer pageSize, String pyCode, String type, String groupFlag) { if (pageNum == null || pageSize == null) { return Result.error(ResultEnum.PARAM_IS_DEFECT); } if (type == null) { type = "99"; } if (ObjectUtils.isEmpty(groupFlag)) { groupFlag = "1"; } JsonResult JsonResult = HisRecipeDao.getStandardPrice(pageNum, pageSize, pyCode, type, groupFlag); if (!JsonResult.success()) { return Result.error(JsonResult.getMessage()); } int pageCount; try { JSONObject jsonObj = JsonResult.getJsonObject("Items"); pageCount = jsonObj.getInteger("PageCount"); } catch (Exception e) { ErrorHelper.println(e); return Result.error(e.getMessage()); } List dataList = JsonResult.getDataMapList(StandardPrice.class, "Items", "Item"); return Result.success(dataList, (pageCount * pageSize)); } public void selfHelpMaxNum(String code) throws ServiceException { SelfHelpDao selfHelpDao = new SelfHelpDao(); ConfigSelfHelp config = selfHelpDao.selectConfigByCode(code); if (config != null && config.getEveryDayNum() != null) { int count = selfHelpDao.selectTodayCount(code); // 当前数量 Integer everyDayNum = config.getEveryDayNum(); // 每日限制数量 log.warn("[申请单]数量限制 everyDayNum={}, count={}", everyDayNum, count); if (count >= everyDayNum) { // 超过数量限制 throw new ServiceException(ResultEnum.SELF_HELP_EXCEED_MAX); } } } public boolean updateMicroOrderState(String outTradeNo, String bankTransNo, String openid) { return new RecipeDao().updateMicroOrderState(outTradeNo, bankTransNo, openid); } }