From c15e67c83394c1734eb4e9802d8f343c6076efc1 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 13 五月 2026 16:16:45 +0800
Subject: [PATCH] Merge branch 'dev_New_pro' into dev_宁夏_英泽防锈
---
src/main/java/com/ruoyi/account/service/impl/financial/FinLedgerServiceImpl.java | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 206 insertions(+), 0 deletions(-)
diff --git a/src/main/java/com/ruoyi/account/service/impl/financial/FinLedgerServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/financial/FinLedgerServiceImpl.java
new file mode 100644
index 0000000..a489c67
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/impl/financial/FinLedgerServiceImpl.java
@@ -0,0 +1,206 @@
+package com.ruoyi.account.service.impl.financial;
+
+import com.ruoyi.account.bean.dto.financial.FinDetailLedgerQueryDto;
+import com.ruoyi.account.bean.dto.financial.FinLedgerQueryDto;
+import com.ruoyi.account.bean.vo.financial.FinLedgerEntryRecordVo;
+import com.ruoyi.account.bean.vo.financial.FinLedgerRowVo;
+import com.ruoyi.account.mapper.financial.FinVoucherEntryMapper;
+import com.ruoyi.account.service.financial.FinLedgerService;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDate;
+import java.time.YearMonth;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.*;
+
+/**
+ * 绉戠洰鎬昏处/鏄庣粏璐︽湇鍔″疄鐜般��
+ */
+@Service
+@RequiredArgsConstructor
+public class FinLedgerServiceImpl implements FinLedgerService {
+
+ private static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM");
+ private static final BigDecimal ZERO = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
+
+ private final FinVoucherEntryMapper finVoucherEntryMapper;
+
+ @Override
+ public List<FinLedgerRowVo> queryGeneralLedger(FinLedgerQueryDto queryDto) {
+ if (queryDto == null || StringUtils.isEmpty(queryDto.getSubjectCode())) {
+ return Collections.emptyList();
+ }
+ YearMonth startMonth = parseMonth(queryDto.getStartMonth(), "寮�濮嬫湀浠�");
+ YearMonth endMonth = parseMonth(queryDto.getEndMonth(), "缁撴潫鏈堜唤");
+ if (startMonth.isAfter(endMonth)) {
+ throw new ServiceException("寮�濮嬫湀浠戒笉鑳藉ぇ浜庣粨鏉熸湀浠�");
+ }
+ return buildLedgerRows(queryDto.getSubjectCode(), startMonth, endMonth, null, null);
+ }
+
+ @Override
+ public List<FinLedgerRowVo> queryDetailLedger(FinDetailLedgerQueryDto queryDto) {
+ if (queryDto == null || StringUtils.isEmpty(queryDto.getSubjectCode())) {
+ return Collections.emptyList();
+ }
+ YearMonth startMonth = parseMonth(queryDto.getStartMonth(), "寮�濮嬫湀浠�");
+ YearMonth endMonth = parseMonth(queryDto.getEndMonth(), "缁撴潫鏈堜唤");
+ if (startMonth.isAfter(endMonth)) {
+ throw new ServiceException("寮�濮嬫湀浠戒笉鑳藉ぇ浜庣粨鏉熸湀浠�");
+ }
+ return buildLedgerRows(queryDto.getSubjectCode(), startMonth, endMonth, queryDto.getAuxiliaryType(), queryDto.getAuxiliaryId());
+ }
+
+ /**
+ * 鏋勫缓璐︾翱琛屾暟鎹紝杈撳嚭鏈熷垵銆佸垎褰曘�佹湰鏈堝悎璁°�佹湰骞寸疮璁°��
+ */
+ private List<FinLedgerRowVo> buildLedgerRows(String subjectCode,
+ YearMonth startMonth,
+ YearMonth endMonth,
+ String auxiliaryType,
+ String auxiliaryId) {
+ LocalDate startDate = startMonth.atDay(1);
+ LocalDate endDate = endMonth.atEndOfMonth();
+
+ List<FinLedgerEntryRecordVo> openingEntries = finVoucherEntryMapper.listPostedEntriesBefore(
+ subjectCode, startDate, auxiliaryType, auxiliaryId
+ );
+ BigDecimal openingBalance = calculateBalance(openingEntries);
+
+ List<FinLedgerEntryRecordVo> currentPeriodEntries = finVoucherEntryMapper.listPostedEntries(
+ subjectCode, startDate, endDate, auxiliaryType, auxiliaryId
+ );
+ Map<YearMonth, List<FinLedgerEntryRecordVo>> monthEntriesMap = groupEntriesByMonth(currentPeriodEntries);
+
+ List<FinLedgerRowVo> rows = new ArrayList<>();
+ BigDecimal runningBalance = openingBalance;
+ BigDecimal yearDebit = ZERO;
+ BigDecimal yearCredit = ZERO;
+
+ for (YearMonth month = startMonth; !month.isAfter(endMonth); month = month.plusMonths(1)) {
+ rows.add(buildOpeningRow(month.atDay(1), runningBalance));
+
+ List<FinLedgerEntryRecordVo> monthEntries = monthEntriesMap.getOrDefault(month, Collections.emptyList());
+ BigDecimal monthDebit = ZERO;
+ BigDecimal monthCredit = ZERO;
+ for (FinLedgerEntryRecordVo entry : monthEntries) {
+ BigDecimal debit = money(entry.getDebit());
+ BigDecimal credit = money(entry.getCredit());
+ runningBalance = runningBalance.add(debit).subtract(credit);
+ monthDebit = monthDebit.add(debit);
+ monthCredit = monthCredit.add(credit);
+
+ FinLedgerRowVo row = new FinLedgerRowVo();
+ row.setRowType("entry");
+ row.setDate(entry.getVoucherDate());
+ row.setVoucherNo(entry.getVoucherNo());
+ row.setSummary(StringUtils.isNotEmpty(entry.getSummary()) ? entry.getSummary() : "");
+ row.setDebit(debit);
+ row.setCredit(credit);
+ row.setBalance(money(runningBalance));
+ row.setDirection(resolveDirection(runningBalance));
+ rows.add(row);
+ }
+
+ rows.add(buildMonthlyTotalRow(month.atEndOfMonth(), monthDebit, monthCredit, runningBalance));
+ yearDebit = yearDebit.add(monthDebit);
+ yearCredit = yearCredit.add(monthCredit);
+ }
+
+ rows.add(buildYearlyTotalRow(endMonth.atEndOfMonth(), yearDebit, yearCredit, runningBalance));
+ return rows;
+ }
+
+ private Map<YearMonth, List<FinLedgerEntryRecordVo>> groupEntriesByMonth(List<FinLedgerEntryRecordVo> entries) {
+ Map<YearMonth, List<FinLedgerEntryRecordVo>> map = new LinkedHashMap<>();
+ for (FinLedgerEntryRecordVo entry : entries) {
+ if (entry.getVoucherDate() == null) {
+ continue;
+ }
+ YearMonth month = YearMonth.from(entry.getVoucherDate());
+ map.computeIfAbsent(month, key -> new ArrayList<>()).add(entry);
+ }
+ return map;
+ }
+
+ private FinLedgerRowVo buildOpeningRow(LocalDate date, BigDecimal openingBalance) {
+ FinLedgerRowVo row = new FinLedgerRowVo();
+ row.setRowType("opening");
+ row.setDate(date);
+ row.setVoucherNo("-");
+ row.setSummary("鏈熷垵浣欓");
+ row.setDebit(ZERO);
+ row.setCredit(ZERO);
+ row.setBalance(money(openingBalance));
+ row.setDirection(resolveDirection(openingBalance));
+ return row;
+ }
+
+ private FinLedgerRowVo buildMonthlyTotalRow(LocalDate date,
+ BigDecimal monthDebit,
+ BigDecimal monthCredit,
+ BigDecimal monthBalance) {
+ FinLedgerRowVo row = new FinLedgerRowVo();
+ row.setRowType("monthly_total");
+ row.setDate(date);
+ row.setVoucherNo("-");
+ row.setSummary("鏈湀鍚堣");
+ row.setDebit(money(monthDebit));
+ row.setCredit(money(monthCredit));
+ row.setBalance(money(monthBalance));
+ row.setDirection(resolveDirection(monthBalance));
+ return row;
+ }
+
+ private FinLedgerRowVo buildYearlyTotalRow(LocalDate date,
+ BigDecimal yearDebit,
+ BigDecimal yearCredit,
+ BigDecimal yearBalance) {
+ FinLedgerRowVo row = new FinLedgerRowVo();
+ row.setRowType("yearly_total");
+ row.setDate(date);
+ row.setVoucherNo("-");
+ row.setSummary("鍚堣");
+ row.setDebit(money(yearDebit));
+ row.setCredit(money(yearCredit));
+ row.setBalance(money(yearBalance));
+ row.setDirection(resolveDirection(yearBalance));
+ return row;
+ }
+
+ private BigDecimal calculateBalance(List<FinLedgerEntryRecordVo> entries) {
+ BigDecimal balance = ZERO;
+ for (FinLedgerEntryRecordVo entry : entries) {
+ balance = balance.add(money(entry.getDebit())).subtract(money(entry.getCredit()));
+ }
+ return money(balance);
+ }
+
+ private String resolveDirection(BigDecimal balance) {
+ return money(balance).compareTo(BigDecimal.ZERO) >= 0 ? "鍊�" : "璐�";
+ }
+
+ private YearMonth parseMonth(String value, String fieldLabel) {
+ if (StringUtils.isEmpty(value)) {
+ throw new ServiceException(fieldLabel + "涓嶈兘涓虹┖锛屾牸寮忓簲涓篩YYY-MM");
+ }
+ try {
+ return YearMonth.parse(value, MONTH_FORMATTER);
+ } catch (DateTimeParseException ex) {
+ throw new ServiceException(fieldLabel + "鏍煎紡閿欒锛屾牸寮忓簲涓篩YYY-MM");
+ }
+ }
+
+ private BigDecimal money(BigDecimal value) {
+ if (value == null) {
+ return ZERO;
+ }
+ return value.setScale(2, RoundingMode.HALF_UP);
+ }
+}
--
Gitblit v1.9.3