From 7f508071701c1833ecd01cc080221a9e5d2fc2e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B5=B7?= <10402852@qq.com> Date: Sat, 17 Aug 2024 09:16:24 +0800 Subject: [PATCH] 'commit' --- .../service/UserRefundServiceImpl.java | 32 +++++-- 业务梳理/自动退款逻辑.md | 86 +++++++++++-------- 2 files changed, 75 insertions(+), 43 deletions(-) diff --git a/Ylt/ms-finance/src/main/java/com/charge/finance/service/UserRefundServiceImpl.java b/Ylt/ms-finance/src/main/java/com/charge/finance/service/UserRefundServiceImpl.java index de8103f..16faeb8 100644 --- a/Ylt/ms-finance/src/main/java/com/charge/finance/service/UserRefundServiceImpl.java +++ b/Ylt/ms-finance/src/main/java/com/charge/finance/service/UserRefundServiceImpl.java @@ -332,7 +332,7 @@ public class UserRefundServiceImpl { return OutData.ERROR("该账户不允许在线退款。"); } } - //检查是否存在未结束的订单 + //检查是否存在未结束的订单,存在未结束的订单,则不能申请退款 int chargeOrderNum = userRefundMapper.countOrderFromRefund(userId); if (chargeOrderNum > 0) { return OutData.ERROR("存在未结束的订单,请等订单结束后申请!"); @@ -342,7 +342,7 @@ public class UserRefundServiceImpl { Map rechargeMap; double refundFee; //t_user_refund - //用户退款表 + //用户申请退款表 String orderNO = "UT" + Tools.getDate4() + userId;//订单号 refundMap.put("userId", userId); refundMap.put("order_no", orderNO); @@ -353,12 +353,13 @@ public class UserRefundServiceImpl { refundMap.put("comm", "");//备注 refundMap.put("create_time", now); refundMap.put("update_time", now); - userRefundMapper.insertUserRefund(refundMap);//插入退款表 + userRefundMapper.insertUserRefund(refundMap);//插入用户申请退款表 //退款金额 if (null == cash) { cash = "0.0"; } + //用户可以申请退款的金额 Double userAbleReal = Double.parseDouble(cash); //进行所有充值订单的退款合法性校验 @@ -370,21 +371,34 @@ public class UserRefundServiceImpl { //进行退款订单是否自动退款的判断 boolean autoRefund = false; //产品管理配置+数据字典配置+退款金额<=退款阈值 才能自动退款 + // select value from t_biz_parameter where state = 1 and code = 'automatic_refund.enabled' + // 系统当前值是0,即不开启自动退款 String autoRefundCheck = commonMapper.getAutoRefundCheck(Const.AUTO_REFUND_CHECK); + //自动退款阈值 + // select * from t_dict where code='automaticRefundAmount' + // select dict_key from t_dict where code = 'automaticRefundAmount' and parent_id != 0 and is_deleted = 0 and is_sealed = 0 order by id desc limit 1 + // 在数据库中就没有找到这个自动退款的阀值,原因不明 String autoRefundAmount = commonMapper.getAutoRefundAmount(Const.AUTOMATIC_REFUND_AMOUNT); - if (StringUtils.isNotEmpty(autoRefundCheck) && Const.AUTOMATIC_REFUND_OPEN.equals(autoRefundCheck) && StringUtils.isNotEmpty(autoRefundAmount) + if (StringUtils.isNotEmpty(autoRefundCheck) //自动退款标识存在 + && Const.AUTOMATIC_REFUND_OPEN.equals(autoRefundCheck)//而且自动退款标识为1(目前数据库中是0) + && StringUtils.isNotEmpty(autoRefundAmount)//自动退款阀值不为空 + //申请退款的金额小于自动退款阀值 && BigDecimal.valueOf(userAbleReal).doubleValue() <= (new BigDecimal(autoRefundAmount)).doubleValue()) { - autoRefund = true; + autoRefund = true;//可以自动退款 } UserAccount uaInfo = userAccountMapper.selectAccount(userId); + //如果退款金额大于用户充值金额 + //Q:为什么会出现这样的情况? + //t_user_account表中有一个字段ua_real_balance,表示用户可用退款金额 + // 这里这样判断应该是怕因为程序BUG导致退款金额大于用户充值金额,对系统的一种保护策略 if (userAbleReal > uaInfo.getUa_real_balance()) {//用户充值金额 userAbleReal = uaInfo.getUa_real_balance();//退款金额不能大于用户充值金额 } - + //遍历每个退款申请 for (int i = 0; i < ids.length; i++) { String idParam = ids[i]; - if (userAbleReal <= 0) { + if (userAbleReal <= 0) {//userAbleReal在循环内应该是逐渐变小,当不再需要继续退款的时候,跳出循环 break; } PayConfig payBean = payRepository.findByPridAndUserId(idParam, userId); @@ -398,11 +412,13 @@ public class UserRefundServiceImpl { return OutData.ERROR("退款失败"); } Double payMoney = payBean.getPayMoney(); - + //本笔充值金额大于用户可以退款的金额 if (payMoney > userAbleReal) { + //本次充值金额部分退掉就够了 refundFee = userAbleReal; // payBean.setRefundMoney(String.valueOf(uaInfo.getUa_real_balance())); } else { + //本次充值金额全部退掉 refundFee = payBean.getPayMoney(); //payBean.setRefundMoney(String.valueOf(payBean.getPayMoney())); } diff --git a/业务梳理/自动退款逻辑.md b/业务梳理/自动退款逻辑.md index 15420e3..89157f5 100644 --- a/业务梳理/自动退款逻辑.md +++ b/业务梳理/自动退款逻辑.md @@ -2,72 +2,88 @@ #### 原始需求 -- 没有参加充值活动,并且,账户余额小于50元(后台可以设置),系统自动退款原路返回。 -- 个人用户----用户充值 ---- 充电消费----余额到用户钱包,可以下次消费,如果没有参加充值送券活动,则该笔充值可以申请退款。后骒审核信息无误,可以原路退回。 +- 没有参加充值活动,并且,账户余额小于$50$元(后台可以设置),系统自动退款原路返回。 +- 个人用户----用户充值 ---- 充电消费----余额到用户钱包,可以下次消费,如果没有参加充值送券活动,则该笔充值可以申请退款。后面审核信息无误,可以原路退回。 -#### 开发思路 +#### 源码解读与分析 -- 微信小程序端调用 /financeapi/userRefund/recDataListNew 获取可以退款的订单列表。 +**$Q_1:$ 用户的账户是通过什么方式进行充值的?** ->

