package com.ynxbd.ali.helper; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayClient; import com.alipay.api.DefaultAlipayClient; import com.alipay.api.domain.AlipayCommerceMedicalAuthinfoAuthQueryModel; import com.alipay.api.domain.AlipayTradeQueryModel; import com.alipay.api.domain.AuthExtendParams; import com.alipay.api.domain.MedicalNationalPayAuthInfo; import com.alipay.api.request.AlipayCommerceMedicalAuthinfoAuthQueryRequest; import com.alipay.api.request.AlipayTradeAppPayRequest; import com.alipay.api.request.AlipayTradeQueryRequest; import com.alipay.api.response.AlipayCommerceMedicalAuthinfoAuthQueryResponse; import com.alipay.api.response.AlipayTradeAppPayResponse; import com.alipay.api.response.AlipayTradeQueryResponse; import com.ynxbd.ali.config.AliConfig; import com.ynxbd.ali.config.AliMIConfig; import com.ynxbd.common.bean.pay.Order; import com.ynxbd.common.helper.common.DateHelper; import com.ynxbd.common.helper.common.ErrorHelper; import com.ynxbd.common.helper.common.JsonHelper; import com.ynxbd.wx.wxfactory.bean.OrderMIEnum; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; import java.math.BigDecimal; import java.net.URLDecoder; import java.util.*; @Slf4j public class AliMedicalHelper { /** * 国家医保局线上业务身份核验信息授权查询接口[alipay_commerce_medical_authinfo_auth_query_response] * * @param openId openId * @param accessToken accessToken * @param patientName 用户姓名 * @param patientCardNo 用户证件号 * @param callUrl 回调地址 * @return */ public static MedicalNationalPayAuthInfo queryMIAuth(String openId, String accessToken, String patientName, String patientCardNo, String reqBizNo, String callUrl) { try { // 初始化SDK AlipayClient alipayClient = new DefaultAlipayClient(AliConfig.getAlipayConfig()); // 构造请求参数以调用接口 AlipayCommerceMedicalAuthinfoAuthQueryRequest request = new AlipayCommerceMedicalAuthinfoAuthQueryRequest(); AlipayCommerceMedicalAuthinfoAuthQueryModel model = new AlipayCommerceMedicalAuthinfoAuthQueryModel(); // 设置用户标识 if (AliConfig.IS_NEW_USER_ID_VERSION) { // 新版 // model.setOpenId("074a1CcTG1LelxKe4xQC0zgNdId0nxi95b5lsNpazWYoCo5"); model.setOpenId(openId); } else { // uid参数未来计划废弃,存量商户可继续使用,新商户请使用openid。请根据应用-开发配置-openid配置选择支持的字段。 model.setAlipayUserId(openId); } // 设置商户请求流水号 model.setReqBizNo(ObjectUtils.isEmpty(reqBizNo) ? UUID.randomUUID().toString() : reqBizNo); // 设置机构编码-固定为NATHSA model.setInsCode("NATHSA"); // 设置线上业务类型编码 model.setOlBizTypeCode("04107"); // 设置授权回调地址{url}?resultCode=SUCCESS&openapiAppId=2021**3&reqBizNo=20230*** model.setCallUrl(callUrl); // 设置olBizTypeCode=04107(医保移动支付业务)时必传 model.setOrgAppId(AliMIConfig.ORG_APP_ID); // 设置机构渠道认证编码 model.setOrgChnlCrtfCode(AliMIConfig.ORG_CHNL_CRTF_CODG); // 设置定点医药机构代码 model.setOrgCode(AliMIConfig.ORG_NO); // 设置扩展信息-亲情账户支付场景增加 AuthExtendParams extendParams = new AuthExtendParams(); // 系统商签约协议的PID extendParams.setSysServiceProviderId(AliConfig.ISV_PARTNER_ID); // 就诊人证件类型 extendParams.setPatientCertType("01"); // 就诊人真实姓名 extendParams.setPatientName(patientName); // 就诊人证件号 extendParams.setPatientCertNo(patientCardNo); model.setExtendParams(extendParams); // 设置线上购药渠道ID // odel.setOnlineDrugChnlAppId("1DBHJRS5I01E0F34A8C00000B959FA87"); request.setBizModel(model); // 第三方代调用模式下请设置app_auth_token // request.putOtherTextParam("app_auth_token", "<-- 请填写应用授权令牌 -->"); // 设置auth_token,同access_token(用户访问令牌) request.putOtherTextParam("auth_token", accessToken); log.info("[支付宝]国家医保局线上业务身份核验信息授权查询接口-入参{}", JsonHelper.toJsonString(request)); AlipayCommerceMedicalAuthinfoAuthQueryResponse response = alipayClient.execute(request); log.info("[支付宝]国家医保局线上业务身份核验信息授权查询接口-调用{} {}", response.isSuccess() ? "[成功]" : "[失败]", response.getBody()); if (response.isSuccess()) { return response.getData(); } // sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接 // String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response); // System.out.println(diagnosisUrl); } catch (Exception e) { ErrorHelper.println(e); } return null; } // public static AlipayClient getGBKAliClient() { // return new DefaultAlipayClient(AliConfig.SERVICE_URL, AliConfig.APP_ID, AliConfig.APP_PRIVATE_KEY, "json", "GBK", AliConfig.ALI_PUBLIC_KEY, "RSA2"); // } /** * 5.2.2.4 APP支付接口alipay.trade.app.pay * * @param orderMIEnum 医保订单类型 * @param openid openid * @param outTradeNo 商户订单号 * @param payOrdId 医保订单id * @param payAuthNo 医保授权 * @param totalAmount 总金额 * @param cashFee 现金部分 * @param subject 订单标题 * @param notifyUrl 携带了业务类型,用于区分挂号和处方缴费 * @param notifyType 业务类型 * @param familyType 保卡类型"1":”亲情支付“,"0":"本人支付",为空默认本人支付。 * @param familyName 家属姓名 * @param familyCardNo 家属卡号 * @param medicalCardInstId 医保电子凭证机构编号,默认位NATHSA * @param medicalCardId 医保电子凭证授权码 获取线上医保业务授权接口返回medicalCardId参数。"6638aabe-7b4d-4d10-bdf0-b44804da3dab" * @return map */ public static Map createOrder(OrderMIEnum orderMIEnum, String openid, String outTradeNo, String payOrdId, String payAuthNo, BigDecimal totalAmount, BigDecimal cashFee, String subject, String notifyUrl, String notifyType, String familyType, String familyName, String familyCardNo, String medicalCardInstId, String medicalCardId) { try { AlipayClient alipayClient = new DefaultAlipayClient(AliConfig.getAlipayConfig()); AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest(); request.setNotifyUrl(notifyUrl); JSONObject bizContent = new JSONObject(); bizContent.put("out_trade_no", outTradeNo); // 订单总金额 bizContent.put("total_amount", totalAmount.toString()); // 订单标题 bizContent.put("subject", subject); bizContent.put("product_code", "QUICK_MSECURITY_PAY"); // JSAPI_PAY|QUICK_MSECURITY_PAY // 亲情账户增加 start bizContent.put("query_options", new String[]{"medical_insurance_info"}); // 亲情账户增加 end JSONObject extendParams = new JSONObject(); extendParams.put("sys_service_provider_id", AliConfig.ISV_PARTNER_ID); extendParams.put("IS_INSURANCE_PAY", "T"); // 是否使用医保支付 extendParams.put("medical_card_inst_id", ObjectUtils.isEmpty(medicalCardInstId) ? "NATHSA" : medicalCardInstId); //医保电子凭证机构号 获取线上医保业务授权接口返回medicalCardInstId参数。 extendParams.put("medical_card_id", medicalCardId); //医保电子凭证授权码 获取线上医保业务授权接口返回medicalCardId参数。 JSONObject medicalRequestContent = new JSONObject(); // 医保参数透传体,没有需传空对象串 extendParams.put("medical_request_content", JSONObject.toJSONString(medicalRequestContent)); JSONObject medicalRequestExt = new JSONObject(); //医保扩展参数 medicalRequestExt.put("gmt_out_create", DateHelper.getCurDateTime());//医疗机构下单时间 medicalRequestExt.put("out_trade_no", outTradeNo); //商户网站唯一订单号 医院订单号medOrgOrd medicalRequestExt.put("serial_no", payOrdId); // 移动支付中心订单号payOrdId medicalRequestExt.put("bill_no", payOrdId); // 移动支付中心订单号payOrdId medicalRequestExt.put("pay_auth_no", payAuthNo); // 移动支付中心返回授权编号 获取线上医保业务授权接口返回payAuthNo参数 // medicalRequestExt.put("org_no", AliMIConfig.ORG_NO); // 医药机构编号 medicalRequestExt.put("org_name", AliMIConfig.ORG_HOSPITAL_NAME); // 医药机构名称 medicalRequestExt.put("payment_city_code", AliMIConfig.CITY_CODE); // 医保结算地城市编码(国标) // medicalRequestExt.put("industry", "HOSPITAL"); //行业标识 医院:HOSPITAL medicalRequestExt.put("chinfo", "gjydzf"); // 渠道标识-默认为gjydzf medicalRequestExt.put("scene", "TREATMENT"); //使用场景 medicalRequestExt.put("insurance_pay_scene", orderMIEnum.ALI_MI_CODE); // 医保结算场景 是 医保结算场景:OUTPATIENT - 门诊;INPATIENT - 住院;APPOINTMENT- 挂号;DRUGSTORE- 药店 extendParams.put("medical_request_ext", JSONObject.toJSONString(medicalRequestExt)); bizContent.put("extend_params", extendParams); // 如需补充资产,如院内预交金等 begin if (cashFee.compareTo(BigDecimal.ZERO) == 0) { // 0元现金支付 JSONArray merchantCardZkt = new JSONArray(); JSONObject zkt = new JSONObject(); zkt.put("amount", totalAmount); // 总金额 zkt.put("forceUse", "Y"); // 固定为Y zkt.put("templateId", "2023062500391002246600206403"); merchantCardZkt.add(zkt); JSONObject presetPayTool = new JSONObject(); presetPayTool.put("MERCHANTCARD_ZKT", merchantCardZkt); extendParams.put("preset_pay_tool", JSONObject.toJSONString(presetPayTool)); extendParams.put("scene", "PLATFORM_DRUG_STORE"); //场景(有三方购药渠道场景使用) } // 如需补充资产,如院内预交金等 end request.setBizContent(JSONObject.toJSONString(bizContent)); log.info("[支付宝]医保下单-入参 {}", JSONObject.toJSONString(request)); AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request); log.info("[支付宝]医保下单-返回 orderStr={}", response.getBody()); if (response.isSuccess()) { Map map = new HashMap<>(); map.put("orderStr", response.getBody()); map.put("outTradeNo", outTradeNo); return map; } } catch (AlipayApiException e) { ErrorHelper.println(e); } return null; } // 5.2.2.5 线下交易查询alipay.trade.query public static Order queryTrade(String outTradeNo, String tradeNo) { Order order = new Order(); try { AlipayClient alipayClient = new DefaultAlipayClient(AliConfig.getAlipayConfig()); // 构造请求参数以调用接口 AlipayTradeQueryRequest request = new AlipayTradeQueryRequest(); AlipayTradeQueryModel model = new AlipayTradeQueryModel(); // 设置订单支付时传入的商户订单号 model.setOutTradeNo(outTradeNo); // 设置支付宝交易号 model.setTradeNo(tradeNo); // 设置查询选项 List queryOptions = new ArrayList<>(); queryOptions.add("trade_settle_info"); queryOptions.add("fund_bill_list"); queryOptions.add("medical_insurance_info"); model.setQueryOptions(queryOptions); request.setBizModel(model); log.info("[支付宝][医保]线下交易查询-入参 {}", JSONObject.toJSONString(request)); AlipayTradeQueryResponse response = alipayClient.execute(request); log.info("[支付宝][医保]线下交易查询-返回 {}", JsonHelper.toJsonString(response)); if (response.isSuccess()) { if ("TRADE_SUCCESS".equals(response.getTradeStatus())) { order.setSuccess(true); } order.setInfo(response.getBody()); order.setTradeState(response.getTradeStatus()); order.setTradeNo(response.getTradeNo()); order.setBankTransNo(response.getTradeNo()); order.setOutTradeNo(response.getOutTradeNo()); order.setTotalFee(new BigDecimal(response.getTotalAmount())); } else { order.setErrorMsg(response.getMsg()); } } catch (AlipayApiException e) { ErrorHelper.println(e); } return order; } // 5.2.2.6 交易退款接口alipay.trade.refund.apply public static String refundTrade(String outTradeNo, String outRefundNo, String tradeNo, BigDecimal refundAmount, String refundReason) { try { AlipayClient alipayClient = new DefaultAlipayClient(AliConfig.getAlipayConfig()); AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest(); JSONObject bizContent = new JSONObject(); bizContent.put("trade_no", tradeNo); bizContent.put("out_trade_no", outTradeNo); bizContent.put("refund_amount", refundAmount.toString()); bizContent.put("out_request_no", outRefundNo); // 退款请求号-如需部分退款,则此参数必传 // 退款原因说明 bizContent.put("refund_reason", refundReason); //亲情账户增加 end JSONObject extendParams = new JSONObject(); extendParams.put("cancel_serial_no", outRefundNo); extendParams.put("cancel_bill_no", outRefundNo); bizContent.put("extend_params", extendParams); request.setBizContent(JSONObject.toJSONString(bizContent)); log.info("[支付宝][医保]交易退款接口-入参 {}", JSONObject.toJSONString(request)); AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request); log.info("[支付宝][医保]交易退款接口-返回 {}", response.getBody()); if (response.isSuccess()) { return response.getBody(); } } catch (AlipayApiException e) { ErrorHelper.println(e); } return null; } // 5.2.2.7 交易退款查询alipay.trade.fastpay.refund.query public static String queryRefund(String outRefundNo, String outTradeNo, String tradeNo) { try { AlipayClient alipayClient = new DefaultAlipayClient(AliConfig.getAlipayConfig()); AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest(); JSONObject bizContent = new JSONObject(); bizContent.put("out_request_no", outRefundNo); bizContent.put("trade_no", tradeNo); bizContent.put("out_trade_no", outTradeNo); bizContent.put("query_options", new String[]{"refund_detail_item_list"}); // 查询本次交易用户付款的支付渠道和亲情账户关系 request.setBizContent(JSONObject.toJSONString(bizContent)); AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request); log.info("[支付宝]交易退款查询-返回 {}", response.getBody()); if (response.isSuccess()) { return response.getBody(); } } catch (AlipayApiException e) { ErrorHelper.println(e); } return null; } // 数据转换 private static String formatOrderInfo(String data) { try { if (ObjectUtils.isEmpty(data)) { return null; } String decode = URLDecoder.decode(data, "UTF-8"); if (ObjectUtils.isEmpty(decode)) { return null; } String[] pairs = decode.split("&"); Map map = new HashMap<>(); for (String pair : pairs) { if (ObjectUtils.isEmpty(pair)) { continue; } String[] keyValue = pair.split("="); if (keyValue.length == 2) { map.put(keyValue[0], keyValue[1]); } } return null; } catch (Exception e) { ErrorHelper.println(e); return null; } } }