提现渠道优化

This commit is contained in:
墨大叔 2024-08-02 17:56:39 +08:00
parent 4fd545fdcb
commit 1d36920701
25 changed files with 361 additions and 297 deletions

View File

@ -3,10 +3,12 @@ package com.ruoyi.common.pay.yst.util;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.pay.yst.config.YstConfig;
import com.ruoyi.common.pay.yst.domain.BizParameter;
import com.ruoyi.common.pay.yst.domain.YstRequest;
import com.ruoyi.common.pay.yst.domain.YstResponse;
import com.ruoyi.common.utils.ServiceUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@ -46,20 +48,25 @@ public class YstClient {
/**
* 发送请求
*/
public <T> YstResponse<T> sendRequest(String api, String transCode, BizParameter param, Class<T> type) throws Exception
public <T> YstResponse<T> sendRequest(String api, String transCode, BizParameter param, Class<T> type)
{
YstRequest request = assembleRequest(transCode, param.toString());
log.info("request:{}", request);
String respStr = post(request.toString(), config.getHost() + api);
log.info("response:{}", respStr);
verify(respStr);
log.info("验签成功");
YstResponse<T> resp = JSON.parseObject(respStr, new TypeReference<YstResponse<T>>() {});
String bizDataStr = resp.getBizData() != null ? resp.getBizData().toString() : null;
if (StringUtils.isNotBlank(bizDataStr)) {
resp.setBizData(JSON.parseObject(bizDataStr, type));
try {
YstRequest request = assembleRequest(transCode, param.toString());
log.info("request:{}", request);
String respStr = post(request.toString(), config.getHost() + api);
log.info("response:{}", respStr);
verify(respStr);
log.info("验签成功");
YstResponse<T> resp = JSON.parseObject(respStr, new TypeReference<YstResponse<T>>() {});
ServiceUtil.assertion(!resp.isSuccess(), resp.getMsg());
String bizDataStr = resp.getBizData() != null ? resp.getBizData().toString() : null;
if (StringUtils.isNotBlank(bizDataStr)) {
resp.setBizData(JSON.parseObject(bizDataStr, type));
}
return resp;
} catch (Exception e) {
throw new ServiceException("【云商通】请求失败" + e.getMessage());
}
return resp;
}
private void verify(String respStr) throws Exception

View File

@ -146,9 +146,9 @@
#elseif($column.list && "" != $column.dictType)
<template v-else-if="column.key === '${javaField}'">
#if($column.htmlType == "checkbox")
<dict-tag :options="dict.type.${column.dictType}" :value="d.row[column.key] ? d.row[column.key].split(',') : []"/>
<dict-tag :options="dict.type.${column.dictType}" :value="d.row[column.key] ? d.row[column.key].split(',') : []"/>
#else
<dict-tag :options="dict.type.${column.dictType}" :value="d.row[column.key]"/>
<dict-tag :options="dict.type.${column.dictType}" :value="d.row[column.key]"/>
#end
</template>
#end

View File

@ -107,7 +107,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#end
#end
</trim>
where ${pkColumn.columnName} = #{${pkColumn.javaField}}
where ${pkColumn.columnName} = #{data.${pkColumn.javaField}}
</update>
<delete id="delete${ClassName}By${pkColumn.capJavaField}" parameterType="${pkColumn.javaType}">

View File

@ -49,22 +49,6 @@ public class Channel extends BaseEntity
@ApiModelProperty("服务费类型")
private String serviceType;
@Excel(name = "提现是否启用")
@ApiModelProperty("提现是否启用")
private Boolean withdrawEnabled;
@Excel(name = "提现服务费类型")
@ApiModelProperty("提现服务费类型")
private String withdrawServiceType;
@Excel(name = "提现服务费")
@ApiModelProperty("提现服务费")
private BigDecimal withdrawServiceRate;
@Excel(name = "提现成本率%")
@ApiModelProperty("提现成本率%")
private BigDecimal withdrawCostRate;
@ApiModelProperty("渠道图片")
@JsonView(JsonViewProfile.App.class)
private String picture;

View File

@ -7,8 +7,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<resultMap type="ChannelVO" id="SmChannelResult" autoMapping="true">
<result property="serviceRate" column="service_rate" typeHandler="com.ruoyi.system.mapper.typehandler.NonNullDecimalTypeHandler"/>
<result property="costRate" column="cost_rate" typeHandler="com.ruoyi.system.mapper.typehandler.NonNullDecimalTypeHandler"/>
<result property="withdrawServiceRate" column="withdraw_service_rate" typeHandler="com.ruoyi.system.mapper.typehandler.NonNullDecimalTypeHandler"/>
<result property="withdrawCostRate" column="withdraw_cost_rate" typeHandler="com.ruoyi.system.mapper.typehandler.NonNullDecimalTypeHandler"/>
</resultMap>
<sql id="selectSmChannelVo">
@ -19,10 +17,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
sc.service_rate,
sc.cost_rate,
sc.service_type,
sc.withdraw_enabled,
sc.withdraw_service_type,
sc.withdraw_service_rate,
sc.withdraw_cost_rate,
sc.picture
from sm_channel sc
</sql>
@ -31,8 +25,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="query.name != null and query.name != ''"> and sc.name like concat('%', #{query.name}, '%')</if>
<if test="query.enabled != null "> and sc.enabled = #{query.enabled}</if>
<if test="query.serviceType != null and query.serviceType != ''"> and sc.service_type = #{query.serviceType}</if>
<if test="query.withdrawEnabled != null "> and sc.withdraw_enabled = #{query.withdrawEnabled}</if>
<if test="query.withdrawServiceType != null and query.withdrawServiceType != ''"> and sc.withdraw_service_type = #{query.withdrawServiceType}</if>
<if test="query.channelIds != null and query.channelIds.size() > 0 ">
and sc.channel_id in
<foreach item="item" collection="query.channelIds" open="(" separator="," close=")">
@ -62,10 +54,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="serviceRate != null">service_rate,</if>
<if test="costRate != null">cost_rate,</if>
<if test="serviceType != null">service_type,</if>
<if test="withdrawEnabled != null">withdraw_enabled,</if>
<if test="withdrawServiceType != null">withdraw_service_type,</if>
<if test="withdrawServiceRate != null">withdraw_service_rate,</if>
<if test="withdrawCostRate != null">withdraw_cost_rate,</if>
<if test="picture != null">picture,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
@ -75,10 +63,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="serviceRate != null">#{serviceRate},</if>
<if test="costRate != null">#{costRate},</if>
<if test="serviceType != null">#{serviceType},</if>
<if test="withdrawEnabled != null">#{withdrawEnabled},</if>
<if test="withdrawServiceType != null">#{withdrawServiceType},</if>
<if test="withdrawServiceRate != null">#{withdrawServiceRate},</if>
<if test="withdrawCostRate != null">#{withdrawCostRate},</if>
<if test="picture != null">#{picture},</if>
</trim>
</insert>
@ -91,10 +75,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="data.serviceRate != null">service_rate = #{data.serviceRate},</if>
<if test="data.costRate != null">cost_rate = #{data.costRate},</if>
<if test="data.serviceType != null">service_type = #{data.serviceType},</if>
<if test="data.withdrawEnabled != null">withdraw_enabled = #{data.withdrawEnabled},</if>
<if test="data.withdrawServiceType != null">withdraw_service_type = #{data.withdrawServiceType},</if>
<if test="data.withdrawServiceRate != null">withdraw_service_rate = #{data.withdrawServiceRate},</if>
<if test="data.withdrawCostRate != null">withdraw_cost_rate = #{data.withdrawCostRate},</if>
<if test="data.picture != null">picture = #{data.picture},</if>
</trim>
where channel_id = #{data.channelId}

View File

@ -79,9 +79,4 @@ public interface ChannelService
*/
<K> Map<K, ChannelVO> selectMap(ChannelQuery query, Function<? super Channel, ? extends K> keyMapper);
/**
* 查询启用的提现渠道列表
*/
List<ChannelVO> selectEnabledWithdrawList(Long userId);
}

View File

@ -110,30 +110,6 @@ public class ChannelServiceImpl implements ChannelService
return this.selectSmChannelList(dto);
}
@Override
public List<ChannelVO> selectEnabledWithdrawList(Long userId) {
// 查询用户账户列表
List<AccountVO> accountList = accountService.selectByUserId(userId);
if (CollectionUtils.isEmptyElement(accountList)) {
return Collections.emptyList();
}
// 过滤出渠道ID列表
List<Long> channelIds = accountList.stream()
.map(item -> AccountType.parse(item.getAccountType()))
.filter(Objects::nonNull)
.map(AccountType::getChannelId)
.collect(Collectors.toList());
if (CollectionUtils.isEmptyElement(channelIds)) {
return Collections.emptyList();
}
// 查询渠道列表
ChannelQuery dto = new ChannelQuery();
dto.setWithdrawEnabled(true);
dto.setChannelIds(channelIds);
return this.selectSmChannelList(dto);
}
/**
* 查询充值渠道映射表
*

View File

@ -1,6 +1,9 @@
package com.ruoyi.ss.channelWithdraw.domain;
import java.math.BigDecimal;
import com.fasterxml.jackson.annotation.JsonView;
import com.ruoyi.common.core.domain.JsonViewProfile;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
@ -19,11 +22,12 @@ public class ChannelWithdraw extends BaseEntity
{
private static final long serialVersionUID = 1L;
@ApiModelProperty("${comment}")
@JsonView(JsonViewProfile.App.class)
private Long channelId;
@Excel(name = "渠道名称")
@ApiModelProperty("渠道名称")
@JsonView(JsonViewProfile.App.class)
private String name;
@Excel(name = "对应账户类型")
@ -40,6 +44,15 @@ public class ChannelWithdraw extends BaseEntity
@Excel(name = "是否启用")
@ApiModelProperty("是否启用")
private Integer enabled;
private Boolean enabled;
@Excel(name = "渠道成本率")
@ApiModelProperty("渠道成本率")
private BigDecimal costRate;
@Excel(name = "图片")
@ApiModelProperty("图片")
@JsonView(JsonViewProfile.App.class)
private String picture;
}

View File

@ -1,11 +1,18 @@
package com.ruoyi.ss.channelWithdraw.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
* @author wjh
* 2024/8/2
*/
@Data
public class ChannelWithdrawQuery extends ChannelWithdraw{
@ApiModelProperty("账户类型列表")
private List<String> accountTypes;
}

View File

@ -4,7 +4,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.ss.channelWithdraw.mapper.ChannelWithdrawMapper">
<resultMap type="ChannelWithdrawVO" id="ChannelWithdrawResult" autoMapping="true"/>
<resultMap type="ChannelWithdrawVO" id="ChannelWithdrawResult" autoMapping="true">
<result property="serviceRate" column="service_rate" typeHandler="com.ruoyi.system.mapper.typehandler.NonNullDecimalTypeHandler"/>
<result property="costRate" column="cost_rate" typeHandler="com.ruoyi.system.mapper.typehandler.NonNullDecimalTypeHandler"/>
</resultMap>
<sql id="selectChannelWithdrawVo">
select
@ -13,7 +16,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
scw.account_type,
scw.service_type,
scw.service_rate,
scw.enabled
scw.enabled,
scw.cost_rate,
scw.picture
from ss_channel_withdraw scw
</sql>
@ -23,6 +28,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="query.accountType != null and query.accountType != ''"> and scw.account_type = #{query.accountType}</if>
<if test="query.serviceType != null and query.serviceType != ''"> and scw.service_type = #{query.serviceType}</if>
<if test="query.enabled != null "> and scw.enabled = #{query.enabled}</if>
<if test="query.accountTypes != null and query.accountTypes.size() > 0">
and scw.account_type in
<foreach item="item" collection="query.accountTypes" open="(" separator="," close=")">
#{item}
</foreach>
</if>
</sql>
<select id="selectChannelWithdrawList" parameterType="ChannelWithdrawQuery" resultMap="ChannelWithdrawResult">
@ -45,6 +56,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="serviceType != null and serviceType != ''">service_type,</if>
<if test="serviceRate != null">service_rate,</if>
<if test="enabled != null">enabled,</if>
<if test="costRate != null">cost_rate,</if>
<if test="picture != null">picture,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="name != null and name != ''">#{name},</if>
@ -52,6 +65,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="serviceType != null and serviceType != ''">#{serviceType},</if>
<if test="serviceRate != null">#{serviceRate},</if>
<if test="enabled != null">#{enabled},</if>
<if test="costRate != null">#{costRate},</if>
<if test="picture != null">#{picture},</if>
</trim>
</insert>
@ -63,8 +78,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="data.serviceType != null and data.serviceType != ''">service_type = #{data.serviceType},</if>
<if test="data.serviceRate != null">service_rate = #{data.serviceRate},</if>
<if test="data.enabled != null">enabled = #{data.enabled},</if>
<if test="data.costRate != null">cost_rate = #{data.costRate},</if>
<if test="data.picture != null">picture = #{data.picture},</if>
</trim>
where channel_id = #{channelId}
where channel_id = #{data.channelId}
</update>
<delete id="deleteChannelWithdrawByChannelId" parameterType="Long">

View File

@ -1,6 +1,8 @@
package com.ruoyi.ss.channelWithdraw.service;
import java.util.List;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.ss.channelWithdraw.domain.ChannelWithdraw;
import com.ruoyi.ss.channelWithdraw.domain.ChannelWithdrawVO;
import com.ruoyi.ss.channelWithdraw.domain.ChannelWithdrawQuery;
@ -60,4 +62,9 @@ public interface ChannelWithdrawService
* @return 结果
*/
public int deleteChannelWithdrawByChannelId(Long channelId);
/**
* 查询用户可用的提现渠道
*/
List<ChannelWithdrawVO> selectEnabledList(Long userId);
}

