1、诊间支付新增处方类型存储,用于判断是否未互联网医院处方,进行数据上报

2、京颐支付接口和退费接口参数调整,金额转换为分存在异常处理。支付回调通知和退费回调通知参数接收调整。
3、新增枚举用于传递京颐支付的支付类型和业务类型。
4、处方缴费上传的患者信息数据,通过HIS的患者id查询。优先级为先查询本地数据,但是扫码支付可能存在未绑定进行支付的情况,防止数据缺失导致数据未上传。
master_pay
王绍全 3 weeks ago
parent 851dac15c5
commit b93db00df9
  1. 14
      src/main/java/com/ynxbd/common/TestA.java
  2. 2
      src/main/java/com/ynxbd/common/action/PatientAction.java
  3. 8
      src/main/java/com/ynxbd/common/action/RecipeAction.java
  4. 49
      src/main/java/com/ynxbd/common/action/pay/JYPSEnum.java
  5. 54
      src/main/java/com/ynxbd/common/action/pay/JYPayAction.java
  6. 4
      src/main/java/com/ynxbd/common/action/pay/MedicalAction.java
  7. 6
      src/main/java/com/ynxbd/common/action/pay/PayAction.java
  8. 1
      src/main/java/com/ynxbd/common/bean/pay/ApiPayNotify.java
  9. 4
      src/main/java/com/ynxbd/common/bean/pay/Recipe.java
  10. 4
      src/main/java/com/ynxbd/common/bean/pay/ReqOrder.java
  11. 106
      src/main/java/com/ynxbd/common/bean/xk/XKChargeOrRefund.java
  12. 63
      src/main/java/com/ynxbd/common/bean/xk/XKCostDetail.java
  13. 22
      src/main/java/com/ynxbd/common/dao/RxDao.java
  14. 18
      src/main/java/com/ynxbd/common/dao/his/HisPatientDao.java
  15. 45
      src/main/java/com/ynxbd/common/helper/http/OkHttpHelper.java
  16. 4
      src/main/java/com/ynxbd/common/service/MedicalService.java
  17. 118
      src/main/java/com/ynxbd/common/service/MicroService.java
  18. 30
      src/main/java/com/ynxbd/common/service/PatientService.java
  19. 8
      src/main/java/com/ynxbd/common/service/PayService.java
  20. 33
      src/main/java/com/ynxbd/common/service/RxService.java
  21. 4
      src/main/java/com/ynxbd/jy/bean/JYPayNotify.java
  22. 109
      src/main/java/com/ynxbd/jy/helper/JYPayHelper.java

@ -1,5 +1,9 @@
package com.ynxbd.common; package com.ynxbd.common;
import cn.hutool.core.util.IdcardUtil;
import com.ynxbd.common.helper.common.AesMicroHelper;
import com.ynxbd.common.helper.common.JsonHelper;
import com.ynxbd.common.helper.http.OkHttpHelper;
import com.ynxbd.wx.wxfactory.AesWxHelper; import com.ynxbd.wx.wxfactory.AesWxHelper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -126,9 +130,9 @@ public class TestA {
// System.out.println(removeIds); // System.out.println(removeIds);
// } // }
public static void main(String[] args) { //
System.out.println(AesWxHelper.encode("1")); // public static void main(String[] args) {
System.out.println(AesWxHelper.encode("100004220302")); // System.out.println(AesWxHelper.decode("562CF576AEC37AA2EC0CCB873ABF67A3060B9C01AD9B8068C43FEAEDDB00E5A6"));
System.out.println(AesWxHelper.encode("100004219291")); // }
}
} }

@ -63,7 +63,7 @@ public class PatientAction extends BaseAction {
return Result.error(ResultEnum.PARAM_IS_DEFECT); return Result.error(ResultEnum.PARAM_IS_DEFECT);
} }
Patient patient = new PatientService().queryPatientByCardNo(cardNo); Patient patient = new PatientService().queryHisPatientByCardNo(cardNo);
if (patient == null) { if (patient == null) {
return Result.error(ResultEnum.PATIENT_NOT_FOUND); return Result.error(ResultEnum.PATIENT_NOT_FOUND);
} }

@ -144,11 +144,11 @@ public class RecipeAction extends BaseAction {
return Result.error(ResultEnum.PARAM_IS_DEFECT); return Result.error(ResultEnum.PARAM_IS_DEFECT);
} }
int days = DateHelper.intervalDays(begDate, endDate, true); int days = DateHelper.intervalDays(begDate, endDate, true);
List<HisRecipe> hisRecipes = new HisRecipeDao().getRxUnPay(null, patientId, "", days); List<HisRecipe> hisRxList = new HisRecipeDao().getRxUnPay(null, patientId, "", days);
List<HisRecipe> resultList = new ArrayList<>(); List<HisRecipe> resultList = new ArrayList<>();
for (HisRecipe hisRecipe : hisRecipes) { for (HisRecipe rxItem : hisRxList) {
if (hisRecipe.getDate() != null && DateHelper.inDateRange(begDate, endDate, hisRecipe.getDate(), DateHelper.DateEnum.yyyy_MM_dd)) { if (rxItem.getDate() != null && DateHelper.inDateRange(begDate, endDate, rxItem.getDate(), DateHelper.DateEnum.yyyy_MM_dd)) {
resultList.add(hisRecipe); resultList.add(rxItem);
} }
} }
return Result.success(resultList); return Result.success(resultList);

@ -0,0 +1,49 @@
package com.ynxbd.common.action.pay;
import com.ynxbd.jy.bean.enums.JYBusinessTypeEnum;
import com.ynxbd.jy.bean.enums.JYOrderTypeEnum;
import lombok.ToString;
@ToString
public enum JYPSEnum {
NO(PEnum.NO, JYOrderTypeEnum._002, JYBusinessTypeEnum.B999),
REG(PEnum.REG, JYOrderTypeEnum._001, JYBusinessTypeEnum.B101),
RECIPE(PEnum.RECIPE, JYOrderTypeEnum._002, JYBusinessTypeEnum.B201),
IN_HOSP(PEnum.IN_HOSP, JYOrderTypeEnum._003, JYBusinessTypeEnum.B301),
OUT_HOSP(PEnum.OUT_HOSP, JYOrderTypeEnum._903, JYBusinessTypeEnum.B302),
OL_REG(PEnum.OL_REG, JYOrderTypeEnum._001, JYBusinessTypeEnum.B101),
MED_RECORD(PEnum.MED_RECORD, JYOrderTypeEnum._001, JYBusinessTypeEnum.B101),
OUT_COLLECT(PEnum.OUT_COLLECT, JYOrderTypeEnum._012, JYBusinessTypeEnum.B999),
TPP_QR_REG(PEnum.TPP_QR_REG, JYOrderTypeEnum._001, JYBusinessTypeEnum.B101),
PEIS_RESERVE(PEnum.PEIS_RESERVE, JYOrderTypeEnum._904, JYBusinessTypeEnum.B999),
;
public final PEnum PS;
public final JYOrderTypeEnum ORDER_TYPE;
public final JYBusinessTypeEnum BUSINESS_TYPE;
JYPSEnum(PEnum PS, JYOrderTypeEnum ORDER_TYPE, JYBusinessTypeEnum BUSINESS_TYPE) {
this.PS = PS;
this.ORDER_TYPE = ORDER_TYPE;
this.BUSINESS_TYPE = BUSINESS_TYPE;
}
public static JYPSEnum findEnum(PEnum ps) {
for (JYPSEnum item : JYPSEnum.values()) {
if (item.PS.equals(ps)) {
return item;
}
}
return NO;
}
}

