Browse Source

第一类团队分润处理完成

skyfffire 1 month ago
parent
commit
79955ada2c

+ 26 - 0
src/main/java/common/model/base/BaseDepositLog.java

@@ -73,6 +73,32 @@ public abstract class BaseDepositLog<M extends BaseDepositLog<M>> extends Model<
 	public java.lang.String getHygOrderNo() {
 		return getStr("hyg_order_no");
 	}
+	/**
+	 * 充值数量,负数是提现
+	 */
+	public void setAmount(java.lang.Integer amount) {
+		set("amount", amount);
+	}
+	
+	/**
+	 * 充值数量,负数是提现
+	 */
+	public java.lang.Integer getAmount() {
+		return getInt("amount");
+	}
+	/**
+	 * 充值记录描述
+	 */
+	public void setDescription(java.lang.String description) {
+		set("description", description);
+	}
+	
+	/**
+	 * 充值记录描述
+	 */
+	public java.lang.String getDescription() {
+		return getStr("description");
+	}
 	/**
 	 * 充值记录创建时间
 	 */

+ 6 - 1
src/main/java/modules/order/OrderService.java

@@ -1,6 +1,7 @@
 package modules.order;
 
 import com.alibaba.fastjson.JSONObject;
+import com.jfinal.aop.Inject;
 import com.jfinal.kit.StrKit;
 import com.jfinal.plugin.activerecord.Db;
 import com.jfinal.plugin.activerecord.Record;
@@ -11,6 +12,7 @@ import common.model.OrderLog;
 import common.model.User;
 import common.utils.bsn.BsnSDK;
 import common.utils.http.MyRet;
+import modules.user.UserService;
 import modules.user.UserTeamService;
 
 import java.math.BigDecimal;