View File

@ -1,6 +1,15 @@
package com.ruoyi.ss.channelWithdraw.service.impl;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.ss.account.domain.AccountVO;
import com.ruoyi.ss.account.domain.enums.AccountType;
import com.ruoyi.ss.account.service.AccountService;
import com.ruoyi.ss.channel.domain.ChannelQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.ss.channelWithdraw.mapper.ChannelWithdrawMapper;
@ -21,6 +30,9 @@ public class ChannelWithdrawServiceImpl implements ChannelWithdrawService
@Autowired
private ChannelWithdrawMapper channelWithdrawMapper;
@Autowired
private AccountService accountService;
/**
* 查询提现渠道
*
@ -92,4 +104,18 @@ public class ChannelWithdrawServiceImpl implements ChannelWithdrawService
{
return channelWithdrawMapper.deleteChannelWithdrawByChannelId(channelId);
}
@Override
public List<ChannelWithdrawVO> selectEnabledList(Long userId) {
// 查询用户账户列表
List<AccountVO> accountList = accountService.selectByUserId(userId);
if (CollectionUtils.isEmptyElement(accountList)) {
return Collections.emptyList();
}
// 查询渠道列表
ChannelWithdrawQuery query = new ChannelWithdrawQuery();
query.setAccountTypes(CollectionUtils.map(accountList, AccountVO::getAccountType));
query.setEnabled(true);
return this.selectChannelWithdrawList(query);
}
}

View File

@ -2,6 +2,7 @@ package com.ruoyi.ss.transactionBill.domain.bo;
import com.ruoyi.ss.account.domain.AccountVO;
import com.ruoyi.ss.channel.domain.ChannelVO;
import com.ruoyi.ss.channelWithdraw.domain.ChannelWithdrawVO;
import com.ruoyi.ss.transactionBill.domain.dto.WithdrawDTO;
import com.ruoyi.ss.user.domain.SmUserVo;
import lombok.Data;
@ -21,7 +22,7 @@ public class WithdrawBO {
private WithdrawDTO dto;
// 渠道
private ChannelVO channel;
private ChannelWithdrawVO channel;
// 用户账号
private AccountVO account;

View File

@ -169,4 +169,14 @@ public interface TransactionBillMapper
* 批量更新套餐结束时间
*/
int batchUpdateSuitEndTime(@Param("billIds") List<Long> billIds,@Param("time") LocalDateTime time);
/**
* 查询提现列表
*/
List<TransactionBillVO> selectWithdrawList(@Param("query") TransactionBillQuery query);
/**
* 查询提现详情
*/
TransactionBillVO selectWithdrawById(Long billId);
}

