|
|
@@ -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; // 事务失败,回滚
|
|
|
+ }
|
|
|
+ });
|
|
|
}
|
|
|
}
|