| | |
| | | import com.doumee.core.model.PageWrap; |
| | | import com.doumee.core.utils.Utils; |
| | | import com.doumee.dao.business.DriverInfoMapper; |
| | | import com.doumee.dao.business.RevenueMapper; |
| | | import com.doumee.dao.business.ShopInfoMapper; |
| | | import com.doumee.dao.business.WithdrawalOrdersMapper; |
| | | import com.doumee.dao.business.model.DriverInfo; |
| | | import com.doumee.dao.business.model.Revenue; |
| | | import com.doumee.dao.business.model.ShopInfo; |
| | | import com.doumee.dao.business.model.WithdrawalOrders; |
| | | import com.doumee.dao.dto.WithdrawalApproveDTO; |
| | | import com.doumee.config.alipay.AlipayFundTransUniTransfer; |
| | | import com.doumee.dao.dto.AlipayTransferDTO; |
| | | import com.doumee.dao.dto.WithdrawalDTO; |
| | | import com.doumee.dao.system.SystemUserMapper; |
| | | import com.doumee.dao.system.model.SystemUser; |
| | | import com.doumee.service.business.WithdrawalOrdersService; |
| | |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Arrays; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | | import java.util.concurrent.ThreadLocalRandom; |
| | | |
| | | /** |
| | | * 提现申请记录Service实现 |
| | |
| | | |
| | | @Autowired |
| | | private DriverInfoMapper driverInfoMapper; |
| | | |
| | | @Autowired |
| | | private RevenueMapper revenueMapper; |
| | | |
| | | @Override |
| | | public Integer create(WithdrawalOrders withdrawalOrders) { |
| | |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void approve(WithdrawalApproveDTO dto) { |
| | | if (dto == null || dto.getId() == null || dto.getStatus() == null) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "审批参数不完整"); |
| | |
| | | |
| | | // 获取当前登录用户 |
| | | Integer currentUserId = getCurrentUserId(); |
| | | Date now = new Date(); |
| | | |
| | | // 审批通过时,调用支付宝打款 |
| | | Integer finalStatus = dto.getStatus(); |
| | | String doneInfo = null; |
| | | if (Constants.ONE.equals(dto.getStatus())) { |
| | | String aliAccount = order.getAliAccount(); |
| | | String aliName = null; |
| | | |
| | | // 从司机或门店获取支付宝账户和实名姓名 |
| | | if (StringUtils.isBlank(aliAccount)) { |
| | | if (Constants.equalsInteger(order.getMemberType(), Constants.ONE)) { |
| | | DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda() |
| | | .eq(DriverInfo::getMemberId, order.getMemberId()) |
| | | .eq(DriverInfo::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (driver != null) { |
| | | aliAccount = driver.getAliAccount(); |
| | | aliName = driver.getAliName(); |
| | | } |
| | | } else if (Constants.equalsInteger(order.getMemberType(), Constants.TWO)) { |
| | | ShopInfo shop = shopInfoMapper.selectOne(new QueryWrapper<ShopInfo>().lambda() |
| | | .eq(ShopInfo::getRegionMemberId, order.getMemberId()) |
| | | .eq(ShopInfo::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (shop != null) { |
| | | aliAccount = shop.getAliAccount(); |
| | | aliName = shop.getAliName(); |
| | | } |
| | | } |
| | | } else { |
| | | // 从 WithdrawalOrders 的 aliAccount 查对应姓名 |
| | | if (Constants.equalsInteger(order.getMemberType(), Constants.ONE)) { |
| | | DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda() |
| | | .eq(DriverInfo::getMemberId, order.getMemberId()) |
| | | .eq(DriverInfo::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (driver != null) { |
| | | aliName = driver.getAliName(); |
| | | } |
| | | } else if (Constants.equalsInteger(order.getMemberType(), Constants.TWO)) { |
| | | ShopInfo shop = shopInfoMapper.selectOne(new QueryWrapper<ShopInfo>().lambda() |
| | | .eq(ShopInfo::getRegionMemberId, order.getMemberId()) |
| | | .eq(ShopInfo::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (shop != null) { |
| | | aliName = shop.getAliName(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (StringUtils.isBlank(aliAccount)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "支付宝提现账户未配置,无法打款"); |
| | | } |
| | | |
| | | // 金额转换:分 → 元 |
| | | Long amountFen = order.getAmount() != null ? order.getAmount() : 0L; |
| | | BigDecimal transAmount = new BigDecimal(amountFen).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP); |
| | | |
| | | AlipayTransferDTO transferDTO = new AlipayTransferDTO(); |
| | | transferDTO.setOutBizNo(order.getOutBillNo()); |
| | | transferDTO.setTransAmount(transAmount); |
| | | transferDTO.setPayeeAccount(aliAccount); |
| | | transferDTO.setPayeeName(aliName); |
| | | transferDTO.setRemark("提现打款"); |
| | | |
| | | String alipayOrderId; |
| | | try { |
| | | alipayOrderId = AlipayFundTransUniTransfer.transfer(transferDTO); |
| | | } catch (BusinessException e) { |
| | | throw e; |
| | | } catch (Exception e) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "支付宝打款失败:" + e.getMessage()); |
| | | } |
| | | doneInfo = "支付宝转账单号:" + alipayOrderId; |
| | | } |
| | | |
| | | WithdrawalOrders update = new WithdrawalOrders(); |
| | | update.setId(dto.getId()); |
| | | update.setStatus(dto.getStatus()); |
| | | update.setStatus(finalStatus); |
| | | update.setUserId(currentUserId); |
| | | update.setApproveTime(new Date()); |
| | | update.setApproveTime(now); |
| | | update.setApproveRemark(dto.getApproveRemark()); |
| | | update.setUpdateTime(new Date()); |
| | | update.setUpdateTime(now); |
| | | if (Constants.ONE.equals(finalStatus)) { |
| | | update.setDoneTime(now); |
| | | update.setDoneInfo(doneInfo); |
| | | } else if (doneInfo != null) { |
| | | update.setDoneTime(now); |
| | | update.setDoneInfo(doneInfo); |
| | | } |
| | | withdrawalOrdersMapper.updateById(update); |
| | | |
| | | // 更新关联的提现 Revenue 记录状态 |
| | | // 通过 objId + objType=1(提现业务) + type=1(提现支出) 找到原始提现支出记录 |
| | | Revenue withdrawalRevenue = revenueMapper.selectOne(new QueryWrapper<Revenue>().lambda() |
| | | .eq(Revenue::getObjId, order.getId()) |
| | | .eq(Revenue::getObjType, Constants.ONE) |
| | | .eq(Revenue::getType, Constants.ONE) |
| | | .eq(Revenue::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (withdrawalRevenue != null) { |
| | | Integer revenueStatus = Constants.ONE.equals(finalStatus) ? Constants.ZERO : Constants.ONE; // 通过=0成功, 驳回=1失败 |
| | | revenueMapper.update(new UpdateWrapper<Revenue>().lambda() |
| | | .set(Revenue::getStatus, revenueStatus) |
| | | .set(Revenue::getUpdateTime, now) |
| | | .eq(Revenue::getId, withdrawalRevenue.getId())); |
| | | } |
| | | |
| | | // 驳回或打款失败时退回余额 |
| | | if (Constants.TWO.equals(finalStatus)) { |
| | | Long amountFen = order.getAmount() != null ? order.getAmount() : 0L; |
| | | if (amountFen > 0 && order.getMemberId() != null) { |
| | | if (Constants.equalsInteger(order.getMemberType(), Constants.ONE)) { |
| | | // 司机:通过 memberId 查 DriverInfo,退回 balance |
| | | DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda() |
| | | .eq(DriverInfo::getMemberId, order.getMemberId()) |
| | | .eq(DriverInfo::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (driver != null) { |
| | | driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda() |
| | | .setSql(" BALANCE = IFNULL(BALANCE, 0) + " + amountFen) |
| | | .eq(DriverInfo::getId, driver.getId())); |
| | | } |
| | | } else if (Constants.equalsInteger(order.getMemberType(), Constants.TWO)) { |
| | | // 门店:通过 memberId 查 ShopInfo,退回 balance |
| | | ShopInfo shop = shopInfoMapper.selectOne(new QueryWrapper<ShopInfo>().lambda() |
| | | .eq(ShopInfo::getRegionMemberId, order.getMemberId()) |
| | | .eq(ShopInfo::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (shop != null) { |
| | | shopInfoMapper.update(new UpdateWrapper<ShopInfo>().lambda() |
| | | .setSql(" BALANCE = IFNULL(BALANCE, 0) + " + amountFen) |
| | | .eq(ShopInfo::getId, shop.getId())); |
| | | } |
| | | } |
| | | // 创建退回 Revenue 记录 |
| | | Revenue revenue = new Revenue(); |
| | | revenue.setMemberId(order.getMemberId()); |
| | | revenue.setMemberType(order.getMemberType()); |
| | | revenue.setType(Constants.TWO); // 2=提现退回 |
| | | revenue.setOptType(Constants.ONE); // 1=收入 |
| | | revenue.setAmount(amountFen); |
| | | revenue.setVaildStatus(Constants.ONE); // 已入账 |
| | | revenue.setObjId(order.getId()); |
| | | revenue.setObjType(Constants.ONE); // 1=提现业务 |
| | | revenue.setOrderNo(order.getOutBillNo()); |
| | | revenue.setStatus(Constants.ZERO); // 0=成功 |
| | | revenue.setDeleted(Constants.ZERO); |
| | | revenue.setCreateTime(now); |
| | | revenueMapper.insert(revenue); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private Integer getCurrentUserId() { |
| | |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void applyDriverWithdrawal(WithdrawalDTO dto, Integer memberId) { |
| | | DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda() |
| | | .eq(DriverInfo::getMemberId, memberId) |
| | | .eq(DriverInfo::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (driver == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "司机信息不存在"); |
| | | } |
| | | long amountFen = dto.getAmount().multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue(); |
| | | long balance = driver.getBalance() != null ? driver.getBalance() : 0L; |
| | | if (amountFen <= 0) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "提现金额必须大于0"); |
| | | } |
| | | if (amountFen > balance) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "提现金额不能超过可用余额"); |
| | | } |
| | | String billNo = generateBillNo(); |
| | | Date now = new Date(); |
| | | // 扣减司机余额 |
| | | driverInfoMapper.update(new UpdateWrapper<DriverInfo>().lambda() |
| | | .setSql(" BALANCE = IFNULL(BALANCE, 0) - " + amountFen) |
| | | .eq(DriverInfo::getId, driver.getId())); |
| | | // 创建提现记录 |
| | | WithdrawalOrders order = new WithdrawalOrders(); |
| | | order.setMemberId(memberId); |
| | | order.setMemberType(Constants.ONE); |
| | | order.setAmount(amountFen); |
| | | order.setStatus(Constants.ZERO); |
| | | order.setType(Constants.ZERO); |
| | | order.setOutBillNo(billNo); |
| | | order.setAliAccount(dto.getAliAccount()); |
| | | order.setDeleted(Constants.ZERO); |
| | | order.setCreateTime(now); |
| | | order.setUpdateTime(now); |
| | | order.setCreateUser(memberId); |
| | | withdrawalOrdersMapper.insert(order); |
| | | // 创建支出 Revenue 记录 |
| | | Revenue revenue = new Revenue(); |
| | | revenue.setMemberId(memberId); |
| | | revenue.setMemberType(Constants.ONE); |
| | | revenue.setType(Constants.ONE); |
| | | revenue.setOptType(-Constants.ONE); |
| | | revenue.setAmount(amountFen); |
| | | revenue.setVaildStatus(Constants.ONE); |
| | | revenue.setObjId(order.getId()); |
| | | revenue.setObjType(Constants.ONE); |
| | | revenue.setOrderNo(billNo); |
| | | revenue.setStatus(Constants.TWO); // 2=处理中 |
| | | revenue.setDeleted(Constants.ZERO); |
| | | revenue.setCreateTime(now); |
| | | revenueMapper.insert(revenue); |
| | | } |
| | | |
| | | @Override |
| | | public void applyShopWithdrawal(WithdrawalDTO dto, Integer shopId) { |
| | | ShopInfo shop = shopInfoMapper.selectById(shopId); |
| | | if (shop == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | long amountFen = dto.getAmount().multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue(); |
| | | long balance = shop.getBalance() != null ? shop.getBalance() : 0L; |
| | | if (amountFen <= 0) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "提现金额必须大于0"); |
| | | } |
| | | if (amountFen > balance) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "提现金额不能超过可用余额"); |
| | | } |
| | | String billNo = generateBillNo(); |
| | | Date now = new Date(); |
| | | // 扣减门店余额 |
| | | shopInfoMapper.update(new UpdateWrapper<ShopInfo>().lambda() |
| | | .setSql(" BALANCE = IFNULL(BALANCE, 0) - " + amountFen) |
| | | .eq(ShopInfo::getId, shopId)); |
| | | // 创建提现记录 |
| | | WithdrawalOrders order = new WithdrawalOrders(); |
| | | order.setMemberId(shop.getRegionMemberId()); |
| | | order.setMemberType(Constants.TWO); |
| | | order.setAmount(amountFen); |
| | | order.setStatus(Constants.ZERO); |
| | | order.setType(Constants.ZERO); |
| | | order.setOutBillNo(billNo); |
| | | order.setAliAccount(dto.getAliAccount()); |
| | | order.setDeleted(Constants.ZERO); |
| | | order.setCreateTime(now); |
| | | order.setUpdateTime(now); |
| | | order.setCreateUser(shop.getRegionMemberId()); |
| | | withdrawalOrdersMapper.insert(order); |
| | | // 创建支出 Revenue 记录 |
| | | Revenue revenue = new Revenue(); |
| | | revenue.setMemberId(shop.getRegionMemberId()); |
| | | revenue.setMemberType(Constants.TWO); |
| | | revenue.setType(Constants.ONE); // 1=提现支出 |
| | | revenue.setOptType(-Constants.ONE); // -1=支出 |
| | | revenue.setAmount(amountFen); |
| | | revenue.setVaildStatus(Constants.ONE); // 已入账 |
| | | revenue.setObjId(order.getId()); |
| | | revenue.setObjType(Constants.ONE); // 1=提现业务 |
| | | revenue.setOrderNo(billNo); |
| | | revenue.setStatus(Constants.TWO); // 2=处理中 |
| | | revenue.setDeleted(Constants.ZERO); |
| | | revenue.setCreateTime(now); |
| | | revenueMapper.insert(revenue); |
| | | } |
| | | |
| | | private String generateBillNo() { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); |
| | | String random = String.valueOf(ThreadLocalRandom.current().nextInt(100000, 999999)); |
| | | return "TX" + sdf.format(new Date()) + random; |
| | | } |
| | | |
| | | } |