View File

@ -8,52 +8,57 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="transferIds" column="transfer_ids" typeHandler="com.ruoyi.system.mapper.typehandler.StringListTypeHandler"/>
</resultMap>
<sql id="BaseColumns">
stb.bill_id,
stb.bill_no,
stb.user_id,
stb.type,
stb.device_id,
stb.mch_id,
stb.money,
stb.arrival_amount,
stb.service_charge,
stb.create_time,
stb.remark,
stb.status,
stb.channel_id,
stb.after_balance,
stb.pay_time,
stb.expire_time,
stb.account_no,
stb.payed_amount,
stb.transfer_ids,
stb.channel_cost,
stb.device_recharge_status,
stb.suit_id,
stb.suit_time,
stb.suit_time_unit,
stb.suit_start_time,
stb.suit_end_time,
stb.suit_expire_time,
stb.store_id,
stb.store_name,
stb.store_address,
stb.device_name,
stb.device_no,
stb.suit_name,
stb.device_mac,
stb.refund_amount,
stb.refund_mch_amount,
stb.refund_service_amount,
stb.pay_picture,
stb.withdraw_type,
stb.offline_image,
</sql>
<sql id="selectSmTransactionBillVo">
select stb.bill_id,
stb.bill_no,
stb.user_id,
stb.type,
stb.device_id,
stb.mch_id,
stb.money,
stb.arrival_amount,
stb.service_charge,
stb.create_time,
stb.remark,
stb.status,
stb.channel_id,
stb.after_balance,
stb.pay_time,
stb.expire_time,
stb.account_no,
stb.payed_amount,
stb.transfer_ids,
stb.channel_cost,
stb.device_recharge_status,
stb.suit_id,
stb.suit_time,
stb.suit_time_unit,
stb.suit_start_time,
stb.suit_end_time,
stb.suit_expire_time,
stb.store_id,
stb.store_name,
stb.store_address,
stb.device_name,
stb.device_no,
stb.suit_name,
stb.device_mac,
stb.refund_amount,
stb.refund_mch_amount,
stb.refund_service_amount,
stb.pay_picture,
stb.withdraw_type,
stb.offline_image,
su.user_name as user_name,
su1.user_name as mch_name,
su1.phonenumber as mch_mobile,
sd.device_no as device_no,
su.phonenumber as user_mobile
select
<include refid="BaseColumns"/>
su.user_name as user_name,
su1.user_name as mch_name,
su1.phonenumber as mch_mobile,
sd.device_no as device_no,
su.phonenumber as user_mobile
from sm_transaction_bill stb
left join sm_user su on su.user_id = stb.user_id
left join sm_user su1 on su1.user_id = stb.mch_id
@ -61,6 +66,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
left join sm_suit ss on ss.suit_id = stb.suit_id
</sql>
<!--查询提现VO-->
<sql id="selectWithdrawVo">
select
<include refid="BaseColumns"/>
su.user_name as user_name,
su1.user_name as mch_name,
su1.phonenumber as mch_mobile,
su.phonenumber as user_mobile,
sc.name as channel_name
from sm_transaction_bill stb
left join sm_user su on su.user_id = stb.user_id
left join sm_user su1 on su1.user_id = stb.mch_id
left join ss_channel_withdraw sc on sc.channel_id = stb.channel_id
</sql>
<sql id="searchCondition">
<if test="query.userId != null "> and stb.user_id = #{query.userId}</if>
<if test="query.billId != null "> and stb.bill_id = #{query.billId}</if>
@ -217,6 +237,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
limit 1
</select>
<select id="selectWithdrawList" resultMap="SmTransactionBillResult">
<include refid="selectWithdrawVo"/>
<where>
<include refid="searchCondition"/>
</where>
</select>
<select id="selectWithdrawById" resultMap="SmTransactionBillResult">
<include refid="selectWithdrawVo"/>
where stb.bill_id = #{billId}
</select>
<insert id="insertSmTransactionBill" parameterType="TransactionBill" useGeneratedKeys="true" keyProperty="billId">
insert into sm_transaction_bill
<trim prefix="(" suffix=")" suffixOverrides=",">

