微信后端代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

401 lines
18 KiB

package com.ynxbd.common.action.pay;
import com.alibaba.fastjson.JSONObject;
import com.ynxbd.ali.config.AliMIConfig;
import com.ynxbd.ali.helper.AliMedicalHelper;
import com.ynxbd.common.action.base.BaseAction;
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.bean.pay.Register;
import com.ynxbd.common.config.interceptor.AesDecode;
import com.ynxbd.common.dao.RecipeDao;
import com.ynxbd.common.dao.his.HisMIDao;
import com.ynxbd.common.helper.common.AesMicroHelper;
import com.ynxbd.common.helper.common.Base64Helper;
import com.ynxbd.common.helper.common.DateHelper;
import com.ynxbd.common.helper.common.HttpHelper;
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.MedicalService;
import com.ynxbd.common.service.params.RequestParams;
import com.ynxbd.wx.wxfactory.*;
import com.ynxbd.wx.wxfactory.bean.*;
import com.ynxbd.wx.wxfactory.medical.WechatMIConfig;
import com.ynxbd.wx.wxfactory.utils.MdRespHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author wsq
* @Date 2020/9/14 15:43
* @Copyright @ 2020 云南新八达科技有限公司 All rights reserved.
*/
@Slf4j
@Namespace("/medical")
public class MedicalAction extends BaseAction {
/**
* 用户信息获取 | 医保上传 | 医保支付下单
*/
@Action("getFeeDetails")
public Result getFeeDetails(String callNo, String payCode, String openid, String qrCode, String patientId, String cardNo, String realName, BigDecimal totalFee, Boolean isSplitTime, String ybAttrib, String ybBZCode, String ybBZName) {
try {
log.info("[医保]上传明细下单 callNo={}, payCode={}, openid={}, qrCode={}, patientId={}, totalFee={}, ybAttrib={}, ybBZCode={}, ybBZName={}", callNo, payCode, openid, qrCode, patientId, totalFee, ybAttrib, ybBZCode, ybBZName);
if (callNo == null || payCode == null || openid == null || qrCode == null || patientId == null || cardNo == null || totalFee == null) {
return Result.error(ResultEnum.PARAM_IS_DEFECT);
}
MerchantEnum merchantEnum = MerchantEnum.findEnumByCode(payCode);
if (merchantEnum == null) { // 支付方式异常
return Result.error(ResultEnum.PAY_TYPE_ERROR);
}
MedicalInfo medicalInfo;
switch (PEnum.toEnum(callNo)) {
case REG:
Register reg = new Register().getRegParams(new RequestParams(request), true);
if ("*".equals(reg.getRegCode())) {
return Result.error("任意医师的号源不能进行医保支付");
}
if (!DateHelper.isToday(reg.getRegDate())) {
return Result.error("医保支付仅支持今日挂号");
}
medicalInfo = new MedicalService().hisRegMIUploadFeeDetails(merchantEnum, qrCode, openid, patientId, cardNo, realName, reg, isSplitTime);
break;
case RECIPE:
String treatNum = getString("treatNum");
String recipeJson = getString("recipeJson"); // 处方JSON集 [{ recipeId: item.id, recipeFee: item.amount }]
if (treatNum == null || recipeJson == null) {
return Result.error(ResultEnum.PARAM_IS_DEFECT);
}
medicalInfo = new MedicalService().hisRxUploadFeeDetails(merchantEnum, qrCode, openid, patientId, cardNo, realName, treatNum, recipeJson, totalFee, ybAttrib, ybBZCode, ybBZName);
break;
default:
return Result.error("调用方式不存在");
}
return Result.success(medicalInfo);
} catch (ServiceException e) {
return Result.error(e);
}
}
/**
* 获取授权链接
*/
@Action("getRefundAuthUrl")
public Result getRefundAuthUrl() {
JSONObject respJson = WxMedicalHelper.getMdAuthUrl("wx-medical-refund.html", null);
return Result.success(respJson);
}
/**
* [处方流转]获取授权链接
*/
@Action("getAuthUrl")
public Result getAuthUrl(String url) {
if (ObjectUtils.isEmpty(url)) {
return Result.error(ResultEnum.PARAM_IS_INVALID);
}
url = decodeReqString(url);
if (ObjectUtils.isEmpty(url)) {
return Result.error(ResultEnum.PARAM_IS_INVALID);
}
JSONObject respJson = WxMedicalHelper.getMdAuthRedirectUrl(url);
return Result.success(respJson);
}
@Action("medicalAuth")
public Result medicalAuth(String openid, String qrCode) {
log.info("[医保建档] openid-{},qrCode={}", openid, qrCode);
MedicalUserInfo info = WxFactory.Medical.Common().getUserInfo(WechatMIConfig.PARTNER_URL, openid, qrCode);
log.info("[医保建档获取用户信息] resp-{}", info);
return Result.success(info);
}
@Action("getMedicalAuthUrl")
public Result getMedicalAuthUrl(String url) {
JSONObject respJson = WxMedicalHelper.getMdAuthUrl(url, null);
return Result.success(respJson);
}
/**
* 获取对账链接
*
* @param billDate 账单日期
* @param billType 账单类型 ALL,返回当日所有订单信息,默认 SUCCESS,返回当日成功支付的订单 REFUND,返回当日退款订单
* @param key 加密密钥
* @return 下载链接
*/
@Action("downBill")
public Result downBill(String billDate, String billType, String key) {
log.info("[医保]下载对账订单,billDate-{}, billType-{}, key-{}", billDate, billType, key);
if (billDate == null || billType == null) {
return Result.error(ResultEnum.PARAM_IS_DEFECT);
}
if (!DateHelper.getCurDate().equals(AesMicroHelper.decode(key))) {
return Result.error(ResultEnum.PARAM_IS_INVALID);
}
return Result.success(WxMedicalHelper.downBill(billDate, billType));
}
/**
* 医保支付下单
*
* @param callNo 业务类型[挂号:register; 处方缴费:recipe]
* @param payCode 调用码[如:wx_medical]
* @param openid openid
* @param patientId 患者id
* @param cardNo 患者证件号
* @param realName 患者真实姓名
* @param treatNum 门诊号(挂号不传,处方必传)
* @param payOrdId -医保订单号id(接口返回)
* @param payAuthNo -医保授权码(接口返回)
* @param mdTrtId -医保-就诊ID(接口返回)
* @param chrgBchno -医保-收费单据号(接口返回)
* @param mdUserId -医保-用户ID(接口返回)
* @param totalFee -订单金额(接口返回)
* @param acctFee -医保-个人账户支付金额(接口返回)
* @param hifpFee -医保-统筹支付金额(接口返回)
* @param insuranceFee -个账 + 统筹支付金额(接口返回)
* @param cashFee -现金金额(接口返回)
* @param familyType 家庭关系(非必传)
* @param familyName 家人姓名(非必传)
* @param familyCardNo 家人证件号码(非必传)
*/
@Action("order")
public Result order(String callNo, String payCode, String openid, String patientId, String cardNo, String realName, String treatNum, String payOrdId, String payAuthNo, String mdTrtId, String chrgBchno, String mdUserId,
BigDecimal totalFee, BigDecimal acctFee, BigDecimal hifpFee, BigDecimal insuranceFee, BigDecimal cashFee, String familyType, String familyName, String familyCardNo, String medicalCardInstId, String medicalCardId) {
try {
log.info("[医保]下单入参 callNo={}, payCode={}, openid={}, patientId={}, totalFee={}", callNo, payCode, openid, patientId, totalFee);
if (callNo == null || payCode == null || openid == null || patientId == null || cardNo == null || totalFee == null) {
return Result.error(ResultEnum.PARAM_IS_DEFECT);
}
String ip = HttpHelper.getIpAddress(request);
switch (PEnum.toEnum(callNo)) {
case REG:
Register reg = new Register().getRegParams(new RequestParams(request), true);
return new MedicalService().createRegOrder(payCode, openid, cardNo, realName, ip, payOrdId, payAuthNo, mdTrtId, chrgBchno, mdUserId,
totalFee, acctFee, hifpFee, insuranceFee, cashFee, callNo, reg,
familyType, familyName, familyCardNo, medicalCardInstId, medicalCardId);
case RECIPE:
String recipeJson = getString("recipeJson");
if (recipeJson == null) {
return Result.error(ResultEnum.PARAM_IS_BLANK);
}
String payWay = getString("payWay");
return new MedicalService().createRxOrder(payCode, openid, patientId, cardNo, realName, ip,
payOrdId, payAuthNo, mdTrtId, chrgBchno, mdUserId,
totalFee, acctFee, hifpFee, insuranceFee, cashFee,
callNo, recipeJson, treatNum, payWay, familyType, familyName, familyCardNo, medicalCardInstId, medicalCardId);
default:
return Result.error("调用方式不存在");
}
} catch (ServiceException e) {
return Result.error(e);
}
}
/**
* HIS医保退费(线上)
*/
@Action("refundMI")
public Result refundMI(String payCode, String callNo, String openid, String qrCode, String outTradeNo, @AesDecode String tradeNo) {
// tradeNo = Base64Helper.decodeEn(tradeNo);
log.info("[医保退费] callNo={}, openid={}, qrCode={}, outTradeNo={}, tradeNo={}", callNo, openid, qrCode, outTradeNo, tradeNo);
if (openid == null || qrCode == null || outTradeNo == null || tradeNo == null) {
return Result.error(ResultEnum.PARAM_IS_DEFECT);
}
MerchantEnum merchantEnum = MerchantEnum.findEnumByCode(payCode);
if (merchantEnum == null) { // 支付方式异常
return Result.error(ResultEnum.PAY_TYPE_ERROR);
}
RecipeDao recipeDao = new RecipeDao();
Recipe recipe = recipeDao.selectByTradeNo(tradeNo);
if (recipe == null) {
return Result.error(ResultEnum.DATA_NOT_FOUND);
}
Boolean isDevUser = MedicalService.isDevUser(recipe.getOpenid());
if (isDevUser == null || !isDevUser) {
return Result.error("不是测试用户");
}
Integer payStatus = recipe.getPayStatus();
Integer hisStatus = recipe.getHisStatus();
String chrgBchno = recipe.getChrgBchno();
String bankTransNo = recipe.getBankTransNo();
String mdUserId = recipe.getMdUserId();
BigDecimal cashFee = recipe.getPayMoney();
BigDecimal acctFee = recipe.getAcctFee();
BigDecimal hifpFee = recipe.getHifpFee();
if (payStatus == null || hisStatus == null || chrgBchno == null || bankTransNo == null || mdUserId == null || cashFee == null || acctFee == null || hifpFee == null) {
log.info("[医保]退费参数缺失 outTradeNo={}, bankTransNo={}, payStatus={}, hisStatus={}, chrgBchno={}, cashFee={}, acctFee={}, hifpFee={}", outTradeNo, bankTransNo, payStatus, hisStatus, chrgBchno, cashFee, acctFee, hifpFee);
return Result.error(ResultEnum.PAY_ORDER_PARAMS_IS_DEFECT);
}
BigDecimal insuranceFee = acctFee.add(hifpFee);
if (payStatus != 0) { // 都已成功禁止退费
return Result.error(ResultEnum.PAY_ORDER_NO_PAY);
}
// if (hisStatus == 0) { // 都已成功禁止退费
// return Result.error(ResultEnum.PAY_ORDER_NO_PAY);
// }
Result result = new MedicalService().refund(merchantEnum, openid, qrCode, chrgBchno.substring(1), outTradeNo, bankTransNo, tradeNo, mdUserId, cashFee, insuranceFee);
String message = result.isOK() ? WxPayHelper.OK : result.getMessage();
if (!recipeDao.updateRefundByTradeNo(tradeNo, message)) {
log.info("[医保]修改退费信息失败 [{}] outTradeNo={}, tradeNo={}", message, outTradeNo, tradeNo);
}
if (result.isOK()) {
return Result.success();
}
return result;
}
/**
* 获取需要退费的订单
*/
@Action("getRefundMIOrders")
public Result getRefundMIOrders(String openid, String begDate, String endDate) {
log.info("[医保]查询需退费订单 openid={}, begDate={}, endDate={}", openid, begDate, endDate);
RecipeDao recipeDao = new RecipeDao();
List<Order> orders = recipeDao.selectRefundList(openid, begDate, endDate);
for (Order order : orders) {
if (order.getTradeNo() != null) {
order.setTradeNo(AesWxHelper.encode(order.getTradeNo()));
}
}
return Result.success(orders);
}
/**
* 查询HIS医保对账记录
*/
@Action("getHisAccountsInfo")
public Result getHisAccountsInfo(String payCode, String mdUserId) {
MerchantEnum merchantEnum = MerchantEnum.findEnumByCode(payCode);
if (merchantEnum == null) {
return Result.error(ResultEnum.PAY_TYPE_ERROR);
}
JsonResult jsonResult = HisMIDao.getMIAccounts(merchantEnum, mdUserId);
return Result.success(jsonResult);
}
/**
* [医保]微信支付订单查询
*
* @param outTradeNo 订单号
* @param medTransId 医保交易流水号
*/
@Action("queryOrder")
public Result queryOrder(String payCode, String outTradeNo, String medTransId, String callNo) {
log.info("[医保]查询订单 payCode={}, outTradeNo={}, medTransId={}, callNo={}", payCode, outTradeNo, medTransId, callNo);
MerchantEnum merchantEnum = MerchantEnum.findEnumByCode(payCode, MerchantEnum.WX_MEDICAL);
if (merchantEnum == null) {
return Result.error(ResultEnum.PAY_TYPE_ERROR);
}
Map<String, Object> orderObj = new HashMap<>();
if (!ObjectUtils.isEmpty(callNo)) { // 传递业务类型,返回费用信息
orderObj = new MedicalService().queryOrderFee(callNo, outTradeNo, medTransId);
}
if (merchantEnum.equals(MerchantEnum.WX_MEDICAL)) {
MIOrder order = WxMedicalHelper.queryOrder(WxCacheHelper.getAccessToken(), outTradeNo, medTransId);
order.setOrderObj(orderObj);
if (order.isOk()) {
return Result.success(order);
}
return Result.error(order.getMessage());
} else if (merchantEnum.equals(MerchantEnum.ALI_MEDICAL)) {
Order order = AliMedicalHelper.queryTrade(outTradeNo, medTransId);
order.setOrderObj(orderObj);
if (order.isSuccess()) {
return Result.success(order);
}
return Result.error(order.getErrorMsg());
} else {
return Result.error(ResultEnum.PAY_TYPE_ERROR);
}
}
/**
* HIS查询医保退费
*/
@Action("queryRefund")
public Result queryRefund(String accessToken, String outTradeNo, String mdTransId) {
MedicalRefundInfo info = WxMedicalHelper.queryRefund(accessToken, outTradeNo, mdTransId);
return Result.success(info);
}
// /**
// * HIS医保退费
// */
// @Action("queryRefund")
// public Result queryRefund(String accessToken, String outTradeNo, String mdTransId) {
// MedicalRefundInfo info = WxMedicalHelper.queryRefund(accessToken, outTradeNo, mdTransId);
// return Result.success(info);
// }
/**
* [医保支付]微信回调通知
*/
@Action("payNotify")
public Result payNotify() {
try {
log.info("[微信][医保]回调通知...");
MedicalNotify notifyInfo = WxMedicalHelper.paidMINotify(request);
// 成功返回
Result.respXml(MdRespHelper.respOk(WechatMIConfig.PAY_KEY));
String openid = notifyInfo.getOpenid();
String bankTransNo = notifyInfo.getMedTransId();
String outTradeNo = notifyInfo.getHospOutTradeNo();
String payInfo = notifyInfo.getInfo();
BigDecimal totalFee = notifyInfo.getTotalFee();
String payDate = notifyInfo.getPayDate();
String payTime = notifyInfo.getPayTime();
String notifyType = notifyInfo.getAttach();
log.info("[微信][医保][{}] 收到通知 outTradeNo={}, bankTransNo={}, notifyType={}",
notifyType, outTradeNo, bankTransNo, notifyType);
new MedicalService().commonNotify(MerchantEnum.WX_MEDICAL, notifyType, outTradeNo, totalFee, bankTransNo, payDate, payTime, openid, payInfo);
return null;
} catch (ServiceException e) {
return Result.respXml(MdRespHelper.resp(e, WechatMIConfig.PAY_KEY));
}
}
}