【金融项目】尚融宝项目(十五)
创始人
2024-02-18 17:06:58
0

29、提现和还款

29.1、提现

29.1.1、需求

在这里插入图片描述

放款成功后,借款人可以申请提现。

参考《汇付宝商户账户技术文档》3.15用户申请提现

在这里插入图片描述

29.1.2、前端整合

pages/user/withdraw.vue


29.1.3、提现接口

1、Controller

UserAccountController

@ApiOperation("用户提现")
@PostMapping("/auth/commitWithdraw/{fetchAmt}")
public R commitWithdraw(@ApiParam(value = "金额", required = true)@PathVariable BigDecimal fetchAmt, HttpServletRequest request) {String token = request.getHeader("token");Long userId = JwtUtils.getUserId(token);String formStr = userAccountService.commitWithdraw(fetchAmt, userId);return R.ok().data("formStr", formStr);
}

2、Service

接口:UserAccountService

String commitWithdraw(BigDecimal fetchAmt, Long userId);

实现:UserAccountServiceImpl

@Resource
private UserBindService userBindService;
@Resource
private UserAccountService userAccountService;@Override
public String commitWithdraw(BigDecimal fetchAmt, Long userId) {//账户可用余额充足:当前用户的余额 >= 当前用户的提现金额BigDecimal amount = userAccountService.getAccount(userId);//获取当前用户的账户余额Assert.isTrue(amount.doubleValue() >= fetchAmt.doubleValue(),ResponseEnum.NOT_SUFFICIENT_FUNDS_ERROR);String bindCode = userBindService.getBindCodeByUserId(userId);Map paramMap = new HashMap<>();paramMap.put("agentId", HfbConst.AGENT_ID);paramMap.put("agentBillNo", LendNoUtils.getWithdrawNo());paramMap.put("bindCode", bindCode);paramMap.put("fetchAmt", fetchAmt);paramMap.put("feeAmt", new BigDecimal(0));paramMap.put("notifyUrl", HfbConst.WITHDRAW_NOTIFY_URL);paramMap.put("returnUrl", HfbConst.WITHDRAW_RETURN_URL);paramMap.put("timestamp", RequestHelper.getTimestamp());String sign = RequestHelper.getSign(paramMap);paramMap.put("sign", sign);//构建自动提交表单String formStr = FormHelper.buildForm(HfbConst.WITHDRAW_URL, paramMap);return formStr;
}

29.1.4、回调接口

1、Controller

UserAccountController

@ApiOperation("用户提现异步回调")
@PostMapping("/notifyWithdraw")
public String notifyWithdraw(HttpServletRequest request) {Map paramMap = RequestHelper.switchMap(request.getParameterMap());log.info("提现异步回调:" + JSON.toJSONString(paramMap));//校验签名if(RequestHelper.isSignEquals(paramMap)) {//提现成功交易if("0001".equals(paramMap.get("resultCode"))) {userAccountService.notifyWithdraw(paramMap);} else {log.info("提现异步回调充值失败:" + JSON.toJSONString(paramMap));return "fail";}} else {log.info("提现异步回调签名错误:" + JSON.toJSONString(paramMap));return "fail";}return "success";
}

2、Service

接口:UserAccountService

void notifyWithdraw(Map paramMap);

实现:UserAccountServiceImpl

@Transactional(rollbackFor = Exception.class)
@Override
public void notifyWithdraw(Map paramMap) {log.info("提现成功");String agentBillNo = (String)paramMap.get("agentBillNo");boolean result = transFlowService.isSaveTransFlow(agentBillNo);if(result){log.warn("幂等性返回");return;}String bindCode = (String)paramMap.get("bindCode");String fetchAmt = (String)paramMap.get("fetchAmt");//根据用户账户修改账户金额baseMapper.updateAccount(bindCode, new BigDecimal("-" + fetchAmt), new BigDecimal(0));//增加交易流水TransFlowBO transFlowBO = new TransFlowBO(agentBillNo,bindCode,new BigDecimal(fetchAmt),TransTypeEnum.WITHDRAW,"提现");transFlowService.saveTransFlow(transFlowBO);
}