@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONObject;
import com.ynxbd.common.action.base.BaseAction; import com.ynxbd.common.action.base.BaseAction;
import com.ynxbd.common.bean.enums.MerchantEnum; import com.ynxbd.common.bean.enums.MerchantEnum;
import com.ynxbd.common.bean.pay.ApiPayNotify; import com.ynxbd.common.bean.pay.ApiPayNotify;
import com.ynxbd.common.bean.pay.Order;
import com.ynxbd.common.bean.pay.ReqOrder; import com.ynxbd.common.bean.pay.ReqOrder;
import com.ynxbd.common.helper.common.HttpHelper; import com.ynxbd.common.helper.common.HttpHelper;
import com.ynxbd.common.helper.common.JsonHelper; import com.ynxbd.common.helper.common.JsonHelper;
@ -49,20 +50,20 @@ public class JYPayAction extends BaseAction {
String title = "支付测试"; String title = "支付测试";
ReqOrder req = new ReqOrder(); ReqOrder req = new ReqOrder();
req.setPatientName("小王"); // req.setPatientName("小王");
req.setPatientGender("男"); // req.setPatientGender("男");
req.setPatientAge("18"); // req.setPatientAge("18");
req.setPatientTel("15559603353"); // req.setPatientTel("15559603353");
req.setTreatNum("T001"); // req.setTreatNum("T001");
req.setPatientIdCardNo("532331199910053810"); // req.setPatientIdCardNo("532331199910053810");
req.setPatientId("1000001"); // req.setPatientId("1000001");
JYOrder jyOrder = new JYOrder(); // JYOrder jyOrder = new JYOrder();
jyOrder.orderTypeEnum = JYOrderTypeEnum._001; // 挂号费 // jyOrder.orderTypeEnum = JYOrderTypeEnum._001; // 挂号费
jyOrder.businessTypeEnum = JYBusinessTypeEnum.B102; // jyOrder.businessTypeEnum = JYBusinessTypeEnum.B102;
//
req.setJyOrder(jyOrder); // req.setJyOrder(jyOrder);
JSONObject prepay = JYPayHelper.createOrder(MerchantEnum.JY, title, merOrderNum, totalFee.toString(), PEnum.REG.CODE, ip, payOpenId, openid, req); JSONObject prepay = JYPayHelper.createOrder(MerchantEnum.JY, title, merOrderNum, totalFee.toString(), PEnum.REG, ip, payOpenId, openid, req);
if (prepay == null) { if (prepay == null) {
return Result.error(ResultEnum.PAY_ERROR_ORDER); // 下单异常 return Result.error(ResultEnum.PAY_ERROR_ORDER); // 下单异常
} }
@ -79,19 +80,16 @@ public class JYPayAction extends BaseAction {
// outRefundNo, refundFee, outTradeNo, bankMerchantNo, tradeNo); // outRefundNo, refundFee, outTradeNo, bankMerchantNo, tradeNo);
// //
// ReqOrder req = new ReqOrder(); // ReqOrder req = new ReqOrder();
// req.setPatientName("小王"); //// req.setPatientName("小王");
// req.setPatientGender("男"); //// req.setPatientGender("男");
// req.setPatientAge("18"); //// req.setPatientAge("18");
// req.setPatientTel("15559603353"); //// req.setPatientTel("15559603353");
// req.setTreatNum("T001"); //// req.setTreatNum("T001");
// req.setPatientIdCardNo("532331199910053810"); //// req.setPatientIdCardNo("532331199910053810");
// req.setPatientId("1000001"); //// req.setPatientId("1000001");
// //
// JSONObject prepay = JYPayHelper.refundPayOrder(JYBusinessTypeEnum.B102, req, outRefundNo, refundFee, outTradeNo, bankMerchantNo, tradeNo); // Order order = JYPayHelper.refundPayOrder(JYBusinessTypeEnum.B102, req, outRefundNo, refundFee, outTradeNo, bankMerchantNo, tradeNo);
// if (prepay == null) { // return Result.success(order);
// return Result.error(); // 下单异常
// }
// return Result.success(prepay);
// } // }
@ -123,10 +121,12 @@ public class JYPayAction extends BaseAction {
} }
Map<String, String> params = reqParamsToMap(); Map<String, String> params = reqParamsToMap();
log.info("[京颐]回调信息: [{}]", params);
String sign = JYPayRSAUtil.createSign(params, JYPayConfig.PRIVATE_KEY); String sign = JYPayRSAUtil.createSign(params, JYPayConfig.PRIVATE_KEY);
log.info("[sign]{}", sign); log.info("[sign]{}", sign);
ApiPayNotify info = JYPayHelper.jyPayNotify(reqParamsToBean(JYPayNotify.class), notifyType); ApiPayNotify info = JYPayHelper.jyPayNotify(params, notifyType);
log.info("【京颐】[{}]收到[{}]通知-{}", pEnum.NAME, (info.isRefundOrder() ? "退款" : "支付"), JsonHelper.toJsonString(info)); log.info("【京颐】[{}]收到[{}]通知-{}", pEnum.NAME, (info.isRefundOrder() ? "退款" : "支付"), JsonHelper.toJsonString(info));
Result.respXml(WxRespHelper.respOk()); // 收到请求-解析成功 Result.respXml(WxRespHelper.respOk()); // 收到请求-解析成功

@ -273,9 +273,9 @@ public class MedicalAction extends BaseAction {
return Result.error(ResultEnum.PARAM_IS_BLANK); return Result.error(ResultEnum.PARAM_IS_BLANK);
} }
String payWay = getReqParamByKey("payWay"); String payWay = getReqParamByKey("payWay");
Integer rxType = getReqParamByKey("rxType", Integer.class);
Recipe rxOrder = JsonHelper.copy(order, Recipe.class); Recipe rxOrder = JsonHelper.copy(order, Recipe.class);
return new MedicalService().createRxOrder(merchantEnum, rxOrder, serverEnum, recipeJson, payWay); return new MedicalService().createRxOrder(merchantEnum, rxOrder, serverEnum, recipeJson, payWay, rxType);
case OUT_HOSP: case OUT_HOSP:
PayInHosp outHospOrder = JsonHelper.copy(order, PayInHosp.class); PayInHosp outHospOrder = JsonHelper.copy(order, PayInHosp.class);

