This commit is contained in:
jinbooks_dev
2025-06-12 09:56:25 +08:00
parent c5065f60e1
commit 1fe9353f44
11 changed files with 278 additions and 265 deletions

View File

@ -103,10 +103,11 @@
<el-form-item v-if="form.level > 1" label="编码" prop="itemCode">
<el-input style="width: 300px" v-model="form.itemCode" placeholder="请输入编码"/>
</el-form-item>
<el-form-item v-if="form.level === 2" label="合计规则" prop="symbol">
<el-form-item v-if="form.level === 2" label="计算" prop="symbol">
<el-radio-group v-model="form.symbol">
<el-radio-button label="加" value="+"/>
<el-radio-button label="减" value="-"/>
<el-radio-button label="函数" value="f"/>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.level > 1" label="取数规则" prop="rule">

View File

@ -71,11 +71,11 @@
<el-input style="width: 300px" v-model="form.itemName" placeholder="请输入名称"/>
</el-form-item>
<el-form-item label="计算" prop="symbol">
<el-select v-model="form.symbol" placeholder="选择" style="width: 300px">
<el-option label="加" value="+"></el-option>
<el-option label="减" value="-"></el-option>
<el-option label="f" value="f"></el-option>
</el-select>
<el-radio-group v-model="form.symbol">
<el-radio-button label="加" value="+"/>
<el-radio-button label="减" value="-"/>
<el-radio-button label="函数" value="f"/>
</el-radio-group>
</el-form-item>
<el-form-item label="行号" prop="sortIndex">
<el-input-number :min="1" v-model="form.sortIndex" placeholder="请输入行号"/>

View File

@ -179,19 +179,25 @@
<!-- <el-form-item label="编码" prop="itemCode">-->
<!-- <el-input disabled style="width: 300px" v-model="form.itemCode" placeholder="请输入编码"/>-->
<!-- </el-form-item>-->
<el-form-item label="编码" prop="itemCode">
<el-input style="width: 300px" v-model="form.itemCode" placeholder="请输入编码" disabled/>
</el-form-item>
<el-form-item label="名称" prop="itemName">
<el-input style="width: 300px" v-model="form.itemName" placeholder="请输入名称"/>
</el-form-item>
<!-- <el-form-item label="行号" prop="sortIndex">-->
<!-- <el-input-number disabled :min="1" v-model="form.sortIndex" placeholder="请输入行号"/>-->
<!-- </el-form-item>-->
<el-form-item v-if="form.level === 2" label="合计规则" prop="symbol">
<el-form-item v-if="form.level === 2" label="计算" prop="symbol">
<el-radio-group v-model="form.symbol">
<el-radio-button label="加" value="+"/>
<el-radio-button label="减" value="-"/>
<el-radio-button label="函数" value="f"/>
</el-radio-group>
</el-form-item>
<el-form-item label="行号" prop="sortIndex">
<el-input-number :min="1" v-model="form.sortIndex" placeholder="请输入行号"/>
</el-form-item>
<el-table v-if="form.level !== 1" v-loading="loading" :data="form.rules" border size="small"
:cell-class-name="tableCellClassName"
@cell-click="cellMouseEnter"

View File

@ -145,6 +145,13 @@
<el-form-item label="名称" prop="itemName">
<el-input style="width: 300px" v-model="form.itemName" placeholder="请输入名称"/>
</el-form-item>
<el-form-item label="计算" prop="symbol">
<el-radio-group v-model="form.symbol">
<el-radio-button label="加" value="+"/>
<el-radio-button label="减" value="-"/>
<el-radio-button label="函数" value="f"/>
</el-radio-group>
</el-form-item>
<el-form-item label="行号" prop="sortIndex">
<el-input-number :min="1" v-model="form.sortIndex" placeholder="请输入行号"/>
</el-form-item>

View File

@ -49,12 +49,5 @@ public interface StatementBalanceSheetConfigService {
Message<Boolean> delete(String id);
Message<StatementSubjectBalance> getSubjectBalance(StatementSubjectBalance params);
void updateRuleBalance(StatementSubjectBalance subjectBalance, StatementRules statementRules);
void refreshItemsBalance(List<StatementBalanceSheetItem> items,
String bookId, String yearPeriod);
StatementBalanceSheetItemListVo insertSubtotals(List<StatementBalanceSheetItem> items);
}

View File