29.2、还款

29.2.1、需求

放款成功后,会生成借款人的还款计划与出借人的回款计划,然后借款人按照还款计划日期操作还款即可。

参考《汇付宝商户账户技术文档》3.14还款扣款,处理业务即可

在这里插入图片描述

29.2.2、前端整合

1、还款按钮

pages/lend/_id.vue

{{ lendReturn.status === 0 ? '还款' : '' }}

2、脚本

pages/lend/_id.vue

commitReturn(lendReturnId) {this.$alert('
您即将前往汇付宝确认还款
','前往汇付宝资金托管平台',{dangerouslyUseHTMLString: true,confirmButtonText: '立即前往',callback: (action) => {if (action === 'confirm') {this.$axios.$post('/api/core/lendReturn/auth/commitReturn/' + lendReturnId).then((response) => {document.write(response.data.formStr)})}},}) }

29.2.3、还款接口

1、Controller

LendReturnController

@ApiOperation("用户还款")
@PostMapping("/auth/commitReturn/{lendReturnId}")
public R commitReturn(@ApiParam(value = "还款计划id", required = true)@PathVariable Long lendReturnId, HttpServletRequest request) {String token = request.getHeader("token");Long userId = JwtUtils.getUserId(token);String formStr = lendReturnService.commitReturn(lendReturnId, userId);return R.ok().data("formStr", formStr);
}

2、Service

接口:LendReturnService

String commitReturn(Long lendReturnId, Long userId);

实现:LendReturnServiceImpl

@Resource
private UserAccountService userAccountService;
@Resource
private LendMapper lendMapper;
@Resource
private UserBindService userBindService;
@Resource
private LendItemReturnService lendItemReturnService;@Transactional(rollbackFor = Exception.class)
@Override
public String commitReturn(Long lendReturnId, Long userId) {//获取还款记录LendReturn lendReturn = baseMapper.selectById(lendReturnId);//判断账号余额是否充足BigDecimal amount = userAccountService.getAccount(userId);Assert.isTrue(amount.doubleValue() >= lendReturn.getTotal().doubleValue(),ResponseEnum.NOT_SUFFICIENT_FUNDS_ERROR);//获取借款人codeString bindCode = userBindService.getBindCodeByUserId(userId);//获取lendLong lendId = lendReturn.getLendId();Lend lend = lendMapper.selectById(lendId);Map paramMap = new HashMap<>();paramMap.put("agentId", HfbConst.AGENT_ID);//商户商品名称paramMap.put("agentGoodsName", lend.getTitle());//批次号paramMap.put("agentBatchNo",lendReturn.getReturnNo());//还款人绑定协议号paramMap.put("fromBindCode", bindCode);//还款总额paramMap.put("totalAmt", lendReturn.getTotal());paramMap.put("note", "");//还款明细List> lendItemReturnDetailList = lendItemReturnService.addReturnDetail(lendReturnId);paramMap.put("data", JSONObject.toJSONString(lendItemReturnDetailList));paramMap.put("voteFeeAmt", new BigDecimal(0));paramMap.put("notifyUrl", HfbConst.BORROW_RETURN_NOTIFY_URL);paramMap.put("returnUrl", HfbConst.BORROW_RETURN_RETURN_URL);paramMap.put("timestamp", RequestHelper.getTimestamp());String sign = RequestHelper.getSign(paramMap);paramMap.put("sign", sign);//构建自动提交表单String formStr = FormHelper.buildForm(HfbConst.BORROW_RETURN_URL, paramMap);return formStr;
}

3、还款明细Service

根据还款id获取回款列表

LendReturnService接口:

List> addReturnDetail(Long lendReturnId);

LendReturnServiceImpl实现:

@Resource
private UserBindService userBindService;
@Resource
private LendItemMapper lendItemMapper;
@Resource
private LendMapper lendMapper;
@Resource
private LendReturnMapper lendReturnMapper;/**
* 添加还款明细
* @param lendReturnId
*/
@Override
public List> addReturnDetail(Long lendReturnId) {//获取还款记录LendReturn lendReturn = lendReturnMapper.selectById(lendReturnId);//获取标的信息Lend lend = lendMapper.selectById(lendReturn.getLendId());//根据还款id获取回款列表List lendItemReturnList = this.selectLendItemReturnList(lendReturnId);List> lendItemReturnDetailList = new ArrayList<>();for(LendItemReturn lendItemReturn : lendItemReturnList) {LendItem lendItem = lendItemMapper.selectById(lendItemReturn.getLendItemId());String bindCode = userBindService.getBindCodeByUserId(lendItem.getInvestUserId());Map map = new HashMap<>();//项目编号map.put("agentProjectCode", lend.getLendNo());//出借编号map.put("voteBillNo", lendItem.getLendItemNo());//收款人(出借人)map.put("toBindCode", bindCode);//还款金额map.put("transitAmt", lendItemReturn.getTotal());//还款本金map.put("baseAmt", lendItemReturn.getPrincipal());//还款利息map.put("benifitAmt", lendItemReturn.getInterest());//商户手续费map.put("feeAmt", new BigDecimal("0"));lendItemReturnDetailList.add(map);}return lendItemReturnDetailList;
}

根据还款计划id获取对应的回款计划列表

接口:

List selectLendItemReturnList(Long lendReturnId);

实现:

@Override
public List selectLendItemReturnList(Long lendReturnId) {QueryWrapper queryWrapper = new QueryWrapper<>();queryWrapper.eq("lend_return_id", lendReturnId);List lendItemReturnList = baseMapper.selectList(queryWrapper);return lendItemReturnList;
}

29.2.4、回调接口

1、Controller

LendReturnController

@ApiOperation("还款异步回调")
@PostMapping("/notifyUrl")
public String notifyUrl(HttpServletRequest request) {Map paramMap = RequestHelper.switchMap(request.getParameterMap());log.info("还款异步回调:" + JSON.toJSONString(paramMap));//校验签名if(RequestHelper.isSignEquals(paramMap)) {if("0001".equals(paramMap.get("resultCode"))) {lendReturnService.notify(paramMap);} else {log.info("还款异步回调失败:" + JSON.toJSONString(paramMap));return "fail";}} else {log.info("还款异步回调签名错误:" + JSON.toJSONString(paramMap));return "fail";}return "success";
}

2、Service

接口:LendReturnService

void notify(Map paramMap);

实现:LendReturnServiceImpl

@Resource
private TransFlowService transFlowService;
@Resource
private UserAccountMapper userAccountMapper;
@Resource
private LendItemReturnMapper lendItemReturnMapper;
@Resource
private LendItemMapper lendItemMapper;@Transactional(rollbackFor = Exception.class)
@Override
public void notify(Map paramMap) {log.info("还款成功");//还款编号String agentBatchNo = (String)paramMap.get("agentBatchNo");boolean result = transFlowService.isSaveTransFlow(agentBatchNo);if(result){log.warn("幂等性返回");return;}//获取还款数据String voteFeeAmt = (String)paramMap.get("voteFeeAmt");QueryWrapper lendReturnQueryWrapper = new QueryWrapper<>();lendReturnQueryWrapper.eq("return_no", agentBatchNo);LendReturn lendReturn = baseMapper.selectOne(lendReturnQueryWrapper);//更新还款状态lendReturn.setStatus(1);lendReturn.setFee(new BigDecimal(voteFeeAmt));lendReturn.setRealReturnTime(LocalDateTime.now());baseMapper.updateById(lendReturn);//更新标的信息Lend lend = lendMapper.selectById(lendReturn.getLendId());//最后一次还款更新标的状态if(lendReturn.getLast()) {lend.setStatus(LendStatusEnum.PAY_OK.getStatus());lendMapper.updateById(lend);}//借款账号转出金额BigDecimal totalAmt = new BigDecimal((String)paramMap.get("totalAmt"));//还款金额String bindCode = userBindService.getBindCodeByUserId(lend.getUserId());userAccountMapper.updateAccount(bindCode, totalAmt.negate(), new BigDecimal(0));//借款人交易流水TransFlowBO transFlowBO = new TransFlowBO(agentBatchNo,bindCode,totalAmt,TransTypeEnum.RETURN_DOWN,"借款人还款扣减,项目编号:" + lend.getLendNo() + ",项目名称:" + lend.getTitle());transFlowService.saveTransFlow(transFlowBO);//获取回款明细List lendItemReturnList = lendItemReturnService.selectLendItemReturnList(lendReturn.getId());lendItemReturnList.forEach(item -> {//更新回款状态item.setStatus(1);item.setRealReturnTime(LocalDateTime.now());lendItemReturnMapper.updateById(item);//更新出借信息LendItem lendItem = lendItemMapper.selectById(item.getLendItemId());lendItem.setRealAmount(lendItem.getRealAmount().add(item.getInterest()));lendItemMapper.updateById(lendItem);//投资账号转入金额String investBindCode = userBindService.getBindCodeByUserId(item.getInvestUserId());userAccountMapper.updateAccount(investBindCode, item.getTotal(), new BigDecimal(0));//投资账号交易流水TransFlowBO investTransFlowBO = new TransFlowBO(LendNoUtils.getReturnItemNo(),investBindCode,item.getTotal(),TransTypeEnum.INVEST_BACK,"还款到账,项目编号:" + lend.getLendNo() + ",项目名称:" + lend.getTitle());transFlowService.saveTransFlow(investTransFlowBO);});
}

30、个人中心

30.1、资金记录

30.1.1、资金列表接口

1、Controller

TransFlowController

package com.atguigu.srb.core.controller.api;@Api(tags = "资金记录")
@RestController
@RequestMapping("/api/core/transFlow")
@Slf4j
public class TransFlowController {@Resourceprivate TransFlowService transFlowService;@ApiOperation("获取列表")@GetMapping("/list")public R list(HttpServletRequest request) {String token = request.getHeader("token");Long userId = JwtUtils.getUserId(token);List list = transFlowService.selectByUserId(userId);return R.ok().data("list", list);}
}

2、Service

接口:TransFlowService

List selectByUserId(Long userId);

实现:TransFlowServiceImpl

@Override
public List selectByUserId(Long userId) {QueryWrapper queryWrapper = new QueryWrapper<>();queryWrapper.eq("user_id", userId).orderByDesc("id");return baseMapper.selectList(queryWrapper);
}

30.1.2、前端整合

脚本

pages/user/fund.vue

fetchTransFlowList() {this.$axios.$get('/api/core/transFlow/list').then((response) => {this.transFlowList = response.data.list})
},

30.2、个人中心首页

30.2.1、后端接口

1、创建VO

package com.atguigu.srb.core.pojo.vo;@Data
@ApiModel(description = "首页用户信息")
public class UserIndexVO {@ApiModelProperty(value = "用户id")private Long userId;@ApiModelProperty(value = "用户姓名")private String name;@ApiModelProperty(value = "用户昵称")private String nickName;@ApiModelProperty(value = "1:出借人 2:借款人")private Integer userType;@ApiModelProperty(value = "用户头像")private String headImg;@ApiModelProperty(value = "绑定状态(0:未绑定,1:绑定成功 -1:绑定失败)")private Integer bindStatus;@ApiModelProperty(value = "帐户可用余额")private BigDecimal amount;@ApiModelProperty(value = "冻结金额")private BigDecimal freezeAmount;@ApiModelProperty(value = "上次登录时间")private LocalDateTime lastLoginTime;
}

2、Controller

UserInfoController

@ApiOperation("获取个人空间用户信息")
@GetMapping("/auth/getIndexUserInfo")
public R getIndexUserInfo(HttpServletRequest request) {String token = request.getHeader("token");Long userId = JwtUtils.getUserId(token);UserIndexVO userIndexVO = userInfoService.getIndexUserInfo(userId);return R.ok().data("userIndexVO", userIndexVO);
}

3、Service

接口:UserInfoService

UserIndexVO getIndexUserInfo(Long userId);

实现:UserInfoServiceImpl

@Override
public UserIndexVO getIndexUserInfo(Long userId) {//用户信息UserInfo userInfo = baseMapper.selectById(userId);//账户信息QueryWrapper userAccountQueryWrapper = new QueryWrapper<>();userAccountQueryWrapper.eq("user_id", userId);UserAccount userAccount = userAccountMapper.selectOne(userAccountQueryWrapper);//登录信息QueryWrapper userLoginRecordQueryWrapper = new QueryWrapper<>();userLoginRecordQueryWrapper.eq("user_id", userId).orderByDesc("id").last("limit 1");UserLoginRecord userLoginRecord = userLoginRecordMapper.selectOne(userLoginRecordQueryWrapper);//组装结果数据UserIndexVO userIndexVO = new UserIndexVO();userIndexVO.setUserId(userInfo.getId());userIndexVO.setUserType(userInfo.getUserType());userIndexVO.setName(userInfo.getName());userIndexVO.setNickName(userInfo.getNickName());userIndexVO.setHeadImg(userInfo.getHeadImg());userIndexVO.setBindStatus(userInfo.getBindStatus());userIndexVO.setAmount(userAccount.getAmount());userIndexVO.setFreezeAmount(userAccount.getFreezeAmount());userIndexVO.setLastLoginTime(userLoginRecord.getCreateTime());return userIndexVO;
}

30.2.2.、前端整合

脚本

pages/user/index.vue

fetchUserData() {this.$axios.$get('/api/core/userInfo/auth/getIndexUserInfo').then((response) => {this.userIndexVO = response.data.userIndexVO})
},

本文章参考B站 尚硅谷《尚融宝》Java微服务分布式金融项目,仅供个人学习使用,部分内容为本人自己见解,与尚硅谷无关。

相关内容

热门资讯

扎哈罗娃:欧盟仍在试图为没收俄... 当地时间12月19日,俄罗斯外交部发言人扎哈罗娃对欧盟峰会结果发表评论称,欧盟在批准向乌克兰提供新贷...
*ST太和(605081)披露... 截至2025年12月19日收盘,*ST太和(605081)报收于10.57元,较前一交易日下跌1.2...
中方:强烈不满,坚决反对,已多... 政知见2025-12-19 16:39:11 撰文 | 熊颖琪 12月19日,外交部发言人郭嘉昆主...
原创 仿... 【版权申明:本文为@影吹斯汀 独家原创稿,未经许可不得以任何形式抄袭or转载,违者必究!】 由詹姆斯...
女子称在亚朵酒店内用牙签,入口... 原标题:女子称在亚朵酒店内用牙签,入口后猛然发现可能是别人用过的,店方回应 近日,有网友发帖称,自己...
捡到宝了!泰国上将:中国没要求... 当地时间2025年12月15日,泰国国防部长对于,泰国特种兵在战场缴获大批,柬埔寨军人放弃的,中国制...
涉嫌严重违纪违法,李舜被查 据省纪委监委驻省教育厅纪检监察组、玉溪市监委消息:云南省教育厅教材和语言文字管理处原处长、一级调研员...
原创 鞠... 2025年12月19日,最近身陷流言蜚语的鞠婧祎被拍到低调现身街头,这是她与经纪公司丝芭传媒爆发合约...
广州越秀南路有两人受伤,警方通... 12月19日晚,广州市公安局越秀分局发布警情通报:2025年12月19日17时37分,广州110接群...
原创 金... 最近,大家都注意到特朗普单方面宣布允许英伟达对华出售H200芯片。作为交换,美国政府将对H200的所...