解释:原来就有的接口,必须小程序来调用

+答:每次充值,是存在一个充值账单的,表名:$t\_account\_recharge$,每次充值都要向这张表中添加一条充值记录,充值有两种情况,一种是不参加活动的,另一种是参加活动的,在系统设计之初就明确了参加活动的充值单是不能参加退款的,后面还会有详细的论述。 -- 微信小程序将拿到的订单ids传递给后端接口 xxxxx: +**$Q_2$:账户余额是怎么产生的?有什么特殊需要注意的地方?** -​ 接口逻辑如下: +答: -​ (1) 获取允许退款的余额阀值,如果小于这个阀值才可以自动退款 +- 用户通过$N$次充值,使得账户余额增加,通过$M$次充电消费,使得账户余额减少。 -​ (2) 没有参加过充值活动的 +充值时可能因为充值活动等原因,实际得到的金额大于充值金额,最终汇集到余额中。 -​ 删除一些无效ID后,生成一个新的ids列表返回给微信小程序,告诉小程序,这些是真的可以自动恳求的订单。 +举个例子:如果用户充了$100$元,因为活动的原因,实得$120$元,那么用户的余额就是$120$元。如果他充电消费了$20$元,那么他的账户余额就是$100$元。很明显,此时账户内的余额是不能进行退款的,要不电站就赔了。 +所以,系统设计者发现:**不能提供余额退款功能!** +既然不能按余额进行退款,那就不退了吗?人家用户假设充了$30$元,用了$25$元,没有参加活动,有余额$5$元,以后也不想来充电了,电站不提供退款肯定是说不通。 -- 微信小程序循环所有ids,调用 /financeapi/userRefund/apply 发起此笔订单的退款申请,这样,在数据库中就生成了这些有效的退款申请单。 ->

