feat: 资产

pull/1121/head
梁宇奇 2025-04-28 18:55:22 +08:00
parent 2ff0f5b670
commit 0a7425da8b
15 changed files with 509 additions and 31 deletions

View File

@ -0,0 +1,97 @@
package com.ruoyi.web.controller.xkt;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.core.controller.XktBaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.web.controller.xkt.vo.account.*;
import com.ruoyi.xkt.dto.account.AlipayBindDTO;
import com.ruoyi.xkt.dto.account.AssetInfoDTO;
import com.ruoyi.xkt.dto.account.TransactionPasswordSetDTO;
import com.ruoyi.xkt.dto.account.WithdrawPrepareResult;
import com.ruoyi.xkt.enums.EAccountOwnerType;
import com.ruoyi.xkt.enums.EPayChannel;
import com.ruoyi.xkt.manager.impl.AliPaymentMangerImpl;
import com.ruoyi.xkt.service.IAssetService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* @author liangyq
* @date 2025-04-07 18:31
*/
@Api(tags = "资产管理")
@RestController
@RequestMapping("/rest/v1/asset")
public class AssetController extends XktBaseController {
@Autowired
private IAssetService assetService;
@Autowired
private AliPaymentMangerImpl aliPaymentManger;
@PreAuthorize("@ss.hasPermi('system:asset:query')")
@ApiOperation(value = "档口资产")
@GetMapping(value = "store/current")
public R<AssetInfoVO> getCurrentStoreAsset() {
AssetInfoDTO dto = assetService.getStoreAssetInfo(SecurityUtils.getStoreId());
return success(BeanUtil.toBean(dto, AssetInfoVO.class));
}
@PreAuthorize("@ss.hasPermi('system:asset:query')")
@ApiOperation(value = "卖家资产")
@GetMapping(value = "user/current")
public R<AssetInfoVO> getCurrentUserAsset() {
AssetInfoDTO dto = assetService.getUserAssetInfo(SecurityUtils.getUserId());
return success(BeanUtil.toBean(dto, AssetInfoVO.class));
}
@PreAuthorize("@ss.hasPermi('system:asset:add')")
@ApiOperation(value = "档口绑定支付宝")
@PostMapping(value = "store/alipay/bind")
public R<AssetInfoVO> bindStoreAlipay(@Validated @RequestBody AlipayStoreBindVO vo) {
AlipayBindDTO dto = BeanUtil.toBean(vo, AlipayBindDTO.class);
dto.setOwnerId(SecurityUtils.getStoreId());
dto.setOwnerType(EAccountOwnerType.STORE.getValue());
return success(BeanUtil.toBean(assetService.bindAlipay(dto), AssetInfoVO.class));
}
@PreAuthorize("@ss.hasPermi('system:asset:add')")
@ApiOperation(value = "卖家绑定支付宝")
@PostMapping(value = "user/alipay/bind")
public R<AssetInfoVO> bindUserAlipay(@Validated @RequestBody AlipayUserBindVO vo) {
AlipayBindDTO dto = BeanUtil.toBean(vo, AlipayBindDTO.class);
dto.setOwnerId(SecurityUtils.getUserId());
dto.setOwnerType(EAccountOwnerType.USER.getValue());
return success(BeanUtil.toBean(assetService.bindAlipay(dto), AssetInfoVO.class));
}
@PreAuthorize("@ss.hasPermi('system:asset:add')")
@ApiOperation(value = "档口设置交易密码")
@PostMapping(value = "store/transaction-password/set")
public R<AssetInfoVO> setTransactionPassword(@Validated @RequestBody TransactionPasswordSetVO vo) {
TransactionPasswordSetDTO dto = BeanUtil.toBean(vo, TransactionPasswordSetDTO.class);
dto.setStoreId(SecurityUtils.getStoreId());
return success(BeanUtil.toBean(assetService.setTransactionPassword(dto), AssetInfoVO.class));
}
@PreAuthorize("@ss.hasPermi('system:asset:add')")
@ApiOperation(value = "档口支付宝提现")
@PostMapping(value = "store/alipay/withdraw")
public R withdrawByAlipay(@Validated @RequestBody WithdrawReqVO vo) {
//创建付款单
WithdrawPrepareResult prepareResult = assetService.prepareWithdraw(SecurityUtils.getStoreId(), vo.getAmount(),
vo.getTransactionPassword(), EPayChannel.ALI_PAY);
//支付宝转账
aliPaymentManger.transfer(prepareResult.getBillNo(), prepareResult.getAccountOwnerNumber(),
prepareResult.getAccountOwnerName(), prepareResult.getAmount());
//付款单到账
assetService.withdrawSuccess(prepareResult.getFinanceBillId());
return success();
}
}