@ -22,7 +22,12 @@ import com.jinbooks.entity.Message;
import com.jinbooks.entity.book.Settlement;
import com.jinbooks.entity.book.dto.BookChangeDto;
import com.jinbooks.entity.statement.StatementBalanceSheet;
import com.jinbooks.entity.statement.StatementBalanceSheetItem;
import com.jinbooks.entity.statement.StatementRules;
import com.jinbooks.entity.statement.StatementSubjectBalance;
import com.jinbooks.entity.statement.dto.StatementParamsDto;
import com.jinbooks.entity.statement.vo.StatementBalanceSheetItemListVo;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@ -51,4 +56,12 @@ public interface StatementBalanceSheetService {
boolean checkout(Settlement dto) ;
void export(StatementParamsDto dto, HttpServletResponse response) throws IOException;
void updateRuleBalance(StatementSubjectBalance subjectBalance, StatementRules statementRules);
void refreshItemsBalance(List<StatementBalanceSheetItem> items,
String bookId, String yearPeriod);
StatementBalanceSheetItemListVo insertSubtotals(List<StatementBalanceSheetItem> items);
}

View File

@ -18,6 +18,7 @@
package com.jinbooks.persistence.service;
import com.jinbooks.entity.Message;
import com.jinbooks.entity.book.BookSubject;
import com.jinbooks.entity.book.Settlement;
import com.jinbooks.entity.statement.StatementSubjectBalance;
@ -33,6 +34,8 @@ import java.util.List;
*/
public interface StatementSubjectBalanceService {
StatementSubjectBalance getSubjectBalance(String bookId, String subjectCode);
public Message<StatementSubjectBalance> getSubjectBalance(StatementSubjectBalance params);
boolean hasVoucher(String bookId, List<String> codes);

View File

@ -22,44 +22,37 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.jinbooks.constants.ConstsSysConfig;
import com.jinbooks.entity.Message;
import com.jinbooks.entity.statement.StatementBalanceSheet;
import com.jinbooks.entity.statement.StatementBalanceSheetItem;
import com.jinbooks.entity.statement.StatementRules;
import com.jinbooks.entity.statement.StatementSubjectBalance;
import com.jinbooks.entity.statement.vo.StatementBalanceSheetItemListVo;
import java.util.function.Function;
import com.jinbooks.enums.AssetOrLiabilityEnum;
import com.jinbooks.enums.StatementPeriodTypeEnum;
import com.jinbooks.enums.StatementSymbolEnum;
import com.jinbooks.enums.StatementTypeEnum;
import com.jinbooks.persistence.mapper.StatementBalanceSheetItemMapper;
import com.jinbooks.persistence.mapper.StatementBalanceSheetMapper;
import com.jinbooks.persistence.mapper.StatementRulesMapper;
import com.jinbooks.persistence.mapper.StatementSubjectBalanceMapper;
import com.jinbooks.persistence.service.ConfigSysService;
import com.jinbooks.persistence.service.StatementBalanceSheetConfigService;
import com.jinbooks.persistence.service.StatementBalanceSheetService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
@RequiredArgsConstructor
@Service
public class StatementBalanceSheetConfigServiceImpl implements StatementBalanceSheetConfigService {
private final StatementBalanceSheetMapper balanceSheetMapper;
private final StatementBalanceSheetItemMapper statementBalanceSheetItemMapper;
private final StatementRulesMapper rulesMapper;
private final StatementSubjectBalanceMapper subjectBalanceMapper;
private final ConfigSysService configSysService;
private final StatementBalanceSheetService statementBalanceSheetService;
/**
* 获取资产负载配置明细
@ -92,7 +85,7 @@ public class StatementBalanceSheetConfigServiceImpl implements StatementBalanceS
List<StatementSubjectBalance> subjectBalances = subjectBalanceMapper.selectList(lqwSubject);
for (StatementSubjectBalance subjectBalance : subjectBalances) {
StatementRules statementRules = rulesMap.get(subjectBalance.getSubjectCode());
updateRuleBalance(subjectBalance, statementRules);
statementBalanceSheetService.updateRuleBalance(subjectBalance, statementRules);
}
}
balanceSheetItem.setRules(rules);
@ -112,8 +105,8 @@ public class StatementBalanceSheetConfigServiceImpl implements StatementBalanceS
lqw.eq(StatementBalanceSheetItem::getBookId, bookId);
lqw.eq(StatementBalanceSheetItem::getBalanceSheetId, ConstsSysConfig.SYS_CONFIG_TEMPLATE_ID);
List<StatementBalanceSheetItem> balanceSheets = statementBalanceSheetItemMapper.selectList(lqw);
refreshItemsBalance(balanceSheets, bookId, configSysService.getCurrentTerm(bookId));
StatementBalanceSheetItemListVo itemListVo = insertSubtotals(balanceSheets);
statementBalanceSheetService.refreshItemsBalance(balanceSheets, bookId, configSysService.getCurrentTerm(bookId));
StatementBalanceSheetItemListVo itemListVo = statementBalanceSheetService.insertSubtotals(balanceSheets);
itemListVo.getAssets().sort(Comparator.comparing(StatementBalanceSheetItem::getItemCode));
itemListVo.getLiability().sort(Comparator.comparing(StatementBalanceSheetItem::getItemCode));
return Message.ok(itemListVo);
@ -173,16 +166,6 @@ public class StatementBalanceSheetConfigServiceImpl implements StatementBalanceS
return Message.ok(statementBalanceSheetItemMapper.deleteById(id) > 0);
}
@Override
public Message<StatementSubjectBalance> getSubjectBalance(StatementSubjectBalance params) {
LambdaQueryWrapper<StatementSubjectBalance> lqw = Wrappers.lambdaQuery();
lqw.eq(StatementSubjectBalance::getBookId, params.getBookId());
lqw.eq(StringUtils.isNotBlank(params.getSubjectCode()), StatementSubjectBalance::getSubjectCode, params.getSubjectCode());
lqw.eq(StringUtils.isNotBlank(params.getSourceId()), StatementSubjectBalance::getSourceId, params.getSourceId());
lqw.eq(StringUtils.isNotBlank(params.getYearPeriod()), StatementSubjectBalance::getYearPeriod, params.getYearPeriod());
return Message.ok(subjectBalanceMapper.selectOne(lqw));
}
/**
* 获取配置
*
@ -198,212 +181,8 @@ public class StatementBalanceSheetConfigServiceImpl implements StatementBalanceS
return Message.ok(rules);
}
@Override
public void updateRuleBalance(StatementSubjectBalance subjectBalance, StatementRules statementRules) {
if (subjectBalance != null) {
statementRules.setOpeningYearBalance(subjectBalance.getOpeningYearBalanceDebit()
.subtract(subjectBalance.getOpeningYearBalanceCredit()));
statementRules.setClosingBalance(subjectBalance.getBalance());
} else {
statementRules.setOpeningYearBalance(BigDecimal.ZERO);
statementRules.setClosingBalance(BigDecimal.ZERO);
}
}
/**
* 刷新信息项对应的余额数据
*
* @param items 信息项组
* @param bookId 所属账簿
* @param yearPeriod 账期
*/
@Override
public void refreshItemsBalance(List<StatementBalanceSheetItem> items,
String bookId, String yearPeriod) {
// 方便更新参数
Map<String, StatementBalanceSheetItem> mapSheet = items.stream()
.collect(Collectors.toMap(StatementBalanceSheetItem::getItemCode, item -> item));
List<String> itemCodes = items.stream().map(StatementBalanceSheetItem::getItemCode).toList();
// 规则查询
LambdaQueryWrapper<StatementRules> lqwRule = Wrappers.lambdaQuery();
lqwRule.in(StatementRules::getItemCode, itemCodes);
lqwRule.eq(StatementRules::getBookId, bookId);
lqwRule.eq(StatementRules::getType, StatementTypeEnum.balance_sheet.name());
List<StatementRules> rules = rulesMapper.selectList(lqwRule);
List<String> subjectCodes = rules.stream().map(StatementRules::getSubjectCode).toList();
if (CollectionUtils.isNotEmpty(subjectCodes)) {
// 查询科目余额
LambdaQueryWrapper<StatementSubjectBalance> lqwSubject = Wrappers.lambdaQuery();
lqwSubject.in(StatementSubjectBalance::getSubjectCode, subjectCodes);
lqwSubject.eq(StatementSubjectBalance::getBookId, bookId);
lqwSubject.eq(StatementSubjectBalance::getYearPeriod, yearPeriod);
List<StatementSubjectBalance> subjectBalances = subjectBalanceMapper.selectList(lqwSubject);
Map<String, StatementSubjectBalance> subjectMap = subjectBalances.stream()
.collect(Collectors.toMap(StatementSubjectBalance::getSubjectCode, item -> item));
// 更新对应规则的余额和报表余额
for (StatementRules statementRules : rules) {
StatementSubjectBalance subjectBalance = subjectMap.get(statementRules.getSubjectCode());
updateRuleBalance(subjectBalance, statementRules);
StatementBalanceSheetItem balanceSheet = mapSheet.get(statementRules.getItemCode());
if (StatementSymbolEnum.PLUS.getValue().equals(statementRules.getSymbol())) {
balanceSheet.setInitialBalance(balanceSheet.getInitialBalance().add(statementRules.getOpeningYearBalance()));
balanceSheet.setCurrentBalance(balanceSheet.getCurrentBalance().add(statementRules.getClosingBalance()));
} else {
balanceSheet.setInitialBalance(balanceSheet.getInitialBalance().subtract(statementRules.getOpeningYearBalance()));
balanceSheet.setCurrentBalance(balanceSheet.getCurrentBalance().subtract(statementRules.getClosingBalance()));
}
}
}
}
/**
* 对资产/负债中的合计类节点1199、1299、1399进行数据聚合并更新这些节点的余额。
*
* @param items 数据组
* @return 结果
*/
@Override
public StatementBalanceSheetItemListVo insertSubtotals(List<StatementBalanceSheetItem> items) {
if (items == null || items.isEmpty()) return null;
// 分组(资产和负债)
Map<String, List<StatementBalanceSheetItem>> grouped = items.stream()
.collect(Collectors.groupingBy(StatementBalanceSheetItem::getAssetOrLiability));
StatementBalanceSheetItemListVo result = new StatementBalanceSheetItemListVo();
// 资产
List<StatementBalanceSheetItem> assetList = grouped.getOrDefault(AssetOrLiabilityEnum.asset.name(), new ArrayList<>());
buildTreeAndSum(assetList);
result.setAssets(assetList);
// 负债 + 所有者权益
List<StatementBalanceSheetItem> liabilityList = grouped.getOrDefault(AssetOrLiabilityEnum.liability.name(), new ArrayList<>());
buildTreeAndSum(liabilityList);
result.setLiability(liabilityList);
return result;
}
/**
* 构建树 + 递归合计
*
* @param flatList 扁平化数据
*/
private void buildTreeAndSum(List<StatementBalanceSheetItem> flatList) {
if (flatList == null || flatList.isEmpty()) return;
// 构建子列表引用(临时构建树结构)
Map<String, List<StatementBalanceSheetItem>> childMap = new HashMap<>();
for (StatementBalanceSheetItem item : flatList) {
String parentCode = item.getParentItemCode();
if (parentCode != null && !parentCode.isBlank()) {
childMap.computeIfAbsent(parentCode, k -> new ArrayList<>()).add(item);
}
}
// 递归聚合所有合计节点(自底向上)
Set<String> visited = new HashSet<>();
for (StatementBalanceSheetItem item : flatList) {
if (!visited.contains(item.getItemCode())) {
sumRecursively(item, childMap, visited);
}
}
// 聚合所有合计节点余额,
// 递归时已经将子节点余额聚合到父节点上,这里只需要将父节点余额聚合到根节点上即可。
final StatementBalanceSheetItem[] maxNode = {null};
final BigDecimal[] currentAllSum = {BigDecimal.ZERO};
final BigDecimal[] initialAllSum = {BigDecimal.ZERO};
// 构建映射关系
Map<String, StatementBalanceSheetItem> itemMap = flatList.stream()
.collect(Collectors.toMap(StatementBalanceSheetItem::getItemCode, Function.identity()));
flatList.stream().filter(item -> item.getLevel() == 1).forEach(node -> {
// 默认定义尾号99为合计项。如1199、1299、1399、1199_1299
if (node.getItemCode().endsWith("99")) {
BigDecimal currentSum = node.getCurrentBalance() != null ? node.getCurrentBalance() : BigDecimal.ZERO;
BigDecimal initialSum = node.getInitialBalance() != null ? node.getInitialBalance() : BigDecimal.ZERO;
// 分割拼接节点,叠加余额
String[] codes = node.getItemCode().split("_");
for (String code : codes) {
code = code.substring(0, 2) + "00";
StatementBalanceSheetItem parent = itemMap.get(code);
if (parent != null) {
currentSum = currentSum.add(parent.getCurrentBalance());
initialSum = initialSum.add(parent.getInitialBalance());
}
}
node.setCurrentBalance(currentSum);
node.setInitialBalance(initialSum);
// 避免重复叠加总额因为节点可能被多次引用如1199_1299
if (codes.length == 1) {
initialAllSum[0] = initialAllSum[0].add(initialSum);
currentAllSum[0] = currentAllSum[0].add(currentSum);
}
// 获取最大节点,一般为总计项
if (maxNode[0] == null || node.getItemCode().compareTo(maxNode[0].getItemCode()) > 0) {
maxNode[0] = node;
}
}
});
flatList.forEach(node -> {
// 顶级节点不允许出现余额,统计项除外
if (node.getItemCode().endsWith("00")) {
node.setCurrentBalance(BigDecimal.ZERO);
node.setInitialBalance(BigDecimal.ZERO);
}
});
// 设置总计项余额
if (maxNode[0] != null) {
maxNode[0].setCurrentBalance(currentAllSum[0]);
maxNode[0].setInitialBalance(initialAllSum[0]);
}
}
/**
* 递归合计
*
* @param node 当前节点
* @param childMap 子列表引用
* @param visited 访问过的节点
*/
private void sumRecursively(StatementBalanceSheetItem node,
Map<String, List<StatementBalanceSheetItem>> childMap,
Set<String> visited) {
if (visited.contains(node.getItemCode())) return;
visited.add(node.getItemCode());
List<StatementBalanceSheetItem> children = childMap.getOrDefault(node.getItemCode(), Collections.emptyList());
BigDecimal currentSum = node.getCurrentBalance() != null ? node.getCurrentBalance() : BigDecimal.ZERO;
BigDecimal initialSum = node.getInitialBalance() != null ? node.getInitialBalance() : BigDecimal.ZERO;
for (StatementBalanceSheetItem child : children) {
sumRecursively(child, childMap, visited);
if (StatementSymbolEnum.PLUS.getValue().equals(child.getSymbol())) {
currentSum = currentSum.add(
child.getCurrentBalance() != null ? child.getCurrentBalance() : BigDecimal.ZERO
);
initialSum = initialSum.add(
child.getInitialBalance() != null ? child.getInitialBalance() : BigDecimal.ZERO
);
} else {
currentSum = currentSum.subtract(
child.getCurrentBalance() != null ? child.getCurrentBalance() : BigDecimal.ZERO
);
initialSum = initialSum.subtract(
child.getInitialBalance() != null ? child.getInitialBalance() : BigDecimal.ZERO
);
}
}
node.setCurrentBalance(currentSum);
node.setInitialBalance(initialSum);
}
/**
* 更新行号,保证插入的行号,不影响到原有布局。
@ -440,19 +219,4 @@ public class StatementBalanceSheetConfigServiceImpl implements StatementBalanceS
}
}
/**
* 获取当前账期报表ID
*
* @param bookId 账簿
* @return StatementBalanceSheet
*/
private StatementBalanceSheet getBalanceSheetCurrentPeriod(String bookId) {
String currentTerm = configSysService.getCurrentTerm(bookId);
LambdaQueryWrapper<StatementBalanceSheet> lqwBalanceSheet = Wrappers.lambdaQuery();
lqwBalanceSheet.eq(StatementBalanceSheet::getBookId, bookId);
lqwBalanceSheet.eq(StatementBalanceSheet::getYearPeriod, currentTerm);
lqwBalanceSheet.eq(StatementBalanceSheet::getPeriodType, StatementPeriodTypeEnum.MONTH.getValue());
return balanceSheetMapper.selectOne(lqwBalanceSheet);
}
}

View File

@ -32,18 +32,20 @@ import com.jinbooks.entity.statement.*;
import com.jinbooks.entity.statement.dto.StatementParamsDto;
import com.jinbooks.entity.statement.vo.StatementBalanceSheetExport;
import com.jinbooks.entity.statement.vo.StatementBalanceSheetItemListVo;
import com.jinbooks.enums.AssetOrLiabilityEnum;
import com.jinbooks.enums.StatementPeriodTypeEnum;
import com.jinbooks.enums.StatementSymbolEnum;
import com.jinbooks.enums.StatementTypeEnum;
import com.jinbooks.persistence.mapper.*;
import com.jinbooks.persistence.service.ConfigSysService;
import com.jinbooks.persistence.service.StatementBalanceSheetConfigService;
import com.jinbooks.persistence.service.StatementBalanceSheetService;
import com.jinbooks.util.excel.ExcelDataModeEnum;
import com.jinbooks.util.excel.ExcelExporter;
import com.jinbooks.util.excel.ExcelParams;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ResourceUtils;
@ -54,6 +56,8 @@ import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@RequiredArgsConstructor
@Service
@ -61,12 +65,13 @@ public class StatementBalanceSheetServiceImpl implements StatementBalanceSheetSe
private final ConfigSysService configSysService;
private final StatementBalanceSheetMapper balanceSheetMapper;
private final StatementBalanceSheetItemMapper balanceSheetItemMapper;
private final StatementBalanceSheetConfigService balanceSheetConfigService;
private final IdentifierGenerator identifierGenerator;
private final StatementRulesMapper statementRulesMapper;
private final StandardStatementBalanceSheetMapper standardStatementBalanceSheetMapper;
private final StandardStatementRulesMapper standardStatementRulesMapper;
private final BookMapper bookMapper;
private final StatementRulesMapper rulesMapper;
private final StatementSubjectBalanceMapper subjectBalanceMapper;
/**
* 报表-资产负债表
@ -123,7 +128,7 @@ public class StatementBalanceSheetServiceImpl implements StatementBalanceSheetSe
// 遍历月份,统计总金额
for (String month : allMonths) {
balanceSheetConfigService.refreshItemsBalance(items, dto.getBookId(), month);
refreshItemsBalance(items, dto.getBookId(), month);
}
}
}else {// 拉取历史数据
@ -134,7 +139,7 @@ public class StatementBalanceSheetServiceImpl implements StatementBalanceSheetSe
items = balanceSheetItemMapper.selectList(itemLqw);
}
StatementBalanceSheetItemListVo itemListVo = balanceSheetConfigService.insertSubtotals(items);
StatementBalanceSheetItemListVo itemListVo = insertSubtotals(items);
itemListVo.getAssets().sort(Comparator.comparing(StatementBalanceSheetItem::getItemCode));
itemListVo.getLiability().sort(Comparator.comparing(StatementBalanceSheetItem::getItemCode));
balanceSheet.setItems(itemListVo);
@ -358,4 +363,213 @@ public class StatementBalanceSheetServiceImpl implements StatementBalanceSheetSe
return true;
}
/**
* 刷新信息项对应的余额数据
*
* @param items 信息项组
* @param bookId 所属账簿
* @param yearPeriod 账期
*/
@Override
public void refreshItemsBalance(List<StatementBalanceSheetItem> items,
String bookId, String yearPeriod) {
// 方便更新参数
Map<String, StatementBalanceSheetItem> mapSheet = items.stream()
.collect(Collectors.toMap(StatementBalanceSheetItem::getItemCode, item -> item));
List<String> itemCodes = items.stream().map(StatementBalanceSheetItem::getItemCode).toList();
// 规则查询
LambdaQueryWrapper<StatementRules> lqwRule = Wrappers.lambdaQuery();
lqwRule.in(StatementRules::getItemCode, itemCodes);
lqwRule.eq(StatementRules::getBookId, bookId);
lqwRule.eq(StatementRules::getType, StatementTypeEnum.balance_sheet.name());
List<StatementRules> rules = rulesMapper.selectList(lqwRule);
List<String> subjectCodes = rules.stream().map(StatementRules::getSubjectCode).toList();
if (CollectionUtils.isNotEmpty(subjectCodes)) {
// 查询科目余额
LambdaQueryWrapper<StatementSubjectBalance> lqwSubject = Wrappers.lambdaQuery();
lqwSubject.in(StatementSubjectBalance::getSubjectCode, subjectCodes);
lqwSubject.eq(StatementSubjectBalance::getBookId, bookId);
lqwSubject.eq(StatementSubjectBalance::getYearPeriod, yearPeriod);
List<StatementSubjectBalance> subjectBalances = subjectBalanceMapper.selectList(lqwSubject);
Map<String, StatementSubjectBalance> subjectMap = subjectBalances.stream()
.collect(Collectors.toMap(StatementSubjectBalance::getSubjectCode, item -> item));
// 更新对应规则的余额和报表余额
for (StatementRules statementRules : rules) {
StatementSubjectBalance subjectBalance = subjectMap.get(statementRules.getSubjectCode());
updateRuleBalance(subjectBalance, statementRules);
StatementBalanceSheetItem balanceSheet = mapSheet.get(statementRules.getItemCode());
if (StatementSymbolEnum.PLUS.getValue().equals(statementRules.getSymbol())) {
balanceSheet.setInitialBalance(balanceSheet.getInitialBalance().add(statementRules.getOpeningYearBalance()));
balanceSheet.setCurrentBalance(balanceSheet.getCurrentBalance().add(statementRules.getClosingBalance()));
} else {
balanceSheet.setInitialBalance(balanceSheet.getInitialBalance().subtract(statementRules.getOpeningYearBalance()));
balanceSheet.setCurrentBalance(balanceSheet.getCurrentBalance().subtract(statementRules.getClosingBalance()));
}
}
}
}
/**
* 对资产/负债中的合计类节点1199、1299、1399进行数据聚合并更新这些节点的余额。
*
* @param items 数据组
* @return 结果
*/
@Override
public StatementBalanceSheetItemListVo insertSubtotals(List<StatementBalanceSheetItem> items) {
if (items == null || items.isEmpty()) return null;
// 分组(资产和负债)
Map<String, List<StatementBalanceSheetItem>> grouped = items.stream()
.collect(Collectors.groupingBy(StatementBalanceSheetItem::getAssetOrLiability));
StatementBalanceSheetItemListVo result = new StatementBalanceSheetItemListVo();
// 资产
List<StatementBalanceSheetItem> assetList = grouped.getOrDefault(AssetOrLiabilityEnum.asset.name(), new ArrayList<>());
buildTreeAndSum(assetList);
result.setAssets(assetList);
// 负债 + 所有者权益
List<StatementBalanceSheetItem> liabilityList = grouped.getOrDefault(AssetOrLiabilityEnum.liability.name(), new ArrayList<>());
buildTreeAndSum(liabilityList);
result.setLiability(liabilityList);
return result;
}
/**
* 构建树 + 递归合计
*
* @param flatList 扁平化数据
*/
private void buildTreeAndSum(List<StatementBalanceSheetItem> flatList) {
if (flatList == null || flatList.isEmpty()) return;
// 构建子列表引用(临时构建树结构)
Map<String, List<StatementBalanceSheetItem>> childMap = new HashMap<>();
for (StatementBalanceSheetItem item : flatList) {
String parentCode = item.getParentItemCode();
if (parentCode != null && !parentCode.isBlank()) {
childMap.computeIfAbsent(parentCode, k -> new ArrayList<>()).add(item);
}
}
// 递归聚合所有合计节点(自底向上)
Set<String> visited = new HashSet<>();
for (StatementBalanceSheetItem item : flatList) {
if (!visited.contains(item.getItemCode())) {
sumRecursively(item, childMap, visited);
}
}
// 聚合所有合计节点余额,
// 递归时已经将子节点余额聚合到父节点上,这里只需要将父节点余额聚合到根节点上即可。
final StatementBalanceSheetItem[] maxNode = {null};
final BigDecimal[] currentAllSum = {BigDecimal.ZERO};
final BigDecimal[] initialAllSum = {BigDecimal.ZERO};
// 构建映射关系
Map<String, StatementBalanceSheetItem> itemMap = flatList.stream()
.collect(Collectors.toMap(StatementBalanceSheetItem::getItemCode, Function.identity()));
flatList.stream().filter(item -> item.getLevel() == 1).forEach(node -> {
// 默认定义尾号99为合计项。如1199、1299、1399、1199_1299
if (node.getItemCode().endsWith("99")) {
BigDecimal currentSum = node.getCurrentBalance() != null ? node.getCurrentBalance() : BigDecimal.ZERO;
BigDecimal initialSum = node.getInitialBalance() != null ? node.getInitialBalance() : BigDecimal.ZERO;
// 分割拼接节点,叠加余额
String[] codes = node.getItemCode().split("_");
for (String code : codes) {
code = code.substring(0, 2) + "00";
StatementBalanceSheetItem parent = itemMap.get(code);
if (parent != null) {
currentSum = currentSum.add(parent.getCurrentBalance());
initialSum = initialSum.add(parent.getInitialBalance());
}
}
node.setCurrentBalance(currentSum);
node.setInitialBalance(initialSum);
// 避免重复叠加总额因为节点可能被多次引用如1199_1299
if (codes.length == 1) {
initialAllSum[0] = initialAllSum[0].add(initialSum);
currentAllSum[0] = currentAllSum[0].add(currentSum);
}
// 获取最大节点,一般为总计项
if (maxNode[0] == null || node.getItemCode().compareTo(maxNode[0].getItemCode()) > 0) {
maxNode[0] = node;
}
}
});
flatList.forEach(node -> {
// 顶级节点不允许出现余额,统计项除外
if (node.getItemCode().endsWith("00")) {
node.setCurrentBalance(BigDecimal.ZERO);
node.setInitialBalance(BigDecimal.ZERO);
}
});
// 设置总计项余额
if (maxNode[0] != null) {
maxNode[0].setCurrentBalance(currentAllSum[0]);
maxNode[0].setInitialBalance(initialAllSum[0]);
}
}
/**
* 递归合计
*
* @param node 当前节点
* @param childMap 子列表引用
* @param visited 访问过的节点
*/
private void sumRecursively(StatementBalanceSheetItem node,
Map<String, List<StatementBalanceSheetItem>> childMap,
Set<String> visited) {
if (visited.contains(node.getItemCode())) return;
visited.add(node.getItemCode());
List<StatementBalanceSheetItem> children = childMap.getOrDefault(node.getItemCode(), Collections.emptyList());
BigDecimal currentSum = node.getCurrentBalance() != null ? node.getCurrentBalance() : BigDecimal.ZERO;
BigDecimal initialSum = node.getInitialBalance() != null ? node.getInitialBalance() : BigDecimal.ZERO;
for (StatementBalanceSheetItem child : children) {
sumRecursively(child, childMap, visited);
if (StatementSymbolEnum.PLUS.getValue().equals(child.getSymbol())) {
currentSum = currentSum.add(
child.getCurrentBalance() != null ? child.getCurrentBalance() : BigDecimal.ZERO
);
initialSum = initialSum.add(
child.getInitialBalance() != null ? child.getInitialBalance() : BigDecimal.ZERO
);
} else if (StatementSymbolEnum.MINUS.getValue().equals(child.getSymbol())){
currentSum = currentSum.subtract(
child.getCurrentBalance() != null ? child.getCurrentBalance() : BigDecimal.ZERO
);
initialSum = initialSum.subtract(
child.getInitialBalance() != null ? child.getInitialBalance() : BigDecimal.ZERO
);
}
}
node.setCurrentBalance(currentSum);
node.setInitialBalance(initialSum);
}
@Override
public void updateRuleBalance(StatementSubjectBalance subjectBalance, StatementRules statementRules) {
if (subjectBalance != null) {
statementRules.setOpeningYearBalance(subjectBalance.getOpeningYearBalanceDebit()
.subtract(subjectBalance.getOpeningYearBalanceCredit()));
statementRules.setClosingBalance(subjectBalance.getBalance());
} else {
statementRules.setOpeningYearBalance(BigDecimal.ZERO);
statementRules.setClosingBalance(BigDecimal.ZERO);
}
}
}