@@ -21,6 +23,9 @@ import java.util.Map;
 import java.util.stream.Collectors;
 
 public class OrderService {
+    @Inject
+    UserService userService;
+    
     public String hello() {
         return "Hello order";
     }
@@ -212,7 +217,7 @@ public class OrderService {
                             AppConfig.LOGGER.info("该订单已确权:{}", order);
                             
                             // 异步执行分润过程
-                            AppConfig.TaskScheduler.submit(new UserTeamService(order));
+                            AppConfig.TaskScheduler.submit(new UserTeamService(order, userService));
                         }
                         
                         // status为2时是交付失败,自动执行退款

+ 6 - 2
src/main/java/modules/user/UserController.java

@@ -277,7 +277,7 @@ public class UserController extends MyController {
     public void hygDeposited() {
         JSONObject requestBodyJson = MyController.getJsonModelByRequestAndType(getRequest(), JSONObject.class);
 
-        AppConfig.LOGGER.info("hygDeposited " + requestBodyJson);
+        AppConfig.LOGGER.info("hygDeposited {}", requestBodyJson);
 
         // 每条回调都保存到数据库
         DepositLog log = new DepositLog();
@@ -299,15 +299,19 @@ public class UserController extends MyController {
                 User user = service.findUserByBankCard(payerAccount);
                 
                 // 有充值信息但是未找到充值者
+                Integer paymentAmount = businessBody.getInteger("paymentAmount");
                 if (user == null) {
+                    log.setDescription("未找到充值者");
+                    log.setAmount(paymentAmount);
                     log.setUserId((long) -1);
                 } else {
                     // 对用户进行充值
-                    Integer paymentAmount = businessBody.getInteger("paymentAmount");
                     user.setBalance(user.getBalance() + paymentAmount);
                     user.update();
                     
                     // 交易者信息存档
+                    log.setDescription("用户充值");
+                    log.setAmount(paymentAmount);
                     log.setUserId(user.getId());
                 }
 

+ 108 - 16
src/main/java/modules/user/UserTeamService.java

@@ -1,31 +1,123 @@
 package modules.user;
 
+import com.jfinal.plugin.activerecord.Db;
 import common.jfinal.AppConfig;
+import common.model.DepositLog;
 import common.model.Order;
+import common.model.User;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 
 public class UserTeamService implements Runnable {    
     Order order;
+    UserService userService;
 
-    public UserTeamService(Order order) {
+    public UserTeamService(Order order, UserService userService) {
+        this.userService = userService;
         this.order = order;
     }
+
+    // 统一分润逻辑,并进行容错和类型转换 (BigDecimal)
+    private void processShare(String mobileNumber, BigDecimal percentage, String description) throws Exception {
+        // 确保 order.getTotalPrice() 返回的是 BigDecimal,或者转换为 BigDecimal
+        BigDecimal totalPrice = order.getBigDecimal("total_price");
+        if (totalPrice == null) {
+            throw new RuntimeException("订单总价为空,无法分润");
+        }
+
+        // 计算分润金额
+        // 使用 BigDecimal 进行精确计算,避免浮点数精度问题
+        BigDecimal shareAmount = totalPrice.multiply(percentage).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
+
+        // 查找用户 (userService 是注入的)
+        User user = userService.findUserByMobileNumber(mobileNumber);
+        if (user == null) {
+            AppConfig.LOGGER.warn("分润用户 {} 不存在,无法分润", mobileNumber);
+            // 根据业务需求抛出异常或跳过
+            return;
+        }
+
+        // 更新用户余额
+        BigDecimal currentBalance = user.getBigDecimal("balance");
+        // 如果 balance 字段为 null,初始化为 0
+        if (currentBalance == null) {
+            currentBalance = BigDecimal.ZERO;
+        }
+        user.set("balance", currentBalance.add(shareAmount));
+        if (!user.update()) {
+            throw new RuntimeException("更新用户 " + user.getStr("nickname") + " 余额失败");
+        }
+
+        // 记录分润日志
+        DepositLog log = new DepositLog();
+        log.set("create_time", System.currentTimeMillis());
+        log.set("is_deleted", 0);
+        log.set("description", description + " " + percentage.intValue() + "%"); // 描述中带上百分比
+        log.set("amount", shareAmount);
+        log.set("user_id", user.getLong("id"));
+        if (!log.save()) {
+            throw new RuntimeException("保存分润日志失败 for user " + user.getStr("nickname"));
+        }
+        AppConfig.LOGGER.info("{} {}: {}", description, user.getStr("nickname"), shareAmount);
+    }
+
+    /**
+     * 第一类、单独账号分润
+     *      0. 大领导 2%
+     *      1. 团队奖励 5%
+     *      2. 市场预留 3%
+     *      4. 宣传外联 4%
+     *      4. 技术公司运维 1%
+     *      5. 平台费用 1%
+     */
+    public void class1() throws Exception {
+        AppConfig.LOGGER.info("正在处理订单 {} 的第一类分润", order.getLong("id"));
+
+        // 确保这些手机号是常量,或者从配置中读取
+        processShare("27788881000", BigDecimal.valueOf(2), "大领导分润");
+        processShare("27788881001", BigDecimal.valueOf(5), "团队奖励");
+        processShare("27788881002", BigDecimal.valueOf(3), "市场预留");
+        processShare("27788881003", BigDecimal.valueOf(4), "宣传外联");
+        // 注意这里是 1%,用 BigDecimal.valueOf(1)
+        processShare("27788881004", BigDecimal.valueOf(1), "技术公司运维");
+        processShare("27788881005", BigDecimal.valueOf(1), "平台费用");
+
+        AppConfig.LOGGER.info("订单 {} 第一类分润处理完成", order.getLong("id"));
+    }
+
+    /**
+     * 第二类、直推分润 10%
+     */
+    public void class2() {}
+
+    /**
+     * 第三类、NFT持有者分润
+     *      1. 10%的部分
+     *      2. 4%的部分
+     */
+    public void class3() {}
+
+    /**
+     * 第四类、持有者激励分润,这个最复杂最后做,可能需要为user加一个时间戳字段
+     */
+    public void class4() {}
     
     @Override
     public void run() {
-        // 第一类、单独账号分润
-        //      1. 团队奖励 5%
-        //      2. 市场预留 3%
-        //      3. 大领导 2%
-        //      4. 宣传外联 4%
-        //      5. 技术公司运维 1%
-        //      6. 平台费用 1%
-        
-        // 第二类、直推分润 10%
-        
-        // 第三类、NFT持有者分润
-        //      1. 10%的部分
-        //      2. 4%的部分
-        
-        // 第四类、持有者激励分润,这个最复杂最后做,可能需要为user加一个时间戳字段
+        // 确保整个分润过程在一个数据库事务中
+        // 因为操作涉及到多个 User 和 DepositLog 的更新和插入
+        Db.tx(() -> {
+            try {
+                this.class1();
+                this.class2(); // 如果有 DB 操作,也需要放在事务中
+                this.class3(); // 如果有 DB 操作,也需要放在事务中
+                this.class4(); // 如果有 DB 操作,也需要放在事务中
+                return true; // 事务成功
+            } catch (Exception e) {
+                AppConfig.LOGGER.error("订单分润处理异常,订单ID: {}, 错误: {}", order.getLong("id"), e.getMessage(), e);
+                return false; // 事务失败,回滚
+            }
+        });
     }
 }

+ 10 - 0
src/test/rest/UserControllerTest.http

@@ -13,6 +13,16 @@ POST {{ baseUrl }}/user/hello
 #POST {{ baseUrl }}/user/hygSign
 #Content-Type: application/json
 
+#### 模拟慧用工充值回调,要加密,不好处理
+#POST {{ baseUrl }}/user/hygDeposited
+#Content-Type: application/json
+#
+#{
+#  "mobile_number": "17781855864",
+#  "pwd_md5": "e10adc3949ba59abbe56e057f20f883e",
+#  "verify_code": ""
+#}
+
 
 ### 登录,可以选择传入pwd_md5(密码登录)或verify_code(验证码登录)。如果两者都传入了,后台会优先使用pwd_md5
 ### 登录成功后会返token回来,后面请求需要用户状态的接口都需要携带到headers里面,key是dl-token