View File

@ -120,7 +120,7 @@ public class StoreOrderController extends XktBaseController {
if (1 == vo.getSrcPage()) {
queryDTO.setOrderUserId(SecurityUtils.getUserId());
} else {
//TODO 当前档口
queryDTO.setStoreId(SecurityUtils.getStoreId());
}
Page<StoreOrderPageItemDTO> pageDTO = storeOrderService.page(queryDTO);
return success(PageVO.of(pageDTO, StoreOrderPageItemVO.class));

View File

@ -0,0 +1,40 @@
package com.ruoyi.web.controller.xkt.vo.account;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
/**
* @author liangyq
* @date 2025-04-23 14:41
*/
@ApiModel
@Data
public class AlipayStoreBindVO {
/**
*
*/
@NotEmpty(message = "账号不能为空")
@ApiModelProperty(value = "账号")
private String accountOwnerNumber;
/**
*
*/
@NotEmpty(message = "姓名不能为空")
@ApiModelProperty(value = "姓名")
private String accountOwnerName;
/**
*
*/
@NotEmpty(message = "手机号不能为空")
@ApiModelProperty(value = "手机号")
private String accountOwnerPhoneNumber;
/**
*
*/
@NotEmpty(message = "验证码不能为空")
@ApiModelProperty(value = "验证码")
private String verifyCode;
}

View File

@ -0,0 +1,40 @@
package com.ruoyi.web.controller.xkt.vo.account;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
/**
* @author liangyq
* @date 2025-04-23 14:41
*/
@ApiModel
@Data
public class AlipayUserBindVO {
/**
*
*/
@NotEmpty(message = "账号不能为空")
@ApiModelProperty(value = "账号")
private String accountOwnerNumber;
/**
*
*/
@NotEmpty(message = "姓名不能为空")
@ApiModelProperty(value = "姓名")
private String accountOwnerName;
/**
*
*/
@NotEmpty(message = "手机号不能为空")
@ApiModelProperty(value = "手机号")
private String accountOwnerPhoneNumber;
/**
*
*/
@NotEmpty(message = "验证码不能为空")
@ApiModelProperty(value = "验证码")
private String verifyCode;
}

View File

@ -0,0 +1,24 @@
package com.ruoyi.web.controller.xkt.vo.account;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author liangyq
* @date 2025-04-23 14:17
*/
@ApiModel
@Data
public class AssetInfoVO {
/**
*
*/
@ApiModelProperty(value = "内部账户")
private InternalAccountVO internalAccount;
/**
*
*/
@ApiModelProperty(value = "支付宝账户")
private ExternalAccountVO alipayAccount;
}

View File

@ -0,0 +1,66 @@
package com.ruoyi.web.controller.xkt.vo.account;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
*
*
* @author liangyq
* @date 2025-04-01 11:57:52.450
**/
@ApiModel
@Data
public class ExternalAccountVO {
/**
* ID
*/
@ApiModelProperty(value = "外部账户ID")
private Long id;
/**
* [1: 2: 3:]
*/
@ApiModelProperty(value = "归属[1:平台 2:档口 3:用户]")
private Integer ownerType;
/**
* ID=-1=store_id=user_id
*/
@ApiModelProperty(value = "归属ID平台=-1档口=store_id用户=user_id")
private Long ownerId;
/**
* [1: 2:]
*/
@ApiModelProperty(value = "账户状态[1:正常 2:冻结]")
private Integer accountStatus;
/**
* [1:]
*/
@ApiModelProperty(value = "账户类型[1:支付宝账户]")
private Integer accountType;
/**
*
*/
@ApiModelProperty(value = "归属人实际账户")
private String accountOwnerNumber;
/**
*
*/
@ApiModelProperty(value = "归属人真实姓名")
private String accountOwnerName;
/**
*
*/
@ApiModelProperty(value = "归属人手机号")
private String accountOwnerPhoneNumber;
/**
*
*/
@ApiModelProperty(value = "归属人认证通过")
private Boolean accountAuthAccess;
/**
*
*/
@ApiModelProperty(value = "备注")
private String remark;
}

View File

@ -0,0 +1,63 @@
package com.ruoyi.web.controller.xkt.vo.account;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
*
*
* @author liangyq
* @date 2025-04-01 11:57:52.493
**/
@ApiModel
@Data
public class InternalAccountVO {
/**
* ID
*/
@ApiModelProperty(value = "内部账户ID")
private Long id;
/**
* [1: 2: 3:]
*/
@ApiModelProperty(value = "归属[1:平台 2:档口 3:用户]")
private Integer ownerType;
/**
* ID=-1=store_id
*/
@ApiModelProperty(value = "归属ID平台=-1档口=store_id")
private Long ownerId;
/**
* [1: 2:]
*/
@ApiModelProperty(value = "账户状态[1:正常 2:冻结]")
private Integer accountStatus;
/**
*
*/
@ApiModelProperty(value = "电话号码")
private String phoneNumber;
/**
*
*/
@ApiModelProperty(value = "余额")
private BigDecimal balance;
/**
*
*/
@ApiModelProperty(value = "可用余额")
private BigDecimal usableBalance;
/**
*
*/
@ApiModelProperty(value = "支付中金额")
private BigDecimal paymentAmount;
/**
*
*/
@ApiModelProperty(value = "备注")
private String remark;
}

View File

@ -0,0 +1,34 @@
package com.ruoyi.web.controller.xkt.vo.account;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
/**
* @author liangyq
* @date 2025-04-23 15:32
*/
@ApiModel
@Data
public class TransactionPasswordSetVO {
/**
*
*/
@NotEmpty(message = "手机号不能为空")
@ApiModelProperty(value = "手机号")
private String phoneNumber;
/**
*
*/
@NotEmpty(message = "验证码不能为空")
@ApiModelProperty(value = "验证码")
private String verifyCode;
/**
*
*/
@NotEmpty(message = "交易密码不能为空")
@ApiModelProperty(value = "交易密码")
private String transactionPassword;
}

View File

@ -0,0 +1,27 @@
package com.ruoyi.web.controller.xkt.vo.account;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
/**
* @author liangyq
* @date 2025-04-23 14:41
*/
@ApiModel
@Data
public class WithdrawReqVO {
@NotNull(message = "金额不能为空")
@ApiModelProperty(value = "金额")
private BigDecimal amount;
@NotEmpty(message = "支付密码不能为空")
@ApiModelProperty(value = "支付密码")
private String transactionPassword;
}

View File

@ -35,6 +35,16 @@ public class SecurityUtils {
}
}
/**
* ID
*
* @return
*/
public static Long getStoreId() {
//TODO
return 1L;
}
/**
*
**/

