尚融宝29-提现和还款

news2024/11/15 22:51:10

目录

一、提现

(一)需求

(二)前端

(三)后端

1、提现接口

2、回调接口

二、还款

(一)需求

(二)前端

(三)后端

1、还款接口

2、回调接口


一、提现

(一)需求

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

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

(二)前端

pages/user/withdraw.vue

<script>
export default {
  data() {
    return {
      fetchAmt: 0,
    }
  },

  methods: {
    commitWithdraw() {
      this.$alert(
        '<div style="size: 18px;color: red;">您即将前往汇付宝提现</div>',
        '前往汇付宝资金托管平台',
        {
          dangerouslyUseHTMLString: true,
          confirmButtonText: '立即前往',
          callback: (action) => {
            if (action === 'confirm') {
              this.$axios
                .$post(
                  '/api/core/userAccount/auth/commitWithdraw/' + this.fetchAmt
                )
                .then((response) => {
                  document.write(response.data.formStr)
                })
            }
          },
        }
      )
    },
  },
}
</script>

(三)后端

1、提现接口

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);
}

接口: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<String, Object> 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;
}

2、回调接口

UserAccountController

@ApiOperation("用户提现异步回调")
@PostMapping("/notifyWithdraw")
public String notifyWithdraw(HttpServletRequest request) {
    Map<String, Object> 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";
}

接口:UserAccountService

void notifyWithdraw(Map<String, Object> paramMap);

 实现:UserAccountServiceImpl

@Transactional(rollbackFor = Exception.class)
@Override
public void notifyWithdraw(Map<String, Object> 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);
}

二、还款

(一)需求

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

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

(二)前端

还款按钮pages/lend/_id.vue

<td>
    <a href="javascript:" @click="commitReturn(lendReturn.id)">
        {{ lendReturn.status === 0 ? '还款' : '' }}
    </a>
</td>

脚本pages/lend/_id.vue

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

(三)后端

1、还款接口

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);
}

接口: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);

    //获取借款人code
    String bindCode = userBindService.getBindCodeByUserId(userId);
    //获取lend
    Long lendId = lendReturn.getLendId();
    Lend lend = lendMapper.selectById(lendId);

    Map<String, Object> 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<Map<String, Object>> 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;
}

还款明细service

根据还款id获取回款列表

LendReturnService接口:

List<Map<String, Object>> 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<Map<String, Object>> addReturnDetail(Long lendReturnId) {

    //获取还款记录
    LendReturn lendReturn = lendReturnMapper.selectById(lendReturnId);
    //获取标的信息
    Lend lend = lendMapper.selectById(lendReturn.getLendId());

    //根据还款id获取回款列表
    List<LendItemReturn> lendItemReturnList = this.selectLendItemReturnList(lendReturnId);
    List<Map<String, Object>> lendItemReturnDetailList = new ArrayList<>();
    for(LendItemReturn lendItemReturn : lendItemReturnList) {
        LendItem lendItem = lendItemMapper.selectById(lendItemReturn.getLendItemId());
        String bindCode = userBindService.getBindCodeByUserId(lendItem.getInvestUserId());

        Map<String, Object> 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<LendItemReturn> selectLendItemReturnList(Long lendReturnId);

实现:

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

2、回调接口

LendReturnController

@ApiOperation("还款异步回调")
@PostMapping("/notifyUrl")
public String notifyUrl(HttpServletRequest request) {

    Map<String, Object> 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";
}

接口:LendReturnService

void notify(Map<String, Object> 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<String, Object> 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<LendReturn>();
    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<LendItemReturn> 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(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);

    });
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/487434.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第一章:概述

1&#xff0c;因特网概述 1.网络、互联网和英特网 网络(Network)由若干结点(Node)和连接这些结点的链路(Link)组成。 多个网络还可以通过路由器互连起来&#xff0c;这样就构成了一个覆盖范围更大的网络&#xff0c;即互联网(或互连网)。因此&#xff0c;互联网是“网络的网络…

UE蓝图基础学习笔记(未完待续2023/05/03)

文章目录 一、项目创建1&#xff09;准备流程&#xff08;选择模板、开发语言、平台、质量等&#xff09;2&#xff09;界面介绍 二、Actor三、操作关卡对象&#xff08;旋转、移动、缩放和坐标轴&#xff09;四、常用快捷键五、运行游戏六、蓝图介绍七、蓝图节点八、操作事件图…

Azure DevOps Server 2022.0.1升级手册

Contents 1. 概述2. 操作方法 2.1 安装操作系统2.2 安装数据库2.4 还原数据2.3 安装和配置Azure DevOps Server 1. 概述 Azure DevOps Server 是微软公司经过20多年的持续开发&#xff0c;逐渐将需求管理、敏捷实践、源代码管理、持续集成等功能集成一体&#xff0c;实现应用软…

AutoHotKey简单入门

简单入门 快捷键 ^j::Send, Hello world! Return^j::代表CtrlJ&#xff0c;其中^代表Ctrl键 Send命令&#xff1a;在光标处输入Hello world! 也就是说&#xff0c;你按下CtrlJ后&#xff0c;将会输入字符串Hello world! Return即返回 热字串 ::ftw::Free the whales Ret…

抖音营销策略:新手如何利用抖音提高品牌曝光度

随着短规频平台的兴起&#xff0c;抖音作为其中的校佼者&#xff0c;已经成为了众多用户和企业的营销利器。但是&#xff0c;对于抖音新手而言&#xff0c;如何在这个平台上快速提升影响力呢?下面不若与众就为大家分享几个实用的方法。 一、关注抖音热门话题和潮流 抖音平台上…

力扣题库刷题笔记581-最短无序连续子数组

1、题目如下&#xff1a; 2、题解代码实现&#xff1a; 浅看题解&#xff0c;解题思路和本人接替思路一毛一样&#xff0c;奈何没有想到用双指针&#xff0c;在代码实现上也存在问题。当知道用双指针的时候&#xff0c;本题也变得相对简单。思路如下&#xff1a; a、输入仅存在…

Vue条件渲染v-if和v-show

条件渲染v-if和v-show <div id"root"><!-- <div v-if"true">v-if</div>--> <!-- <div v-show"true">v-show</div>--> n:{{n}}<button click"n">点击n</button><div v…

法规标准-UN R152标准解读

UN R152是做什么的&#xff1f; UN R152 全名为关于M1和N1型机动车高级紧急制动系统&#xff08;AEBS&#xff09;型式认证的统一规定&#xff0c;是联合国对于M1和N1型车辆AEBS系统认证的要求说明&#xff0c;当满足其要求内容时&#xff0c;才可通过联合国的认证&#xff0c…

数字化转型导师坚鹏:面向数字化转型的大数据顶层设计实践

面向数字化转型的大数据顶层设计实践 课程背景&#xff1a; 数字化背景下&#xff0c;很多企业存在以下问题&#xff1a; 不清楚大数据思维如何建立&#xff1f; 不清楚企业大数据分析方法&#xff1f; 不了解大数据应用成功案例&#xff1f; 课程特色&#xff1a; …

(转载)01.Matplotlib 图像结构-figure()axes设置

​概要&#xff1a;介绍matplotlib 绘制图像起手&#xff0c; figure() 的设置&#xff0c; axes() 的设置。主要的内容可移步最后部分的总结。 04 Matplotlib 总结 Matplotlib 提供了matplotlib.figure图形类模块&#xff0c;它包含了创建图形对象的方法。通过调用 pyplot 模…

Hive3面试基础

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、基本知识Hive31.表的类型和表的存储格式a)b)c)创建表i&#xff09;ii&#xff09; 2.表 二、使用步骤1.引入库2.读入数据 总结 前言 面试准备之Hive 回顾…