View File

@ -25,6 +25,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jinbooks.entity.Message;
import com.jinbooks.entity.SubjectAuxiliary;
import com.jinbooks.entity.base.AssistAcc;
import com.jinbooks.entity.book.BookSubject;
@ -73,6 +74,16 @@ public class StatementSubjectBalanceServiceImpl implements StatementSubjectBalan
queryWrapper.eq(StatementSubjectBalance::getSubjectCode, subjectCode);
return subjectBalanceMapper.selectOne(queryWrapper);
}
@Override
public Message<StatementSubjectBalance> getSubjectBalance(StatementSubjectBalance params) {
LambdaQueryWrapper<StatementSubjectBalance> lqw = Wrappers.lambdaQuery();
lqw.eq(StatementSubjectBalance::getBookId, params.getBookId());
lqw.eq(StringUtils.isNotBlank(params.getSubjectCode()), StatementSubjectBalance::getSubjectCode, params.getSubjectCode());
lqw.eq(StringUtils.isNotBlank(params.getSourceId()), StatementSubjectBalance::getSourceId, params.getSourceId());
lqw.eq(StringUtils.isNotBlank(params.getYearPeriod()), StatementSubjectBalance::getYearPeriod, params.getYearPeriod());
return Message.ok(subjectBalanceMapper.selectOne(lqw));
}
/**
* 判断科目是否有凭证

View File

@ -22,7 +22,8 @@ import com.jinbooks.authn.annotation.CurrentUser;
import com.jinbooks.entity.Message;
import com.jinbooks.entity.idm.UserInfo;
import com.jinbooks.entity.statement.StatementSubjectBalance;
import com.jinbooks.persistence.service.StatementBalanceSheetConfigService;
import com.jinbooks.persistence.service.StatementSubjectBalanceService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
@ -36,7 +37,7 @@ import org.springframework.web.bind.annotation.*;
@Slf4j
@RequiredArgsConstructor
public class StatementSubjectBalanceController {
private final StatementBalanceSheetConfigService configService;
private final StatementSubjectBalanceService statementSubjectBalanceService;
/**
* 获取单个
@ -45,7 +46,7 @@ public class StatementSubjectBalanceController {
public Message<StatementSubjectBalance> getSubjectBalance(StatementSubjectBalance params,
@CurrentUser UserInfo userInfo) {
params.setBookId(userInfo.getBookId());
return configService.getSubjectBalance(params);
return statementSubjectBalanceService.getSubjectBalance(params);
}
}