@ -92,7 +92,7 @@ public class PayAction extends BaseAction {
* @param awaitSecond 待秒数,0继续执行不等待(不传或null 为0) * @param awaitSecond 待秒数,0继续执行不等待(不传或null 为0)
*/ */
@Action("recipePay") @Action("recipePay")
public Result recipePay(boolean isPrepay, String payCode, String payOpenId, String openid, String patientId, String treatNum, String totalFee, String recipeJson, String payWay, Integer awaitSecond) { public Result recipePay(boolean isPrepay, String payCode, String payOpenId, String openid, String patientId, String treatNum, String totalFee, String recipeJson, String payWay, Integer rxType, Integer awaitSecond) {
try { try {
MerchantEnum merchantEnum = MerchantEnum.findEnumByCode(payCode); MerchantEnum merchantEnum = MerchantEnum.findEnumByCode(payCode);
if (merchantEnum == null) { // 支付方式异常 if (merchantEnum == null) { // 支付方式异常
@ -109,7 +109,7 @@ public class PayAction extends BaseAction {
} }
} }
Result result = rxService.medInsPrepay(merchantEnum, payOpenId, openid, patientId, treatNum, totalFee, recipeJson, payWay, awaitSecond, isHttpsWithProxy()); Result result = rxService.medInsPrepay(merchantEnum, payOpenId, openid, patientId, treatNum, totalFee, recipeJson, payWay, rxType, awaitSecond, isHttpsWithProxy());
if (!result.isOK() || result.getData() != null) { // 业务错误 || 存在返回数据-需提前返回 if (!result.isOK() || result.getData() != null) { // 业务错误 || 存在返回数据-需提前返回
return result; return result;
} }
@ -136,7 +136,7 @@ public class PayAction extends BaseAction {
} }
// 订单信息预存 // 订单信息预存
if (!rxService.saveRxData(merchantEnum, payOpenId, openid, recipeJson, payWay, patientId, treatNum, totalFee, new ApiPrepayResp(respJson))) { if (!rxService.saveRxData(merchantEnum, payOpenId, openid, recipeJson, payWay, rxType, patientId, treatNum, totalFee, new ApiPrepayResp(respJson))) {
log.info("{} [处方支付]预存支付信息失败 patientId={}", merchantEnum.NAME, patientId); log.info("{} [处方支付]预存支付信息失败 patientId={}", merchantEnum.NAME, patientId);
return Result.error(ResultEnum.SPECIFIED_QUESTIONED_USER_NOT_EXIST); return Result.error(ResultEnum.SPECIFIED_QUESTIONED_USER_NOT_EXIST);
} }

@ -21,6 +21,7 @@ public class ApiPayNotify {
private String mixTradeNo; private String mixTradeNo;
private String transactionId; private String transactionId;
private String refundTransId; private String refundTransId;
private String refundTime;
private BigDecimal totalFee; private BigDecimal totalFee;

@ -46,6 +46,6 @@ public class Recipe extends Order implements Serializable {
private String feeId; private String feeId;
// 预结算信息 // 预结算信息
private String feeInfo; private String feeInfo;
// 处方类型[1:普通处方; 10:互联网医院处方; 11:互联网医院流转处方; 15:生育门诊; 20:慢特病处方;]
private Integer rxType;
} }

@ -2,8 +2,6 @@ package com.ynxbd.common.bean.pay;
import com.ynxbd.jy.bean.JYOrder; import com.ynxbd.jy.bean.JYOrder;
import com.ynxbd.jy.bean.enums.JYBusinessTypeEnum;
import com.ynxbd.jy.bean.enums.JYOrderTypeEnum;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
@ -12,7 +10,7 @@ import lombok.ToString;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
// 医保请求参数 // 京颐请求参数
@Setter @Setter
@Getter @Getter

@ -0,0 +1,106 @@
package com.ynxbd.common.bean.xk;
/*
* Copyright (c) 2022
* User:Administrator
* File:XKMedicineDeliver.java
* Date:2022/12/01 13:58:01
*/
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import java.math.BigDecimal;
import java.util.List;
// 4.3.1.11 收费/退费 ChargeOrRefund
@Getter
@Setter
@ToString
@NoArgsConstructor
public class XKChargeOrRefund {
private String callNo;
/**
* 患者就诊卡证类型
*/
private String idcardTypeCode;
/**
* 患者就诊卡证号码
*/
private String idcardNo;
/**
* 姓名
*/
private String name;
/**
* 性别代码
*/
private String genderCode;
/**
* 出生日期
*/
private String birthDate;
/**
* 门诊编号
*/
private String visitNo;
/**
* 结算序号
*/
private String accountNo;
/**
* 原结算序号
*/
private String originalAccountNo;
/**
* 支付平台订单号
*/
private String orderNo;
/**
* 总费用(元)
*/
private BigDecimal totalFee;
/**
* 自付金额 (元)
*/
private BigDecimal individualPay;
/**
* 收费/退费标志
*/
private String chargeRefundCode;
/**
* 医疗费用支付途径
*/
private String payTypeCode;
/**
* 科室编码
*/
private String deptCode;
/**
* 科室名称
*/
private String deptName;
/**
* 科室对应诊疗科目编码
*/
private String deptClassCode;
/**
* 科室对应诊疗科目名称
*/
private String deptClassName;
/**
* 收费/退费日期时间
*/
private String rcdDatetime;
/**
* 收费明细
*/
private List<XKCostDetail> items;
public boolean hasRefund() {
return "2".equals(this.chargeRefundCode);
}
}

@ -0,0 +1,63 @@
package com.ynxbd.common.bean.xk;
/*
* Copyright (c) 2022
* User:Administrator
* File:XKMedicineDeliver.java
* Date:2022/12/01 13:58:01
*/
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import java.math.BigDecimal;
// 4.3.1.11.1 收费明细 CostDetail
@Getter
@Setter
@ToString
@NoArgsConstructor
public class XKCostDetail {
/**
* 项目明细编号
*/
private String projDeno;
/**
* 项目名称 (包含药品)
*/
private String projName;
/**
* 收费/退费标志
*/
private String chargeRefundCode;
/**
* 收费项目监管分类代码
*/
private String statCatCode;
/**
* 收费项目财务分类代码
*/
private String pinCatCode;
/**
* 是否属于门诊医保项目
*/
private String ifOutMedIns;
/**
* 项目数量
*/
private BigDecimal projCnt;
/**
* 项目单价 (元)
*/
private BigDecimal projUnitPrice;
/**
* 项目总价 (元)
*/
private BigDecimal projAmount;
/**
* 项目自付金额 (元)
*/
private BigDecimal individualPay;
}

@ -73,7 +73,7 @@ public class RxDao {
* @return 是否存储成功 * @return 是否存储成功
*/ */
public boolean insertMedical(Recipe recipe) { public boolean insertMedical(Recipe recipe) {
String sql = "insert into pay(updateTime, hisStatus, payStatus, openId, patientId, payWay, payMoney, totalFee, outTradeNo, bankTransNo, tradeNo, recipeId, treatNum, authCode, invoiceTransNo, hisTransNo, operateUser, deptCode, deptName, reqDeptCode, reqDeptName, hospitalArea, PayOrdId, AcctFee, HifpFee, ChrgBchno, MdTrtId, MdUserId, RecipeJson, PayMchCode, PayOpenId, BizTradeNo, MixTradeNo) values (now(),?,?,?,?,?,?,?,?,?,?, ?,?,?,?,?,?,?,?,?,?, ?,?,?,?,?,?,?,?,?,?,?,?)"; String sql = "insert into pay(updateTime, hisStatus, payStatus, openId, patientId, payWay, payMoney, totalFee, outTradeNo, bankTransNo, tradeNo, recipeId, treatNum, authCode, invoiceTransNo, hisTransNo, operateUser, deptCode, deptName, reqDeptCode, reqDeptName, hospitalArea, PayOrdId, AcctFee, HifpFee, ChrgBchno, MdTrtId, MdUserId, RecipeJson, RxType, PayMchCode, PayOpenId, BizTradeNo, MixTradeNo) values (now(),?,?,?,?,?,?,?,?,?,?, ?,?,?,?,?,?,?,?,?,?, ?,?,?,?,?,?,?,?,?,?,?,?,?)";
return DataBase.insert(sql, ps -> { return DataBase.insert(sql, ps -> {
ps.setInt(1, recipe.getHisStatus()); ps.setInt(1, recipe.getHisStatus());
ps.setInt(2, recipe.getPayStatus()); ps.setInt(2, recipe.getPayStatus());
@ -107,10 +107,11 @@ public class RxDao {
ps.setString(26, recipe.getMdTrtId()); ps.setString(26, recipe.getMdTrtId());
ps.setString(27, recipe.getMdUserId()); ps.setString(27, recipe.getMdUserId());
ps.setString(28, recipe.getRecipeJson()); ps.setString(28, recipe.getRecipeJson());
ps.setString(29, recipe.getPayMchCode()); ps.setInt(29, recipe.getRxType());
ps.setString(30, recipe.getPayOpenId()); ps.setString(30, recipe.getPayMchCode());
ps.setString(31, recipe.getBizTradeNo()); ps.setString(31, recipe.getPayOpenId());
ps.setString(32, recipe.getMixTradeNo()); ps.setString(32, recipe.getBizTradeNo());
ps.setString(33, recipe.getMixTradeNo());
}) > 0; }) > 0;
} }
@ -142,10 +143,11 @@ public class RxDao {
ps.setString(22, item.getFeeId()); ps.setString(22, item.getFeeId());
ps.setString(23, item.getFeeInfo()); ps.setString(23, item.getFeeInfo());
ps.setString(24, item.getOrderType()); ps.setString(24, item.getOrderType());
ps.setString(25, item.getPayMchCode()); ps.setInt(25, item.getRxType());
ps.setString(26, item.getPayOpenId()); ps.setString(26, item.getPayMchCode());
ps.setString(27, item.getBizTradeNo()); ps.setString(27, item.getPayOpenId());
ps.setString(28, item.getMixTradeNo()); ps.setString(28, item.getBizTradeNo());
ps.setString(29, item.getMixTradeNo());
} }
/** /**
@ -155,7 +157,7 @@ public class RxDao {
* @return 是否存储成功 * @return 是否存储成功
*/ */
public int insertBatch(List<Recipe> rxList) { public int insertBatch(List<Recipe> rxList) {
String sql = "insert into pay(updateTime, hisStatus, payStatus, openId, patientId, payWay, payMoney, totalFee, outTradeNo, bankTransNo, tradeNo, recipeId, treatNum, authCode, invoiceTransNo, hisTransNo, operateUser, deptCode, deptName, reqDeptCode, reqDeptName, hospitalArea, feeId, feeInfo, orderType, payMchCode, payOpenId, bizTradeNo, mixTradeNo) values (now(),?,?,?,?,?,?,?,?,?,?, ?,?,?,?,?,?,?,?,?,?, ?,?,?,?,?,?,?,?)"; String sql = "insert into pay(updateTime, hisStatus, payStatus, openId, patientId, payWay, payMoney, totalFee, outTradeNo, bankTransNo, tradeNo, recipeId, treatNum, authCode, invoiceTransNo, hisTransNo, operateUser, deptCode, deptName, reqDeptCode, reqDeptName, hospitalArea, feeId, feeInfo, orderType, rxType, payMchCode, payOpenId, bizTradeNo, mixTradeNo) values (now(),?,?,?,?,?,?,?,?,?,?, ?,?,?,?,?,?,?,?,?,?, ?,?,?,?,?,?,?,?,?)";
if (rxList.size() == 1) { if (rxList.size() == 1) {
return DataBase.insert(sql, ps -> { return DataBase.insert(sql, ps -> {
setRxInsertPs(ps, rxList.get(0)); setRxInsertPs(ps, rxList.get(0));

@ -123,7 +123,7 @@ public class HisPatientDao {
* @param patientId 患者id * @param patientId 患者id
* @return hisResult * @return hisResult
*/ */
public JsonResult queryPatientByPatientId(String patientId) throws ServiceException { public Patient queryHisPatientByPatientId(String patientId) throws ServiceException {
if (StringUtils.isEmpty(patientId)) { if (StringUtils.isEmpty(patientId)) {
throw new ServiceException(ResultEnum.PARAM_IS_DEFECT); throw new ServiceException(ResultEnum.PARAM_IS_DEFECT);
} }
@ -135,8 +135,8 @@ public class HisPatientDao {
* *
* @param cardNo 证件号 * @param cardNo 证件号
*/ */
public JsonResult queryPatientByCardNo(String cardNo) throws ServiceException { public Patient queryHisPatientByCardNo(String cardNo) throws ServiceException {
if (StringUtils.isEmpty(cardNo)) { if (ObjectUtils.isEmpty(cardNo)) {
throw new ServiceException(ResultEnum.PARAM_IS_DEFECT); throw new ServiceException(ResultEnum.PARAM_IS_DEFECT);
} }
return queryPatientInfo(cardNo, "0"); return queryPatientInfo(cardNo, "0");
@ -148,7 +148,7 @@ public class HisPatientDao {
* @param cardNo 卡号 * @param cardNo 卡号
* @param cardType 类型 {0:身份证; 1:健康卡;999:患者ID(PatientId) 此步骤对于已经获得PatientId 需要查询患者信息的情景。} * @param cardType 类型 {0:身份证; 1:健康卡;999:患者ID(PatientId) 此步骤对于已经获得PatientId 需要查询患者信息的情景。}
*/ */
public JsonResult queryPatientInfo(String cardNo, String cardType) throws ServiceException { public Patient queryPatientInfo(String cardNo, String cardType) throws ServiceException {
if (StringUtils.isEmpty(cardNo) || cardType == null) { if (StringUtils.isEmpty(cardNo) || cardType == null) {
throw new ServiceException(ResultEnum.PARAM_IS_DEFECT); throw new ServiceException(ResultEnum.PARAM_IS_DEFECT);
} }
@ -159,7 +159,15 @@ public class HisPatientDao {
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("CardNo", cardNo); params.put("CardNo", cardNo);
params.put("CardType", cardType); params.put("CardType", cardType);
return HisFactory.His().getJsonResult(HisEnum.AP_Query_Patient, params); JsonResult jsonResult = HisFactory.His().getJsonResult(HisEnum.AP_Query_Patient, params);
if (!jsonResult.success()) {
throw new ServiceException(jsonResult.getMessage());
}
Patient patient = jsonResult.dataMapToBean(Patient.class);
if (patient == null) {
throw new ServiceException(ResultEnum.DATA_NOT_FOUND);
}
return patient;
} }

@ -152,6 +152,51 @@ public class OkHttpHelper {
}); });
} }
public static void postAsync(String url, MapParams mapParams) {
OkHttpClient client = getOkHttpClient(url);
if (client == null) {
return;
}
Map<String, Object> requestParams = new HashMap<>();
if (mapParams != null) {
mapParams.setParams(requestParams);
}
// 构建表单参数
FormBody.Builder formBuilder = new FormBody.Builder();
for (Map.Entry<String, Object> entry : requestParams.entrySet()) {
formBuilder.add(entry.getKey(), entry.getValue() == null ? "" : entry.getValue().toString());
}
RequestBody requestBody = formBuilder.build();
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
log.error(e.getMessage(), e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try (ResponseBody responseBody = response.body()) {
if (!response.isSuccessful()) {
if (responseBody != null) {
log.error("请求失败,响应内容:{}", responseBody.string());
}
} else {
if (responseBody != null) {
log.info("请求成功,响应内容:{}", responseBody.string());
}
}
}
}
});
}
// public static String postCookie(String url, RequestBody requestBody, Header header) { // public static String postCookie(String url, RequestBody requestBody, Header header) {
// OkHttpClient client = getOkHttpClient(url); // OkHttpClient client = getOkHttpClient(url);
// if (client == null) { // if (client == null) {

@ -403,7 +403,7 @@ public class MedicalService {
/** /**
* [医保]处方下单 * [医保]处方下单
*/ */
public Result createRxOrder(MerchantEnum merchantEnum, Recipe order, PEnum serverEnum, String recipeJson, String payWay) { public Result createRxOrder(MerchantEnum merchantEnum, Recipe order, PEnum serverEnum, String recipeJson, String payWay, Integer rxType) {
String treatNum = order.getTreatNum(); String treatNum = order.getTreatNum();
String payOrdId = order.getPayOrdId(); String payOrdId = order.getPayOrdId();
String outTradeNo = order.getOutTradeNo(); String outTradeNo = order.getOutTradeNo();
@ -415,6 +415,7 @@ public class MedicalService {
// 0:公众号内支付,1:扫码支付 // 0:公众号内支付,1:扫码支付
payWay = payWay == null ? "0" : payWay; payWay = payWay == null ? "0" : payWay;
rxType = rxType == null ? 0 : rxType;
Recipe rxInfo = new RxService().recipeJsonToInfo(treatNum, recipeJson); Recipe rxInfo = new RxService().recipeJsonToInfo(treatNum, recipeJson);
log.info("[医保][处方]JSON解析 RxInfo={}", rxInfo); log.info("[医保][处方]JSON解析 RxInfo={}", rxInfo);
@ -451,6 +452,7 @@ public class MedicalService {
String bankTransNo = medOrder.mapGetBankTansNo(); String bankTransNo = medOrder.mapGetBankTansNo();
order.setBankTransNo(bankTransNo); order.setBankTransNo(bankTransNo);
order.setPayWay(payWay); order.setPayWay(payWay);
order.setRxType(rxType);
// ------------------------------------------- // -------------------------------------------
order.setRecipeJson(recipeJsonStr); order.setRecipeJson(recipeJsonStr);
order.setDeptCode(rxInfo.getDeptCode()); order.setDeptCode(rxInfo.getDeptCode());

@ -1,12 +1,19 @@
package com.ynxbd.common.service; package com.ynxbd.common.service;
import cn.hutool.core.util.StrUtil;
import com.ynxbd.common.bean.Patient;
import com.ynxbd.common.bean.pay.Recipe;
import com.ynxbd.common.bean.xk.XKChargeOrRefund;
import com.ynxbd.common.bean.xk.XKCostDetail;
import com.ynxbd.common.helper.common.AesMicroHelper; import com.ynxbd.common.helper.common.AesMicroHelper;
import com.ynxbd.common.helper.common.JsonHelper;
import com.ynxbd.common.helper.http.OkHttpHelper; import com.ynxbd.common.helper.http.OkHttpHelper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import okhttp3.FormBody; import org.apache.commons.lang3.ObjectUtils;
import okhttp3.RequestBody;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/** /**
* @author 李进才 * @author 李进才
@ -17,17 +24,100 @@ import java.math.BigDecimal;
@Slf4j @Slf4j
public class MicroService { public class MicroService {
public void OLReg(String openid, BigDecimal totalFee, String outTradeNo, String bankTransNo, String payDate, String payTime) { public void notifyOLReg(String openid, BigDecimal totalFee, String outTradeNo, String bankTransNo, String payDate, String payTime) {
RequestBody body = new FormBody.Builder(). try {
add("callNo", "ol_register"). log.info("[问诊挂号]回调 outTradeNo-{}, bankTransNo-{}, openid-{}, totalFee-{}, payDate-{}, payTime-{}", outTradeNo, bankTransNo, openid, totalFee, payDate, payTime);
add("outTradeNo", AesMicroHelper.encode(outTradeNo)). OkHttpHelper.postAsync("http://127.0.0.1/micro/pay/payNotice", map -> {
add("bankTransNo", AesMicroHelper.encode(bankTransNo)). map.put("callNo", "ol_register");
add("openid", AesMicroHelper.encode(openid)). map.put("outTradeNo", AesMicroHelper.encode(outTradeNo));
add("totalFee", AesMicroHelper.encode(totalFee.toString())). map.put("bankTransNo", AesMicroHelper.encode(bankTransNo));
add("payDate", payDate). map.put("openid", AesMicroHelper.encode(openid));
add("payTime", payTime). map.put("totalFee", AesMicroHelper.encode(totalFee.toString()));
build(); map.put("payDate", payDate);
log.info("[互联网医院在线问诊支付回调] outTradeNo-{}, bankTransNo-{}, openid-{}, totalFee-{}, payDate-{}, payTime-{}", outTradeNo, bankTransNo, openid, totalFee, payDate, payTime); map.put("payTime", payTime);
OkHttpHelper.post("http://127.0.0.1/micro/pay/payNotice", body); });
} catch (Exception e) {
log.error("", e);
}
}
public void uploadRxFee(List<Recipe> rxList, boolean isNotFailRx, BigDecimal totalFee, boolean isMedIns) {
try {
System.out.println("[监管平台]处方缴费上报...");
if (rxList.isEmpty()) {
log.warn("[监管平台]缴费处方数量为0");
return;
}
Recipe rx = rxList.get(0);
if (rx == null) {
log.warn("[监管平台]处方信息缺失");
return;
}
String openId = rx.getOpenid();
String patientId = rx.getPatientId();
String treatNum = rx.getTreatNum();
String deptCode = rx.getDeptCode();
String deptName = rx.getDeptName();
String bankTransNo = rx.getBankTransNo();
if (StrUtil.hasBlank(openId, patientId, treatNum, deptCode, deptName, bankTransNo)) {
log.warn("[监管平台]查询HIS患者信息失败 openId={}, patientId={}, treatNum={}, deptCode={}, deptName={}, bankTransNo={}",
openId, patientId, treatNum, deptCode, deptName, bankTransNo);
return;
}
Patient patient = new PatientService().queryByOpenIdAndEPId(openId, patientId);
if (patient == null) {
patient = new PatientService().queryHisPatientByPatientId(patientId);
if (patient == null) {
log.warn("[监管平台]查询HIS患者信息失败 patientId={}", patientId);
return;
}
}
String idCardNo = patient.getIdCardNo();
String name = patient.getName();
String birthdate = patient.getBirthday();
String sex = patient.getSex();
final String chargeRefundCode = "1";
List<XKCostDetail> items = new ArrayList<>();
for (Recipe item : rxList) {
XKCostDetail detail = new XKCostDetail();
detail.setProjDeno(item.getTradeNo());
detail.setProjName("处方" + (ObjectUtils.isEmpty(item.getRecipeId()) ? "" : item.getRecipeId()));
detail.setChargeRefundCode(chargeRefundCode);
detail.setStatCatCode("1102"); // 1102:诊查费
detail.setPinCatCode("9901"); // 9901:其他费
detail.setIfOutMedIns(isMedIns ? "1" : "0"); // 是否属于门诊医保项目 0、否,1、是
detail.setProjUnitPrice(item.getPayMoney()); // 项目单价(元)
detail.setProjCnt(new BigDecimal(1)); // 项目数量
detail.setProjAmount(item.getPayMoney()); // projAmount
items.add(detail);
}
XKChargeOrRefund xk = new XKChargeOrRefund();
xk.setIdcardNo(idCardNo);
xk.setName(name);
xk.setBirthDate(birthdate);
xk.setGenderCode("男".equals(sex) ? "1" : "2");
xk.setVisitNo(treatNum);
xk.setAccountNo(bankTransNo);
xk.setOrderNo(bankTransNo);
xk.setTotalFee(totalFee);
xk.setIndividualPay(totalFee);
xk.setChargeRefundCode(chargeRefundCode);
xk.setPayTypeCode(isMedIns ? "02" : "07");
xk.setDeptCode(deptCode);
xk.setDeptName(deptName);
xk.setItems(items);
OkHttpHelper.postAsync("http://127.0.0.1/micro/xk/rxChargeOrRefund", map -> {
map.put("data", AesMicroHelper.encode(JsonHelper.toJsonString(xk)));
});
} catch (Exception e) {
log.error("", e);
}
} }
} }

@ -6,11 +6,9 @@ import com.ynxbd.common.bean.User;
import com.ynxbd.common.bean.enums.HCardTypeEnum; import com.ynxbd.common.bean.enums.HCardTypeEnum;
import com.ynxbd.common.cache.GmcCacheManager; import com.ynxbd.common.cache.GmcCacheManager;
import com.ynxbd.common.config.HealthCardConfig; import com.ynxbd.common.config.HealthCardConfig;
import com.ynxbd.common.config.db.DataBase;
import com.ynxbd.common.dao.PatientDao; import com.ynxbd.common.dao.PatientDao;
import com.ynxbd.common.dao.his.HisPatientDao; import com.ynxbd.common.dao.his.HisPatientDao;
import com.ynxbd.common.helper.common.*; import com.ynxbd.common.helper.common.*;
import com.ynxbd.common.result.JsonResult;
import com.ynxbd.common.result.Result; import com.ynxbd.common.result.Result;
import com.ynxbd.common.result.ResultEnum; import com.ynxbd.common.result.ResultEnum;
import com.ynxbd.common.result.ServiceException; import com.ynxbd.common.result.ServiceException;
@ -484,25 +482,25 @@ public class PatientService {
// } // }
/**
* [患者]根据患者ID查询信息
*
* @param patientId 患者id
* @return patient
*/
public Patient queryHisPatientByPatientId(String patientId) throws ServiceException {
return new HisPatientDao().queryHisPatientByPatientId(patientId);
}
/** /**
* [患者]根据cardNo查询信息 * [患者]根据cardNo查询信息
* *
* @param cardNo cardNo * @param cardNo cardNo
* @return patient * @return patient
*/ */
public Patient queryPatientByCardNo(String cardNo) throws ServiceException { public Patient queryHisPatientByCardNo(String cardNo) throws ServiceException {
if (ObjectUtils.isEmpty(cardNo)) { return new HisPatientDao().queryHisPatientByCardNo(cardNo);
throw new ServiceException(ResultEnum.PARAM_IS_DEFECT);
}
JsonResult jsonResult = new HisPatientDao().queryPatientByCardNo(cardNo);
if (!jsonResult.success()) {
throw new ServiceException(jsonResult.getMessage());
}
Patient patient = jsonResult.dataMapToBean(Patient.class);
if (patient == null) {
throw new ServiceException(ResultEnum.DATA_NOT_FOUND);
}
return patient;
} }
@ -514,7 +512,7 @@ public class PatientService {
*/ */
public boolean hasHisBindByCardNo(String cardNo) { public boolean hasHisBindByCardNo(String cardNo) {
try { try {
Patient patient = queryPatientByCardNo(cardNo); Patient patient = queryHisPatientByCardNo(cardNo);
if (patient == null) { if (patient == null) {
return false; return false;
} }

@ -15,6 +15,7 @@ import com.ynxbd.common.result.Result;
import com.ynxbd.common.result.ResultEnum; import com.ynxbd.common.result.ResultEnum;
import com.ynxbd.common.result.ServiceException; import com.ynxbd.common.result.ServiceException;
import com.ynxbd.common.service.cache.PayCache; import com.ynxbd.common.service.cache.PayCache;
import com.ynxbd.jy.bean.enums.JYBusinessTypeEnum;
import com.ynxbd.jy.helper.JYPayHelper; import com.ynxbd.jy.helper.JYPayHelper;
import com.ynxbd.wx.wxfactory.WxMedHelper; import com.ynxbd.wx.wxfactory.WxMedHelper;
import com.ynxbd.wx.wxfactory.WxPayHelper; import com.ynxbd.wx.wxfactory.WxPayHelper;
@ -87,7 +88,7 @@ public class PayService {
break; break;
case OL_REG: case OL_REG:
new MicroService().OLReg(openid, totalFee, outTradeNo, bankTransNo, payDate, payTime); new MicroService().notifyOLReg(openid, totalFee, outTradeNo, bankTransNo, payDate, payTime);
break; break;
case PEIS_RESERVE: case PEIS_RESERVE:
@ -297,6 +298,9 @@ public class PayService {
} }
return BCMHelper.refund(outTradeNo, outRefundNo, tradeDateStr, refundMoney, refundDesc); return BCMHelper.refund(outTradeNo, outRefundNo, tradeDateStr, refundMoney, refundDesc);
case JY:
log.info("【京颐退款】outTradeNo={}, outRefundNo={}, tradeDate={}", outTradeNo, outRefundNo, tradeDate);
return JYPayHelper.refundPayOrder(JYBusinessTypeEnum.B102, new ReqOrder(), outRefundNo, refundMoney, outTradeNo, null, null);
default: default:
break; break;
} }
@ -562,7 +566,7 @@ public class PayService {
return BCMHelper.createOrder(merchantEnum, title, bizTradeNo, totalFee, pEnum.CODE); return BCMHelper.createOrder(merchantEnum, title, bizTradeNo, totalFee, pEnum.CODE);
} else if (MerchantEnum.JY.equals(merchantEnum)) { // 京颐 } else if (MerchantEnum.JY.equals(merchantEnum)) { // 京颐
return JYPayHelper.createOrder(merchantEnum, title, bizTradeNo, totalFee, pEnum.CODE, ip, payOpenId, msgOpenId, new ReqOrder()); return JYPayHelper.createOrder(merchantEnum, title, bizTradeNo, totalFee, pEnum, ip, payOpenId, msgOpenId, new ReqOrder());
} }
return null; return null;
} }

@ -2,10 +2,7 @@ package com.ynxbd.common.service;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.ynxbd.common.action.pay.PEnum; import com.ynxbd.common.action.pay.PEnum;
import com.ynxbd.common.bean.ConfigSelfHelp; import com.ynxbd.common.bean.*;
import com.ynxbd.common.bean.HisRecipe;
import com.ynxbd.common.bean.SelfHelpCount;
import com.ynxbd.common.bean.StandardPrice;
import com.ynxbd.common.bean.enums.MerchantEnum; import com.ynxbd.common.bean.enums.MerchantEnum;
import com.ynxbd.common.bean.pay.ApiPrepayResp; import com.ynxbd.common.bean.pay.ApiPrepayResp;
import com.ynxbd.common.bean.pay.Order; import com.ynxbd.common.bean.pay.Order;
@ -96,7 +93,7 @@ public class RxService {
* @param treatNum 门诊号 * @param treatNum 门诊号
* @return 是否完成操作 * @return 是否完成操作
*/ */
public Result medInsPrepay(MerchantEnum merchantEnum, String payOpenId, String openid, String patientId, String treatNum, String totalFee, String recipeJson, String payWay, Integer awaitSecond, boolean isHttps) { public Result medInsPrepay(MerchantEnum merchantEnum, String payOpenId, String openid, String patientId, String treatNum, String totalFee, String recipeJson, String payWay, Integer rxType, Integer awaitSecond, boolean isHttps) {
try { try {
Result result = PayService.isPaymentPermittedByTime(); Result result = PayService.isPaymentPermittedByTime();
if (result != null) { if (result != null) {
@ -129,7 +126,7 @@ public class RxService {
if ("0".equals(totalFee)) { if ("0".equals(totalFee)) {
String bizTradeNo = merchantEnum.createBizTradeNo(); String bizTradeNo = merchantEnum.createBizTradeNo();
// 订单信息预存 // 订单信息预存
if (!rxService.saveRxData(merchantEnum, payOpenId, openid, recipeJson, payWay, patientId, treatNum, totalFee, new ApiPrepayResp(bizTradeNo))) { if (!rxService.saveRxData(merchantEnum, payOpenId, openid, recipeJson, payWay, rxType, patientId, treatNum, totalFee, new ApiPrepayResp(bizTradeNo))) {
log.info("{} [处方支付]预存支付信息失败 patientId={}", merchantEnum.NAME, patientId); log.info("{} [处方支付]预存支付信息失败 patientId={}", merchantEnum.NAME, patientId);
return Result.error(ResultEnum.SPECIFIED_QUESTIONED_USER_NOT_EXIST); return Result.error(ResultEnum.SPECIFIED_QUESTIONED_USER_NOT_EXIST);
} }
@ -228,8 +225,8 @@ public class RxService {
* @param treatNum 门诊号 * @param treatNum 门诊号
* @return 是否完成操作 * @return 是否完成操作
*/ */
public boolean saveRxData(MerchantEnum merchantEnum, String payOpenId, String openid, String recipeJson, String payWay, String patientId, String treatNum, String totalFee, ApiPrepayResp prepayResp) throws ServiceException { public boolean saveRxData(MerchantEnum merchantEnum, String payOpenId, String openid, String recipeJson, String payWay, Integer rxType, String patientId, String treatNum, String totalFee, ApiPrepayResp prepayResp) throws ServiceException {
log.info("{}[处方支付]预存信息 patientId={}, treatNum={}, recipeJson={}", merchantEnum.NAME, patientId, treatNum, recipeJson); log.info("{}[处方支付]预存信息 patientId={}, treatNum={}, rxType={}, recipeJson={}", merchantEnum.NAME, patientId, treatNum, rxType, recipeJson);
List<Recipe> rxList = JsonHelper.parseArray(recipeJson, Recipe.class); List<Recipe> rxList = JsonHelper.parseArray(recipeJson, Recipe.class);
if (rxList == null || rxList.isEmpty()) { if (rxList == null || rxList.isEmpty()) {
throw new ServiceException("[处方支付]勾选处方数量为0 或 数据转换失败"); throw new ServiceException("[处方支付]勾选处方数量为0 或 数据转换失败");
@ -244,6 +241,7 @@ public class RxService {
RxDao rxDao = new RxDao(); RxDao rxDao = new RxDao();
// 0:公众号内支付,1:扫码支付 // 0:公众号内支付,1:扫码支付
payWay = payWay == null ? "0" : payWay; payWay = payWay == null ? "0" : payWay;
rxType = rxType == null ? 0 : rxType;
for (Recipe rxItem : rxList) { for (Recipe rxItem : rxList) {
if (ObjectUtils.isEmpty(rxItem.getRecipeId()) || ObjectUtils.isEmpty(rxItem.getRecipeFee())) { if (ObjectUtils.isEmpty(rxItem.getRecipeId()) || ObjectUtils.isEmpty(rxItem.getRecipeFee())) {
@ -258,6 +256,7 @@ public class RxService {
rxItem.setBizTradeNo(bizTradeNo); rxItem.setBizTradeNo(bizTradeNo);
rxItem.setMixTradeNo(mixTradeNo); rxItem.setMixTradeNo(mixTradeNo);
rxItem.setPayWay(payWay); rxItem.setPayWay(payWay);
rxItem.setRxType(rxType);
// recipe.setTradeNo(CodeHelper.getHisTradeNo()); // 本次his交易流水号 // recipe.setTradeNo(CodeHelper.getHisTradeNo()); // 本次his交易流水号
rxItem.setTradeNo(null); // 本次his交易流水号 rxItem.setTradeNo(null); // 本次his交易流水号
rxItem.setTotalFee(new BigDecimal(totalFee)); rxItem.setTotalFee(new BigDecimal(totalFee));
@ -304,10 +303,10 @@ public class RxService {
PayService.saveOrderNo(PEnum.RECIPE, outTradeNo, openid, payInfo, null); PayService.saveOrderNo(PEnum.RECIPE, outTradeNo, openid, payInfo, null);
} }
List<Recipe> recipeList = rxDao.selectListByOutTradeNo(outTradeNo); List<Recipe> rxList = rxDao.selectListByOutTradeNo(outTradeNo);
if (!rxDao.updateNotifyPaid(outTradeNo, bankTransNo, bankMerchantNo, recipeList)) { if (!rxDao.updateNotifyPaid(outTradeNo, bankTransNo, bankMerchantNo, rxList)) {
log.info("{} [处方]更新商户信息失败(1) outTradeNo={}, bankTransNo={}", merchantEnum.NAME, outTradeNo, bankTransNo); log.info("{} [处方]更新商户信息失败(1) outTradeNo={}, bankTransNo={}", merchantEnum.NAME, outTradeNo, bankTransNo);
if (!rxDao.updateNotifyPaid(outTradeNo, bankTransNo, bankMerchantNo, recipeList)) { if (!rxDao.updateNotifyPaid(outTradeNo, bankTransNo, bankMerchantNo, rxList)) {
log.info("{} [处方]更新商户信息失败(2) outTradeNo={}, bankTransNo={}", merchantEnum.NAME, outTradeNo, bankTransNo); log.info("{} [处方]更新商户信息失败(2) outTradeNo={}, bankTransNo={}", merchantEnum.NAME, outTradeNo, bankTransNo);
return false; return false;
} }
@ -315,7 +314,7 @@ public class RxService {
// 订单金额验证 // 订单金额验证
BigDecimal rxTotalFee = BigDecimal.ZERO; BigDecimal rxTotalFee = BigDecimal.ZERO;
for (Recipe recipe : recipeList) { for (Recipe recipe : rxList) {
rxTotalFee = rxTotalFee.add(recipe.getPayMoney()); rxTotalFee = rxTotalFee.add(recipe.getPayMoney());
} }
@ -331,7 +330,7 @@ public class RxService {
// HIS缴费 // HIS缴费
String patientId = null; String patientId = null;
Recipe rxInfo; Recipe rxInfo;
for (Recipe rxItem : recipeList) { for (Recipe rxItem : rxList) {
patientId = rxItem.getPatientId(); patientId = rxItem.getPatientId();
rxItem.setBankTransNo(bankTransNo); rxItem.setBankTransNo(bankTransNo);
// HIS处方缴费 // HIS处方缴费
@ -346,7 +345,7 @@ public class RxService {
if (rxItem.getTreatNum().contains("P-")) { if (rxItem.getTreatNum().contains("P-")) {
// 体检缴费失败的所有费用进行退回 // 体检缴费失败的所有费用进行退回
if (rxInfo.isRefund()) { if (rxInfo.isRefund()) {
failedList = recipeList; failedList = rxList;
for (Recipe failed : failedList) { for (Recipe failed : failedList) {
failed.setErrorCode(rxInfo.getErrorCode()); failed.setErrorCode(rxInfo.getErrorCode());
failed.setErrorMsg(rxInfo.getErrorMsg()); failed.setErrorMsg(rxInfo.getErrorMsg());
@ -386,13 +385,17 @@ public class RxService {
} }
} }
String tip = String.format("共计缴费处方单数:%s,失败数:%s,超时数:%s", recipeList.size(), (failedList.size() - outTimeList.size()), outTimeList.size()); String tip = String.format("共计缴费处方单数:%s,失败数:%s,超时数:%s", rxList.size(), (failedList.size() - outTimeList.size()), outTimeList.size());
log.info("{} [处方]{}", merchantEnum.NAME, tip); log.info("{} [处方]{}", merchantEnum.NAME, tip);
if (WeChatConfig.APP_ID.equals(HospConfigEnum.红河州第一人民医院.WX_APP_ID)) { if (WeChatConfig.APP_ID.equals(HospConfigEnum.红河州第一人民医院.WX_APP_ID)) {
TZReserveConfig.reserveRun(patientId); // 天助医技预约 TZReserveConfig.reserveRun(patientId); // 天助医技预约
} }
if (MerchantEnum.JY.equals(merchantEnum)) {
new MicroService().uploadRxFee(rxList, failedList.isEmpty(), new BigDecimal(totalFee), false);
}
new HealthUploadService().rxReportHISData(merchantEnum, openid, patientId); new HealthUploadService().rxReportHISData(merchantEnum, openid, patientId);
return true; return true;
} }

@ -55,8 +55,12 @@ public class JYPayNotify {
// 退款==================================================== // 退款====================================================
// 商户退款流水号,由应用端(应用方、接入方)生成,要求唯一。对应入参 // 商户退款流水号,由应用端(应用方、接入方)生成,要求唯一。对应入参
private String refundTransId; private String refundTransId;
// 退费时间-20260928012108
private String refundTime;
// 退款金额,精确到分,例如100 // 退款金额,精确到分,例如100
private Long refundAmt; private Long refundAmt;
// 退费状态
private String refundState;
// 交易状态,退款交易状态,详见数据字典#交易流水状态 // 交易状态,退款交易状态,详见数据字典#交易流水状态
private String tranStatus; private String tranStatus;
// 交易代码,002 撤销 004 退费 005 冲正,详细请参考数据字典#交易代码 // 交易代码,002 撤销 004 退费 005 冲正,详细请参考数据字典#交易代码

@ -1,8 +1,11 @@
package com.ynxbd.jy.helper; package com.ynxbd.jy.helper;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.ynxbd.common.action.pay.JYPSEnum;
import com.ynxbd.common.action.pay.PEnum;
import com.ynxbd.common.bean.enums.MerchantEnum; import com.ynxbd.common.bean.enums.MerchantEnum;
import com.ynxbd.common.bean.pay.ApiPayNotify; import com.ynxbd.common.bean.pay.ApiPayNotify;
import com.ynxbd.common.bean.pay.Order;
import com.ynxbd.common.bean.pay.ReqOrder; import com.ynxbd.common.bean.pay.ReqOrder;
import com.ynxbd.common.helper.common.DateHelper; import com.ynxbd.common.helper.common.DateHelper;
import com.ynxbd.common.helper.common.JsonHelper; import com.ynxbd.common.helper.common.JsonHelper;
@ -52,31 +55,31 @@ public class JYPayHelper {
* @param title 商品标题 * @param title 商品标题
* @param totalFee 订单金额 * @param totalFee 订单金额
* @param merOrderNum 应用商户订单号 * @param merOrderNum 应用商户订单号
* @param notifyType 回调类型 * @param pEnum 业务类型
* @param ip ip地址 * @param ip ip地址
* @param payOpenId 用于下单的openId * @param payOpenId 用于下单的openId
* @param msgOpenId 用于推送的openId * @param msgOpenId 用于推送的openId
* @return 成功返回 json, 否则返回null * @return 成功返回 json, 否则返回null
*/ */
public static JSONObject createOrder(MerchantEnum merchantEnum, String title, String merOrderNum, String totalFee, String notifyType, String ip, String payOpenId, String msgOpenId, ReqOrder reqOrder) { public static JSONObject createOrder(MerchantEnum merchantEnum, String title, String merOrderNum, String totalFee, PEnum pEnum, String ip, String payOpenId, String msgOpenId, ReqOrder reqOrder) {
try { try {
String notifyType = pEnum.CODE;
JYPSEnum jyEnum = JYPSEnum.findEnum(pEnum);
if (ObjectUtils.isEmpty(payOpenId) || ObjectUtils.isEmpty(merOrderNum) if (ObjectUtils.isEmpty(payOpenId) || ObjectUtils.isEmpty(merOrderNum)
|| merchantEnum == null || totalFee == null || notifyType == null) { || merchantEnum == null || totalFee == null || notifyType == null) {
log.error("【京硕】预下单参数缺失"); log.error("【京硕】预下单参数缺失");
return null; return null;
} }
String cents; int orderAmt = new BigDecimal(totalFee).movePointRight(2).intValue(); // 金额转换=>单位分
try { if (orderAmt == 0) {
cents = new BigDecimal(totalFee).movePointRight(2).toString(); // 金额转换=>单位分 log.error("【京硕】订单金额转换异常,或金额为0");
} catch (Exception e) {
log.error("【京硕】预下单金额转换异常:", e);
return null; return null;
} }
log.info("【京硕】预下单 {},{},{},{},{}", title, merOrderNum, totalFee, ip, merchantEnum.NOTIFY_URL); log.info("【京硕】预下单 {},{},{},{},{}", title, merOrderNum, totalFee, ip, merchantEnum.NOTIFY_URL);
JYOrder jyOrder = reqOrder.jyOrder;
Map<String, String> params = new HashMap<>(); Map<String, String> params = new HashMap<>();
params.put("openId", payOpenId); params.put("openId", payOpenId);
params.put("hospitalId", JYPayConfig.HOSP_ID); // 医院ID params.put("hospitalId", JYPayConfig.HOSP_ID); // 医院ID
@ -86,28 +89,28 @@ public class JYPayHelper {
params.put("hisOrderNum", null); // HIS订单号:可以为发票号[该接口若不传,在业务完成后调用2.1.6接口] params.put("hisOrderNum", null); // HIS订单号:可以为发票号[该接口若不传,在业务完成后调用2.1.6接口]
params.put("hisTransNum", null); // HIS流水号:可以为发票号[该接口若不传,在业务完成后调用2.1.6接口] params.put("hisTransNum", null); // HIS流水号:可以为发票号[该接口若不传,在业务完成后调用2.1.6接口]
// 金额 // 金额
params.put("orderAmt", cents); // 交易金额:只接收整数,单位:分,例如100表示壹圆整;支付宝医保支付传总金额 params.put("orderAmt", Integer.toString(orderAmt)); // 交易金额:只接收整数,单位:分,例如100表示壹圆整;支付宝医保支付传总金额
params.put("orderType", jyOrder.orderTypeEnum.CODE); // 如:001:挂号费 002:医药费; params.put("orderType", jyEnum.ORDER_TYPE.CODE); // 如:001:挂号费 002:医药费;
params.put("backURL", WeChatConfig.getBaseURL() + merchantEnum.NOTIFY_URL + "?notifyType=" + notifyType); // 商户异步回调地址:后台发起异步回调地址, 扫码枪支付方式无需回调的可以不 params.put("backURL", WeChatConfig.getBaseURL() + merchantEnum.NOTIFY_URL + "?notifyType=" + notifyType); // 商户异步回调地址:后台发起异步回调地址, 扫码枪支付方式无需回调的可以不
params.put("backParamsType", "key-value"); // 商户异步回调入参格式:后台发起异步回调时参数格式,取值有:key-value和json,默认值是key-value。 params.put("backParamsType", "key-value"); // 商户异步回调入参格式:后台发起异步回调时参数格式,取值有:key-value和json,默认值是key-value。
params.put("payType", "WX_PUBLIC"); // 如:UPOP_APP, UPOP_WEB;详见附录5.1[微信公众号支付(WX_PUBLIC)] params.put("payType", "WX_PUBLIC"); // 如:UPOP_APP, UPOP_WEB;详见附录5.1[微信公众号支付(WX_PUBLIC)]
params.put("bussinessType", jyOrder.businessTypeEnum.CODE); // 业务类型:综合支付对应用权限控制是否必传 最大不超过4位,详见数据字典5.2 该接口若不传,需要调用2.1.6接口再次更新 params.put("bussinessType", jyEnum.BUSINESS_TYPE.CODE); // 业务类型:综合支付对应用权限控制是否必传 最大不超过4位,详见数据字典5.2 该接口若不传,需要调用2.1.6接口再次更新
params.put("patientName", reqOrder.getPatientName()); // 微信医保支付必传。其余支付方式若该接口若不传,需要调用2.1.6接口再次更新 // params.put("patientName", reqOrder.getPatientName()); // 微信医保支付必传。其余支付方式若该接口若不传,需要调用2.1.6接口再次更新
params.put("patientGender", reqOrder.getPatientGender()); // 患者性别。综合支付对应用权限控制是否必传 1男 2女 9其他 最大不超过4位 该接口若不传,需要调用2.1.6接口再次更新 // params.put("patientGender", reqOrder.getPatientGender()); // 患者性别。综合支付对应用权限控制是否必传 1男 2女 9其他 最大不超过4位 该接口若不传,需要调用2.1.6接口再次更新
params.put("patientAge", reqOrder.getPatientAge()); // 患者年龄。综合支付对应用权限控制是否必传 该接口若不传,需要调用2.1.6接口再次更新 // params.put("patientAge", reqOrder.getPatientAge()); // 患者年龄。综合支付对应用权限控制是否必传 该接口若不传,需要调用2.1.6接口再次更新
params.put("patientIdNo", reqOrder.getPatientIdCardNo()); // 微信医保支付必传。其余支付方式若该接口若不传,需要调用2.1.6接口再次更新 // params.put("patientIdNo", reqOrder.getPatientIdCardNo()); // 微信医保支付必传。其余支付方式若该接口若不传,需要调用2.1.6接口再次更新
params.put("patientPhoneNumber", reqOrder.getPatientTel()); // 综合支付对应用权限控制是否必传 最大不超过16位 该接口若不传,需要调用2.1.6接口再次更新 // params.put("patientPhoneNumber", reqOrder.getPatientTel()); // 综合支付对应用权限控制是否必传 最大不超过16位 该接口若不传,需要调用2.1.6接口再次更新
params.put("patientId", reqOrder.getPatientId()); // 患者ID:综合支付对应用权限控制是否必传 最大不超过32位 该接口若不传,需要调用2.1.6接口再次更新 // params.put("patientId", reqOrder.getPatientId()); // 患者ID:综合支付对应用权限控制是否必传 最大不超过32位 该接口若不传,需要调用2.1.6接口再次更新
params.put("patientCardNo", reqOrder.getPatientId()); // 患者卡号:综合支付对应用权限控制是否必传 最大不超过32位该接口若不传,需要调用2.1.6接口再次更新 // params.put("patientCardNo", reqOrder.getPatientId()); // 患者卡号:综合支付对应用权限控制是否必传 最大不超过32位该接口若不传,需要调用2.1.6接口再次更新
params.put("clinicNo", reqOrder.getTreatNum()); // 门诊号:综合支付对应用权限控制是否必传 最大不超过32位该接口若不传,需要调用2.1.6接口再次更新 // params.put("clinicNo", reqOrder.getTreatNum()); // 门诊号:综合支付对应用权限控制是否必传 最大不超过32位该接口若不传,需要调用2.1.6接口再次更新
params.put("inpNo", reqOrder.getTreatNum()); // 住院号:综合支付对应用权限控制是否必传 最大不超过32位该接口若不传,需要调用2.1.6接口再次更新 // params.put("inpNo", reqOrder.getTreatNum()); // 住院号:综合支付对应用权限控制是否必传 最大不超过32位该接口若不传,需要调用2.1.6接口再次更新
params.put("hisTransDoneTime", null); // HIS业务完成时间:综合支付对应用权限控制是否必传 YYYY-MM-DD HH:MM:SS 该接口若不传,需要调用2.1.6接口再次更新 // params.put("hisTransDoneTime", null); // HIS业务完成时间:综合支付对应用权限控制是否必传 YYYY-MM-DD HH:MM:SS 该接口若不传,需要调用2.1.6接口再次更新
params.put("hisOperatorNo", jyOrder.getHisOperatorNo()); // HIS操作员编号:综合支付对应用权限控制是否必传HIS操作员编号和HIS操作员姓名必须成对出现该接口若不传,需要调用2.1.6接口再次更新 // params.put("hisOperatorNo", null); // HIS操作员编号:综合支付对应用权限控制是否必传HIS操作员编号和HIS操作员姓名必须成对出现该接口若不传,需要调用2.1.6接口再次更新
params.put("hisOperatorName", jyOrder.getHisOperatorName()); // HIS操作员姓名:综合支付对应用权限控制是否必传 HIS操作员编号和HIS操作员姓名必须成对出现 该接口若不传,需要调用2.1.6接口再次更新 // params.put("hisOperatorName", null); // HIS操作员姓名:综合支付对应用权限控制是否必传 HIS操作员编号和HIS操作员姓名必须成对出现 该接口若不传,需要调用2.1.6接口再次更新
params.put("receiptNo", null); // 综合支付对应用权限控制是否必传最大不超过200位 该接口若不传,需要调用2.1.6接口再次更新 // params.put("receiptNo", null); // 综合支付对应用权限控制是否必传最大不超过200位 该接口若不传,需要调用2.1.6接口再次更新
params.put("remarks", ""); // 备注 建行渠道格式为json,参考样式:{"REMARK1":"REM1","REMARK2":"REM2"} 农行渠道参考样式:{"TerminalNo":"1234567"} // params.put("remarks", ""); // 备注 建行渠道格式为json,参考样式:{"REMARK1":"REM1","REMARK2":"REM2"} 农行渠道参考样式:{"TerminalNo":"1234567"}
// 医保支付====================================== // 医保支付======================================
// params.put("orderTotalAmt", cents); // orderTotalAmt:微信医保支付必传,有社保交易数据时,订单总金额=自费实际金额+社保金额+减免金额 // params.put("orderTotalAmt", cents); // orderTotalAmt:微信医保支付必传,有社保交易数据时,订单总金额=自费实际金额+社保金额+减免金额
@ -192,29 +195,28 @@ public class JYPayHelper {
* *
* @return 成功返回 json, 否则返回null * @return 成功返回 json, 否则返回null
*/ */
public static JSONObject refundPayOrder(JYBusinessTypeEnum businessTypeEnum, ReqOrder patient, String outRefundNo, BigDecimal refundFee, String outTradeNo, String bankMerchantNo, String tradeNo) { public static Order refundPayOrder(JYBusinessTypeEnum businessTypeEnum, ReqOrder patient, String outRefundNo, BigDecimal refundFee, String outTradeNo, String bankMerchantNo, String tradeNo) {
Order order = new Order();
try { try {
log.info("【京硕】退款申请 {},{},{},{}", outTradeNo, bankMerchantNo, tradeNo, refundFee); log.info("【京硕】退款申请 {},{},{},{}", outTradeNo, bankMerchantNo, tradeNo, refundFee);
if (ObjectUtils.isEmpty(outTradeNo) && ObjectUtils.isEmpty(bankMerchantNo) && ObjectUtils.isEmpty(tradeNo)) { if (ObjectUtils.isEmpty(outTradeNo) && ObjectUtils.isEmpty(bankMerchantNo) && ObjectUtils.isEmpty(tradeNo)) {
return null; order.setErrorMsg("【京硕】退款参数缺失");
order.setRefundResult("退款参数缺失");
return order;
} }
String refundCents; int refundAmt = refundFee.movePointRight(2).intValue(); // 单位分
try { if (refundAmt == 0) {
if (refundFee == null) { order.setErrorMsg("【京硕】退费金额转换异常,或退费金额为0");
return null; order.setRefundResult("退费金额转换异常,或退费金额为0");
} return order;
refundCents = refundFee.movePointRight(2).toString(); // 金额转换=>单位分
} catch (Exception e) {
log.info("【京硕】退款申请-金额转换异常:", e);
return null;
} }
Map<String, String> params = new HashMap<>(); Map<String, String> params = new HashMap<>();
params.put("applicationId", JYPayConfig.APPLICATION_ID); params.put("applicationId", JYPayConfig.APPLICATION_ID);
params.put("merchantId", JYPayConfig.MERCHANT_ID); params.put("merchantId", JYPayConfig.MERCHANT_ID);
params.put("refundAmt", refundCents); // 微信医保和支付宝医保只支持全部退款(支付宝医保为总金额)。只接收整数,单位:分,例如100表示壹圆整; params.put("refundAmt", Integer.toString(refundAmt)); // 微信医保和支付宝医保只支持全部退款(支付宝医保为总金额)。只接收整数,单位:分,例如100表示壹圆整;
params.put("refundTransId", outRefundNo); // 由应用方生成的退款流水号,要求唯一。同一笔退款流水若重复发送,该流水号不能变,否则平台会认为发起一笔新的退款流水。 params.put("refundTransId", outRefundNo); // 由应用方生成的退款流水号,要求唯一。同一笔退款流水若重复发送,该流水号不能变,否则平台会认为发起一笔新的退款流水。
params.put("orderId", outTradeNo); // 支付平台订单号 params.put("orderId", outTradeNo); // 支付平台订单号
params.put("merOrderNum", bankMerchantNo); // 应用方自己生成的订单唯一标识[BankMerchantNo] params.put("merOrderNum", bankMerchantNo); // 应用方自己生成的订单唯一标识[BankMerchantNo]
@ -247,7 +249,9 @@ public class JYPayHelper {
String signValue = createSign(params); String signValue = createSign(params);
if (signValue == null) { if (signValue == null) {
return null; order.setErrorMsg("【京硕】签名错误");
order.setRefundResult("签名错误");
return order;
} }
params.put("signValue", signValue); // 数字签名:由接入方生成的签名,支付平台根据该字段对入参进行验签;签名生成规则参考4加签验签规则 params.put("signValue", signValue); // 数字签名:由接入方生成的签名,支付平台根据该字段对入参进行验签;签名生成规则参考4加签验签规则
@ -256,13 +260,20 @@ public class JYPayHelper {
log.info("【京硕】退款申请-响应-{}", JsonHelper.toJsonString(result)); log.info("【京硕】退款申请-响应-{}", JsonHelper.toJsonString(result));
if (!result.isSuccess()) { if (!result.isSuccess()) {
log.error("【京硕】退款申请-失败:{}", result.getMessage()); log.error("【京硕】退款申请-失败:{}", result.getMessage());
return null; order.setErrorCode(result.getCode());
order.setErrorMsg(result.getMessage());
order.setRefundResult(result.getMessage());
return order;
} }
return result.getData(); // JSONObject data = result.getData();
order.setRefundResult("OK");
order.setSuccess(true); // 操作成功标识
return order;
} catch (Exception e) { } catch (Exception e) {
log.error("【京硕】退款申请异常信息:", e); log.error("【京硕】退款申请异常信息:", e);
order.setErrorMsg("【京硕】" + e.getMessage());
return order;
} }
return null;
} }
/** /**
@ -391,18 +402,19 @@ public class JYPayHelper {
return Base64.getEncoder().encodeToString(signature.sign()); return Base64.getEncoder().encodeToString(signature.sign());
} }
public static ApiPayNotify jyPayNotify(JYPayNotify notifyInfo, String attach) { public static ApiPayNotify jyPayNotify(Map<String, String> params, String attach) {
JYPayNotify notifyInfo = JsonHelper.parseObject(JsonHelper.toJsonString(params), JYPayNotify.class);
ApiPayNotify data = new ApiPayNotify(); ApiPayNotify data = new ApiPayNotify();
data.setOpenId(notifyInfo.getOpenId()); data.setOpenId(notifyInfo.getOpenId());
BigDecimal totalFeeCent = new BigDecimal(notifyInfo.getOrderAmt()); BigDecimal totalFeeCent = new BigDecimal(notifyInfo.getOrderAmt());
Map<String, String> dateMap = getDateMap(notifyInfo.getPaymentTime()); if (!ObjectUtils.isEmpty(notifyInfo.getPaymentTime())) {
data.setPayDate(dateMap.get(WxSignHelper.DATE_KEY)); Map<String, String> dateMap = getDateMap(notifyInfo.getPaymentTime());
data.setPayTime(dateMap.get(WxSignHelper.TIME_KEY)); data.setPayDate(dateMap.get(DATE_KEY));
data.setPayTime(dateMap.get(TIME_KEY));
data.setPayDate(dateMap.get(WxSignHelper.DATE_KEY)); }
data.setPayTime(dateMap.get(WxSignHelper.TIME_KEY));
data.setMerchantEnum(MerchantEnum.JY); data.setMerchantEnum(MerchantEnum.JY);
data.setOpenId(notifyInfo.getOpenId()); data.setOpenId(notifyInfo.getOpenId());
@ -410,6 +422,7 @@ public class JYPayHelper {
data.setBizTradeNo(notifyInfo.getMerchantNo()); data.setBizTradeNo(notifyInfo.getMerchantNo());
data.setTransactionId(notifyInfo.getFinalTransNo()); data.setTransactionId(notifyInfo.getFinalTransNo());
data.setRefundTransId(notifyInfo.getRefundTransId()); data.setRefundTransId(notifyInfo.getRefundTransId());
data.setRefundTime(notifyInfo.getRefundTime());
data.setTotalFee(totalFeeCent.movePointLeft(2)); data.setTotalFee(totalFeeCent.movePointLeft(2));
data.setPayInfo(null); data.setPayInfo(null);

Loading…
Cancel
Save