个人代码管理

项目描述&#xff1a; 在公司使用软件大家会经常使用GitLab进行代码管理&#xff0c;但是GitLab对于个人使用会有&#xff0c;操作相对复杂&#xff0c;且需要收费。GitHub的代码又都是开放的。经过上网查找和尝试&#xff0c;找到了一个可以日常用来保存自己代码的工具。&…

吴恩达和OpenAI的《面向开发者的ChatGPT提示工程》精华笔记

《ChatGPT Prompt Engineering for Developers》 面向开发者的ChatGPT提示工程 shadow 趁着假期&#xff0c;学习了prompt课程&#xff0c;做了一些精简和关键知识点的梳理&#xff0c;分享给大家。 LLM 可完成的任务 包括: 总结&#xff08;如总结用户评论&#xff09; 推断&a…

streamlit+pywebview,纯python以前后端形式写桌面应用

1、VSCode VSCode VSCode扩展&#xff1a;Python 2、配置PowerShell执行策略 以管理员身份运行PowerShell&#xff0c;运行Set-ExecutionPolicy RemoteSigned&#xff0c;并输入Y&#xff0c;回车确认 3、配置Python环境 只安装Python&#xff1a;华为镜像、阿里镜像、new…

DC-DC直流隔离升压高压输出电源模块12v24v48v转50V110V200V250V350V400V500V600V800V1000V微功率

特点 效率高达 80%以上1*2英寸标准封装单电压输出价格低稳压输出工作温度: -40℃~85℃阻燃封装&#xff0c;满足UL94-V0 要求温度特性好可直接焊在PCB 上 应用 HRB W2~40W 系列模块电源是一种DC-DC升压变换器。该模块电源的输入电压分为&#xff1a;4.5~9V、9~18V、及18~36V、…

Android 编译模块 (小记)

1.整编 source build/envbuild.sh lunch xxx make 2.单独编译模块 2.1 去Android.bp 中找模块名 比如我想编译system/core/fastboot&#xff0c;那么我就去找这个路径下的Android.bp/ Android.mk Android.bp 中找每个模块的那么就行 然后直接make这个name make fastboot_…

通过【Stable-Diffusion WEBUI】复刻属于你的女神:再谈模型与参数

文章目录 &#xff08;零&#xff09;前言&#xff08;一&#xff09;复刻优秀的作品&#xff08;1.1&#xff09;模型&#xff08;1.1.1&#xff09;Model Hash &#xff08;1.2&#xff09;提示词&#xff08;1.2.1&#xff09;反推提示词 &#xff08;1.3&#xff09;参数 &…

GaussDB数据库基础函数介绍-上

目录 一、函数在数据库中的作用 二、GaussDB常用基础函数介绍与示例 1、数字操作函数 2、时间和日期处理函数 3、类型转换函数 4、数组函数 5、范围函数 6、窗口函数 7、聚集函数 8、安全函数 9、系统信息函数 10、动态脱敏函数. Tip&#xff1a;由于篇幅缘故&…

shell脚本的条件判断式

文章目录 shell脚本的条件判断式利用 if...then单层、简单条件判断式多重、复杂条件判断式例题1例题2 利用case...esac判断例题1 利用function功能例题1 shell脚本的条件判断式 很多时候我们必须要根据某些数来判断程序该如何举例来说&#xff0c;我们在之前的练习中让用户输入…

jsp网上拍卖管理系统统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 jsp网上拍卖管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&a…