解释:原来就有的接口,必须小程序来调用

+系统设计者在这样的前提下,想到不能退款的原因是:参加了充值活动造成余额是虚的,是不是可以把参加活动的充值单不参加讨论就能解决问题呢? +按这个思路思考,把充值订单进行区分,划分为两类: -- 微信小程序调用 后端接口yyyyy,将ids作为参数让后端接口把此人的所有已申请的退款记录通过审核。 - -```html -http://10.10.14.77:7003/financeapi/userRefund/agreeV2?rechargeId=431052&memo=%E6%88%91%E5%90%8C%E6%84%8F&rechargeOperer=superadmin&refundFee=171.03 -``` +1. 不参加活动的订单 (有效退款订单) +2. 参加活动的订单 (无效退款订单) +同时,系统设计者在用户账户表上就做了分类处理: +![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202408170858077.png) -> **下面是相关的一些细节** -#### 阀值 +### 系统源码上是支持用户申请退款,然后系统自动完成退款的,逻辑也是 -tkMoneyFaZhi +- 不参加活动的充值 -| tkMoneyFaZhi | 退款金额阀值 | 50 | -| ------------ | ------------ | ---- | -| | | | +- 低于约定的阀值 -- + ### 但不清楚为什么现在的配置上没有开启自动退款,需要向快卜的开发人员咨询。 -``` -D:\dsWork\YltProject\Ylt\ms-finance\src\main\java\com\charge\finance\controller\RecManageController.java -``` +```java +//进行退款订单是否自动退款的判断 +boolean autoRefund = false; +//产品管理配置+数据字典配置+退款金额<=退款阈值 才能自动退款 +// select value from t_biz_parameter where state = 1 and code = 'automatic_refund.enabled' -$Q$:如何知道一条充值订单是不是可以退款? +// 系统当前值是0,即不开启自动退款 +String autoRefundCheck = commonMapper.getAutoRefundCheck(Const.AUTO_REFUND_CHECK); +//自动退款阈值 +// select * from t_dict where code='automaticRefundAmount' +// select dict_key from t_dict where code = 'automaticRefundAmount' and parent_id != 0 and is_deleted = 0 and is_sealed = 0 order by id desc limit 1 +// 在数据库中就没有找到这个自动退款的阀值,原因不明 +String autoRefundAmount = commonMapper.getAutoRefundAmount(Const.AUTOMATIC_REFUND_AMOUNT); + if (StringUtils.isNotEmpty(autoRefundCheck) //自动退款标识存在 + && Const.AUTOMATIC_REFUND_OPEN.equals(autoRefundCheck)//而且自动退款标识为1(目前数据库中是0) + && StringUtils.isNotEmpty(autoRefundAmount)//自动退款阀值不为空 + //申请退款的金额小于自动退款阀值 + && BigDecimal.valueOf(userAbleReal).doubleValue() <= (new BigDecimal(autoRefundAmount)).doubleValue()) { + autoRefund = true;//可以自动退款 + } -用户在申请退款时,如果这笔充值参加了活动,用户就不能选择这笔充值退款。 -$refund\_state$ $6$款状态(0未退款 1已退款 2 退款失败 3退款申请审核 4未退款驳回 5建帮活动不可退款) - -![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202408151410729.png) - -```sql -select * from t_account_recharge where user_id=53958 and refund_state=6 order by id desc +... + + + //自动退款逻辑 +if (autoRefund) { + autoRefundAsync(payBean.getId(), refundReason); +} + ``` +![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202408170846535.png) +