View File

@ -134,7 +134,7 @@ public interface TransactionBillService
*
* @param dto id
*/
boolean passWithdraw(WithdrawApprovalDTO dto);
int passWithdraw(WithdrawApprovalDTO dto);
/**
* 提现审核拒绝
@ -143,33 +143,6 @@ public interface TransactionBillService
*/
boolean rejectWithdraw(WithdrawApprovalDTO dto);
/**
* 提现打款
* @param billId 提现单id
*/
boolean payWithdraw(Long billId);
/**
* 提现成功
*
* @param billId id
* @param payTime
*/
void withdrawSuccess(Long billId, LocalDateTime payTime);
/**
* 提现失败
* @param billId id
*/
void withdrawFailed(Long billId);
/**
* 更新微信批次明细单号
* @param billId 提现单号
* @param transferIds 微信批次明细列表
*/
boolean updateWxTransferDetailIds(Long billId, List<String> transferIds);
/**
* 查询商户统计信息
* @param dto 查询条件
@ -280,4 +253,14 @@ public interface TransactionBillService
* 微信支付
*/
PrepayWithRequestPaymentResponse wxPay(TransactionBill bill);
/**
* 查询提现列表
*/
List<TransactionBillVO> selectWithdrawList(TransactionBillQuery query);
/**
* 查询提现详情
*/
TransactionBillVO selectWithdrawById(Long billId);
}

