package com.yeshi.makemoney.app.service.impl.money;
|
|
import com.alipay.api.AlipayApiException;
|
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
|
import com.google.gson.Gson;
|
import com.ks.lib.common.exception.ParamsException;
|
import com.yeshi.makemoney.app.dao.money.ExtractMapper;
|
import com.yeshi.makemoney.app.dao.money.ExtractMapper.DaoQuery;
|
import com.yeshi.makemoney.app.dto.money.ExtractConfig;
|
import com.yeshi.makemoney.app.dto.mq.ExtractTransferResultMQMsg;
|
import com.yeshi.makemoney.app.entity.SystemEnum;
|
import com.yeshi.makemoney.app.entity.config.SystemConfigKey;
|
import com.yeshi.makemoney.app.entity.money.Extract;
|
import com.yeshi.makemoney.app.entity.money.ExtractPayType;
|
import com.yeshi.makemoney.app.entity.money.UserMoneyRecord;
|
import com.yeshi.makemoney.app.entity.user.UserInfo;
|
import com.yeshi.makemoney.app.exception.money.ExtractException;
|
import com.yeshi.makemoney.app.exception.money.UserMoneyBalanceException;
|
import com.yeshi.makemoney.app.service.inter.config.SystemConfigService;
|
import com.yeshi.makemoney.app.service.inter.money.ExtractService;
|
import com.yeshi.makemoney.app.service.inter.money.UserExtractMoneyLimitService;
|
import com.yeshi.makemoney.app.service.inter.money.UserMoneyRecordService;
|
import com.yeshi.makemoney.app.service.inter.money.UserMoneyService;
|
import com.yeshi.makemoney.app.service.inter.user.UserInfoService;
|
import com.yeshi.makemoney.app.service.query.money.ExtractQuery;
|
import com.yeshi.makemoney.app.utils.Constant;
|
import com.yeshi.makemoney.app.utils.factory.UserMoneyRecordFactory;
|
import com.yeshi.makemoney.app.utils.mq.CMQManager;
|
import com.yeshi.makemoney.app.utils.pay.AlipayUtil;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.yeshi.utils.GsonUtil;
|
import org.yeshi.utils.StringUtil;
|
import org.yeshi.utils.TimeUtil;
|
import org.yeshi.utils.bean.BeanUtil;
|
import org.yeshi.utils.wx.WXPayUtil;
|
import org.yeshi.utils.wx.WXUtil;
|
|
import javax.annotation.Resource;
|
import java.math.BigDecimal;
|
import java.util.Arrays;
|
import java.util.Date;
|
import java.util.List;
|
import java.util.Map;
|
|
@Service
|
public class ExtractServiceImpl implements ExtractService {
|
|
private Logger logger = LoggerFactory.getLogger(ExtractService.class);
|
|
@Resource
|
private ExtractMapper extractMapper;
|
|
@Resource
|
private UserMoneyService userMoneyService;
|
|
@Resource
|
private UserInfoService userInfoService;
|
|
@Resource
|
private SystemConfigService systemConfigService;
|
|
@Resource
|
private UserMoneyRecordService userMoneyRecordService;
|
|
@Resource
|
private UserExtractMoneyLimitService userExtractMoneyLimitService;
|
|
@Override
|
public List<Extract> list(ExtractQuery extractQuery, int page, int pageSize) {
|
DaoQuery daoQuery = new DaoQuery();
|
daoQuery.uid = extractQuery.getUid();
|
daoQuery.minCreateTime = extractQuery.toStartTime();
|
daoQuery.maxCreateTime = extractQuery.toEndTime();
|
daoQuery.sortList = Arrays.asList(new String[]{"create_time desc"});
|
daoQuery.start = (page - 1) * pageSize;
|
daoQuery.count = pageSize;
|
return extractMapper.list(daoQuery);
|
}
|
|
@Override
|
public long count(ExtractQuery extractQuery) {
|
DaoQuery daoQuery = new DaoQuery();
|
daoQuery.uid = extractQuery.getUid();
|
daoQuery.minCreateTime = extractQuery.toStartTime();
|
daoQuery.maxCreateTime = extractQuery.toEndTime();
|
return extractMapper.count(daoQuery);
|
}
|
|
@Override
|
public Extract get(Long id) {
|
return extractMapper.selectByPrimaryKey(id);
|
}
|
|
@Override
|
public boolean isFirst(Long uid) {
|
DaoQuery daoQuery = new DaoQuery();
|
daoQuery.uid = uid;
|
return extractMapper.count(daoQuery) < 1L;
|
}
|
|
private ExtractConfig getExtractConfig(SystemEnum system) {
|
String value = systemConfigService.getValueCache(system, SystemConfigKey.extractConfig);
|
if (StringUtil.isNullOrEmpty(value)) {
|
return null;
|
}
|
return new Gson().fromJson(value, ExtractConfig.class);
|
}
|
|
private void validateExtract(BigDecimal money, UserInfo user) throws ExtractException {
|
ExtractConfig config = getExtractConfig(user.getSystem());
|
if (config == null) {
|
throw new ExtractException(ExtractException.CODE_EXTRACT_CONFIG_ERROR, "提现配置错误");
|
}
|
|
|
if (money.compareTo(config.getMinMoney()) < 0) {
|
throw new ExtractException(ExtractException.CODE_MONEY_LIMIT, String.format("最低提现金额为%s元", config.getMinMoney().toString()));
|
}
|
|
|
if (money.compareTo(config.getMaxMoney()) > 0) {
|
throw new ExtractException(ExtractException.CODE_MONEY_LIMIT, String.format("最高提现金额为%s元", config.getMaxMoney().toString()));
|
}
|
|
//单日累计提现金额
|
DaoQuery daoQuery = new DaoQuery();
|
daoQuery.uid = user.getId();
|
long currentTime = System.currentTimeMillis();
|
daoQuery.minCreateTime = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(currentTime, "yyyyMMdd"), "yyyyMMdd"));
|
daoQuery.maxCreateTime = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(currentTime + 1000 * 60 * 60 * 1000L, "yyyyMMdd"), "yyyyMMdd"));
|
BigDecimal todayMoney = extractMapper.sumMoney(daoQuery);
|
if (todayMoney == null) {
|
todayMoney = new BigDecimal(0);
|
}
|
if (todayMoney.add(money).compareTo(config.getMaxMoneyPerDay()) > 0) {
|
throw new ExtractException(ExtractException.CODE_MONEY_LIMIT, String.format("单日累计最高提现金额为%s元", config.getMaxMoneyPerDay().toString()));
|
}
|
|
//最高提现次数限制
|
long count = extractMapper.count(daoQuery);
|
if (count >= config.getMaxNumPerDay()) {
|
throw new ExtractException(ExtractException.CODE_MONEY_LIMIT, String.format("单日累计最高提现次数为%s次", config.getMaxNumPerDay().toString()));
|
}
|
|
//小金额提现限制
|
if (money.compareTo(new BigDecimal(1)) < 0) {
|
//是否已经用完新用户额度
|
if (!canExtractLittleMoney(user.getId(), config.getNewerLittleMoneyNum(), new Date(currentTime))) {
|
throw new ExtractException(ExtractException.CODE_LITTLE_MONEY_LIMIT, "今日小于1元提现次数已用尽");
|
}
|
}
|
|
}
|
|
@Override
|
public boolean canExtractLittleMoney(Long uid, int maxNewerCount, Date date) {
|
//判断新人
|
long count = countByMaxMoney(uid, new BigDecimal(1), Arrays.asList(new Integer[]{Extract.STATE_NOT_PROCESS, Extract.STATE_PROCESSING, Extract.STATE_PASS}), null);
|
if (maxNewerCount > count) {
|
return true;
|
}
|
|
//判断激励分配
|
int limit = userExtractMoneyLimitService.getLittleMoneyLimit(uid, date);
|
if (limit <= 0) {
|
return false;
|
}
|
count = countByMaxMoney(uid, new BigDecimal(1), Arrays.asList(new Integer[]{Extract.STATE_NOT_PROCESS, Extract.STATE_PROCESSING, Extract.STATE_PASS}), new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(date.getTime(), "yyyyMMdd"), "yyyyMMdd")));
|
if (count < limit) {
|
return true;
|
}
|
return false;
|
}
|
|
|
@Transactional(rollbackFor = Exception.class)
|
@Override
|
public void addExtract(Extract extract) throws ParamsException, ExtractException, UserMoneyBalanceException {
|
if (extract == null || extract.getUser() == null || extract.getUser().getId() == null || extract.getMoney() == null || extract.getType() == null) {
|
throw new ParamsException(ParamsException.CODE_PARAMS_NOT_ENOUGH, "参数不完整");
|
}
|
|
if (extract.getType() == ExtractPayType.alipay) {
|
if (StringUtil.isNullOrEmpty(extract.getAccount()) || StringUtil.isNullOrEmpty(extract.getName())) {
|
throw new ParamsException(ParamsException.CODE_PARAMS_NOT_ENOUGH, "支付宝名称与账号不能为空");
|
}
|
} else {
|
if (StringUtil.isNullOrEmpty(extract.getAccount())) {
|
throw new ParamsException(ParamsException.CODE_PARAMS_NOT_ENOUGH, "账号不能为空");
|
}
|
}
|
|
if (extract.getState() == null) {
|
extract.setState(Extract.STATE_NOT_PROCESS);
|
}
|
if (extract.getCreateTime() == null) {
|
extract.setCreateTime(new Date());
|
}
|
|
UserInfo user = userInfoService.get(extract.getUser().getId());
|
if (user == null) {
|
throw new ExtractException(ExtractException.CODE_USER_ERROR, "用户不存在");
|
}
|
|
//验证是否可提交提现
|
validateExtract(extract.getMoney(), user);
|
|
extractMapper.insertSelective(extract);
|
UserMoneyRecord record = UserMoneyRecordFactory.createExtract(extract);
|
try {
|
userMoneyService.subUserMoney(record);
|
} catch (ParamsException e) {
|
throw new ParamsException(ParamsException.CODE_PARAMS_NOT_ENOUGH, "资金记录参数错误:" + e.getCode());
|
}
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
@Override
|
public void passExtract(Long id, Long adminId) throws ExtractException {
|
Extract extract = extractMapper.selectByPrimaryKeyForUpdate(id);
|
if (extract == null) {
|
throw new ExtractException(ExtractException.CODE_NOT_EXIST, "提现记录不存在");
|
}
|
|
if (extract.getState() != Extract.STATE_NOT_PROCESS) {
|
throw new ExtractException(ExtractException.CODE_ALREADY_DONE, "提现已经处理");
|
}
|
|
UserInfo user = userInfoService.get(extract.getUser().getId());
|
if (user == null) {
|
throw new ExtractException(ExtractException.CODE_USER_ERROR, "用户不存在");
|
}
|
|
//转账
|
Extract updateExtract = new Extract();
|
updateExtract.setId(id);
|
updateExtract.setState(Extract.STATE_PROCESSING);
|
extractMapper.updateByPrimaryKeySelective(updateExtract);
|
|
if (extract.getType() == ExtractPayType.alipay) {
|
transferByAlipay(extract, adminId);
|
} else {
|
transferByWX(extract, adminId, systemConfigService.getValueCache(user.getSystem(), SystemConfigKey.wxAppId));
|
}
|
|
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
@Override
|
public void rejectExtract(Long id, Long adminId, String reason) throws ExtractException, UserMoneyBalanceException, ParamsException {
|
Extract extract = extractMapper.selectByPrimaryKeyForUpdate(id);
|
if (extract == null) {
|
throw new ExtractException(ExtractException.CODE_NOT_EXIST, "提现记录不存在");
|
}
|
if (extract.getState() != Extract.STATE_NOT_PROCESS) {
|
throw new ExtractException(ExtractException.CODE_ALREADY_DONE, "提现已经处理");
|
}
|
|
UserMoneyRecord userMoneyRecord = UserMoneyRecordFactory.createExtractReject(extract);
|
|
// 增加资金
|
userMoneyService.addUserMoney(userMoneyRecord);
|
// 更新原来的状态
|
Extract updateExtract = new Extract();
|
updateExtract.setId(id);
|
updateExtract.setState(Extract.STATE_REJECT);
|
updateExtract.setReason(reason);
|
extractMapper.updateByPrimaryKeySelective(updateExtract);
|
//TODO 消息
|
}
|
|
@Override
|
public void processExtractResult(ExtractTransferResultMQMsg msg) throws ParamsException {
|
if (msg == null) {
|
return;
|
}
|
|
Extract extract = extractMapper.selectByPrimaryKey(msg.getExtractId());
|
if (msg.getAlipayResult() != null) {
|
//支付宝转账
|
AlipayFundTransUniTransferResponse response = msg.getAlipayResult();
|
boolean noMoney = "PAYER_BALANCE_NOT_ENOUGH".equals(response.getSubCode()) || "BALANCE_IS_NOT_ENOUGH".equals(response.getSubCode());
|
if (response.isSuccess()) {
|
String code = response.getCode();
|
if ("10000".equals(code)) {
|
extractSuccess(extract, response.getOrderId());
|
} else {
|
extractFail(extract, noMoney, response.getSubMsg());
|
}
|
} else {
|
extractFail(extract, noMoney, response.getSubMsg());
|
}
|
} else {
|
//微信转账
|
Map<String, String> resultMap = WXUtil.parseXML(msg.getWxResult());
|
if ("SUCCESS".equalsIgnoreCase(resultMap.get("return_code")) && "SUCCESS".equalsIgnoreCase(resultMap.get("result_code"))) {
|
extractSuccess(extract, resultMap.get("payment_no"));
|
} else {
|
logger.error("微信转账结果处理,转账未成功:{}", msg.getWxResult());
|
String errCode = resultMap.get("err_code");
|
String errMsg = resultMap.get("err_code_des");
|
boolean noMoney = "NOTENOUGH".equalsIgnoreCase(errCode);
|
extractFail(extract, noMoney, errMsg);
|
}
|
}
|
}
|
|
@Override
|
public long countByMaxMoney(Long uid, BigDecimal money, List<Integer> stateList, Date minCreateTime) {
|
DaoQuery daoQuery = new DaoQuery();
|
daoQuery.uid = uid;
|
daoQuery.maxMoney = money;
|
daoQuery.stateList = stateList;
|
daoQuery.minCreateTime = minCreateTime;
|
return extractMapper.count(daoQuery);
|
}
|
|
/**
|
* 提现到支付宝
|
*
|
* @param extract
|
* @param adminId
|
*/
|
private void transferByAlipay(Extract extract, Long adminId) {
|
//获取用户的系统
|
UserInfo user = userInfoService.get(extract.getUser().getId());
|
String appName = user.getSystem().getName();
|
//备注
|
String remark = appName + "APP渠道提现";
|
//理由
|
String reason = String.format("用户ID【%s】发起的提现", user.getSystem().name() + user.getId());
|
|
AlipayFundTransUniTransferResponse response = null;
|
try {
|
response = AlipayUtil.transferNoThrowException(String.format("e_%s_%s", user.getSystem().name(), extract.getId()), extract.getAccount(), extract.getName(), extract.getMoney(), remark, reason);
|
} catch (AlipayApiException e) {
|
logger.error("支付宝转账异常:转账ID:{},异常内容:{} ", extract.getId(), e);
|
}
|
|
try {
|
CMQManager.getInstance().addExtractResultMsg(new ExtractTransferResultMQMsg(extract.getId(), response, adminId));
|
logger.info("提现:添加处理队列成功-" + extract.getId());
|
} catch (Exception e) {
|
logger.error("提现:支付宝提现CMQ异常:{}", new Gson().toJson(response) + ",提现信息" + GsonUtil.toJson(extract));
|
}
|
}
|
|
private void transferByWX(Extract extract, Long adminId, String wxAPPId) {
|
//获取用户的系统
|
UserInfo user = userInfoService.get(extract.getUser().getId());
|
String appName = user.getSystem().getName();
|
//理由
|
String result = WXPayUtil.payToOpenId(wxAPPId, extract.getAccount(), Constant.wxTransferConfig.getMchId(), Constant.wxTransferConfig.getKey(), Constant.wxTransferConfig.getCertPwd(), this.getClass().getClassLoader().getResourceAsStream(Constant.wxTransferConfig.getCertPath()), "makemoney" + extract.getId(), extract.getMoney(), "提现", extract.getIp());
|
try {
|
CMQManager.getInstance().addExtractResultMsg(new ExtractTransferResultMQMsg(extract.getId(), result, adminId));
|
logger.info("提现:添加处理队列成功-" + extract.getId());
|
} catch (Exception e) {
|
logger.error("提现:微信提现CMQ异常:{}", result + ",提现信息" + GsonUtil.toJson(extract));
|
}
|
}
|
|
|
private void extractSuccess(Extract extract, String thirdNo) {
|
Extract updateExtract = new Extract();
|
updateExtract.setId(extract.getId());
|
updateExtract.setState(Extract.STATE_PASS);
|
updateExtract.setSuccessTime(new Date());
|
updateExtract.setReason("提现成功");
|
extractMapper.updateByPrimaryKeySelective(updateExtract);
|
|
try {
|
logger.info("转账成功:[提现IP:" + extract.getIp() + ",所转账号:" + extract.getAccount() + ",真实姓名:"
|
+ extract.getName() + ",所转金额:" + extract.getMoney() + "]");
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
|
UserMoneyRecord record = null;
|
try {
|
record = UserMoneyRecordFactory.createExtract(extract);
|
} catch (ParamsException e) {
|
e.printStackTrace();
|
}
|
|
if (record != null) {
|
// 改变资金记录状态
|
UserMoneyRecord detail = userMoneyRecordService.selectBySerialNo(record.getSerialNo());
|
if (detail != null) {
|
UserMoneyRecord update = new UserMoneyRecord(detail.getId());
|
update.setShow(true);
|
update.setUpdateTime(new Date());
|
userMoneyRecordService.update(update);
|
}
|
}
|
// TODO 通知转账成功
|
}
|
|
|
private void extractFail(Extract extract, boolean noMoney, String msg) throws ParamsException {
|
UserInfo user = extract.getUser();
|
//余额不足
|
if (noMoney) {
|
Extract updateExtract = new Extract();
|
updateExtract.setId(extract.getId());
|
updateExtract.setState(Extract.STATE_PROCESSING);
|
updateExtract.setReason(msg);
|
extractMapper.updateByPrimaryKeySelective(updateExtract);
|
} else {
|
Extract updateExtract = new Extract();
|
updateExtract.setId(extract.getId());
|
updateExtract.setState(Extract.STATE_REJECT);
|
updateExtract.setReason(msg);
|
extractMapper.updateByPrimaryKeySelective(updateExtract);
|
UserMoneyRecord userMoneyDetail = UserMoneyRecordFactory.createExtractReject(extract);
|
// 增加资金
|
userMoneyService.addUserMoney(userMoneyDetail);
|
try {
|
logger.info("转账失败:[提现IP:" + extract.getIp() + ",所转账号:" + extract.getAccount() + ",真实姓名:"
|
+ extract.getName() + ",所转金额:" + extract.getMoney() + ",失败原因" + extract.getReason() + "]");
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
// 新版提现
|
//TODO 通知转账被拒绝
|
}
|
}
|
|
|
}
|