|
|
@@ -0,0 +1,211 @@
|
|
|
+package org.dromara.main.service.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.date.DateUtil;
|
|
|
+import cn.hutool.core.util.RandomUtil;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.dromara.common.core.exception.ServiceException;
|
|
|
+import org.dromara.main.domain.CompanyAccountFlow;
|
|
|
+import org.dromara.main.mapper.CompanyAccountFlowMapper;
|
|
|
+import org.dromara.main.service.ICompanyAccountService;
|
|
|
+import org.dromara.system.domain.SysTenant;
|
|
|
+import org.dromara.system.mapper.SysTenantMapper;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.util.Date;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 企业账户服务实现
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@RequiredArgsConstructor
|
|
|
+@Service
|
|
|
+public class CompanyAccountServiceImpl implements ICompanyAccountService {
|
|
|
+
|
|
|
+ private final SysTenantMapper sysTenantMapper;
|
|
|
+ private final CompanyAccountFlowMapper companyAccountFlowMapper;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Boolean checkAvailableBalance(Long companyId, BigDecimal amount) {
|
|
|
+ SysTenant tenant = getTenant(companyId);
|
|
|
+ return defaultAmount(tenant.getAvailableBalance()).compareTo(defaultAmount(amount)) >= 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Boolean addCommission(Long companyId, BigDecimal amount, Long orderId, String orderNo, String remark) {
|
|
|
+ SysTenant tenant = getTenant(companyId);
|
|
|
+ BigDecimal delta = defaultAmount(amount);
|
|
|
+ BigDecimal availableBefore = defaultAmount(tenant.getAvailableBalance());
|
|
|
+ BigDecimal availableAfter = availableBefore.add(delta);
|
|
|
+
|
|
|
+ updateTenantBalance(tenant.getId(), availableAfter, null, null, null);
|
|
|
+ insertFlow(tenant, 1, delta, 1, availableBefore, availableAfter, 4, orderId, orderNo, remark);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Boolean payByBalance(Long companyId, BigDecimal amount, Long orderId, String orderNo, String remark) {
|
|
|
+ SysTenant tenant = getTenant(companyId);
|
|
|
+ BigDecimal delta = defaultAmount(amount);
|
|
|
+ BigDecimal availableBefore = defaultAmount(tenant.getAvailableBalance());
|
|
|
+ BigDecimal inUseBefore = defaultAmount(tenant.getInUseBalance());
|
|
|
+ if (availableBefore.compareTo(delta) < 0) {
|
|
|
+ throw new ServiceException("可使用余额不足,当前可用余额:{}元", availableBefore);
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal availableAfter = availableBefore.subtract(delta);
|
|
|
+ BigDecimal inUseAfter = inUseBefore.add(delta);
|
|
|
+ updateTenantBalance(tenant.getId(), availableAfter, inUseAfter, null, null);
|
|
|
+
|
|
|
+ insertFlow(tenant, 2, delta, 1, availableBefore, availableAfter, 2, orderId, orderNo, remark);
|
|
|
+ insertFlow(tenant, 1, delta, 2, inUseBefore, inUseAfter, 2, orderId, orderNo, remark + "(冻结)");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Boolean deductInUseBalance(Long companyId, BigDecimal amount, Long orderId, String orderNo, String remark) {
|
|
|
+ SysTenant tenant = getTenant(companyId);
|
|
|
+ BigDecimal delta = defaultAmount(amount);
|
|
|
+ BigDecimal inUseBefore = defaultAmount(tenant.getInUseBalance());
|
|
|
+ BigDecimal totalConsumeBefore = defaultAmount(tenant.getTotalConsume());
|
|
|
+ if (inUseBefore.compareTo(delta) < 0) {
|
|
|
+ throw new ServiceException("使用中余额不足");
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal inUseAfter = inUseBefore.subtract(delta);
|
|
|
+ BigDecimal totalConsumeAfter = totalConsumeBefore.add(delta);
|
|
|
+ updateTenantBalance(tenant.getId(), null, inUseAfter, null, totalConsumeAfter);
|
|
|
+
|
|
|
+ insertFlow(tenant, 2, delta, 2, inUseBefore, inUseAfter, 8, orderId, orderNo, remark);
|
|
|
+ insertFlow(tenant, 1, delta, 4, totalConsumeBefore, totalConsumeAfter, 8, orderId, orderNo, remark);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Boolean refundToAvailable(Long companyId, BigDecimal amount, Long orderId, String orderNo, String remark) {
|
|
|
+ SysTenant tenant = getTenant(companyId);
|
|
|
+ BigDecimal delta = defaultAmount(amount);
|
|
|
+ BigDecimal inUseBefore = defaultAmount(tenant.getInUseBalance());
|
|
|
+ BigDecimal availableBefore = defaultAmount(tenant.getAvailableBalance());
|
|
|
+ if (inUseBefore.compareTo(delta) < 0) {
|
|
|
+ throw new ServiceException("使用中余额不足");
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal inUseAfter = inUseBefore.subtract(delta);
|
|
|
+ BigDecimal availableAfter = availableBefore.add(delta);
|
|
|
+ updateTenantBalance(tenant.getId(), availableAfter, inUseAfter, null, null);
|
|
|
+
|
|
|
+ insertFlow(tenant, 2, delta, 2, inUseBefore, inUseAfter, 3, orderId, orderNo, remark + "(解冻)");
|
|
|
+ insertFlow(tenant, 1, delta, 1, availableBefore, availableAfter, 3, orderId, orderNo, remark);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Boolean applyWithdraw(Long companyId, BigDecimal amount, String withdrawNo, String remark) {
|
|
|
+ SysTenant tenant = getTenant(companyId);
|
|
|
+ BigDecimal delta = defaultAmount(amount);
|
|
|
+ BigDecimal availableBefore = defaultAmount(tenant.getAvailableBalance());
|
|
|
+ BigDecimal withdrawingBefore = defaultAmount(tenant.getWithdrawingBalance());
|
|
|
+ if (availableBefore.compareTo(delta) < 0) {
|
|
|
+ throw new ServiceException("可使用余额不足,当前可用余额:{}元", availableBefore);
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal availableAfter = availableBefore.subtract(delta);
|
|
|
+ BigDecimal withdrawingAfter = withdrawingBefore.add(delta);
|
|
|
+ updateTenantBalance(tenant.getId(), availableAfter, null, withdrawingAfter, null);
|
|
|
+
|
|
|
+ insertFlow(tenant, 2, delta, 1, availableBefore, availableAfter, 5, null, withdrawNo, remark);
|
|
|
+ insertFlow(tenant, 1, delta, 3, withdrawingBefore, withdrawingAfter, 5, null, withdrawNo, remark + "(冻结)");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Boolean deductWithdrawingBalance(Long companyId, BigDecimal amount, String withdrawNo, String remark) {
|
|
|
+ SysTenant tenant = getTenant(companyId);
|
|
|
+ BigDecimal delta = defaultAmount(amount);
|
|
|
+ BigDecimal withdrawingBefore = defaultAmount(tenant.getWithdrawingBalance());
|
|
|
+ if (withdrawingBefore.compareTo(delta) < 0) {
|
|
|
+ throw new ServiceException("提现中余额不足");
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal withdrawingAfter = withdrawingBefore.subtract(delta);
|
|
|
+ updateTenantBalance(tenant.getId(), null, null, withdrawingAfter, null);
|
|
|
+
|
|
|
+ insertFlow(tenant, 2, delta, 3, withdrawingBefore, withdrawingAfter, 6, null, withdrawNo, remark);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Boolean refundWithdrawToAvailable(Long companyId, BigDecimal amount, String withdrawNo, String remark) {
|
|
|
+ SysTenant tenant = getTenant(companyId);
|
|
|
+ BigDecimal delta = defaultAmount(amount);
|
|
|
+ BigDecimal withdrawingBefore = defaultAmount(tenant.getWithdrawingBalance());
|
|
|
+ BigDecimal availableBefore = defaultAmount(tenant.getAvailableBalance());
|
|
|
+ if (withdrawingBefore.compareTo(delta) < 0) {
|
|
|
+ throw new ServiceException("提现中余额不足");
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal withdrawingAfter = withdrawingBefore.subtract(delta);
|
|
|
+ BigDecimal availableAfter = availableBefore.add(delta);
|
|
|
+ updateTenantBalance(tenant.getId(), availableAfter, null, withdrawingAfter, null);
|
|
|
+
|
|
|
+ insertFlow(tenant, 2, delta, 3, withdrawingBefore, withdrawingAfter, 7, null, withdrawNo, remark + "(解冻)");
|
|
|
+ insertFlow(tenant, 1, delta, 1, availableBefore, availableAfter, 7, null, withdrawNo, remark);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private SysTenant getTenant(Long companyId) {
|
|
|
+ SysTenant tenant = sysTenantMapper.selectById(companyId);
|
|
|
+ if (tenant == null) {
|
|
|
+ throw new ServiceException("企业不存在");
|
|
|
+ }
|
|
|
+ return tenant;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void updateTenantBalance(Long tenantId, BigDecimal availableBalance, BigDecimal inUseBalance,
|
|
|
+ BigDecimal withdrawingBalance, BigDecimal totalConsume) {
|
|
|
+ SysTenant update = new SysTenant();
|
|
|
+ update.setId(tenantId);
|
|
|
+ update.setAvailableBalance(availableBalance);
|
|
|
+ update.setInUseBalance(inUseBalance);
|
|
|
+ update.setWithdrawingBalance(withdrawingBalance);
|
|
|
+ update.setTotalConsume(totalConsume);
|
|
|
+ sysTenantMapper.updateById(update);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void insertFlow(SysTenant tenant, Integer flowType, BigDecimal amount, Integer balanceType,
|
|
|
+ BigDecimal balanceBefore, BigDecimal balanceAfter, Integer businessType,
|
|
|
+ Long businessId, String businessNo, String remark) {
|
|
|
+ CompanyAccountFlow flow = new CompanyAccountFlow();
|
|
|
+ flow.setCompanyId(tenant.getId());
|
|
|
+ flow.setTenantId(tenant.getTenantId());
|
|
|
+ flow.setFlowNo(generateFlowNo());
|
|
|
+ flow.setFlowType(flowType);
|
|
|
+ flow.setAmount(amount);
|
|
|
+ flow.setBalanceType(balanceType);
|
|
|
+ flow.setBalanceBefore(balanceBefore);
|
|
|
+ flow.setBalanceAfter(balanceAfter);
|
|
|
+ flow.setBusinessType(businessType);
|
|
|
+ flow.setBusinessId(businessId);
|
|
|
+ flow.setBusinessNo(businessNo);
|
|
|
+ flow.setRemark(remark);
|
|
|
+ companyAccountFlowMapper.insert(flow);
|
|
|
+ }
|
|
|
+
|
|
|
+ private BigDecimal defaultAmount(BigDecimal amount) {
|
|
|
+ return amount == null ? BigDecimal.ZERO : amount;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String generateFlowNo() {
|
|
|
+ return "CF" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + RandomUtil.randomNumbers(4);
|
|
|
+ }
|
|
|
+}
|