From eb63e4dfa4355191271ac603bb1b7808259cfcd4 Mon Sep 17 00:00:00 2001
From: gongchunyi <deslre0381@gmail.com>
Date: 星期四, 29 一月 2026 18:31:57 +0800
Subject: [PATCH] feat: 支收对比分析统计DTO
---
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java | 615 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 585 insertions(+), 30 deletions(-)
diff --git a/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java b/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
index 83948ce..828d6ae 100644
--- a/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
+++ b/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -2,8 +2,11 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.mapper.AccountIncomeMapper;
+import com.ruoyi.account.pojo.AccountExpense;
+import com.ruoyi.home.mapper.HomeMapper;
+import com.ruoyi.account.mapper.AccountExpenseMapper;
import com.ruoyi.approve.mapper.ApproveProcessMapper;
import com.ruoyi.approve.pojo.ApproveProcess;
import com.ruoyi.basic.mapper.CustomerMapper;
@@ -12,7 +15,6 @@
import com.ruoyi.basic.mapper.SupplierManageMapper;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.pojo.Product;
-import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.basic.pojo.SupplierManage;
import com.ruoyi.collaborativeApproval.mapper.NoticeMapper;
import com.ruoyi.collaborativeApproval.pojo.Notice;
@@ -86,6 +88,9 @@
private SalesLedgerProductMapper salesLedgerProductMapper;
@Autowired
+ private StockInventoryMapper stockInventoryMapper;
+
+ @Autowired
private ProcurementRecordMapper procurementRecordStorageMapper;
@Autowired
@@ -125,7 +130,9 @@
private SysUserMapper sysUserMapper;
@Autowired
private SysUserDeptMapper sysUserDeptMapper;
- private StockInventoryMapper stockInventoryMapper;
+
+ @Autowired
+ private HomeMapper homeMapper;
@Override
public HomeBusinessDto business() {
@@ -179,38 +186,13 @@
homeBusinessDto.setMonthPurchaseHaveMoney(unReceiptPaymentAmount.setScale(2, RoundingMode.HALF_UP).toString());
}
// 缁熻搴撳瓨
-// List<ProcurementRecordStorage> procurementRecordStorages = procurementRecordStorageMapper.selectList(null);
-// BigDecimal stockAmount = procurementRecordStorages.stream()
-// .map(ProcurementRecordStorage::getInboundNum)
-// .filter(Objects::nonNull)
-// .reduce(BigDecimal.ZERO, BigDecimal::add);
-// // 鑷畾涔夊簱瀛�
-// List<CustomStorage> customStorages = customStorageMapper.selectList(null);
-// BigDecimal customStockAmount = customStorages.stream()
-// .map(CustomStorage::getInboundNum)
-// .filter(Objects::nonNull)
-// .reduce(BigDecimal.ZERO, BigDecimal::add);
-// List<ProcurementRecordOut> procurementRecordOuts = procurementRecordOutMapper.selectList(null);
-// BigDecimal outboundAmount = procurementRecordOuts.stream()
-// .map(ProcurementRecordOut::getInboundNum)
-// .filter(Objects::nonNull)
-// .reduce(BigDecimal.ZERO, BigDecimal::add);
-// BigDecimal stock = stockAmount.add(customStockAmount).subtract(outboundAmount);
BigDecimal stockQuantityTotal = stockInventoryMapper.selectTotal();
homeBusinessDto.setInventoryNum(stockQuantityTotal.setScale(2, RoundingMode.HALF_UP).toString());
// 鑾峰彇褰撳ぉ鍏ュ簱鏁伴噺
- LambdaQueryWrapper<ProcurementRecordStorage> procurementRecordStorageLambdaQueryWrapper = new LambdaQueryWrapper<>();
- procurementRecordStorageLambdaQueryWrapper.ge(ProcurementRecordStorage::getCreateTime, now) // 澶т簬绛変簬褰撳ぉ
- .lt(ProcurementRecordStorage::getCreateTime, now.plusDays(1)); // 灏忎簬鏄庡ぉ
- List<ProcurementRecordStorage> procurementRecordStorages1 = procurementRecordStorageMapper.selectList(procurementRecordStorageLambdaQueryWrapper);
- BigDecimal stockAmount1 = procurementRecordStorages1.stream()
- .map(ProcurementRecordStorage::getInboundNum)
- .filter(Objects::nonNull)
- .reduce(BigDecimal.ZERO, BigDecimal::add);
-// homeBusinessDto.setInventoryNum(stock.setScale(2, RoundingMode.HALF_UP).toString());
- homeBusinessDto.setTodayInventoryNum(stockAmount1.setScale(2, RoundingMode.HALF_UP).toString());
+ BigDecimal bigDecimal = stockInventoryMapper.selectTotalByDate(LocalDate.now());
+ homeBusinessDto.setTodayInventoryNum(bigDecimal.setScale(2, RoundingMode.HALF_UP).toString());
return homeBusinessDto;
}
@@ -924,4 +906,577 @@
}
return result;
}
+
+ @Override
+ public List<MapDto> productSalesAnalysis() {
+ // 鑾峰彇鎵�鏈変骇鍝佸ぇ绫荤殑閿�鍞
+ List<Map<String, Object>> analysisResults = salesLedgerProductMapper.selectProductSalesAnalysis();
+ if (CollectionUtils.isEmpty(analysisResults)) {
+ return new ArrayList<>();
+ }
+
+ // 璁$畻鎬婚攢鍞
+ BigDecimal totalSalesAmount = analysisResults.stream()
+ .map(r -> (BigDecimal) r.get("value"))
+ .filter(Objects::nonNull)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+ return analysisResults.stream()
+ .map(result -> {
+ MapDto mapDto = new MapDto();
+ String name = (String) result.get("name");
+ BigDecimal value = (BigDecimal) result.get("value");
+
+ mapDto.setName(name);
+ mapDto.setValue(value != null ? value.setScale(2, RoundingMode.HALF_UP).toString() : "0.00");
+
+ if (totalSalesAmount.compareTo(BigDecimal.ZERO) == 0 || value == null) {
+ mapDto.setRate("0.00");
+ } else {
+ String rate = value.divide(totalSalesAmount, 4, RoundingMode.HALF_UP)
+ .multiply(new BigDecimal("100"))
+ .setScale(2, RoundingMode.HALF_UP)
+ .toString();
+ mapDto.setRate(rate);
+ }
+ return mapDto;
+ })
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public List<MapDto> rawMaterialPurchaseAmountRatio() {
+ // 鑾峰彇鎵�鏈夊師鏉愭枡鐨勯噰璐
+ List<Map<String, Object>> analysisResults = salesLedgerProductMapper.selectRawMaterialPurchaseAnalysis();
+ if (CollectionUtils.isEmpty(analysisResults)) {
+ return new ArrayList<>();
+ }
+
+ // 璁$畻鎬婚噰璐
+ BigDecimal totalPurchaseAmount = analysisResults.stream()
+ .map(r -> (BigDecimal) r.get("value"))
+ .filter(Objects::nonNull)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+ return analysisResults.stream()
+ .map(result -> {
+ MapDto mapDto = new MapDto();
+ String name = (String) result.get("name");
+ BigDecimal value = (BigDecimal) result.get("value");
+
+ mapDto.setName(name);
+ mapDto.setValue(value != null ? value.setScale(2, RoundingMode.HALF_UP).toString() : "0.00");
+
+ if (totalPurchaseAmount.compareTo(BigDecimal.ZERO) == 0 || value == null) {
+ mapDto.setRate("0.00");
+ } else {
+ String rate = value.divide(totalPurchaseAmount, 4, RoundingMode.HALF_UP)
+ .multiply(new BigDecimal("100"))
+ .setScale(2, RoundingMode.HALF_UP)
+ .toString();
+ mapDto.setRate(rate);
+ }
+ return mapDto;
+ })
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public List<MapDto> salesPurchaseStorageProductCount() {
+ LocalDate now = LocalDate.now();
+ DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+ String currentMonthStart = now.with(TemporalAdjusters.firstDayOfMonth()).format(dtf);
+ String currentMonthNow = now.format(dtf);
+
+ LocalDate lastMonth = now.minusMonths(1);
+ String lastMonthStart = lastMonth.with(TemporalAdjusters.firstDayOfMonth()).format(dtf);
+ String lastMonthEnd = lastMonth.with(TemporalAdjusters.lastDayOfMonth()).format(dtf);
+
+ // 閿�鍞�
+ int currentSales = salesLedgerProductMapper.selectProductCountByTypeAndDate(1, currentMonthStart, currentMonthNow);
+ int lastSales = salesLedgerProductMapper.selectProductCountByTypeAndDate(1, lastMonthStart, lastMonthEnd);
+
+ // 閲囪喘
+ int currentPurchase = salesLedgerProductMapper.selectProductCountByTypeAndDate(2, currentMonthStart, currentMonthNow);
+ int lastPurchase = salesLedgerProductMapper.selectProductCountByTypeAndDate(2, lastMonthStart, lastMonthEnd);
+
+ // 鍌ㄥ瓨
+ int currentStorage = stockInventoryMapper.selectStorageProductCountByDate(currentMonthStart, currentMonthNow);
+ int lastStorage = stockInventoryMapper.selectStorageProductCountByDate(lastMonthStart, lastMonthEnd);
+
+ List<MapDto> list = new ArrayList<>();
+ list.add(createMapDto("閿�鍞骇鍝佹暟", currentSales, lastSales));
+ list.add(createMapDto("閲囪喘浜у搧鏁�", currentPurchase, lastPurchase));
+ list.add(createMapDto("鍌ㄥ瓨浜у搧鏁�", currentStorage, lastStorage));
+
+ return list;
+ }
+
+ private MapDto createMapDto(String name, int current, int last) {
+ MapDto dto = new MapDto();
+ dto.setName(name);
+ dto.setValue(String.valueOf(current));
+
+ if (last == 0) {
+ dto.setRate(current > 0 ? "100.00" : "0.00");
+ } else {
+ BigDecimal curDec = new BigDecimal(current);
+ BigDecimal lastDec = new BigDecimal(last);
+ // 澧為暱鐜�
+ String rate = curDec.subtract(lastDec)
+ .divide(lastDec, 4, RoundingMode.HALF_UP)
+ .multiply(new BigDecimal("100"))
+ .setScale(2, RoundingMode.HALF_UP)
+ .toString();
+ dto.setRate(rate);
+ }
+ return dto;
+ }
+
+ @Override
+ public List<Map<String, Object>> productInOutAnalysis(Integer type) {
+ String targetName;
+ if (type == 1) {
+ targetName = "鍘熸潗鏂�";
+ } else if (type == 2) {
+ targetName = "鎴愬搧";
+ } else if (type == 3) {
+ targetName = "鍗婃垚鍝�";
+ } else {
+ return new ArrayList<>();
+ }
+
+ LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(Product::getProductName, targetName).isNull(Product::getParentId);
+ Product rootCategory = productMapper.selectOne(queryWrapper);
+
+ if (rootCategory == null) {
+ log.warn("鏈壘鍒板悕绉颁负 {} 鐨勯《绾т骇鍝佸垎绫�", targetName);
+ return new ArrayList<>();
+ }
+ Long rootCategoryId = rootCategory.getId();
+
+ LocalDate now = LocalDate.now();
+ DateTimeFormatter displayDtf = DateTimeFormatter.ofPattern("M/d");
+
+ String startDate = now.minusDays(6).toString();
+ String endDate = now.toString();
+
+ List<Map<String, Object>> inCounts = stockInventoryMapper.selectDailyStockInCounts(rootCategoryId, startDate, endDate + " 23:59:59");
+
+ List<Map<String, Object>> outCounts = stockInventoryMapper.selectDailyStockOutCounts(rootCategoryId, startDate, endDate + " 23:59:59");
+
+ Map<LocalDate, BigDecimal> inMap = inCounts.stream()
+ .collect(Collectors.toMap(
+ m -> ((java.sql.Date) m.get("date")).toLocalDate(),
+ m -> (BigDecimal) m.get("count"),
+ BigDecimal::add
+ ));
+
+ Map<LocalDate, BigDecimal> outMap = outCounts.stream()
+ .collect(Collectors.toMap(
+ m -> ((java.sql.Date) m.get("date")).toLocalDate(),
+ m -> (BigDecimal) m.get("count"),
+ BigDecimal::add
+ ));
+
+ List<Map<String, Object>> result = new ArrayList<>();
+
+ for (int i = 6; i >= 0; i--) {
+ LocalDate date = now.minusDays(i);
+
+ Map<String, Object> dataPoint = new LinkedHashMap<>();
+ dataPoint.put("date", date.format(displayDtf)); // 1/23
+ dataPoint.put("inCount", inMap.getOrDefault(date, BigDecimal.ZERO));
+ dataPoint.put("outCount", outMap.getOrDefault(date, BigDecimal.ZERO));
+
+ result.add(dataPoint);
+ }
+
+ return result;
+ }
+
+ @Override
+ public List<MapDto> productTurnoverDays() {
+ return homeMapper.productTurnoverDays();
+ }
+
+ @Autowired
+ private AccountExpenseMapper accountExpenseMapper;
+
+ @Autowired
+ private AccountIncomeMapper accountIncomeMapper;
+
+
+ public List<Map<String, Object>> incomeExpenseAnalysis(Integer type) {
+
+ LocalDate today = LocalDate.now();
+ LocalDate startDate;
+ LocalDate endDate;
+ String dateFormat;
+ DateTimeFormatter formatter;
+ List<String> xAxis = new ArrayList<>();
+
+ // 1. 鏃堕棿鑼冨洿 & X 杞�
+ if (type == 3) {
+ // 鏈搴︼紙鎸夋湀锛�
+ Month currentMonth = today.getMonth();
+ Month firstMonthOfQuarter = currentMonth.firstMonthOfQuarter();
+ startDate = today.withMonth(firstMonthOfQuarter.getValue())
+ .with(TemporalAdjusters.firstDayOfMonth());
+ endDate = startDate.plusMonths(2)
+ .with(TemporalAdjusters.lastDayOfMonth());
+
+ dateFormat = "%Y-%m";
+ formatter = DateTimeFormatter.ofPattern("yyyy-MM");
+
+ LocalDate tmp = startDate;
+ while (!tmp.isAfter(endDate)) {
+ xAxis.add(tmp.format(formatter));
+ tmp = tmp.plusMonths(1);
+ }
+
+ } else {
+ // 鍛� / 鏈堬紙鎸夊ぉ锛�
+ dateFormat = "%Y-%m-%d";
+ formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+ if (type == 1) {
+ startDate = today.with(DayOfWeek.MONDAY);
+ endDate = today.with(DayOfWeek.SUNDAY);
+ } else {
+ startDate = today.with(TemporalAdjusters.firstDayOfMonth());
+ endDate = today.with(TemporalAdjusters.lastDayOfMonth());
+ }
+
+ LocalDate tmp = startDate;
+ while (!tmp.isAfter(endDate)) {
+ xAxis.add(tmp.format(formatter));
+ tmp = tmp.plusDays(1);
+ }
+ }
+
+ String startStr = startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+ String endStr = endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+
+ // 2. 鏌ヨ鏁版嵁
+ List<IncomeExpenseAnalysisDto> incomeList = accountIncomeMapper.selectIncomeStats(startStr, endStr, dateFormat);
+
+// List<IncomeExpenseAnalysisDto> purchaseList =
+// purchaseLedgerMapper.selectPurchaseStats(startStr, endStr, dateFormat);
+
+ List<IncomeExpenseAnalysisDto> expenseList = accountExpenseMapper.selectAccountExpenseStats(startStr, endStr, dateFormat);
+
+ // 3. 杞� Map锛堣嚜鍔ㄥ悎骞讹級
+ Map<String, BigDecimal> incomeMap = incomeList.stream()
+ .collect(Collectors.toMap(
+ IncomeExpenseAnalysisDto::getDateStr,
+ IncomeExpenseAnalysisDto::getAmount,
+ BigDecimal::add));
+
+// Map<String, BigDecimal> purchaseMap = purchaseList.stream()
+// .collect(Collectors.toMap(
+// IncomeExpenseAnalysisDto::getDateStr,
+// IncomeExpenseAnalysisDto::getAmount,
+// BigDecimal::add));
+
+ Map<String, BigDecimal> expenseMap = expenseList.stream()
+ .collect(Collectors.toMap(
+ IncomeExpenseAnalysisDto::getDateStr,
+ IncomeExpenseAnalysisDto::getAmount,
+ BigDecimal::add));
+
+ // 4. 缁勮杩斿洖
+ List<Map<String, Object>> result = new ArrayList<>();
+
+ for (String dateStr : xAxis) {
+ Map<String, Object> item = new HashMap<>();
+ item.put("date", dateStr);
+
+ // 鏀跺叆
+ BigDecimal income = incomeMap.getOrDefault(dateStr, BigDecimal.ZERO);
+ item.put("income", income.setScale(2, RoundingMode.HALF_UP));
+
+ // 鏀嚭 = 閲囪喘 + 璐㈠姟鏀嚭
+// BigDecimal purchase = purchaseMap.getOrDefault(dateStr, BigDecimal.ZERO);
+ BigDecimal expense = expenseMap.getOrDefault(dateStr, BigDecimal.ZERO);
+// BigDecimal totalExpense = purchase.add(expense);
+ BigDecimal totalExpense = expense;
+
+ item.put("expense", totalExpense.setScale(2, RoundingMode.HALF_UP));
+
+ result.add(item);
+ }
+
+ return result;
+ }
+
+
+ @Override
+ public List<MapDto> profitTrendAnalysis() {
+ LocalDate today = LocalDate.now();
+ LocalDate startDate = today.minusMonths(11).with(TemporalAdjusters.firstDayOfMonth());
+ LocalDate endDate = today.with(TemporalAdjusters.lastDayOfMonth());
+
+ String dateFormat = "%Y-%m";
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
+
+ List<String> months = new ArrayList<>();
+ LocalDate temp = startDate;
+ while (!temp.isAfter(endDate)) {
+ months.add(temp.format(formatter));
+ temp = temp.plusMonths(1);
+ }
+
+ String startStr = startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+ String endStr = endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+
+// List<IncomeExpenseAnalysisDto> incomeList = salesLedgerMapper.selectIncomeStats(startStr, endStr, dateFormat);
+ List<IncomeExpenseAnalysisDto> incomeList = new ArrayList<>();
+ List<IncomeExpenseAnalysisDto> purchaseList = purchaseLedgerMapper.selectPurchaseStats(startStr, endStr, dateFormat);
+ List<IncomeExpenseAnalysisDto> expenseList = accountExpenseMapper.selectAccountExpenseStats(startStr, endStr, dateFormat);
+
+ Map<String, BigDecimal> incomeMap = incomeList.stream().collect(Collectors.toMap(IncomeExpenseAnalysisDto::getDateStr, IncomeExpenseAnalysisDto::getAmount, BigDecimal::add));
+ Map<String, BigDecimal> purchaseMap = purchaseList.stream().collect(Collectors.toMap(IncomeExpenseAnalysisDto::getDateStr, IncomeExpenseAnalysisDto::getAmount, BigDecimal::add));
+ Map<String, BigDecimal> expenseMap = expenseList.stream().collect(Collectors.toMap(IncomeExpenseAnalysisDto::getDateStr, IncomeExpenseAnalysisDto::getAmount, BigDecimal::add));
+
+ List<MapDto> result = new ArrayList<>();
+
+ for (String month : months) {
+ MapDto dto = new MapDto();
+ dto.setName(month);
+
+ BigDecimal income = incomeMap.getOrDefault(month, BigDecimal.ZERO);
+
+ BigDecimal purchase = purchaseMap.getOrDefault(month, BigDecimal.ZERO);
+ income = BigDecimal.ZERO;
+ BigDecimal expense = expenseMap.getOrDefault(month, BigDecimal.ZERO);
+ BigDecimal totalExpense = purchase.add(expense);
+
+ BigDecimal profit = income.subtract(totalExpense);
+
+ dto.setValue(profit.setScale(2, RoundingMode.HALF_UP).toString());
+ result.add(dto);
+ }
+
+ return result;
+ }
+
+ @Override
+ public List<MapDto> expenseCompositionAnalysis(Integer type) {
+ List<MapDto> result = new ArrayList<>();
+
+ if (type == 2) {
+ List<MapDto> customerList = salesLedgerMapper.selectCustomerSalesComposition();
+ if (customerList != null) {
+ result.addAll(customerList);
+ }
+ } else {
+ BigDecimal rawMaterialAmount = salesLedgerProductMapper.selectRawMaterialExpense();
+ MapDto rawMaterialDto = new MapDto();
+ rawMaterialDto.setName("鍘熸潗鏂�");
+ rawMaterialDto.setValue(rawMaterialAmount != null ? rawMaterialAmount.toString() : "0");
+ result.add(rawMaterialDto);
+
+ List<MapDto> expenseList = accountExpenseMapper.selectExpenseComposition(null, null);
+ if (expenseList != null) {
+ result.addAll(expenseList);
+ }
+ }
+
+ BigDecimal total = BigDecimal.ZERO;
+ for (MapDto dto : result) {
+ if (dto.getValue() != null) {
+ total = total.add(new BigDecimal(dto.getValue()));
+ }
+ }
+
+ if (total.compareTo(BigDecimal.ZERO) > 0) {
+ for (MapDto dto : result) {
+ if (dto.getValue() != null) {
+ BigDecimal val = new BigDecimal(dto.getValue());
+ String rate = val.divide(total, 4, RoundingMode.HALF_UP)
+ .multiply(new BigDecimal("100"))
+ .setScale(2, RoundingMode.HALF_UP)
+ .toString();
+ dto.setRate(rate);
+ } else {
+ dto.setRate("0.00");
+ }
+ }
+ } else {
+ for (MapDto dto : result) {
+ dto.setRate("0.00");
+ }
+ }
+
+ return result;
+ }
+
+
+ @Override
+ public MonthlyIncomeDto monthlyIncome() {
+ MonthlyIncomeDto dto = new MonthlyIncomeDto();
+ LocalDate now = LocalDate.now();
+ YearMonth currentMonth = YearMonth.from(now);
+ LocalDateTime startOfMonth = currentMonth.atDay(1).atStartOfDay();
+ LocalDateTime endOfMonth = currentMonth.atEndOfMonth().atTime(23, 59, 59);
+
+ LambdaQueryWrapper<SalesLedgerProduct> wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(SalesLedgerProduct::getType, 1);
+ wrapper.ge(SalesLedgerProduct::getRegisterDate, startOfMonth);
+ wrapper.le(SalesLedgerProduct::getRegisterDate, endOfMonth);
+
+ List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(wrapper);
+
+ if (CollectionUtils.isEmpty(products)) {
+ return dto;
+ }
+
+ BigDecimal collected = products.stream()
+ .map(SalesLedgerProduct::getInvoiceTotal)
+ .filter(Objects::nonNull)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+ dto.setMonthlyIncome(collected);
+
+ BigDecimal overdue = products.stream()
+ .map(SalesLedgerProduct::getPendingInvoiceTotal)
+ .filter(Objects::nonNull)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+ dto.setOverdueNum(overdue);
+
+ BigDecimal total = collected.add(overdue);
+
+ if (total.compareTo(BigDecimal.ZERO) > 0) {
+ String collectionRate = collected.divide(total, 4, RoundingMode.HALF_UP)
+ .multiply(new BigDecimal("100"))
+ .setScale(2, RoundingMode.HALF_UP)
+ .toString();
+ dto.setCollectionRate(collectionRate);
+
+ String overdueRate = overdue.divide(total, 4, RoundingMode.HALF_UP)
+ .multiply(new BigDecimal("100"))
+ .setScale(2, RoundingMode.HALF_UP)
+ .toString();
+ dto.setOverdueRate(overdueRate);
+ }
+
+ return dto;
+ }
+
+ public MonthlyExpenditureDto monthlyExpenditure() {
+
+ MonthlyExpenditureDto dto = new MonthlyExpenditureDto();
+
+ // 褰撴湀鏃堕棿鑼冨洿
+ LocalDate now = LocalDate.now();
+ YearMonth currentMonth = YearMonth.from(now);
+ LocalDateTime startOfMonth = currentMonth.atDay(1).atStartOfDay();
+ LocalDateTime endOfMonth = currentMonth.atEndOfMonth().atTime(23, 59, 59);
+
+ // 閲囪喘鍙拌处锛坱ype = 2锛�
+ LambdaQueryWrapper<SalesLedgerProduct> purchaseWrapper = new LambdaQueryWrapper<>();
+ purchaseWrapper.eq(SalesLedgerProduct::getType, 2);
+ purchaseWrapper.ge(SalesLedgerProduct::getRegisterDate, startOfMonth);
+ purchaseWrapper.le(SalesLedgerProduct::getRegisterDate, endOfMonth);
+
+ List<SalesLedgerProduct> purchaseProducts =
+ salesLedgerProductMapper.selectList(purchaseWrapper);
+
+ BigDecimal rawMaterialCost = BigDecimal.ZERO; // 鍘熸潗鏂欐垚鏈�
+ BigDecimal paidAmount = BigDecimal.ZERO; // 宸蹭粯娆鹃噾棰�
+ BigDecimal pendingAmount = BigDecimal.ZERO; // 寰呬粯娆鹃噾棰�
+
+ if (!CollectionUtils.isEmpty(purchaseProducts)) {
+ for (SalesLedgerProduct p : purchaseProducts) {
+
+ if (p.getTaxInclusiveTotalPrice() != null) {
+ rawMaterialCost = rawMaterialCost.add(p.getTaxInclusiveTotalPrice());
+ }
+
+ if (p.getTicketsTotal() != null) {
+ paidAmount = paidAmount.add(p.getTicketsTotal());
+ }
+
+ if (p.getPendingTicketsTotal() != null) {
+ pendingAmount = pendingAmount.add(p.getPendingTicketsTotal());
+ }
+ }
+ }
+
+ // 鍏朵粬璐圭敤
+ LambdaQueryWrapper<AccountExpense> expenseWrapper = new LambdaQueryWrapper<>();
+ expenseWrapper.ge(AccountExpense::getExpenseDate,
+ java.sql.Date.valueOf(currentMonth.atDay(1)));
+ expenseWrapper.le(AccountExpense::getExpenseDate,
+ java.sql.Date.valueOf(currentMonth.atEndOfMonth()));
+
+ List<AccountExpense> expenses =
+ accountExpenseMapper.selectList(expenseWrapper);
+
+ BigDecimal otherExpense = BigDecimal.ZERO;
+ if (!CollectionUtils.isEmpty(expenses)) {
+ for (AccountExpense e : expenses) {
+ if (e.getExpenseMoney() != null) {
+ otherExpense = otherExpense.add(e.getExpenseMoney());
+ }
+ }
+ }
+
+ // 鏈堝害鎬绘敮鍑�
+// BigDecimal monthlyExpenditure = rawMaterialCost.add(otherExpense);
+ BigDecimal monthlyExpenditure = otherExpense;
+ dto.setMonthlyExpenditure(monthlyExpenditure);
+
+ // 宸蹭粯娆� 梅锛堝凡浠樻 + 寰呬粯娆撅級
+ BigDecimal totalPayable = paidAmount.add(pendingAmount);
+ if (totalPayable.compareTo(BigDecimal.ZERO) > 0) {
+ String paymentRate = paidAmount
+ .divide(totalPayable, 4, RoundingMode.HALF_UP)
+ .multiply(BigDecimal.valueOf(100))
+ .setScale(2, RoundingMode.HALF_UP)
+ .toString();
+ dto.setPaymentRate(paymentRate);
+ }
+
+ // 鍞彴璐︼紙type = 1锛�
+ LambdaQueryWrapper<SalesLedgerProduct> salesWrapper = new LambdaQueryWrapper<>();
+ salesWrapper.eq(SalesLedgerProduct::getType, 1);
+ salesWrapper.ge(SalesLedgerProduct::getRegisterDate, startOfMonth);
+ salesWrapper.le(SalesLedgerProduct::getRegisterDate, endOfMonth);
+
+ List<SalesLedgerProduct> salesProducts =
+ salesLedgerProductMapper.selectList(salesWrapper);
+
+ BigDecimal revenue = BigDecimal.ZERO;
+ if (!CollectionUtils.isEmpty(salesProducts)) {
+ for (SalesLedgerProduct s : salesProducts) {
+ if (s.getInvoiceAmount() != null) {
+ revenue = revenue.add(s.getInvoiceAmount());
+ }
+ }
+ }
+
+ // 姣涘埄娑� & 鍒╂鼎鐜�
+ if (revenue.compareTo(BigDecimal.ZERO) > 0) {
+
+ // 姣涘埄娑� = 閿�鍞敹鍏� - 鍘熸潗鏂欐垚鏈�
+ BigDecimal grossProfit = revenue.subtract(rawMaterialCost);
+ dto.setGrossProfit(grossProfit);
+
+ // 鍒╂鼎鐜� = (閿�鍞敹鍏� - 鏈堝害鎬绘敮鍑�) / 閿�鍞敹鍏�
+ BigDecimal profit = revenue.subtract(monthlyExpenditure);
+ String profitMarginRate = profit
+ .divide(revenue, 4, RoundingMode.HALF_UP)
+ .multiply(BigDecimal.valueOf(100))
+ .setScale(2, RoundingMode.HALF_UP)
+ .toString();
+
+ dto.setProfitMarginRate(profitMarginRate);
+ }
+
+ return dto;
+ }
+
}
--
Gitblit v1.9.3