View File

@ -5,6 +5,7 @@ import com.ruoyi.ss.channel.domain.Channel;
import com.ruoyi.ss.channel.domain.ChannelQuery;
import com.ruoyi.ss.channel.domain.ChannelVO;
import com.ruoyi.ss.channel.service.ChannelService;
import com.ruoyi.ss.channelWithdraw.service.ChannelWithdrawService;
import com.ruoyi.ss.transactionBill.domain.vo.TransactionBillVO;
import com.ruoyi.ss.transactionBill.service.TransactionAssembler;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -1,12 +1,16 @@
package com.ruoyi.ss.transactionBill.service.impl;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.ss.account.domain.AccountQuery;
import com.ruoyi.ss.account.domain.AccountVO;
import com.ruoyi.ss.account.domain.enums.AccountType;
import com.ruoyi.ss.account.service.AccountService;
import com.ruoyi.ss.channel.domain.ChannelVO;
import com.ruoyi.ss.channel.service.ChannelService;
import com.ruoyi.ss.channelWithdraw.domain.ChannelWithdraw;
import com.ruoyi.ss.channelWithdraw.domain.ChannelWithdrawVO;
import com.ruoyi.ss.channelWithdraw.service.ChannelWithdrawService;
import com.ruoyi.ss.device.domain.vo.DeviceVO;
import com.ruoyi.ss.device.service.DeviceService;
import com.ruoyi.ss.suit.domain.SuitVO;
@ -33,17 +37,25 @@ public class TransactionBillConverterImpl implements TransactionBillConverter {
@Autowired
private DeviceService deviceService;
@Autowired
private ISmUserService userService;
@Autowired
private SuitService suitService;
@Autowired
private ChannelService channelService;
@Autowired
private AccountService accountService;
@Autowired
private SuitAssembler suitAssembler;
@Autowired
private ChannelWithdrawService channelWithdrawService;
/**
* 将参数转为充值BO
*
@ -99,14 +111,15 @@ public class TransactionBillConverterImpl implements TransactionBillConverter {
ServiceUtil.assertion(user == null, "用户不存在");
// 渠道
ChannelVO channel = channelService.selectSmChannelByChannelId(dto.getChannelId());
ChannelWithdrawVO channel = channelWithdrawService.selectChannelWithdrawByChannelId(dto.getChannelId());
ServiceUtil.assertion(channel == null, "提现渠道不存在");
ServiceUtil.assertion(channel.getEnabled() == null || !channel.getEnabled(), "提现渠道不可用");
// 获取收款账户
AccountType accountType = AccountType.parseByChannel(channel.getChannelId());
ServiceUtil.assertion(StringUtils.isBlank(channel.getAccountType()), "提现渠道没有对应的收款账户类型,请联系管理员处理");
AccountQuery accountQuery = new AccountQuery();
accountQuery.setUserId(user.getUserId());
accountQuery.setAccountType(accountType.getType());
accountQuery.setAccountType(channel.getAccountType());
AccountVO account = accountService.selectOne(accountQuery);
ServiceUtil.assertion(account == null, "收款账户不存在");

View File

@ -8,9 +8,9 @@ import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.*;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.ss.account.domain.AccountVO;
import com.ruoyi.ss.account.service.AccountService;
import com.ruoyi.ss.channel.domain.ChannelVO;
import com.ruoyi.ss.channel.service.ChannelService;
import com.ruoyi.ss.channelWithdraw.domain.ChannelWithdrawVO;
import com.ruoyi.ss.channelWithdraw.service.ChannelWithdrawService;
import com.ruoyi.ss.dashboard.BillCountVo;
import com.ruoyi.ss.device.domain.vo.DeviceVO;
import com.ruoyi.ss.device.service.DeviceService;
@ -22,9 +22,7 @@ import com.ruoyi.ss.refund.domain.RefundVO;
import com.ruoyi.ss.refund.service.RefundConverter;
import com.ruoyi.ss.refund.service.RefundService;
import com.ruoyi.ss.store.domain.StoreVo;
import com.ruoyi.ss.store.service.IStoreService;
import com.ruoyi.ss.suit.domain.SuitVO;
import com.ruoyi.ss.suit.service.SuitService;
import com.ruoyi.ss.transactionBill.domain.TransactionBill;
import com.ruoyi.ss.transactionBill.domain.TransactionBillQuery;
import com.ruoyi.ss.transactionBill.domain.vo.TransactionBillVO;
@ -77,7 +75,7 @@ public class TransactionBillServiceImpl implements TransactionBillService {
private TransactionBillMapper transactionBillMapper;
@Autowired
private ChannelService channelService;
private ChannelWithdrawService channelWithdrawService;
@Autowired
private TransactionBillValidator transactionBillValidator;
@ -103,15 +101,6 @@ public class TransactionBillServiceImpl implements TransactionBillService {
@Autowired
private RedisLock redisLock;
@Autowired
private AccountService smAccountService;
@Autowired
private IStoreService storeService;
@Autowired
private SuitService suitService;
@Autowired
private ScheduledExecutorService scheduledExecutorService;
@ -359,13 +348,13 @@ public class TransactionBillServiceImpl implements TransactionBillService {
ServiceUtil.assertion(!redisLock.lock(RedisLockKey.ADD_WITHDRAW, userId), "请勿频繁操作提现");
try {
WithdrawDTO dto = bo.getDto();
ChannelVO channel = bo.getChannel();
ChannelWithdrawVO channel = bo.getChannel();
SmUserVo user = bo.getUser();
AccountVO account = bo.getAccount();
// 处理提现手续费
ServiceUtil.assertion(channel == null, "提现渠道不存在");
ServiceUtil.assertion(channel.getWithdrawEnabled() == null || !channel.getWithdrawEnabled(), "提现渠道不可用");
ServiceUtil.assertion(channel.getEnabled() == null || !channel.getEnabled(), "提现渠道不可用");
UserWithdrawServiceVO serviceInfo = this.getUserWithdrawService(user, channel);
ServiceUtil.assertion(serviceInfo == null, "服务费配置出错,请联系管理员处理");
ServiceUtil.assertion(StringUtils.isBlank(serviceInfo.getServiceType()), "服务费配置出错,请联系管理员处理");
@ -393,7 +382,7 @@ public class TransactionBillServiceImpl implements TransactionBillService {
bill.setAccountNo(account.getAccountNo());
bill.setChannelId(channel.getChannelId());
bill.setWithdrawType(WithdrawType.ONLINE.getType());
bill.setChannelCost(channel.getWithdrawCostRate().multiply(bill.getMoney()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)); // 渠道成本
bill.setChannelCost(channel.getCostRate().multiply(bill.getMoney()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)); // 渠道成本
transactionTemplate.execute(status -> {
// 减少余额并判断提现金额是否超额减少的是交易金额
@ -433,11 +422,11 @@ public class TransactionBillServiceImpl implements TransactionBillService {
* 获取用户提现服务费
* 用户 > 渠道
*/
private UserWithdrawServiceVO getUserWithdrawService(SmUserVo user, ChannelVO channel) {
private UserWithdrawServiceVO getUserWithdrawService(SmUserVo user, ChannelWithdrawVO channel) {
if (user != null && StringUtils.hasText(user.getWithdrawServiceType()) && user.getWithdrawServiceRate() != null ) {
return new UserWithdrawServiceVO(user.getWithdrawServiceType(), user.getWithdrawServiceRate());
} else if (channel != null && StringUtils.hasText(channel.getWithdrawServiceType()) && channel.getWithdrawServiceRate() != null) {
return new UserWithdrawServiceVO(channel.getWithdrawServiceType(), channel.getWithdrawServiceRate());
} else if (channel != null && StringUtils.hasText(channel.getServiceType()) && channel.getServiceRate() != null) {
return new UserWithdrawServiceVO(channel.getServiceType(), channel.getServiceRate());
}
return null;
}
@ -448,25 +437,56 @@ public class TransactionBillServiceImpl implements TransactionBillService {
* @param dto id
*/
@Override
public boolean passWithdraw(WithdrawApprovalDTO dto) {
public int passWithdraw(WithdrawApprovalDTO dto) {
ServiceUtil.assertion(dto.getBillId() == null, "提现申请ID不允许为空");
Long lockKey = dto.getBillId();
ServiceUtil.assertion(!redisLock.lock(RedisLockKey.APPROVAL_WITHDRAW, lockKey), "该提现申请正在审核,请刷新后重试");
try {
transactionTemplate.execute(status -> {
int updateCount = this.approvalWithdraw(dto, TransactionBillStatus.WITHDRAW_PASSED);
ServiceUtil.assertion(updateCount != 1, "提现审核失败,请刷新后重试");
return updateCount;
Integer result = transactionTemplate.execute(status -> {
int update = 0;
// 线下打款修改状态为已打款
if (WithdrawType.OFFLINE.getType().equals(dto.getWithdrawType())) {
update = this.approvalWithdraw(dto, TransactionBillStatus.WITHDRAW_SUCCESS);
}
// 线上打款修改状态为打款中
else if (WithdrawType.ONLINE.getType().equals(dto.getWithdrawType())) {
update = this.approvalWithdraw(dto, TransactionBillStatus.WITHDRAW_PAYING);
} else {
throw new ServiceException("不支持的提现打款方式");
}
ServiceUtil.assertion(update != 1, "提现审核失败,请刷新后重试");
// 线上打款发起打款
if (WithdrawType.ONLINE.getType().equals(dto.getWithdrawType())) {
TransactionBillVO withdraw = this.selectWithdrawById(dto.getBillId());
int pay = this.startPayOnline(withdraw);
ServiceUtil.assertion(pay != 1, "发起打款失败");
}
return update;
});
this.payWithdraw(dto.getBillId());
return true;
return result == null ? 0 : result;
} finally {
redisLock.unlock(RedisLockKey.APPROVAL_WITHDRAW, lockKey);
}
}
/**
* 提现线上打款
*/
private int startPayOnline(TransactionBillVO bill) {
throw new ServiceException("线上打款开发中");
// 微信
// if (TransactionBillPayType.WECHAT.getType().equals(bill.getChannelId())) {
// InitiateBatchTransferResponse res = wxPayService.payWithdraw(bill.getBillId());
// log.debug(String.valueOf(res));
// } else {
// throw new ServiceException("其他打款渠道正在开发中");
// }
}
/**
* 审核操作
*/
@ -509,88 +529,6 @@ public class TransactionBillServiceImpl implements TransactionBillService {
}
}
/**
* 提现打款
* @param billId 提现单id
*/
@Override
public boolean payWithdraw(Long billId) {
ServiceUtil.assertion(billId == null, "参数错误提现打款id不允许为空");
ServiceUtil.assertion(!redisLock.lock(RedisLockKey.PAY_WITHDRAW, billId), "该提现申请正在打款,请刷新后重试");
try {
TransactionBillVO bill = transactionBillMapper.selectSmTransactionBillByBillId(billId);
ServiceUtil.assertion(bill == null, "单据不存在");
transactionTemplate.execute(status -> {
// 更新为打款中
int updateCount = transactionBillMapper.doPayWithdraw(billId);
ServiceUtil.assertion(updateCount != 1, "单据状态发生变化,请刷新后重试");
// 发起打款线上
if (WithdrawType.ONLINE.getType().equals(bill.getWithdrawType())) {
// 微信
if (TransactionBillPayType.WECHAT.getType().equals(bill.getChannelId())) {
InitiateBatchTransferResponse res = wxPayService.payWithdraw(billId);
log.debug(String.valueOf(res));
} else {
throw new ServiceException("其他打款渠道正在开发中");
}
}
// 线下
else if(WithdrawType.OFFLINE.getType().equals(bill.getWithdrawType())) {
this.payWithdrawByOffline(bill);
} else {
throw new ServiceException("不支持的打款方式");
}
return updateCount;
});
return true;
} finally {
redisLock.unlock(RedisLockKey.PAY_WITHDRAW, billId);
}
}
/**
* 线下打款
*/
private void payWithdrawByOffline(TransactionBillVO bill) {
this.withdrawSuccess(bill.getBillId(), LocalDateTime.now());
}
@Override
public void withdrawSuccess(Long billId, LocalDateTime payTime) {
transactionTemplate.execute(status -> {
// 修改状态
int updateCount = transactionBillMapper.withdrawSuccess(billId, payTime);
ServiceUtil.assertion(updateCount != 1, "单据状态发生变化,请刷新后重试");
return updateCount;
});
}
@Override
@Transactional
public void withdrawFailed(Long billId) {
// 修改状态
int updateCount = transactionBillMapper.withdrawFailed(billId);
ServiceUtil.assertion(updateCount != 1, "单据状态发生变化,请刷新后重试");
}
/**
* 更新微信批次明细单号
* @param billId 提现单号
* @param transferIds 微信批次明细列表
*/
@Override
public boolean updateWxTransferDetailIds(Long billId, List<String> transferIds) {
ServiceUtil.assertion(billId == null || CollectionUtils.isEmpty(transferIds), "参数错误:提现单号或微信批次明细列表为空");
TransactionBill bill = new TransactionBill();
bill.setBillId(billId);
bill.setTransferIds(transferIds);
return transactionBillMapper.updateSmTransactionBill(bill) == 1;
}
@Override
public List<BillCountVo> selectLandlordCount(TransactionBillQuery dto) {
List<BillCountVo> list = this.selectCount(dto);
@ -1115,7 +1053,7 @@ public class TransactionBillServiceImpl implements TransactionBillService {
@Override
public UserWithdrawServiceVO getUserWithdrawService(Long userId, Long channelId) {
SmUserVo user = userService.selectSmUserByUserId(userId);
ChannelVO channel = channelService.selectSmChannelByChannelId(channelId);
ChannelWithdrawVO channel = channelWithdrawService.selectChannelWithdrawByChannelId(channelId);
return this.getUserWithdrawService(user, channel);
}
@ -1151,4 +1089,15 @@ public class TransactionBillServiceImpl implements TransactionBillService {
redisLock.unlock(RedisLockKey.PREPAY, lockKey);
}
}
@Override
public List<TransactionBillVO> selectWithdrawList(TransactionBillQuery query) {
query.setType(TransactionBillType.WITHDRAW.getType());
return transactionBillMapper.selectWithdrawList(query);
}
@Override
public TransactionBillVO selectWithdrawById(Long billId) {
return transactionBillMapper.selectWithdrawById(billId);
}
}

View File

@ -17,27 +17,24 @@ import org.springframework.web.bind.annotation.RestController;
* 2024/4/15
*/
@RestController
@RequestMapping("/app/channel")
@RequestMapping("/app/channel/recharge")
public class AppChannelController extends BaseController {
@Autowired
private ChannelService channelService;
@Autowired
private TransactionBillService transactionBillService;
@ApiOperation("获取充值渠道列表")
@JsonView(JsonViewProfile.App.class)
@GetMapping("/recharge/enabledList")
@GetMapping("/enabledList")
public AjaxResult getRechargeEnabledList() {
return success(channelService.selectEnabledRechargeList());
}
@ApiOperation("获取提现渠道列表")
@JsonView(JsonViewProfile.App.class)
@GetMapping("/recharge/enabledWithdrawList")
@GetMapping("/enabledWithdrawList")
public AjaxResult getWithdrawEnabledList() {
return success(channelService.selectEnabledWithdrawList(getUserId()));
return error("本接口即将弃用,请使用/app/channel/withdraw/enabledList");
}
}

View File

@ -0,0 +1,32 @@
package com.ruoyi.web.controller.app;
import com.fasterxml.jackson.annotation.JsonView;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.JsonViewProfile;
import com.ruoyi.ss.channelWithdraw.service.ChannelWithdrawService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author wjh
* 2024/8/2
*/
@RestController
@RequestMapping("/app/channel/withdraw")
public class AppChannelWithdrawController extends BaseController {
@Autowired
private ChannelWithdrawService channelWithdrawService;
@ApiOperation("获取提现渠道列表")
@GetMapping("/enabledList")
@JsonView(JsonViewProfile.App.class)
public AjaxResult getWithdrawEnabledList() {
return success(channelWithdrawService.selectEnabledList(getUserId()));
}
}

View File

@ -31,18 +31,14 @@ public class MchWithdrawController extends BaseController {
@Autowired
private TransactionBillValidator transactionBillValidator;
@Autowired
private TransactionAssembler transactionAssembler;
@ApiOperation("查询本人提现详情")
@GetMapping("/{billId}")
@JsonView(JsonViewProfile.AppMch.class)
public AjaxResult getWithdrawInfo(@PathVariable Long billId) {
TransactionBillVO bill = transactionBillService.selectSmTransactionBillByBillId(billId);
TransactionBillVO bill = transactionBillService.selectWithdrawById(billId);
if (bill == null || !transactionBillValidator.isUser(bill, getUserId())) {
return success();
}
transactionAssembler.assembleChannelName(Collections.singletonList(bill));
return AjaxResult.success(bill);
}

View File

@ -87,10 +87,6 @@ public class SmChannelController extends BaseController
channel.setServiceRate(form.getServiceRate());
channel.setCostRate(form.getCostRate());
channel.setServiceType(form.getServiceType());
channel.setWithdrawEnabled(form.getWithdrawEnabled());
channel.setWithdrawServiceType(form.getWithdrawServiceType());
channel.setWithdrawServiceRate(form.getWithdrawServiceRate());
channel.setWithdrawCostRate(form.getWithdrawCostRate());
channel.setPicture(form.getPicture());
return toAjax(smChannelService.updateSmChannel(channel));
}

View File

@ -136,14 +136,14 @@ public class SmTransactionBillController extends BaseController
return success(smTransactionBillService.rejectWithdraw(dto));
}
@ApiOperation("提现打款")
@PreAuthorize("@ss.hasPermi('system:bill:pay')")
@PutMapping("/withdraw/pay/{billId}")
@Log(title = "提现打款", businessType = BusinessType.UPDATE)
public AjaxResult payWithdraw(@PathVariable Long billId)
{
return success(smTransactionBillService.payWithdraw(billId));
}
// @ApiOperation("提现打款")
// @PreAuthorize("@ss.hasPermi('system:bill:pay')")
// @PutMapping("/withdraw/pay/{billId}")
// @Log(title = "提现打款", businessType = BusinessType.UPDATE)
// public AjaxResult payWithdraw(@PathVariable Long billId)
// {
// return success(smTransactionBillService.payWithdraw(billId));
// }
@ApiModelProperty("刷新支付结果")
@PreAuthorize("@ss.hasPermi('system:bill:edit')")

View File

@ -0,0 +1,42 @@
package com.ruoyi.web.controller.ss;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.ss.transactionBill.domain.TransactionBillQuery;
import com.ruoyi.ss.transactionBill.service.TransactionBillService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author wjh
* 2024/8/2
*/
@RestController
@RequestMapping("/ss/withdraw")
public class WithdrawController extends BaseController {
@Autowired
private TransactionBillService transactionBillService;
/**
* 查询提现列表
*/
@GetMapping("/list")
public TableDataInfo list(TransactionBillQuery query) {
startPage();
return getDataTable(transactionBillService.selectWithdrawList(query));
}
/**
* 查询提现详情
*/
@GetMapping("/{billId}")
public AjaxResult getInfo(@PathVariable("billId") Long billId) {
return success(transactionBillService.selectWithdrawById(billId));
}
}