| | |
| | | package com.ruoyi.home.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | 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; |
| | | import com.ruoyi.basic.mapper.ProductMapper; |
| | | import com.ruoyi.basic.mapper.ProductModelMapper; |
| | | import com.ruoyi.basic.mapper.SupplierManageMapper; |
| | | import com.ruoyi.basic.pojo.Customer; |
| | | import com.ruoyi.basic.pojo.Product; |
| | | import com.ruoyi.basic.pojo.SupplierManage; |
| | | import com.ruoyi.collaborativeApproval.mapper.NoticeMapper; |
| | | import com.ruoyi.collaborativeApproval.pojo.Notice; |
| | | import com.ruoyi.common.enums.ApproveTypeEnum; |
| | | import com.ruoyi.common.utils.SecurityUtils; |
| | | import com.ruoyi.device.mapper.DeviceMaintenanceMapper; |
| | | import com.ruoyi.device.mapper.DeviceRepairMapper; |
| | | import com.ruoyi.device.pojo.DeviceMaintenance; |
| | | import com.ruoyi.device.pojo.DeviceRepair; |
| | | import com.ruoyi.dto.MapDto; |
| | | import com.ruoyi.framework.security.LoginUser; |
| | | import com.ruoyi.home.dto.*; |
| | | import com.ruoyi.home.service.HomeService; |
| | | import com.ruoyi.lavorissue.mapper.LavorIssueMapper; |
| | | import com.ruoyi.lavorissue.pojo.LaborIssue; |
| | | import com.ruoyi.procurementrecord.mapper.CustomStorageMapper; |
| | | import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper; |
| | | import com.ruoyi.procurementrecord.mapper.ProcurementRecordOutMapper; |
| | | import com.ruoyi.procurementrecord.pojo.CustomStorage; |
| | | import com.ruoyi.procurementrecord.pojo.ProcurementRecordOut; |
| | | import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage; |
| | | import com.ruoyi.procurementrecord.utils.StockUtils; |
| | | import com.ruoyi.production.dto.ProductOrderDto; |
| | | import com.ruoyi.production.dto.ProductWorkOrderDto; |
| | | import com.ruoyi.production.mapper.ProductOrderMapper; |
| | | import com.ruoyi.production.mapper.ProductWorkOrderMapper; |
| | | import com.ruoyi.production.pojo.ProductWorkOrder; |
| | | import com.ruoyi.project.system.domain.SysDept; |
| | | import com.ruoyi.project.system.domain.SysUser; |
| | | import com.ruoyi.project.system.domain.SysUserDept; |
| | | import com.ruoyi.project.system.mapper.SysDeptMapper; |
| | | import com.ruoyi.project.system.mapper.SysUserDeptMapper; |
| | | import com.ruoyi.project.system.mapper.SysUserMapper; |
| | | import com.ruoyi.purchase.mapper.PaymentRegistrationMapper; |
| | | import com.ruoyi.purchase.mapper.PurchaseLedgerMapper; |
| | | import com.ruoyi.purchase.pojo.PaymentRegistration; |
| | |
| | | import com.ruoyi.sales.pojo.ReceiptPayment; |
| | | import com.ruoyi.sales.pojo.SalesLedger; |
| | | import com.ruoyi.sales.pojo.SalesLedgerProduct; |
| | | import com.ruoyi.staff.mapper.StaffOnJobMapper; |
| | | import com.ruoyi.staff.pojo.StaffOnJob; |
| | | import com.ruoyi.stock.mapper.StockInventoryMapper; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.text.ParseException; |
| | | import java.text.SimpleDateFormat; |
| | | import java.time.*; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.time.temporal.ChronoUnit; |
| | | import java.time.temporal.TemporalAdjusters; |
| | | import java.util.*; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | |
| | | private SalesLedgerProductMapper salesLedgerProductMapper; |
| | | |
| | | @Autowired |
| | | private ProcurementRecordOutMapper procurementRecordOutMapper; |
| | | private StockInventoryMapper stockInventoryMapper; |
| | | |
| | | @Autowired |
| | | private ProcurementRecordMapper procurementRecordStorageMapper; |
| | | |
| | | @Autowired |
| | | private CustomStorageMapper customStorageMapper; |
| | | |
| | | @Autowired |
| | | private QualityInspectMapper qualityStatisticsMapper; |
| | |
| | | private PaymentRegistrationMapper paymentRegistrationMapper; |
| | | |
| | | @Autowired |
| | | private LavorIssueMapper lavorIssueMapper; |
| | | |
| | | @Autowired |
| | | private SysDeptMapper sysDeptMapper; |
| | | |
| | | @Autowired |
| | | private NoticeMapper noticeMapper; |
| | | @Autowired |
| | | private ProductOrderMapper productOrderMapper; |
| | | @Autowired |
| | | private ProductWorkOrderMapper productWorkOrderMapper; |
| | | @Autowired |
| | | private ProductModelMapper productModelMapper; |
| | | @Autowired |
| | | private ProductMapper productMapper; |
| | | @Autowired |
| | | private StockUtils stockUtils; |
| | | @Autowired |
| | | private StaffOnJobMapper staffOnJobMapper; |
| | | @Autowired |
| | | private CustomerMapper customerMapper; |
| | | @Autowired |
| | | private SupplierManageMapper supplierManageMapper; |
| | | @Autowired |
| | | private SysUserMapper sysUserMapper; |
| | | @Autowired |
| | | private SysUserDeptMapper sysUserDeptMapper; |
| | | |
| | | @Autowired |
| | | private HomeMapper homeMapper; |
| | | |
| | | @Override |
| | | public HomeBusinessDto business() { |
| | |
| | | salesLedgerLambdaQueryWrapper.ge(SalesLedger::getEntryDate, currentMonth.atDay(1).atStartOfDay()) // 大于等于本月第一天 |
| | | .lt(SalesLedger::getEntryDate, currentMonth.plusMonths(1).atDay(1).atStartOfDay()); // 小于下月第一天 |
| | | List<SalesLedger> salesLedgers = salesLedgerMapper.selectList(salesLedgerLambdaQueryWrapper); |
| | | if(!CollectionUtils.isEmpty(salesLedgers)){ |
| | | if (!CollectionUtils.isEmpty(salesLedgers)) { |
| | | // 合计合同金额 |
| | | BigDecimal contractAmount = salesLedgers.stream().map(SalesLedger::getContractAmount) |
| | | .filter(Objects::nonNull) |
| | |
| | | .lt(PurchaseLedger::getEntryDate, currentMonth.plusMonths(1).atDay(1).atStartOfDay()); // 小于下月第一天 |
| | | // 执行查询并计算总和 |
| | | List<PurchaseLedger> purchaseLedgers = purchaseLedgerMapper.selectList(queryWrapper); |
| | | if(!CollectionUtils.isEmpty(purchaseLedgers)){ |
| | | if (!CollectionUtils.isEmpty(purchaseLedgers)) { |
| | | LambdaQueryWrapper<SalesLedgerProduct> salesLedgerProductMapperLambdaQueryWrapperCopy = new LambdaQueryWrapper<SalesLedgerProduct>(); |
| | | salesLedgerProductMapperLambdaQueryWrapperCopy.eq(SalesLedgerProduct::getType, 2) |
| | | .in(SalesLedgerProduct::getSalesLedgerId, purchaseLedgers.stream().map(PurchaseLedger::getId).collect(Collectors.toList())); |
| | |
| | | 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; |
| | | } |
| | | |
| | |
| | | BigDecimal subtract = weekContractAmount.subtract(lastYearWeekContractAmount); |
| | | String weekYny = ""; |
| | | // 周同比 |
| | | if(subtract.compareTo(BigDecimal.ZERO) == 0 || lastYearWeekContractAmount.compareTo(BigDecimal.ZERO) == 0){ |
| | | if (subtract.compareTo(BigDecimal.ZERO) == 0 || lastYearWeekContractAmount.compareTo(BigDecimal.ZERO) == 0) { |
| | | weekYny = "0.00"; |
| | | }else{ |
| | | } else { |
| | | weekYny = String.format("%.2f", subtract.divide(lastYearWeekContractAmount, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100"))); |
| | | |
| | | } |
| | |
| | | BigDecimal subtract1 = todayContractAmount.subtract(lastYearYesterdayContractAmount); // 修改:使用 todayContractAmount 而不是 yesterdayContractAmount |
| | | // 日环比 |
| | | String chain = ""; |
| | | if(subtract1.compareTo(BigDecimal.ZERO) == 0 || lastYearYesterdayContractAmount.compareTo(BigDecimal.ZERO) == 0){ |
| | | if (subtract1.compareTo(BigDecimal.ZERO) == 0 || lastYearYesterdayContractAmount.compareTo(BigDecimal.ZERO) == 0) { |
| | | chain = "0.00"; |
| | | }else{ |
| | | } else { |
| | | chain = String.format("%.2f", subtract1.divide(lastYearYesterdayContractAmount, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100"))); |
| | | } |
| | | |
| | |
| | | Map<String, BigDecimal> collect = salesLedgers.stream().collect(Collectors.groupingBy(SalesLedger::getCustomerName, Collectors.reducing(BigDecimal.ZERO, |
| | | SalesLedger::getContractAmount, BigDecimal::add))); |
| | | List<MapDto> mapDtos = new ArrayList<>(); |
| | | collect.forEach((k,v)->{ |
| | | collect.forEach((k, v) -> { |
| | | MapDto mapDto = new MapDto(); |
| | | mapDto.setName(k); |
| | | // 修改:将金额值保留两位小数 |
| | | mapDto.setValue(v.setScale(2, RoundingMode.HALF_UP).toString()); |
| | | if(contractAmount.compareTo(new BigDecimal(0)) == 0){ |
| | | if (contractAmount.compareTo(new BigDecimal(0)) == 0) { |
| | | mapDto.setRate("0"); |
| | | }else{ |
| | | } else { |
| | | mapDto.setRate(String.format("%.2f", v.divide(contractAmount, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")))); |
| | | } |
| | | mapDtos.add(mapDto); |
| | |
| | | .filter(inspect -> inspect.getInspectType().equals(1)) |
| | | .map(QualityInspect::getQuantity) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | processNum= processNum.add(reduce1); |
| | | processNum = processNum.add(reduce1); |
| | | BigDecimal reduce2 = monthInspects.stream() |
| | | .filter(inspect -> inspect.getInspectType().equals(2)) |
| | | .map(QualityInspect::getQuantity) |
| | |
| | | LambdaQueryWrapper<ApproveProcess> approveProcessLambdaQueryWrapper = new LambdaQueryWrapper<>(); |
| | | approveProcessLambdaQueryWrapper.eq(ApproveProcess::getApproveDelete, 0) |
| | | .eq(ApproveProcess::getApproveUserCurrentId, loginUser.getUserId()) |
| | | .ne(ApproveProcess::getApproveStatus, 2) |
| | | .eq(ApproveProcess::getTenantId, loginUser.getTenantId()); |
| | | .ne(ApproveProcess::getApproveStatus, 2); |
| | | // .eq(ApproveProcess::getTenantId, loginUser.getTenantId()); |
| | | List<ApproveProcess> approveProcesses = approveProcessMapper.selectList(approveProcessLambdaQueryWrapper); |
| | | if(CollectionUtils.isEmpty(approveProcesses)){ |
| | | if (CollectionUtils.isEmpty(approveProcesses)) { |
| | | approveProcesses = new ArrayList<>(); |
| | | } |
| | | // 查询未领用劳保记录 |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | |
| | | LaborIssue laborIssue1 = new LaborIssue(); |
| | | laborIssue1.setAdoptedDate(new Date()); |
| | | laborIssue1.setIssueDate(sdf.parse(sdf.format(new Date()))); |
| | | List<LaborIssue> laborIssues = lavorIssueMapper.list(laborIssue1); |
| | | if(!CollectionUtils.isEmpty(laborIssues)){ |
| | | for (LaborIssue laborIssue : laborIssues) { |
| | | ApproveProcess approveProcess = new ApproveProcess(); |
| | | approveProcess.setApproveId(laborIssue.getOrderNo()); |
| | | approveProcess.setApproveDeptName(sysDeptMapper.selectDeptById(loginUser.getTenantId()).getDeptName()); |
| | | approveProcess.setApproveTime(laborIssue.getIssueDate()); |
| | | approveProcess.setApproveReason(laborIssue.getDictTypeName() + "-" + laborIssue.getDictName() + "超时未领取"); |
| | | approveProcesses.add(approveProcess); |
| | | approveProcesses.forEach(a -> { |
| | | if (a.getApproveType() != null) { |
| | | a.setApproveTypeName(ApproveTypeEnum.getNameByCode(a.getApproveType())); |
| | | } |
| | | } |
| | | }); |
| | | // // 查询未领用劳保记录 |
| | | // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | // |
| | | // LaborIssue laborIssue1 = new LaborIssue(); |
| | | // laborIssue1.setAdoptedDate(new Date()); |
| | | // laborIssue1.setIssueDate(sdf.parse(sdf.format(new Date()))); |
| | | // List<LaborIssue> laborIssues = lavorIssueMapper.list(laborIssue1); //staff_join_leave_record表被删除 |
| | | // if(!CollectionUtils.isEmpty(laborIssues)){ |
| | | // for (LaborIssue laborIssue : laborIssues) { |
| | | // ApproveProcess approveProcess = new ApproveProcess(); |
| | | // approveProcess.setApproveId(laborIssue.getOrderNo()); |
| | | // approveProcess.setApproveDeptName(sysDeptMapper.selectDeptById(loginUser.getTenantId()).getDeptName()); |
| | | // approveProcess.setApproveTime(laborIssue.getIssueDate()); |
| | | // approveProcess.setApproveReason(laborIssue.getDictTypeName() + "-" + laborIssue.getDictName() + "超时未领取"); |
| | | // approveProcesses.add(approveProcess); |
| | | // } |
| | | // } |
| | | |
| | | |
| | | return approveProcesses; |
| | | } |
| | | |
| | | /** |
| | | * |
| | | * @param type 1-周 2-月 3-季度 |
| | | * @return |
| | | */ |
| | |
| | | LocalDate today = LocalDate.now(); |
| | | LocalDate startDate = null; |
| | | LocalDate endDate = null; |
| | | switch (type){ |
| | | switch (type) { |
| | | case 1: |
| | | // 获取本周周一 |
| | | startDate = today.with(DayOfWeek.MONDAY); |
| | |
| | | |
| | | return statisticsReceivablePayableDto; |
| | | } |
| | | |
| | | public static <T> BigDecimal sumAmount(List<T> list, java.util.function.Function<T, BigDecimal> amountExtractor) { |
| | | return list.stream() |
| | | // 提取金额时,将null替换为BigDecimal.ZERO |
| | |
| | | // 累加,初始值为0,避免空流问题 |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | } |
| | | |
| | | @Autowired |
| | | private DeviceRepairMapper deviceRepairMapper; |
| | | |
| | |
| | | .eq(Notice::getStatus, 1) // 1表示发布状态 |
| | | .ge(Notice::getExpirationDate, new Date())); // 过期时间大于等于当前日期 |
| | | } |
| | | |
| | | @Override |
| | | public ProductionProgressDto productionProgress() { |
| | | ProductionProgressDto productionProgressDto = new ProductionProgressDto(); |
| | | ProductOrderDto orderDto = new ProductOrderDto(); |
| | | orderDto.setStartTime(LocalDateTime.now().minusMonths(1)); |
| | | orderDto.setEndTime(LocalDateTime.now()); |
| | | List<ProductOrderDto> productOrderDtos = productOrderMapper.pageProductOrder(new Page<>(1, -1), orderDto).getRecords(); |
| | | productionProgressDto.setCompletedOrderDetails(productOrderDtos); |
| | | long totalCount = productOrderDtos.size(); |
| | | long count = productOrderDtos.stream().filter(productOrderDto -> productOrderDto.getCompleteQuantity().compareTo(productOrderDto.getQuantity()) >= 0).count(); |
| | | long count2 = productOrderDtos.stream().filter(productOrderDto -> productOrderDto.getCompleteQuantity().compareTo(BigDecimal.ZERO) == 0).count(); |
| | | productionProgressDto.setTotalOrderCount(totalCount); |
| | | productionProgressDto.setCompletedOrderCount(count); |
| | | productionProgressDto.setUncompletedOrderCount(count2); |
| | | productionProgressDto.setPartialCompletedOrderCount(totalCount - count - count2); |
| | | return productionProgressDto; |
| | | } |
| | | |
| | | @Override |
| | | public ProductionTurnoverDto workInProcessTurnover() { |
| | | ProductionTurnoverDto productionTurnoverDto = new ProductionTurnoverDto(); |
| | | ProductWorkOrderDto workOrder = new ProductWorkOrderDto(); |
| | | workOrder.setPlanStartTime(LocalDate.now().minusMonths(1)); |
| | | workOrder.setPlanEndTime(LocalDate.now()); |
| | | List<ProductWorkOrderDto> productWorkOrders = productWorkOrderMapper.pageProductWorkOrder(new Page<>(1, -1), workOrder).getRecords(); |
| | | long sum = productWorkOrders.stream() |
| | | .filter(productWorkOrder -> productWorkOrder.getPlanQuantity().compareTo(productWorkOrder.getCompleteQuantity()) > 0) |
| | | .map(ProductWorkOrder::getPlanQuantity) |
| | | .mapToLong(BigDecimal::longValue) |
| | | .sum(); |
| | | if (sum == 0) return null; |
| | | productionTurnoverDto.setTotalOrderCount(sum);//总在制品数量 |
| | | productionTurnoverDto.setAverageTurnoverDays(BigDecimal.valueOf(sum).divide(BigDecimal.valueOf(ChronoUnit.DAYS.between(LocalDateTime.now().minusMonths(1), LocalDateTime.now())), 2, RoundingMode.HALF_UP)); |
| | | long completeQuantity = productWorkOrders.stream() |
| | | .filter(productWorkOrder -> productWorkOrder.getCompleteQuantity().compareTo(productWorkOrder.getPlanQuantity()) >= 0) |
| | | .map(ProductWorkOrder::getCompleteQuantity) |
| | | .mapToLong(BigDecimal::longValue) |
| | | .sum(); |
| | | productionTurnoverDto.setTurnoverEfficiency(BigDecimal.valueOf(completeQuantity).divide(BigDecimal.valueOf(sum), 2, RoundingMode.HALF_UP)); |
| | | Map<String, List<ProductWorkOrderDto>> map = productWorkOrders.stream() |
| | | .filter(productWorkOrder -> productWorkOrder.getPlanQuantity().compareTo(productWorkOrder.getCompleteQuantity()) > 0) |
| | | .collect(Collectors.groupingBy(ProductWorkOrderDto::getProcessName)); |
| | | List<String> strings = new ArrayList<>(); |
| | | List<Long> processQuantityDetails = new ArrayList<>(); |
| | | map.entrySet().stream().forEach(entry -> { |
| | | String key = entry.getKey(); |
| | | long completeSum = entry.getValue().stream().map(ProductWorkOrderDto::getCompleteQuantity).mapToLong(BigDecimal::longValue).sum(); |
| | | strings.add(key); |
| | | processQuantityDetails.add(completeSum); |
| | | }); |
| | | productionTurnoverDto.setProcessDetails(strings); |
| | | productionTurnoverDto.setProcessQuantityDetails(processQuantityDetails); |
| | | return productionTurnoverDto; |
| | | } |
| | | |
| | | @Override |
| | | public DeptStaffDistributionDto deptStaffDistribution() { |
| | | DeptStaffDistributionDto dto = new DeptStaffDistributionDto(); |
| | | List<MapDto> items = new ArrayList<>(); |
| | | |
| | | // 查询所有正常且未删除的部门 |
| | | List<SysDept> depts = sysDeptMapper.selectDeptList(new SysDept()); |
| | | if (CollectionUtils.isEmpty(depts)) { |
| | | dto.setItems(items); |
| | | return dto; |
| | | } |
| | | |
| | | long totalUsers = 0; |
| | | List<Map<String, Object>> countsByDept = new ArrayList<>(); |
| | | |
| | | for (SysDept dept : depts) { |
| | | if ("0".equals(dept.getStatus()) && "0".equals(dept.getDelFlag())) { |
| | | Long count = sysUserDeptMapper.selectCount(new LambdaQueryWrapper<SysUserDept>() |
| | | .eq(SysUserDept::getDeptId, dept.getDeptId())); |
| | | if (count > 0) { |
| | | Map<String, Object> map = new HashMap<>(); |
| | | map.put("name", dept.getDeptName()); |
| | | map.put("count", count); |
| | | countsByDept.add(map); |
| | | totalUsers += count; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (totalUsers > 0) { |
| | | BigDecimal total = BigDecimal.valueOf(totalUsers); |
| | | for (Map<String, Object> map : countsByDept) { |
| | | MapDto mapDto = new MapDto(); |
| | | mapDto.setName((String) map.get("name")); |
| | | Long count = (Long) map.get("count"); |
| | | mapDto.setValue(count.toString()); |
| | | mapDto.setRate(BigDecimal.valueOf(count).multiply(new BigDecimal("100")) |
| | | .divide(total, 2, RoundingMode.HALF_UP).toString()); |
| | | items.add(mapDto); |
| | | } |
| | | } |
| | | |
| | | dto.setTotal(totalUsers); |
| | | dto.setItems(items); |
| | | return dto; |
| | | } |
| | | |
| | | @Override |
| | | public HomeSummaryDto summaryStatistics() { |
| | | HomeSummaryDto dto = new HomeSummaryDto(); |
| | | LocalDate now = LocalDate.now(); |
| | | YearMonth currentMonth = YearMonth.from(now); |
| | | YearMonth prevMonth = currentMonth.minusMonths(1); |
| | | |
| | | LocalDateTime currentMonthEnd = currentMonth.atEndOfMonth().atTime(23, 59, 59); |
| | | LocalDateTime prevMonthEnd = prevMonth.atEndOfMonth().atTime(23, 59, 59); |
| | | |
| | | // 总工作人员 |
| | | Long currentStaff = countStaff(currentMonthEnd); |
| | | Long prevStaff = countStaff(prevMonthEnd); |
| | | dto.setTotalStaff(currentStaff); |
| | | dto.setStaffGrowthRate(calculateMoM(currentStaff, prevStaff)); |
| | | |
| | | // 总客户数 |
| | | Long currentCustomers = countCustomers(currentMonthEnd); |
| | | Long prevCustomers = countCustomers(prevMonthEnd); |
| | | dto.setTotalCustomer(currentCustomers); |
| | | dto.setCustomerGrowthRate(calculateMoM(currentCustomers, prevCustomers)); |
| | | |
| | | // 总供应商数 |
| | | Long currentSuppliers = countSuppliers(currentMonthEnd); |
| | | Long prevSuppliers = countSuppliers(prevMonthEnd); |
| | | dto.setTotalSupplier(currentSuppliers); |
| | | dto.setSupplierGrowthRate(calculateMoM(currentSuppliers, prevSuppliers)); |
| | | |
| | | return dto; |
| | | } |
| | | |
| | | private Long countStaff(LocalDateTime dateTime) { |
| | | Long sysUserCount = sysUserMapper.selectCount(new LambdaQueryWrapper<SysUser>() |
| | | .eq(SysUser::getDelFlag, "0") |
| | | .le(SysUser::getCreateTime, dateTime)); |
| | | Long staffCountItem = staffOnJobMapper.selectCount(new LambdaQueryWrapper<StaffOnJob>() |
| | | .le(StaffOnJob::getCreateTime, dateTime)); |
| | | return sysUserCount + staffCountItem; |
| | | } |
| | | |
| | | |
| | | private Long countCustomers(LocalDateTime dateTime) { |
| | | return customerMapper.selectCount(new LambdaQueryWrapper<Customer>() |
| | | .le(Customer::getMaintenanceTime, dateTime.toLocalDate())); |
| | | } |
| | | |
| | | private Long countSuppliers(LocalDateTime dateTime) { |
| | | return supplierManageMapper.selectCount(new LambdaQueryWrapper<SupplierManage>() |
| | | .le(SupplierManage::getCreateTime, dateTime)); |
| | | } |
| | | |
| | | private String calculateMoM(Number current, Number prev) { |
| | | BigDecimal curVal = new BigDecimal(current.toString()); |
| | | BigDecimal prevVal = new BigDecimal(prev.toString()); |
| | | if (prevVal.compareTo(BigDecimal.ZERO) == 0) { |
| | | return curVal.compareTo(BigDecimal.ZERO) > 0 ? "100.00" : "0.00"; |
| | | } |
| | | return curVal.subtract(prevVal) |
| | | .divide(prevVal, 4, RoundingMode.HALF_UP) |
| | | .multiply(new BigDecimal("100")) |
| | | .setScale(2, RoundingMode.HALF_UP) |
| | | .toString(); |
| | | } |
| | | |
| | | @Override |
| | | public List<SupplierPurchaseRankingDto> supplierPurchaseRanking(Integer type) { |
| | | LocalDate today = LocalDate.now(); |
| | | LocalDate startDate; |
| | | LocalDate endDate; |
| | | switch (type) { |
| | | case 1: // 周 |
| | | startDate = today.with(DayOfWeek.MONDAY); |
| | | endDate = today.with(DayOfWeek.SUNDAY); |
| | | break; |
| | | case 2: // 月 |
| | | startDate = today.with(TemporalAdjusters.firstDayOfMonth()); |
| | | endDate = today.with(TemporalAdjusters.lastDayOfMonth()); |
| | | break; |
| | | case 3: // 季度 |
| | | Month currentMonth = today.getMonth(); |
| | | Month firstMonthOfQuarter = currentMonth.firstMonthOfQuarter(); |
| | | Month lastMonthOfQuarter = Month.of(firstMonthOfQuarter.getValue() + 2); |
| | | |
| | | startDate = today.withMonth(firstMonthOfQuarter.getValue()).with(TemporalAdjusters.firstDayOfMonth()); |
| | | endDate = today.withMonth(lastMonthOfQuarter.getValue()).with(TemporalAdjusters.lastDayOfMonth()); |
| | | break; |
| | | default: |
| | | return new ArrayList<>(); |
| | | } |
| | | |
| | | QueryWrapper<PurchaseLedger> queryWrapper = new QueryWrapper<>(); |
| | | queryWrapper.select("supplier_name", "SUM(contract_amount) as total_amount") |
| | | .ge("entry_date", startDate) |
| | | .le("entry_date", endDate) |
| | | // .ne("approval_status", 3) |
| | | .groupBy("supplier_name") |
| | | .orderByDesc("total_amount") |
| | | .last("LIMIT 5"); |
| | | |
| | | List<Map<String, Object>> maps = purchaseLedgerMapper.selectMaps(queryWrapper); |
| | | return maps.stream().map(map -> { |
| | | SupplierPurchaseRankingDto dto = new SupplierPurchaseRankingDto(); |
| | | dto.setSupplierName(map.get("supplier_name") != null ? map.get("supplier_name").toString() : ""); |
| | | Object amount = map.get("total_amount"); |
| | | dto.setTotalAmount(amount != null ? new BigDecimal(amount.toString()) : BigDecimal.ZERO); |
| | | return dto; |
| | | }).collect(Collectors.toList()); |
| | | } |
| | | |
| | | @Override |
| | | public CustomerRevenueAnalysisDto customerRevenueAnalysis(Long customerId, Integer type) { |
| | | CustomerRevenueAnalysisDto dto = new CustomerRevenueAnalysisDto(); |
| | | List<MapDto> items = new ArrayList<>(); |
| | | LocalDate today = LocalDate.now(); |
| | | |
| | | LocalDate start; |
| | | LocalDate end; |
| | | boolean groupByMonth = false; |
| | | |
| | | switch (type) { |
| | | case 1: // 周 |
| | | start = today.with(DayOfWeek.MONDAY); |
| | | end = today.with(DayOfWeek.SUNDAY); |
| | | break; |
| | | case 2: // 月 |
| | | start = today.with(TemporalAdjusters.firstDayOfMonth()); |
| | | end = today.with(TemporalAdjusters.lastDayOfMonth()); |
| | | break; |
| | | case 3: // 季度 |
| | | Month firstMonthOfQuarter = today.getMonth().firstMonthOfQuarter(); |
| | | start = today.withMonth(firstMonthOfQuarter.getValue()).with(TemporalAdjusters.firstDayOfMonth()); |
| | | end = today.withMonth(firstMonthOfQuarter.plus(2).getValue()).with(TemporalAdjusters.lastDayOfMonth()); |
| | | groupByMonth = true; |
| | | break; |
| | | default: |
| | | dto.setItems(items); |
| | | return dto; |
| | | } |
| | | |
| | | List<SalesLedger> list = salesLedgerMapper.selectList(new LambdaQueryWrapper<SalesLedger>() |
| | | .eq(SalesLedger::getCustomerId, customerId) |
| | | .ge(SalesLedger::getEntryDate, start) |
| | | .le(SalesLedger::getEntryDate, end)); |
| | | |
| | | if (groupByMonth) { |
| | | for (int i = 0; i < 3; i++) { |
| | | LocalDate m = start.plusMonths(i); |
| | | String monthName = m.getMonthValue() + "月"; |
| | | BigDecimal sum = list.stream() |
| | | .filter(l -> l.getEntryDate() != null) |
| | | .filter(l -> { |
| | | LocalDate ld = l.getEntryDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); |
| | | return ld.getMonth() == m.getMonth() && ld.getYear() == m.getYear(); |
| | | }) |
| | | .map(SalesLedger::getContractAmount) |
| | | .filter(Objects::nonNull) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | MapDto mapDto = new MapDto(); |
| | | mapDto.setName(monthName); |
| | | mapDto.setValue(sum.setScale(2, RoundingMode.HALF_UP).toString()); |
| | | items.add(mapDto); |
| | | } |
| | | } else { |
| | | long days = ChronoUnit.DAYS.between(start, end) + 1; |
| | | for (int i = 0; i < days; i++) { |
| | | LocalDate d = start.plusDays(i); |
| | | String dayName = d.getMonthValue() + "/" + d.getDayOfMonth(); |
| | | BigDecimal sum = list.stream() |
| | | .filter(l -> l.getEntryDate() != null) |
| | | .filter(l -> l.getEntryDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().equals(d)) |
| | | .map(SalesLedger::getContractAmount) |
| | | .filter(Objects::nonNull) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | MapDto mapDto = new MapDto(); |
| | | mapDto.setName(dayName); |
| | | mapDto.setValue(sum.setScale(2, RoundingMode.HALF_UP).toString()); |
| | | items.add(mapDto); |
| | | } |
| | | } |
| | | |
| | | dto.setItems(items); |
| | | return dto; |
| | | } |
| | | |
| | | @Override |
| | | public ProductCategoryDistributionDto productCategoryDistribution() { |
| | | ProductCategoryDistributionDto dto = new ProductCategoryDistributionDto(); |
| | | List<ProductCategoryDistributionDto.MajorCategoryDto> majorItems = new ArrayList<>(); |
| | | |
| | | // 查询所有的产品类别 |
| | | List<Product> allProducts = productMapper.selectList(new LambdaQueryWrapper<>()); |
| | | if (CollectionUtils.isEmpty(allProducts)) { |
| | | dto.setItems(majorItems); |
| | | return dto; |
| | | } |
| | | |
| | | // 分离大类和小类 |
| | | List<Product> majorCategories = allProducts.stream() |
| | | .filter(p -> p.getParentId() == null) |
| | | .collect(Collectors.toList()); |
| | | List<Product> minorCategories = allProducts.stream() |
| | | .filter(p -> p.getParentId() != null) |
| | | .collect(Collectors.toList()); |
| | | |
| | | // 按父类ID对小类进行分组 |
| | | Map<Long, List<Product>> minorGroupMap = minorCategories.stream() |
| | | .collect(Collectors.groupingBy(Product::getParentId)); |
| | | |
| | | int totalMinorCount = minorCategories.size(); |
| | | |
| | | for (Product major : majorCategories) { |
| | | ProductCategoryDistributionDto.MajorCategoryDto majorDto = new ProductCategoryDistributionDto.MajorCategoryDto(); |
| | | majorDto.setName(major.getProductName()); |
| | | |
| | | List<Product> children = minorGroupMap.getOrDefault(major.getId(), new ArrayList<>()); |
| | | int childrenSize = children.size(); |
| | | // 设置小类的总数 |
| | | majorDto.setValue(String.valueOf(childrenSize)); |
| | | |
| | | // 计算占比 |
| | | if (totalMinorCount > 0) { |
| | | BigDecimal rate = BigDecimal.valueOf(childrenSize) |
| | | .multiply(new BigDecimal("100")) |
| | | .divide(BigDecimal.valueOf(totalMinorCount), 2, RoundingMode.HALF_UP); |
| | | majorDto.setRate(rate.toString()); |
| | | } else { |
| | | majorDto.setRate("0.00"); |
| | | } |
| | | |
| | | List<ProductCategoryDistributionDto.MinorCategoryDto> minorDtos = new ArrayList<>(); |
| | | for (Product minor : children) { |
| | | ProductCategoryDistributionDto.MinorCategoryDto minorDto = new ProductCategoryDistributionDto.MinorCategoryDto(); |
| | | minorDto.setName(minor.getProductName()); |
| | | minorDto.setValue("0"); |
| | | minorDto.setRate("0.00"); |
| | | minorDto.setChildren(new ArrayList<>()); |
| | | minorDtos.add(minorDto); |
| | | } |
| | | majorDto.setChildren(minorDtos); |
| | | majorItems.add(majorDto); |
| | | } |
| | | |
| | | dto.setItems(majorItems); |
| | | return dto; |
| | | } |
| | | |
| | | @Override |
| | | public List<CustomerContributionRankingDto> customerContributionRanking(Integer type) { |
| | | LocalDate today = LocalDate.now(); |
| | | LocalDate startDate = null; |
| | | LocalDate endDate = null; |
| | | switch (type) { |
| | | case 1: |
| | | startDate = today.with(DayOfWeek.MONDAY); |
| | | endDate = today.with(DayOfWeek.SUNDAY); |
| | | break; |
| | | case 2: |
| | | startDate = today.with(TemporalAdjusters.firstDayOfMonth()); |
| | | endDate = today.with(TemporalAdjusters.lastDayOfMonth()); |
| | | break; |
| | | case 3: |
| | | Month currentMonth = today.getMonth(); |
| | | Month firstMonthOfQuarter = currentMonth.firstMonthOfQuarter(); |
| | | Month lastMonthOfQuarter = Month.of(firstMonthOfQuarter.getValue() + 2); |
| | | startDate = today.withMonth(firstMonthOfQuarter.getValue()).with(TemporalAdjusters.firstDayOfMonth()); |
| | | endDate = today.withMonth(lastMonthOfQuarter.getValue()).with(TemporalAdjusters.lastDayOfMonth()); |
| | | break; |
| | | } |
| | | |
| | | QueryWrapper<SalesLedger> queryWrapper = new QueryWrapper<>(); |
| | | queryWrapper.select("customer_name", "SUM(contract_amount) as total_amount") |
| | | .isNotNull("customer_name") |
| | | .groupBy("customer_name") |
| | | .orderByDesc("total_amount") |
| | | .last("LIMIT 5"); |
| | | |
| | | if (startDate != null && endDate != null) { |
| | | queryWrapper.between("entry_date", startDate, endDate); |
| | | } |
| | | |
| | | List<Map<String, Object>> maps = salesLedgerMapper.selectMaps(queryWrapper); |
| | | List<CustomerContributionRankingDto> result = new ArrayList<>(); |
| | | for (Map<String, Object> map : maps) { |
| | | CustomerContributionRankingDto rankingDto = new CustomerContributionRankingDto(); |
| | | rankingDto.setCustomerName(map.get("customer_name").toString()); |
| | | rankingDto.setTotalAmount(map.get("total_amount") != null ? new BigDecimal(map.get("total_amount").toString()) : BigDecimal.ZERO); |
| | | result.add(rankingDto); |
| | | } |
| | | 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); |
| | | |
| | | // 采购台账(type = 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; |
| | | } |
| | | |
| | | } |