新增了提现记录表,保存提现记录,定时器主动向Adapay查询提现状态
This commit is contained in:
parent
9c5dda67aa
commit
9bd5811918
|
|
@ -179,10 +179,11 @@ public class OrderDetailServiceImpl implements OrderDetailService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String createCode() {
|
public synchronized String createCode() {
|
||||||
INDEX.compareAndSet(9999L, 1L);
|
INDEX.compareAndSet(9999L, 1L);
|
||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
return "od" + now.format(MINI_FORMATTER) + INDEX.getAndIncrement();
|
// 得到的CODE长度相同
|
||||||
|
return "od" + now.format(MINI_FORMATTER) + String.format("%04d", INDEX.getAndIncrement());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -65,9 +65,10 @@ public class OrderMasterServiceImpl implements OrderMasterService {
|
||||||
private final static ThreadLocal<SimpleDateFormat> dateFormat = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMddHHmmss"));
|
private final static ThreadLocal<SimpleDateFormat> dateFormat = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMddHHmmss"));
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String createOrderCode() {
|
public synchronized String createOrderCode() {
|
||||||
INDEX.compareAndSet(9999L, 1L);
|
INDEX.compareAndSet(9999L, 1L);
|
||||||
return "om" + dateFormat.get().format(new Date()) + INDEX.getAndIncrement();
|
// 得到的CODE长度相同
|
||||||
|
return "om" + dateFormat.get().format(new Date()) + String.format("%04d", INDEX.getAndIncrement());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
package com.ghy.payment.domain;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提现记录
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class DrawCashRecord {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 由Adapay生成的取现对象 id
|
||||||
|
*/
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
private Long dept_id;
|
||||||
|
/**
|
||||||
|
* 控制台 主页面应用的app_id
|
||||||
|
*/
|
||||||
|
private String app_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取现类型:T1-T+1取现;D1-D+1取现;D0-即时取现。
|
||||||
|
*/
|
||||||
|
private String cash_type;
|
||||||
|
/**
|
||||||
|
* 取现对象创建时的 10 位时间戳
|
||||||
|
*/
|
||||||
|
private String created_time;
|
||||||
|
/**
|
||||||
|
* 用户对象的member_id,若是商户本身取现时为0
|
||||||
|
*/
|
||||||
|
private String member_id;
|
||||||
|
/**
|
||||||
|
* 取现对象,cash
|
||||||
|
*/
|
||||||
|
private String object;
|
||||||
|
/**
|
||||||
|
* 请求订单号,只能为英文、数字或者下划线的一种或多种组合,保证在app_id下唯一
|
||||||
|
*/
|
||||||
|
private String order_no;
|
||||||
|
/**
|
||||||
|
* 取现金额,必须大于0,保留两位小数点,如0.10、100.05等
|
||||||
|
*/
|
||||||
|
private String cash_amt;
|
||||||
|
/**
|
||||||
|
* 取现成功后的到账金额,值为取现金额 - 取现手续费金额。
|
||||||
|
*/
|
||||||
|
private String real_amt;
|
||||||
|
/**
|
||||||
|
* 取现手续费金额
|
||||||
|
*/
|
||||||
|
private String fee_amt;
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
* pending 交易处理中
|
||||||
|
* succeeded 交易成功
|
||||||
|
* failed 交易失败
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
/**
|
||||||
|
* 是否 prod模式,true 是 prod模式,false 是 mock模式
|
||||||
|
*/
|
||||||
|
private String prod_mode;
|
||||||
|
/**
|
||||||
|
* 错误码 https://docs.adapay.tech/api/errors.html#id6
|
||||||
|
*/
|
||||||
|
private String error_code;
|
||||||
|
/**
|
||||||
|
* 错误类型
|
||||||
|
* invalid_request_error 请求错误,传入了不正确的地址、参数或值
|
||||||
|
* api_error Adapay 服务器出现的异常错误
|
||||||
|
* channel_error 第三方支付渠道出现的错误导致请求出现错误,通常您需要对这些可能出现的情况进行处理或者联系我们
|
||||||
|
*/
|
||||||
|
private String error_type;
|
||||||
|
private String error_msg;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.ghy.payment.mapper;
|
||||||
|
|
||||||
|
import com.ghy.payment.domain.DrawCashRecord;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface DrawCashRecordMapper {
|
||||||
|
|
||||||
|
int insert(DrawCashRecord record);
|
||||||
|
|
||||||
|
int update(DrawCashRecord record);
|
||||||
|
|
||||||
|
DrawCashRecord selectById(String id);
|
||||||
|
|
||||||
|
List<DrawCashRecord> selectByStatus(String status);
|
||||||
|
|
||||||
|
int updateStatus(@Param("id") String id, @Param("status") String status);
|
||||||
|
}
|
||||||
|
|
@ -10,9 +10,9 @@ import com.ghy.payment.service.impl.PayReverseCallbackService;
|
||||||
import com.ghy.payment.service.impl.RefundCallbackService;
|
import com.ghy.payment.service.impl.RefundCallbackService;
|
||||||
import com.huifu.adapay.core.exception.BaseAdaPayException;
|
import com.huifu.adapay.core.exception.BaseAdaPayException;
|
||||||
import com.huifu.adapay.model.*;
|
import com.huifu.adapay.model.*;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
@ -25,11 +25,12 @@ import java.util.List;
|
||||||
/**
|
/**
|
||||||
* @author HH 2022/3/25
|
* @author HH 2022/3/25
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class AdapayService {
|
public class AdapayService {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(AdapayService.class);
|
@Resource
|
||||||
|
private ThreadPoolTaskExecutor executor;
|
||||||
@Resource
|
@Resource
|
||||||
private PayCallbackService payCallbackService;
|
private PayCallbackService payCallbackService;
|
||||||
@Resource
|
@Resource
|
||||||
|
|
@ -100,9 +101,9 @@ public class AdapayService {
|
||||||
confirmParams.put("div_members", divMembers);
|
confirmParams.put("div_members", divMembers);
|
||||||
confirmParams.put("fee_mode", feeMode);
|
confirmParams.put("fee_mode", feeMode);
|
||||||
confirmParams.put("description", description);
|
confirmParams.put("description", description);
|
||||||
logger.info("发起支付确认 dept[{}] param:{}", deptId, confirmParams.toJSONString());
|
log.info("发起支付确认 dept[{}] param:{}", deptId, confirmParams.toJSONString());
|
||||||
JSONObject response = (JSONObject) PaymentConfirm.create(confirmParams, deptId.toString());
|
JSONObject response = (JSONObject) PaymentConfirm.create(confirmParams, deptId.toString());
|
||||||
logger.info("支付确认结果 dept[{}] response:{}", deptId, response.toJSONString());
|
log.info("支付确认结果 dept[{}] response:{}", deptId, response.toJSONString());
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -278,13 +279,30 @@ public class AdapayService {
|
||||||
cashParam.put("notify_url", adapayProperties.getNotifyUrl());
|
cashParam.put("notify_url", adapayProperties.getNotifyUrl());
|
||||||
cashParam.put("remark", remark);
|
cashParam.put("remark", remark);
|
||||||
cashParam.put("fee_mode", feeMode);
|
cashParam.put("fee_mode", feeMode);
|
||||||
logger.info("发起提现 dept[{}] param:{}", deptId, cashParam.toJSONString());
|
log.info("发起提现 dept[{}] param:{}", deptId, cashParam.toJSONString());
|
||||||
JSONObject response = (JSONObject) Drawcash.create(cashParam, deptId.toString());
|
JSONObject response = (JSONObject) Drawcash.create(cashParam, deptId.toString());
|
||||||
logger.info("提现结果 dept[{}] response:{}", deptId, response.toJSONString());
|
log.info("提现结果 dept[{}] response:{}", deptId, response.toJSONString());
|
||||||
drawCashCallbackService.onResponse(response);
|
response.put("dept_id", deptId);
|
||||||
|
executor.execute(() -> drawCashCallbackService.onResponse(response));
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过该功能,可以查询已发起的取现交易状态。
|
||||||
|
*
|
||||||
|
* @param deptId [必填]商户ID
|
||||||
|
* @param orderNo [必填项]请求订单号,只能为英文、数字或者下划线的一种或多种组合,保证在app_id下唯一
|
||||||
|
* @return https://docs.adapay.tech/api/wallet.html#query-cash-response
|
||||||
|
* 失败示例: {"error_msg":"未查到相关取现信息","error_type":"invalid_request_error","prod_mode":"true","error_code":"cash_error","status":"failed"}
|
||||||
|
* 成功示例: {"cash_list":[{"cash_id":"0021110483925412449046528","trans_stat":"P","cash_amt":"19.87"}],"prod_mode":"true","status":"succeeded"}
|
||||||
|
*/
|
||||||
|
public JSONObject queryDrawCash(@NotNull Long deptId, @NotNull String orderNo) throws BaseAdaPayException {
|
||||||
|
Assert.hasText(orderNo, "orderNo is blank!");
|
||||||
|
JSONObject queryCashParam = new JSONObject();
|
||||||
|
queryCashParam.put("order_no", orderNo);
|
||||||
|
return (JSONObject) Drawcash.query(queryCashParam, deptId.toString());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付宝正扫支付
|
* 支付宝正扫支付
|
||||||
*/
|
*/
|
||||||
|
|
@ -351,9 +369,9 @@ public class AdapayService {
|
||||||
paymentParams.put("div_members", divMembers);
|
paymentParams.put("div_members", divMembers);
|
||||||
paymentParams.put("device_info", deviceInfo);
|
paymentParams.put("device_info", deviceInfo);
|
||||||
paymentParams.put("expend", expend);
|
paymentParams.put("expend", expend);
|
||||||
logger.debug("paymentParams: {}", paymentParams.toJSONString());
|
log.debug("paymentParams: {}", paymentParams.toJSONString());
|
||||||
JSONObject response = (JSONObject) Payment.create(paymentParams, deptId.toString());
|
JSONObject response = (JSONObject) Payment.create(paymentParams, deptId.toString());
|
||||||
payCallbackService.onResponse(response);
|
executor.execute(() -> payCallbackService.onResponse(response));
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -380,7 +398,7 @@ public class AdapayService {
|
||||||
refundParams.put("refund_amt", refundAmt);
|
refundParams.put("refund_amt", refundAmt);
|
||||||
refundParams.put("refund_order_no", refundOrderNo);
|
refundParams.put("refund_order_no", refundOrderNo);
|
||||||
JSONObject response = (JSONObject) Refund.create(paymentId, refundParams, deptId.toString());
|
JSONObject response = (JSONObject) Refund.create(paymentId, refundParams, deptId.toString());
|
||||||
refundCallbackService.onResponse(response);
|
executor.execute(() -> refundCallbackService.onResponse(response));
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -444,7 +462,7 @@ public class AdapayService {
|
||||||
reverseParams.put("notify_url", adapayProperties.getNotifyUrl());
|
reverseParams.put("notify_url", adapayProperties.getNotifyUrl());
|
||||||
reverseParams.put("order_no", "PAYMENT_REVERSE" + System.currentTimeMillis());
|
reverseParams.put("order_no", "PAYMENT_REVERSE" + System.currentTimeMillis());
|
||||||
JSONObject response = (JSONObject) PaymentReverse.create(reverseParams, deptId.toString());
|
JSONObject response = (JSONObject) PaymentReverse.create(reverseParams, deptId.toString());
|
||||||
payReverseCallbackService.onResponse(response);
|
executor.execute(() -> payReverseCallbackService.onResponse(response));
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
package com.ghy.payment.service;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.ghy.common.adapay.model.AdapayStatusEnum;
|
||||||
|
import com.ghy.payment.domain.DrawCashRecord;
|
||||||
|
import com.ghy.payment.mapper.DrawCashRecordMapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时器
|
||||||
|
* 主动与Adapay同步支付、撤销支付、提现订单的状态
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@EnableScheduling
|
||||||
|
public class AdapaySyncTimer {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AdapayService adapayService;
|
||||||
|
@Resource
|
||||||
|
private DrawCashRecordMapper drawCashRecordMapper;
|
||||||
|
|
||||||
|
@Scheduled(fixedRate = 5 * 60 * 1000L)
|
||||||
|
public void syncDrawCash() {
|
||||||
|
List<DrawCashRecord> records = drawCashRecordMapper.selectByStatus("pending");
|
||||||
|
if (CollectionUtils.isEmpty(records)) {
|
||||||
|
log.debug("No pending drawCashRecord.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (DrawCashRecord record : records) {
|
||||||
|
Long deptId = record.getDept_id();
|
||||||
|
String orderNo = record.getOrder_no();
|
||||||
|
if (deptId == null || StringUtils.isBlank(orderNo)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
JSONObject response = adapayService.queryDrawCash(deptId, orderNo);
|
||||||
|
// 这个status代表API调用状态 不代表提现状态
|
||||||
|
if (AdapayStatusEnum.succeeded.code.equals(response.getString("status"))) {
|
||||||
|
JSONArray cashList = response.getJSONArray("cash_list");
|
||||||
|
if (!CollectionUtils.isEmpty(cashList)) {
|
||||||
|
JSONObject cash = cashList.getJSONObject(0);
|
||||||
|
// 这个才是提现状态
|
||||||
|
String transStat = cash.getString("trans_stat");
|
||||||
|
switch (transStat) {
|
||||||
|
// 提现成功
|
||||||
|
case "S":
|
||||||
|
drawCashRecordMapper.updateStatus(record.getId(), "succeeded");
|
||||||
|
break;
|
||||||
|
// 提现失败
|
||||||
|
case "F":
|
||||||
|
drawCashRecordMapper.updateStatus(record.getId(), "failed");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.error("DrawCash.query请求失败: {}", response.toJSONString());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,29 +2,35 @@ package com.ghy.payment.service.impl;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.ghy.common.adapay.model.Event;
|
import com.ghy.common.adapay.model.Event;
|
||||||
|
import com.ghy.payment.domain.DrawCashRecord;
|
||||||
|
import com.ghy.payment.mapper.DrawCashRecordMapper;
|
||||||
import com.ghy.payment.service.CallBackService;
|
import com.ghy.payment.service.CallBackService;
|
||||||
import org.slf4j.Logger;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提现回调
|
* 提现回调
|
||||||
*
|
*
|
||||||
* @author HH 2022/5/30
|
* @author HH 2022/5/30
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@Service("drawCashCallbackService")
|
@Service("drawCashCallbackService")
|
||||||
public class DrawCashCallbackService implements CallBackService {
|
public class DrawCashCallbackService implements CallBackService {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(DrawCashCallbackService.class);
|
@Resource
|
||||||
|
private DrawCashRecordMapper drawCashRecordMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCallback(Event event) {
|
public void onCallback(Event event) {
|
||||||
logger.info("提现 callback: {}", event.toString());
|
log.info("提现 callback: {}", event.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(JSONObject response) {
|
public void onResponse(JSONObject response) {
|
||||||
logger.info("提现 response: {}", response.toString());
|
DrawCashRecord record = response.toJavaObject(DrawCashRecord.class);
|
||||||
|
drawCashRecordMapper.insert(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.ghy.payment.mapper.DrawCashRecordMapper">
|
||||||
|
|
||||||
|
<sql id="select_columns">
|
||||||
|
SELECT `id`,
|
||||||
|
`dept_id`,
|
||||||
|
`app_id`,
|
||||||
|
`cash_amt`,
|
||||||
|
`cash_type`,
|
||||||
|
`created_time`,
|
||||||
|
`fee_amt`,
|
||||||
|
`member_id`,
|
||||||
|
`object`,
|
||||||
|
`order_no`,
|
||||||
|
`real_amt`,
|
||||||
|
`status`,
|
||||||
|
`prod_mode`,
|
||||||
|
`error_code`,
|
||||||
|
`error_type`,
|
||||||
|
`error_msg`
|
||||||
|
FROM draw_cash_record
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<insert id="insert" parameterType="com.ghy.payment.domain.DrawCashRecord">
|
||||||
|
INSERT INTO draw_cash_record(`id`, `dept_id`, `app_id`, `cash_amt`, `cash_type`, `created_time`,
|
||||||
|
`fee_amt`, `member_id`, `object`, `order_no`,
|
||||||
|
`real_amt`, `status`, `prod_mode`, `error_code`, `error_type`, `error_msg`)
|
||||||
|
VALUES (#{id}, #{dept_id}, #{app_id}, #{cash_amt}, #{cash_type}, #{created_time},
|
||||||
|
#{fee_amt}, #{member_id}, #{object}, #{order_no},
|
||||||
|
#{real_amt}, #{status}, #{prod_mode}, #{error_code}, #{error_type}, #{error_msg})
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="update" parameterType="com.ghy.payment.domain.DrawCashRecord">
|
||||||
|
UPDATE draw_cash_record
|
||||||
|
<set>
|
||||||
|
<if test="real_amt != null and real_amt != ''">`real_amt` = #{real_amt},</if>
|
||||||
|
<if test="fee_amt != null and fee_amt != ''">`fee_amt` = #{fee_amt},</if>
|
||||||
|
<if test="status != null and status != ''">`status` = #{status},</if>
|
||||||
|
<if test="error_code != null and error_code != ''">`error_code` = #{error_code},</if>
|
||||||
|
<if test="error_type != null and error_type != ''">`error_type` = #{error_type},</if>
|
||||||
|
<if test="error_msg != null and error_msg != ''">`error_msg` = #{error_msg},</if>
|
||||||
|
</set>
|
||||||
|
WHERE `id` = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<update id="updateStatus">
|
||||||
|
UPDATE draw_cash_record
|
||||||
|
SET `status` = #{status}
|
||||||
|
WHERE `id` = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<select id="selectById" resultType="com.ghy.payment.domain.DrawCashRecord">
|
||||||
|
<include refid="select_columns"/>
|
||||||
|
WHERE `id` = #{id}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectByStatus" resultType="com.ghy.payment.domain.DrawCashRecord">
|
||||||
|
<include refid="select_columns"/>
|
||||||
|
WHERE `status` = #{status}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
Loading…
Reference in New Issue