boss 2 週間 前
コミット
63886d2c16

+ 24 - 0
fs-admin/src/main/java/com/fs/admin/controller/CompanyAdminController.java

@@ -3,6 +3,7 @@ package com.fs.admin.controller;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.company.domain.Company;
@@ -11,7 +12,9 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
+import java.math.BigDecimal;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 总后台租户管理控制器
@@ -115,4 +118,25 @@ public class CompanyAdminController extends BaseController {
         result.put("disabledCount", all.size() - activeCount);
         return AjaxResult.success(result);
     }
+
+    /**
+     * 租户充值/扣款
+     */
+    @PreAuthorize("@ss.hasPermi('admin:company:edit')")
+    @Log(title = "租户管理", businessType = BusinessType.UPDATE)
+    @PostMapping("/{companyId}/recharge")
+    public AjaxResult rechargeCompany(@PathVariable Long companyId, @RequestBody Map<String, Object> params) {
+        String operateType = (String) params.get("operateType");
+        BigDecimal amount = null;
+        Object amountObj = params.get("amount");
+        if (amountObj != null) {
+            amount = new BigDecimal(amountObj.toString());
+        }
+        String remark = (String) params.get("remark");
+        R r = companyService.rechargeCompany(companyId, operateType, amount, remark);
+        if (r != null && Integer.valueOf(200).equals(r.get("code"))) {
+            return AjaxResult.success();
+        }
+        return AjaxResult.error(r != null ? (String) r.get("msg") : "操作失败");
+    }
 }

+ 11 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyService.java

@@ -210,4 +210,15 @@ public interface ICompanyService
     String checkMchTransferStatus(String outBatchNo,Long companyId);
 
     R checkMchTransferStatusByBatchID(String batchId, Long companyId);
+
+    /**
+     * 总后台租户充值/扣款
+     *
+     * @param companyId 租户ID
+     * @param operateType 操作类型: recharge-充值, deduct-扣款
+     * @param amount 金额(正数)
+     * @param remark 备注
+     * @return 操作结果
+     */
+    R rechargeCompany(Long companyId, String operateType, BigDecimal amount, String remark);
 }

+ 68 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java

@@ -1974,4 +1974,72 @@ public class CompanyServiceImpl implements ICompanyService
         }));
     }
 
+    /**
+     * 总后台租户充值/扣款
+     * 使用 selectCompanyByIdForUpdate 行锁保证原子性,
+     * 同一事务内更新余额并写入 company_money_logs 日志
+     *
+     * @param companyId    租户ID
+     * @param operateType  操作类型: recharge-充值, deduct-扣款
+     * @param amount       金额(正数)
+     * @param remark       备注
+     * @return 操作结果
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public R rechargeCompany(Long companyId, String operateType, BigDecimal amount, String remark) {
+        if (companyId == null || companyId <= 0) {
+            return R.fail("租户ID不能为空");
+        }
+        if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
+            return R.fail("金额必须大于0");
+        }
+        if (!"recharge".equals(operateType) && !"deduct".equals(operateType)) {
+            return R.fail("操作类型只能为 recharge 或 deduct");
+        }
+
+        Company company = companyMapper.selectCompanyByIdForUpdate(companyId);
+        if (company == null) {
+            return R.fail("租户不存在");
+        }
+
+        BigDecimal newBalance;
+        BigDecimal logMoney;
+        int logsType;
+        String logRemark;
+
+        if ("recharge".equals(operateType)) {
+            newBalance = company.getMoney().add(amount);
+            logMoney = amount;
+            logsType = 20; // 后台充值
+            logRemark = StringUtils.isNotEmpty(remark) ? "后台充值: " + remark : "后台充值";
+        } else {
+            // deduct
+            if (company.getMoney().compareTo(amount) < 0) {
+                return R.fail("余额不足,当前余额: " + company.getMoney());
+            }
+            newBalance = company.getMoney().subtract(amount);
+            logMoney = amount.multiply(new BigDecimal(-1));
+            logsType = 21; // 后台扣款
+            logRemark = StringUtils.isNotEmpty(remark) ? "后台扣款: " + remark : "后台扣款";
+        }
+
+        company.setMoney(newBalance);
+        companyMapper.updateCompany(company);
+
+        CompanyMoneyLogs log = new CompanyMoneyLogs();
+        log.setCompanyId(companyId);
+        log.setRemark(logRemark);
+        log.setMoney(logMoney);
+        log.setLogsType(logsType);
+        log.setBalance(newBalance);
+        log.setCreateTime(new Date());
+        moneyLogsMapper.insertCompanyMoneyLogs(log);
+
+        logger.info("后台操作租户余额, companyId={}, operateType={}, amount={}, newBalance={}",
+                companyId, operateType, amount, newBalance);
+
+        return R.ok();
+    }
+
 }