View File

@ -9,9 +9,13 @@ import lombok.Data;
@Data
public class AlipayBindDTO {
/**
* ID
* ID=-1=store_id=user_id
*/
private Long storeId;
private Long ownerId;
/**
* [1: 2: 3:]
*/
private Integer ownerType;
/**
*
*/

View File

@ -11,7 +11,7 @@ import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AccountInfoDTO {
public class AssetInfoDTO {
/**
*
*/

View File

@ -0,0 +1,41 @@
package com.ruoyi.xkt.dto.account;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* @author liangyq
* @date 2025-04-28 18:33
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class WithdrawPrepareResult {
/**
* ID
*/
private Long financeBillId;
/**
*
*/
private String billNo;
/**
*
*/
private BigDecimal amount;
/**
*
*/
private String accountOwnerNumber;
/**
*
*/
private String accountOwnerName;
/**
*
*/
private String accountOwnerPhoneNumber;
}

View File

@ -1,9 +1,9 @@
package com.ruoyi.xkt.service;
import com.ruoyi.xkt.dto.account.AccountInfoDTO;
import com.ruoyi.xkt.dto.account.AlipayBindDTO;
import com.ruoyi.xkt.dto.account.AssetInfoDTO;
import com.ruoyi.xkt.dto.account.TransactionPasswordSetDTO;
import com.ruoyi.xkt.dto.finance.FinanceBillExt;
import com.ruoyi.xkt.dto.account.WithdrawPrepareResult;
import com.ruoyi.xkt.enums.EPayChannel;
import java.math.BigDecimal;
@ -12,7 +12,7 @@ import java.math.BigDecimal;
* @author liangyq
* @date 2025-04-22 21:06
*/
public interface IAccountService {
public interface IAssetService {
/**
*
*
@ -22,7 +22,8 @@ public interface IAccountService {
* @param payChannel
* @return
*/
FinanceBillExt prepareWithdraw(Long storeId, BigDecimal amount, String transactionPassword, EPayChannel payChannel);
WithdrawPrepareResult prepareWithdraw(Long storeId, BigDecimal amount, String transactionPassword,
EPayChannel payChannel);
/**
*
@ -32,12 +33,20 @@ public interface IAccountService {
void withdrawSuccess(Long financeBillId);
/**
*
*
*
* @param storeId
* @return
*/
AccountInfoDTO getStoreAccountInfo(Long storeId);
AssetInfoDTO getStoreAssetInfo(Long storeId);
/**
*
*
* @param userId
* @return
*/
AssetInfoDTO getUserAssetInfo(Long userId);
/**
*
@ -45,7 +54,7 @@ public interface IAccountService {
* @param storeId
* @return
*/
AccountInfoDTO createInternalAccountIfNotExists(Long storeId);
AssetInfoDTO createInternalAccountIfNotExists(Long storeId);
/**
*
@ -53,7 +62,7 @@ public interface IAccountService {
* @param transactionPasswordSet
* @return
*/
AccountInfoDTO setTransactionPassword(TransactionPasswordSetDTO transactionPasswordSet);
AssetInfoDTO setTransactionPassword(TransactionPasswordSetDTO transactionPasswordSet);
/**
*
@ -61,6 +70,6 @@ public interface IAccountService {
* @param alipayBind
* @return
*/
AccountInfoDTO bindAlipay(AlipayBindDTO alipayBind);
AssetInfoDTO bindAlipay(AlipayBindDTO alipayBind);
}

View File

@ -14,7 +14,7 @@ import com.ruoyi.xkt.enums.EAccountOwnerType;
import com.ruoyi.xkt.enums.EAccountStatus;
import com.ruoyi.xkt.enums.EAccountType;
import com.ruoyi.xkt.enums.EPayChannel;
import com.ruoyi.xkt.service.IAccountService;
import com.ruoyi.xkt.service.IAssetService;
import com.ruoyi.xkt.service.IExternalAccountService;
import com.ruoyi.xkt.service.IFinanceBillService;
import com.ruoyi.xkt.service.IInternalAccountService;
@ -31,7 +31,7 @@ import java.math.BigDecimal;
*/
@Slf4j
@Service
public class AccountServiceImpl implements IAccountService {
public class AssetServiceImpl implements IAssetService {
@Autowired
private IFinanceBillService financeBillService;
@ -43,8 +43,8 @@ public class AccountServiceImpl implements IAccountService {
@Transactional(rollbackFor = Exception.class)
@Override
public FinanceBillExt prepareWithdraw(Long storeId, BigDecimal amount, String transactionPassword,
EPayChannel payChannel) {
public WithdrawPrepareResult prepareWithdraw(Long storeId, BigDecimal amount, String transactionPassword,
EPayChannel payChannel) {
Assert.notNull(storeId);
Assert.notEmpty(transactionPassword);
Assert.isTrue(NumberUtil.isLessOrEqual(amount, BigDecimal.ZERO), "提现金额异常");
@ -61,7 +61,13 @@ public class AccountServiceImpl implements IAccountService {
if (!StrUtil.equals(SecureUtil.md5(transactionPassword), internalAccount.getTransactionPassword())) {
throw new ServiceException("支付密码错误");
}
return financeBillService.createWithdrawPaymentBill(storeId, amount, payChannel);
FinanceBillExt financeBillExt = financeBillService.createWithdrawPaymentBill(storeId, amount, payChannel);
return new WithdrawPrepareResult(financeBillExt.getFinanceBill().getId(),
financeBillExt.getFinanceBill().getBillNo(),
financeBillExt.getFinanceBill().getTransAmount(),
externalAccount.getAccountOwnerNumber(),
externalAccount.getAccountOwnerName(),
externalAccount.getAccountOwnerPhoneNumber());
}
@Transactional(rollbackFor = Exception.class)
@ -71,18 +77,27 @@ public class AccountServiceImpl implements IAccountService {
}
@Override
public AccountInfoDTO getStoreAccountInfo(Long storeId) {
public AssetInfoDTO getStoreAssetInfo(Long storeId) {
Assert.notNull(storeId);
InternalAccount internalAccount = internalAccountService.getAccount(storeId, EAccountOwnerType.STORE);
ExternalAccount alipayExternalAccount = externalAccountService.getAccount(storeId, EAccountOwnerType.STORE,
EAccountType.ALI_PAY);
return new AccountInfoDTO(BeanUtil.toBean(internalAccount, InternalAccountDTO.class),
return new AssetInfoDTO(BeanUtil.toBean(internalAccount, InternalAccountDTO.class),
BeanUtil.toBean(alipayExternalAccount, ExternalAccountDTO.class));
}
@Override
public AssetInfoDTO getUserAssetInfo(Long userId) {
Assert.notNull(userId);
ExternalAccount alipayExternalAccount = externalAccountService.getAccount(userId, EAccountOwnerType.USER,
EAccountType.ALI_PAY);
return new AssetInfoDTO(null,
BeanUtil.toBean(alipayExternalAccount, ExternalAccountDTO.class));
}
@Transactional(rollbackFor = Exception.class)
@Override
public AccountInfoDTO createInternalAccountIfNotExists(Long storeId) {
public AssetInfoDTO createInternalAccountIfNotExists(Long storeId) {
Assert.notNull(storeId);
InternalAccount internalAccount = internalAccountService.getAccount(storeId, EAccountOwnerType.STORE);
if (internalAccount == null) {
@ -91,12 +106,12 @@ public class AccountServiceImpl implements IAccountService {
addDTO.setOwnerType(EAccountOwnerType.STORE.getValue());
internalAccountService.createAccount(addDTO);
}
return getStoreAccountInfo(storeId);
return getStoreAssetInfo(storeId);
}
@Transactional(rollbackFor = Exception.class)
@Override
public AccountInfoDTO setTransactionPassword(TransactionPasswordSetDTO transactionPasswordSet) {
public AssetInfoDTO setTransactionPassword(TransactionPasswordSetDTO transactionPasswordSet) {
Assert.notNull(transactionPasswordSet.getStoreId());
Assert.notEmpty(transactionPasswordSet.getPhoneNumber());
Assert.notEmpty(transactionPasswordSet.getVerifyCode());
@ -106,19 +121,24 @@ public class AccountServiceImpl implements IAccountService {
EAccountOwnerType.STORE);
internalAccountService.setTransactionPassword(internalAccount.getId(), transactionPasswordSet.getPhoneNumber(),
SecureUtil.md5(transactionPasswordSet.getTransactionPassword()));
return getStoreAccountInfo(transactionPasswordSet.getStoreId());
return getStoreAssetInfo(transactionPasswordSet.getStoreId());
}
@Transactional(rollbackFor = Exception.class)
@Override
public AccountInfoDTO bindAlipay(AlipayBindDTO alipayBind) {
Assert.notNull(alipayBind.getStoreId());
public AssetInfoDTO bindAlipay(AlipayBindDTO alipayBind) {
Assert.notNull(alipayBind.getOwnerId());
EAccountOwnerType ownerType = EAccountOwnerType.of(alipayBind.getOwnerType());
if (EAccountOwnerType.STORE != ownerType
&& EAccountOwnerType.USER != ownerType) {
throw new ServiceException("账户归属异常");
}
Assert.notEmpty(alipayBind.getAccountOwnerName());
Assert.notEmpty(alipayBind.getAccountOwnerNumber());
Assert.notEmpty(alipayBind.getAccountOwnerPhoneNumber());
//TODO 验证码
ExternalAccount alipayExternalAccount = externalAccountService.getAccount(alipayBind.getStoreId(),
EAccountOwnerType.STORE, EAccountType.ALI_PAY);
ExternalAccount alipayExternalAccount = externalAccountService.getAccount(alipayBind.getOwnerId(),
ownerType, EAccountType.ALI_PAY);
if (alipayExternalAccount != null) {
//修改
ExternalAccountUpdateDTO updateDTO = new ExternalAccountUpdateDTO();
@ -131,8 +151,8 @@ public class AccountServiceImpl implements IAccountService {
} else {
//新增
ExternalAccountAddDTO addDTO = new ExternalAccountAddDTO();
addDTO.setOwnerId(alipayBind.getStoreId());
addDTO.setOwnerType(EAccountOwnerType.STORE.getValue());
addDTO.setOwnerId(alipayBind.getOwnerId());
addDTO.setOwnerType(ownerType.getValue());
addDTO.setAccountType(EAccountType.ALI_PAY.getValue());
addDTO.setAccountOwnerName(alipayBind.getAccountOwnerName());
addDTO.setAccountOwnerNumber(alipayBind.getAccountOwnerNumber());
@ -140,7 +160,10 @@ public class AccountServiceImpl implements IAccountService {
addDTO.setAccountAuthAccess(true);
externalAccountService.createAccount(addDTO);
}
return getStoreAccountInfo(alipayBind.getStoreId());
if (EAccountOwnerType.USER == ownerType) {
return getUserAssetInfo(alipayBind.getOwnerId());
}
return getStoreAssetInfo(alipayBind.getOwnerId());
}