feat(account): 增加增值税报表功能并优化设备维护流程
- 在 AccountingReportController 中新增增值税图表数据和明细查询接口
- 修改 AccountStatementMapper 数据访问层以支持增值税进销项对比
- 更新 MyBatis XML 映射文件实现完整的增值税数据查询逻辑
- 调整 HomeController 中的订单状态定义,将 END 状态改为 PAUSED
- 为设备维护模块添加批量完成和单个完成功能
- 优化首页服务类中的统计查询方法,增加日期范围筛选参数
- 添加设备维护 DTO 类用于批量操作的数据传输
- 更新数据库连接配置文件以使用新的测试数据库
| | |
| | | import com.ruoyi.account.bean.vo.StatementAccountVo; |
| | | import com.ruoyi.account.pojo.AccountStatement; |
| | | import com.ruoyi.purchase.dto.VatDto; |
| | | import com.ruoyi.purchase.dto.VatSummaryDto; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | |
| | | /** |
| | | * <p> |
| | | * Mapper 接口 |
| | | * </p> |
| | | * |
| | | * @author 芯导软件(江苏)有限公司 |
| | | * @since 2026-05-19 09:42:47 |
| | | */ |
| | | import java.util.List; |
| | | |
| | | @Mapper |
| | | public interface AccountStatementMapper extends BaseMapper<AccountStatement> { |
| | | |
| | | |
| | | IPage<StatementAccountVo> listPageAccountStatement(Page page, @Param("req") StatementAccountDto statementAccountDto); |
| | | |
| | | IPage<VatDto> selectVatDtoPage(Page page, @Param("month") String month); |
| | | IPage<VatDto> selectVatDtoPage(Page page, @Param("month") String month, @Param("type") String type); |
| | | |
| | | List<VatSummaryDto> selectVatSummary(@Param("year") String year); |
| | | |
| | | IPage<VatDto> listVatDetail(Page page, @Param("month") String month); |
| | | } |
| | |
| | | @Getter |
| | | public enum SparePartsRequisitionRecordSourceTypeEnum implements BaseEnum<Integer> { |
| | | SparePartsRequisitionRecordSourceTypeRepair(0, "维修"), |
| | | SparePartsRequisitionRecordSourceTypeMaintenance(1, "保养"); |
| | | SparePartsRequisitionRecordSourceTypeMaintenance(1, "保养"), |
| | | SparePartsRequisitionRecordSourceTypeDirectOutbound(2, "直接出库"); |
| | | |
| | | private final Integer code; |
| | | private final String value; |
| | |
| | | |
| | | |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.ruoyi.device.dto.DeviceMaintenanceBatchCompleteDto; |
| | | import com.ruoyi.device.dto.DeviceMaintenanceDto; |
| | | import com.ruoyi.device.pojo.DeviceLedger; |
| | | import com.ruoyi.device.pojo.DeviceMaintenance; |
| | |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.AllArgsConstructor; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.Arrays; |
| | |
| | | deviceMaintenanceService.export(response, ids); |
| | | } |
| | | |
| | | @PostMapping("/batchComplete") |
| | | @Operation(summary = "一键保养完成") |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public AjaxResult batchComplete(@RequestBody DeviceMaintenanceBatchCompleteDto dto) { |
| | | return deviceMaintenanceService.batchComplete(dto); |
| | | } |
| | | |
| | | @PutMapping("/complete/{id}") |
| | | @Operation(summary = "保养完成") |
| | | public AjaxResult complete(@PathVariable Long id) { |
| | | return deviceMaintenanceService.complete(id); |
| | | } |
| | | |
| | | @PutMapping("/batchComplete") |
| | | @Operation(summary = "一键保养完成") |
| | | public AjaxResult batchComplete(String dateStr) { |
| | | return deviceMaintenanceService.batchComplete(dateStr); |
| | | } |
| | | |
| | | } |
| | |
| | | @Schema(description = "保养图片") |
| | | private List<StorageBlobDTO> storageBlobDTOs; |
| | | |
| | | @Schema(description = "日期分组字段(yyyy-MM-dd)") |
| | | private String dateStr; |
| | | |
| | | } |
| | | |
| | |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.ruoyi.device.dto.DeviceMaintenanceBatchCompleteDto; |
| | | import com.ruoyi.device.dto.DeviceMaintenanceDto; |
| | | import com.ruoyi.device.pojo.DeviceMaintenance; |
| | | import com.ruoyi.device.vo.DeviceMaintenanceVo; |
| | |
| | | void export(HttpServletResponse response, Long[] ids); |
| | | |
| | | DeviceMaintenanceVo detailById(Long id); |
| | | |
| | | AjaxResult batchComplete(DeviceMaintenanceBatchCompleteDto dto); |
| | | |
| | | AjaxResult complete(Long id); |
| | | |
| | | AjaxResult batchComplete(String dateStr); |
| | | } |
| | |
| | | package com.ruoyi.device.service.impl; |
| | | |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ruoyi.basic.enums.RecordTypeEnum; |
| | | import com.ruoyi.basic.utils.FileUtil; |
| | | import com.ruoyi.common.utils.SecurityUtils; |
| | | import com.ruoyi.common.utils.bean.BeanUtils; |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | | import com.ruoyi.device.dto.DeviceMaintenanceBatchCompleteDto; |
| | | import com.ruoyi.device.dto.DeviceMaintenanceDto; |
| | | import com.ruoyi.device.execl.DeviceMaintenanceExeclDto; |
| | | import com.ruoyi.device.mapper.DeviceMaintenanceMapper; |
| | |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | // 若设置了实际保养日期,则自动标记为完结 |
| | | if (deviceMaintenance.getMaintenanceActuallyTime() != null && deviceMaintenance.getStatus() == null) { |
| | | deviceMaintenance.setStatus(1); |
| | | } |
| | | |
| | | if (this.updateById(deviceMaintenance)) { |
| | | // 处理图片上传 |
| | | fileUtil.saveStorageAttachmentByRecordTypeAndRecordId("file", RecordTypeEnum.DEVICE_MAINTENANCE, deviceMaintenance.getId(), deviceMaintenance.getStorageBlobDTOs()); |
| | |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public AjaxResult complete(Long id) { |
| | | DeviceMaintenance record = this.getById(id); |
| | | if (record == null) { |
| | | return AjaxResult.error("保养记录不存在"); |
| | | } |
| | | if (record.getStatus() != null && record.getStatus() == 1) { |
| | | return AjaxResult.error("该保养记录已完成"); |
| | | } |
| | | record.setStatus(1); |
| | | record.setMaintenanceActuallyName(SecurityUtils.getLoginUser().getNickName()); |
| | | record.setMaintenanceActuallyTime(LocalDateTime.now()); |
| | | this.updateById(record); |
| | | return AjaxResult.success(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public AjaxResult batchComplete(String dateStr) { |
| | | if (StringUtils.isBlank(dateStr)) { |
| | | return AjaxResult.error("日期参数不能为空"); |
| | | } |
| | | LocalDate date = LocalDate.parse(dateStr); |
| | | LocalDateTime startOfDay = date.atStartOfDay(); |
| | | LocalDateTime endOfDay = date.atTime(LocalTime.MAX); |
| | | List<DeviceMaintenance> records = this.lambdaQuery() |
| | | .eq(DeviceMaintenance::getStatus, 0) |
| | | .ge(DeviceMaintenance::getCreateTime, startOfDay) |
| | | .le(DeviceMaintenance::getCreateTime, endOfDay) |
| | | .list(); |
| | | if (records.isEmpty()) { |
| | | return AjaxResult.error("该日期下没有待完成的保养记录"); |
| | | } |
| | | String nickName = SecurityUtils.getLoginUser().getNickName(); |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | for (DeviceMaintenance record : records) { |
| | | record.setStatus(1); |
| | | record.setMaintenanceActuallyName(nickName); |
| | | record.setMaintenanceActuallyTime(now); |
| | | } |
| | | this.updateBatchById(records); |
| | | return AjaxResult.success("已完成 " + records.size() + " 条保养记录"); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public AjaxResult batchComplete(DeviceMaintenanceBatchCompleteDto dto) { |
| | | if (dto.getMaintenancePlanDate() == null) { |
| | | return AjaxResult.error("计划保养日期不能为空"); |
| | | } |
| | | LambdaQueryWrapper<DeviceMaintenance> wrapper = new LambdaQueryWrapper<>(); |
| | | wrapper.eq(DeviceMaintenance::getStatus, 0) |
| | | .apply("DATE(maintenance_plan_time) = {0}", dto.getMaintenancePlanDate().toString()); |
| | | List<DeviceMaintenance> list = this.list(wrapper); |
| | | if (list.isEmpty()) { |
| | | return AjaxResult.success("该日期下没有待保养的记录"); |
| | | } |
| | | list.forEach(task -> { |
| | | task.setStatus(1); |
| | | if (StringUtils.isNotBlank(dto.getMaintenanceActuallyName())) { |
| | | task.setMaintenanceActuallyName(dto.getMaintenanceActuallyName()); |
| | | } |
| | | if (dto.getMaintenanceActuallyTime() != null) { |
| | | task.setMaintenanceActuallyTime(dto.getMaintenanceActuallyTime()); |
| | | } |
| | | if (StringUtils.isNotBlank(dto.getMaintenanceResult())) { |
| | | task.setMaintenanceResult(dto.getMaintenanceResult()); |
| | | } |
| | | }); |
| | | this.updateBatchById(list); |
| | | return AjaxResult.success("共完成 " + list.size() + " 条保养记录"); |
| | | } |
| | | |
| | | @Override |
| | | public void export(HttpServletResponse response, Long[] ids) { |
| | | List<DeviceMaintenance> supplierManageList = deviceMaintenanceMapper.selectList(null); |
| | | ArrayList<DeviceMaintenanceExeclDto> deviceLedgerExeclDtos = new ArrayList<>(); |
| | |
| | | private static final Integer ORDER_STATUS_WAIT = 1; |
| | | private static final Integer ORDER_STATUS_RUNNING = 2; |
| | | private static final Integer ORDER_STATUS_COMPLETED = 3; |
| | | //private static final Integer ORDER_STATUS_END = 4; // 已取消 |
| | | private static final Integer ORDER_STATUS_END = 5; |
| | | private static final Integer ORDER_STATUS_PAUSED = 4; |
| | | |
| | | /********************************************************基础类*****************************************************/ |
| | | @GetMapping("/todos") |
| | |
| | | /********************************************************营销采购类**************************************************/ |
| | | @GetMapping("/supplierPurchaseRanking") |
| | | @Operation(summary = "供应商采购排名") |
| | | public R supplierPurchaseRanking(@DefaultType Integer type) { |
| | | List<SupplierPurchaseRankingDto> list = homeService.supplierPurchaseRanking(type); |
| | | public R supplierPurchaseRanking(@DefaultType Integer type, |
| | | @RequestParam(required = false) String startDate, |
| | | @RequestParam(required = false) String endDate) { |
| | | List<SupplierPurchaseRankingDto> list = homeService.supplierPurchaseRanking(type, startDate, endDate); |
| | | return R.ok(list); |
| | | } |
| | | |
| | |
| | | |
| | | @GetMapping("/customerContributionRanking") |
| | | @Operation(summary = "客户金额贡献排名") |
| | | public R customerContributionRanking(@DefaultType Integer type) { |
| | | List<CustomerContributionRankingDto> list = homeService.customerContributionRanking(type); |
| | | public R customerContributionRanking(@DefaultType Integer type, |
| | | @RequestParam(required = false) String startDate, |
| | | @RequestParam(required = false) String endDate) { |
| | | List<CustomerContributionRankingDto> list = homeService.customerContributionRanking(type, startDate, endDate); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | @GetMapping("/productSalesAnalysis") |
| | | @Operation(summary = "各产品销售金额分析") |
| | | public R productSalesAnalysis() { |
| | | List<MapDto> list = homeService.productSalesAnalysis(); |
| | | public R productSalesAnalysis( |
| | | @RequestParam(required = false) String startDate, |
| | | @RequestParam(required = false) String endDate) { |
| | | List<MapDto> list = homeService.productSalesAnalysis(startDate, endDate); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | @GetMapping("/rawMaterialPurchaseAmountRatio") |
| | | @Operation(summary = "原材料采购金额占比") |
| | | public R rawMaterialPurchaseAmountRatio(){ |
| | | List<MapDto> list = homeService.rawMaterialPurchaseAmountRatio(); |
| | | public R rawMaterialPurchaseAmountRatio( |
| | | @RequestParam(required = false) String startDate, |
| | | @RequestParam(required = false) String endDate){ |
| | | List<MapDto> list = homeService.rawMaterialPurchaseAmountRatio(startDate, endDate); |
| | | return R.ok(list); |
| | | } |
| | | |
| | |
| | | } |
| | | Integer statusFromParam = parseOrderStatus(status); |
| | | if (!isBlank(status) && statusFromParam == null && !"all".equalsIgnoreCase(status.trim())) { |
| | | return R.fail("status参数不合法,可选值:all/waiting/inProgress/completed/end 或 1/2/3/5"); |
| | | return R.fail("status参数不合法,可选值:all/waiting/inProgress/completed/paused 或 1/2/3/4"); |
| | | } |
| | | Integer queryStatus = resolveOrderStatus(status, tab); |
| | | |
| | |
| | | long waitingCount = 0L; |
| | | long inProgressCount = 0L; |
| | | long completedCount = 0L; |
| | | long endCount = 0L; |
| | | long pausedCount = 0L; |
| | | List<Map<String, Object>> statusCountRows = productionOrderMapper.countHomeOrderProgressByStatus(startTime, endTime); |
| | | if (statusCountRows != null) { |
| | | for (Map<String, Object> countRow : statusCountRows) { |
| | |
| | | inProgressCount = cnt; |
| | | } else if (Objects.equals(statusKey, ORDER_STATUS_COMPLETED)) { |
| | | completedCount = cnt; |
| | | } else if (Objects.equals(statusKey, ORDER_STATUS_END)) { |
| | | endCount = cnt; |
| | | } else if (Objects.equals(statusKey, ORDER_STATUS_PAUSED)) { |
| | | pausedCount = cnt; |
| | | } |
| | | } |
| | | } |
| | |
| | | result.put("waitingCount", waitingCount); |
| | | result.put("inProgressCount", inProgressCount); |
| | | result.put("completedCount", completedCount); |
| | | result.put("endCount", endCount); |
| | | result.put("pausedCount", pausedCount); |
| | | result.put("records", records); |
| | | return R.ok(result); |
| | | } |
| | |
| | | |
| | | @GetMapping("/salesPurchaseStorageProductCount") |
| | | @Operation(summary = "销售-采购-储存产品数") |
| | | public R salesPurchaseStorageProductCount(){ |
| | | List<MapDto> list = homeService.salesPurchaseStorageProductCount(); |
| | | public R salesPurchaseStorageProductCount( |
| | | @RequestParam(required = false) String startDate, |
| | | @RequestParam(required = false) String endDate){ |
| | | List<MapDto> list = homeService.salesPurchaseStorageProductCount(startDate, endDate); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | @GetMapping("/productInOutAnalysis") |
| | | @Operation(summary = "产品出入库分析") |
| | | public R productInOutAnalysis(@DefaultType Integer type){ |
| | | List<Map<String, Object>> result = homeService.productInOutAnalysis(type); |
| | | public R productInOutAnalysis(@DefaultType Integer type, |
| | | @RequestParam(required = false) String startDate, |
| | | @RequestParam(required = false) String endDate){ |
| | | List<Map<String, Object>> result = homeService.productInOutAnalysis(type, startDate, endDate); |
| | | return R.ok(result); |
| | | } |
| | | |
| | | @GetMapping("/productTurnoverDays") |
| | | @Operation(summary = "产品周转天数") |
| | | public R productTurnoverDays(){ |
| | | List<MapDto> list = homeService.productTurnoverDays(); |
| | | public R productTurnoverDays( |
| | | @RequestParam(required = false) String startDate, |
| | | @RequestParam(required = false) String endDate){ |
| | | List<MapDto> list = homeService.productTurnoverDays(startDate, endDate); |
| | | return R.ok(list); |
| | | } |
| | | |
| | |
| | | if ("3".equals(normalized) || "completed".equals(normalized)) { |
| | | return ORDER_STATUS_COMPLETED; |
| | | } |
| | | if ("5".equals(normalized) || "end".equals(normalized)) { |
| | | return ORDER_STATUS_END; |
| | | if ("4".equals(normalized) || "paused".equals(normalized)) { |
| | | return ORDER_STATUS_PAUSED; |
| | | } |
| | | return null; |
| | | } |
| | |
| | | if (Objects.equals(status, ORDER_STATUS_COMPLETED)) { |
| | | return "completed"; |
| | | } |
| | | if (Objects.equals(status, ORDER_STATUS_END)) { |
| | | return "end"; |
| | | if (Objects.equals(status, ORDER_STATUS_PAUSED)) { |
| | | return "paused"; |
| | | } |
| | | if (Objects.equals(status, ORDER_STATUS_WAIT)) { |
| | | return "waiting"; |
| | |
| | | if (Objects.equals(status, ORDER_STATUS_COMPLETED)) { |
| | | return "completed"; |
| | | } |
| | | if (Objects.equals(status, ORDER_STATUS_END)) { |
| | | return "end"; |
| | | if (Objects.equals(status, ORDER_STATUS_PAUSED)) { |
| | | return "paused"; |
| | | } |
| | | return "all"; |
| | | } |
| | |
| | | if (Objects.equals(status, ORDER_STATUS_COMPLETED)) { |
| | | return "已完成"; |
| | | } |
| | | if (Objects.equals(status, ORDER_STATUS_END)) { |
| | | return "已结束"; |
| | | if (Objects.equals(status, ORDER_STATUS_PAUSED)) { |
| | | return "已暂停"; |
| | | } |
| | | return "未知"; |
| | | } |
| | |
| | | .select(ProductionOrder::getQuantity, ProductionOrder::getCompleteQuantity) |
| | | .ge(ProductionOrder::getCreateTime, day.atStartOfDay()) |
| | | .lt(ProductionOrder::getCreateTime, day.plusDays(1).atStartOfDay()) |
| | | .ne(ProductionOrder::getStatus, ORDER_STATUS_END)); |
| | | .ne(ProductionOrder::getStatus, ORDER_STATUS_PAUSED)); |
| | | |
| | | BigDecimal totalQuantity = BigDecimal.ZERO; |
| | | BigDecimal totalCompleteQuantity = BigDecimal.ZERO; |
| | |
| | | |
| | | import com.ruoyi.dto.MapDto; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 首页统计 Mapper |
| | | * |
| | | * @author antigravity |
| | | */ |
| | | @Mapper |
| | | public interface HomeMapper { |
| | | /** |
| | |
| | | * @return 产品周转天数列表 |
| | | */ |
| | | List<MapDto> productTurnoverDays(); |
| | | |
| | | List<MapDto> productTurnoverDaysByDate(@Param("startDate") String startDate, @Param("endDate") String endDate); |
| | | |
| | | /** |
| | | * 查询采购品大类分布(各产品小类的采购数量/金额) |
| | | * |
| | | * @return 采购分布列表 |
| | | */ |
| | | List<MapDto> selectPurchaseCategoryDistribution(); |
| | | } |
| | |
| | | |
| | | HomeSummaryDto summaryStatistics(); |
| | | |
| | | List<SupplierPurchaseRankingDto> supplierPurchaseRanking(Integer type); |
| | | List<SupplierPurchaseRankingDto> supplierPurchaseRanking(Integer type, String startDate, String endDate); |
| | | |
| | | CustomerRevenueAnalysisDto customerRevenueAnalysis(Long customerId, Integer type); |
| | | |
| | | ProductCategoryDistributionDto productCategoryDistribution(); |
| | | |
| | | List<CustomerContributionRankingDto> customerContributionRanking(Integer type); |
| | | List<CustomerContributionRankingDto> customerContributionRanking(Integer type, String startDate, String endDate); |
| | | |
| | | List<MapDto> productSalesAnalysis(); |
| | | List<MapDto> productSalesAnalysis(String startDate, String endDate); |
| | | |
| | | List<MapDto> rawMaterialPurchaseAmountRatio(); |
| | | List<MapDto> rawMaterialPurchaseAmountRatio(String startDate, String endDate); |
| | | |
| | | List<MapDto> salesPurchaseStorageProductCount(); |
| | | List<MapDto> salesPurchaseStorageProductCount(String startDate, String endDate); |
| | | |
| | | List<Map<String, Object>> productInOutAnalysis(Integer type); |
| | | List<Map<String, Object>> productInOutAnalysis(Integer type, String startDate, String endDate); |
| | | |
| | | List<MapDto> productTurnoverDays(); |
| | | List<MapDto> productTurnoverDays(String startDate, String endDate); |
| | | |
| | | List<Map<String, Object>> incomeExpenseAnalysis(Integer type); |
| | | |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<SupplierPurchaseRankingDto> supplierPurchaseRanking(Integer type) { |
| | | LocalDate today = LocalDate.now(); |
| | | public List<SupplierPurchaseRankingDto> supplierPurchaseRanking(Integer type, String startDateStr, String endDateStr) { |
| | | LocalDate startDate; |
| | | LocalDate endDate; |
| | | if (com.ruoyi.common.utils.StringUtils.isNotBlank(startDateStr) && com.ruoyi.common.utils.StringUtils.isNotBlank(endDateStr)) { |
| | | startDate = LocalDate.parse(startDateStr); |
| | | endDate = LocalDate.parse(endDateStr); |
| | | } else { |
| | | LocalDate today = LocalDate.now(); |
| | | switch (type) { |
| | | case 1: // 周 |
| | | startDate = today.with(DayOfWeek.MONDAY); |
| | |
| | | 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"); |
| | |
| | | majorDto.setRate("0.00"); |
| | | } |
| | | |
| | | // 查询各产品小类的采购数量 |
| | | Map<String, BigDecimal> purchaseDataMap = new java.util.HashMap<>(); |
| | | List<com.ruoyi.dto.MapDto> purchaseDistribution = homeMapper.selectPurchaseCategoryDistribution(); |
| | | if (purchaseDistribution != null) { |
| | | for (com.ruoyi.dto.MapDto item : purchaseDistribution) { |
| | | if (item.getName() != null && item.getValue() != null) { |
| | | purchaseDataMap.put(item.getName(), new BigDecimal(item.getValue())); |
| | | } |
| | | } |
| | | } |
| | | |
| | | BigDecimal majorTotalChildrenValue = BigDecimal.ZERO; |
| | | List<ProductCategoryDistributionDto.MinorCategoryDto> minorDtos = new ArrayList<>(); |
| | | for (Product minor : children) { |
| | | ProductCategoryDistributionDto.MinorCategoryDto minorDto = new ProductCategoryDistributionDto.MinorCategoryDto(); |
| | | minorDto.setName(minor.getProductName()); |
| | | minorDto.setValue("0"); |
| | | BigDecimal minorValue = purchaseDataMap.getOrDefault(minor.getProductName(), BigDecimal.ZERO); |
| | | minorDto.setValue(minorValue.toString()); |
| | | minorDto.setRate("0.00"); |
| | | minorDto.setChildren(new ArrayList<>()); |
| | | minorDtos.add(minorDto); |
| | | majorTotalChildrenValue = majorTotalChildrenValue.add(minorValue); |
| | | } |
| | | majorDto.setChildren(minorDtos); |
| | | // 使用实际采购数据更新大类的 value |
| | | if (majorTotalChildrenValue.compareTo(BigDecimal.ZERO) > 0) { |
| | | majorDto.setValue(majorTotalChildrenValue.toString()); |
| | | } |
| | | majorItems.add(majorDto); |
| | | } |
| | | |
| | | // 计算大类占比 |
| | | BigDecimal totalAllValue = BigDecimal.ZERO; |
| | | for (ProductCategoryDistributionDto.MajorCategoryDto m : majorItems) { |
| | | try { |
| | | totalAllValue = totalAllValue.add(new BigDecimal(m.getValue())); |
| | | } catch (NumberFormatException ignored) { |
| | | } |
| | | } |
| | | if (totalAllValue.compareTo(BigDecimal.ZERO) > 0) { |
| | | for (ProductCategoryDistributionDto.MajorCategoryDto m : majorItems) { |
| | | try { |
| | | BigDecimal val = new BigDecimal(m.getValue()); |
| | | m.setRate(val.divide(totalAllValue, 4, RoundingMode.HALF_UP) |
| | | .multiply(new BigDecimal("100")) |
| | | .setScale(2, RoundingMode.HALF_UP) |
| | | .toString()); |
| | | } catch (NumberFormatException ignored) { |
| | | } |
| | | } |
| | | } |
| | | // 计算小类占比(在同大类内) |
| | | for (ProductCategoryDistributionDto.MajorCategoryDto m : majorItems) { |
| | | if (m.getChildren() == null || m.getChildren().isEmpty()) { |
| | | continue; |
| | | } |
| | | BigDecimal parentVal = BigDecimal.ZERO; |
| | | for (ProductCategoryDistributionDto.MinorCategoryDto child : m.getChildren()) { |
| | | try { |
| | | parentVal = parentVal.add(new BigDecimal(child.getValue())); |
| | | } catch (NumberFormatException ignored) { |
| | | } |
| | | } |
| | | if (parentVal.compareTo(BigDecimal.ZERO) > 0) { |
| | | for (ProductCategoryDistributionDto.MinorCategoryDto child : m.getChildren()) { |
| | | try { |
| | | BigDecimal childVal = new BigDecimal(child.getValue()); |
| | | child.setRate(childVal.divide(parentVal, 4, RoundingMode.HALF_UP) |
| | | .multiply(new BigDecimal("100")) |
| | | .setScale(2, RoundingMode.HALF_UP) |
| | | .toString()); |
| | | } catch (NumberFormatException ignored) { |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | dto.setItems(majorItems); |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<CustomerContributionRankingDto> customerContributionRanking(Integer type) { |
| | | public List<CustomerContributionRankingDto> customerContributionRanking(Integer type, String startDateStr, String endDateStr) { |
| | | LocalDate startDate; |
| | | LocalDate endDate; |
| | | if (com.ruoyi.common.utils.StringUtils.isNotBlank(startDateStr) && com.ruoyi.common.utils.StringUtils.isNotBlank(endDateStr)) { |
| | | startDate = LocalDate.parse(startDateStr); |
| | | endDate = LocalDate.parse(endDateStr); |
| | | } else { |
| | | LocalDate today = LocalDate.now(); |
| | | LocalDate startDate = null; |
| | | LocalDate endDate = null; |
| | | switch (type) { |
| | | case 1: |
| | | startDate = today.with(DayOfWeek.MONDAY); |
| | |
| | | startDate = today.withMonth(firstMonthOfQuarter.getValue()).with(TemporalAdjusters.firstDayOfMonth()); |
| | | endDate = today.withMonth(lastMonthOfQuarter.getValue()).with(TemporalAdjusters.lastDayOfMonth()); |
| | | break; |
| | | default: |
| | | return new ArrayList<>(); |
| | | } |
| | | } |
| | | |
| | | QueryWrapper<SalesLedger> queryWrapper = new QueryWrapper<>(); |
| | | queryWrapper.select("customer_name", "SUM(contract_amount) as total_amount") |
| | | .isNotNull("customer_name") |
| | | .between("entry_date", startDate, endDate) |
| | | .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<>(); |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<MapDto> productSalesAnalysis() { |
| | | // 获取所有产品大类的销售额 |
| | | List<Map<String, Object>> analysisResults = salesLedgerProductMapper.selectProductSalesAnalysis(); |
| | | public List<MapDto> productSalesAnalysis(String startDateStr, String endDateStr) { |
| | | List<Map<String, Object>> analysisResults; |
| | | if (com.ruoyi.common.utils.StringUtils.isNotBlank(startDateStr) && com.ruoyi.common.utils.StringUtils.isNotBlank(endDateStr)) { |
| | | analysisResults = salesLedgerProductMapper.selectProductSalesAnalysisByDate(startDateStr, endDateStr); |
| | | } else { |
| | | analysisResults = salesLedgerProductMapper.selectProductSalesAnalysis(); |
| | | } |
| | | if (CollectionUtils.isEmpty(analysisResults)) { |
| | | return new ArrayList<>(); |
| | | } |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<MapDto> rawMaterialPurchaseAmountRatio() { |
| | | // 获取所有原材料的采购额 |
| | | List<Map<String, Object>> analysisResults = salesLedgerProductMapper.selectRawMaterialPurchaseAnalysis(); |
| | | public List<MapDto> rawMaterialPurchaseAmountRatio(String startDateStr, String endDateStr) { |
| | | List<Map<String, Object>> analysisResults; |
| | | if (com.ruoyi.common.utils.StringUtils.isNotBlank(startDateStr) && com.ruoyi.common.utils.StringUtils.isNotBlank(endDateStr)) { |
| | | analysisResults = salesLedgerProductMapper.selectRawMaterialPurchaseAnalysisByDate(startDateStr, endDateStr); |
| | | } else { |
| | | analysisResults = salesLedgerProductMapper.selectRawMaterialPurchaseAnalysis(); |
| | | } |
| | | if (CollectionUtils.isEmpty(analysisResults)) { |
| | | return new ArrayList<>(); |
| | | } |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<MapDto> salesPurchaseStorageProductCount() { |
| | | public List<MapDto> salesPurchaseStorageProductCount(String startDate, String endDate) { |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | LocalDateTime currentMonthStart = now.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN); |
| | | LocalDateTime lastMonth = now.minusMonths(1); |
| | | LocalDateTime lastMonthStart = lastMonth.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN); |
| | | LocalDateTime lastMonthEnd = lastMonth.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX); |
| | | LocalDateTime currentMonthStart; |
| | | LocalDateTime currentMonthEnd; |
| | | LocalDateTime lastMonthStart; |
| | | LocalDateTime lastMonthEnd; |
| | | |
| | | // 销售 |
| | | int currentSales = salesLedgerProductMapper.selectProductCountByTypeAndDate(1, currentMonthStart, now); |
| | | int lastSales = salesLedgerProductMapper.selectProductCountByTypeAndDate(1, lastMonthStart, lastMonthEnd); |
| | | // 采购 |
| | | int currentPurchase = salesLedgerProductMapper.selectProductCountByTypeAndDate(2, currentMonthStart, now); |
| | | if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) { |
| | | LocalDate start = LocalDate.parse(startDate); |
| | | LocalDate end = LocalDate.parse(endDate); |
| | | currentMonthStart = start.atStartOfDay(); |
| | | currentMonthEnd = end.atTime(LocalTime.MAX); |
| | | long daysBetween = java.time.temporal.ChronoUnit.DAYS.between(start, end) + 1; |
| | | LocalDate lastStart = start.minusDays(daysBetween); |
| | | LocalDate lastEnd = start.minusDays(1); |
| | | lastMonthStart = lastStart.atStartOfDay(); |
| | | lastMonthEnd = lastEnd.atTime(LocalTime.MAX); |
| | | } else { |
| | | currentMonthStart = now.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN); |
| | | currentMonthEnd = now; |
| | | LocalDateTime lastMonth = now.minusMonths(1); |
| | | lastMonthStart = lastMonth.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN); |
| | | lastMonthEnd = lastMonth.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX); |
| | | } |
| | | |
| | | // 销售订单数(统计sales_ledger表) |
| | | int currentSales = Math.toIntExact(salesLedgerMapper.selectCount(new LambdaQueryWrapper<SalesLedger>() |
| | | .ge(SalesLedger::getEntryDate, currentMonthStart) |
| | | .le(SalesLedger::getEntryDate, currentMonthEnd))); |
| | | int lastSales = Math.toIntExact(salesLedgerMapper.selectCount(new LambdaQueryWrapper<SalesLedger>() |
| | | .ge(SalesLedger::getEntryDate, lastMonthStart) |
| | | .le(SalesLedger::getEntryDate, lastMonthEnd))); |
| | | // 采购产品数 |
| | | int currentPurchase = salesLedgerProductMapper.selectProductCountByTypeAndDate(2, currentMonthStart, currentMonthEnd); |
| | | int lastPurchase = salesLedgerProductMapper.selectProductCountByTypeAndDate(2, lastMonthStart, lastMonthEnd); |
| | | // 储存 |
| | | int currentStorage = stockInventoryMapper.selectStorageProductCountByDate(currentMonthStart, now); |
| | | // 储存产品数 |
| | | int currentStorage = stockInventoryMapper.selectStorageProductCountByDate(currentMonthStart, currentMonthEnd); |
| | | int lastStorage = stockInventoryMapper.selectStorageProductCountByDate(lastMonthStart, lastMonthEnd); |
| | | |
| | | List<MapDto> list = new ArrayList<>(); |
| | | list.add(createMapDto("销售产品数", currentSales, lastSales)); |
| | | list.add(createMapDto("销售订单数", currentSales, lastSales)); |
| | | list.add(createMapDto("采购产品数", currentPurchase, lastPurchase)); |
| | | list.add(createMapDto("储存产品数", currentStorage, lastStorage)); |
| | | |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<Map<String, Object>> productInOutAnalysis(Integer type) { |
| | | public List<Map<String, Object>> productInOutAnalysis(Integer type, String startDateStr, String endDateStr) { |
| | | String targetName; |
| | | if (type == 1) { |
| | | targetName = "原材料"; |
| | |
| | | LocalDate now = LocalDate.now(); |
| | | DateTimeFormatter displayDtf = DateTimeFormatter.ofPattern("M/d"); |
| | | |
| | | String startDate = now.minusDays(6).toString(); |
| | | String endDate = now.toString(); |
| | | LocalDate start; |
| | | LocalDate end; |
| | | if (com.ruoyi.common.utils.StringUtils.isNotBlank(startDateStr) && com.ruoyi.common.utils.StringUtils.isNotBlank(endDateStr)) { |
| | | start = LocalDate.parse(startDateStr); |
| | | end = LocalDate.parse(endDateStr); |
| | | } else { |
| | | end = now; |
| | | start = now.minusDays(6); |
| | | } |
| | | String startDate = start.toString(); |
| | | String endDate = end.toString(); |
| | | |
| | | List<Map<String, Object>> inCounts = stockInventoryMapper.selectDailyStockInCounts(rootCategoryId, startDate, |
| | | endDate + " 23:59:59"); |
| | |
| | | |
| | | List<Map<String, Object>> result = new ArrayList<>(); |
| | | |
| | | for (int i = 6; i >= 0; i--) { |
| | | LocalDate date = now.minusDays(i); |
| | | long daysBetween = ChronoUnit.DAYS.between(start, end); |
| | | for (int i = (int) daysBetween; i >= 0; i--) { |
| | | LocalDate date = end.minusDays(i); |
| | | |
| | | Map<String, Object> dataPoint = new LinkedHashMap<>(); |
| | | dataPoint.put("date", date.format(displayDtf)); // 1/23 |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<MapDto> productTurnoverDays() { |
| | | public List<MapDto> productTurnoverDays(String startDateStr, String endDateStr) { |
| | | if (com.ruoyi.common.utils.StringUtils.isNotBlank(startDateStr) && com.ruoyi.common.utils.StringUtils.isNotBlank(endDateStr)) { |
| | | return homeMapper.productTurnoverDaysByDate(startDateStr, endDateStr); |
| | | } |
| | | return homeMapper.productTurnoverDays(); |
| | | } |
| | | |
| | |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.io.IOException; |
| | | |
| | | /** |
| | | * @author :yys |
| | | * @date : 2025/9/19 10:52 |
| | | */ |
| | | @RestController |
| | | @Tag(name = "巡检任务记录") |
| | | @RequestMapping("/inspectionTask") |
| | |
| | | |
| | | private InspectionTaskService inspectionTaskService; |
| | | |
| | | /** |
| | | * 巡检任务表表查询 |
| | | */ |
| | | @GetMapping("/list") |
| | | @Operation(summary = "巡检任务表表查询") |
| | | @Operation(summary = "巡检任务表查询") |
| | | public R<IPage<InspectionTaskDto>> list(Page<InspectionTask> page, InspectionTaskDto inspectionTaskDto) { |
| | | IPage<InspectionTaskDto> list = inspectionTaskService.selectInspectionTaskList(page, inspectionTaskDto); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 导出 |
| | | */ |
| | | @PostMapping("/export") |
| | | @Operation(summary = "导出定时任务记录") |
| | | public void export(HttpServletResponse response) { |
| | |
| | | util.exportExcel(response, list.getRecords(), "导出定时任务记录"); |
| | | } |
| | | |
| | | /** |
| | | * 巡检任务表新增修改 |
| | | */ |
| | | @PostMapping("/addOrEditInspectionTask") |
| | | @Operation(summary = "巡检任务表新增修改") |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | return R.ok(inspectionTaskService.addOrEditInspectionTask(inspectionTaskDto)); |
| | | } |
| | | |
| | | /** |
| | | * 巡检任务表删除 |
| | | */ |
| | | @DeleteMapping("/delInspectionTask") |
| | | @Operation(summary = "巡检任务表删除") |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | return R.ok(inspectionTaskService.delByIds(ids)); |
| | | } |
| | | |
| | | @PutMapping("/complete/{id}") |
| | | @Operation(summary = "巡检完成") |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public R complete(@PathVariable Long id) { |
| | | return R.ok(inspectionTaskService.complete(id)); |
| | | } |
| | | |
| | | @PutMapping("/batchComplete") |
| | | @Operation(summary = "一键巡检完成") |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public R batchComplete(String dateStr) { |
| | | return R.ok(inspectionTaskService.batchComplete(dateStr)); |
| | | } |
| | | |
| | | } |
| | |
| | | @Schema(description = "巡检地点详细描述") |
| | | private String inspectionLocation; |
| | | |
| | | @Schema(description = "状态 0=待巡检, 1=已完成") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "软删除标志,0=未删除,1=已删除") |
| | | private Integer deleted; |
| | | |
| | |
| | | import com.ruoyi.inspectiontask.dto.InspectionTaskDto; |
| | | import com.ruoyi.inspectiontask.pojo.InspectionTask; |
| | | |
| | | /** |
| | | * @author :yys |
| | | * @date : 2025/9/19 10:49 |
| | | */ |
| | | public interface InspectionTaskService extends IService<InspectionTask> { |
| | | |
| | | IPage<InspectionTaskDto> selectInspectionTaskList(Page<InspectionTask> page, InspectionTaskDto inspectionTaskDto); |
| | |
| | | int addOrEditInspectionTask(InspectionTaskDto inspectionTaskDto); |
| | | |
| | | int delByIds(Long[] ids); |
| | | |
| | | int complete(Long id); |
| | | |
| | | int batchComplete(String dateStr); |
| | | } |
| | |
| | | // 保存文件(字段不传则保留历史) |
| | | saveInspectionAttachments(inspectionTask.getId(), inspectionTaskDto); |
| | | |
| | | // 巡检结果设置后,自动标记为已完成 |
| | | if (StringUtils.isNotBlank(inspectionTaskDto.getInspectionResult())) { |
| | | InspectionTask statusUpdate = new InspectionTask(); |
| | | statusUpdate.setId(inspectionTask.getId()); |
| | | statusUpdate.setStatus(1); |
| | | inspectionTaskMapper.updateById(statusUpdate); |
| | | } |
| | | |
| | | return i; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public int complete(Long id) { |
| | | InspectionTask task = inspectionTaskMapper.selectById(id); |
| | | if (task == null) { |
| | | throw new IllegalArgumentException("巡检任务不存在"); |
| | | } |
| | | if (task.getStatus() != null && task.getStatus() == 1) { |
| | | throw new IllegalArgumentException("该巡检任务已完成"); |
| | | } |
| | | task.setStatus(1); |
| | | if (task.getInspectionResult() == null) { |
| | | task.setInspectionResult("1"); |
| | | } |
| | | return inspectionTaskMapper.updateById(task); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public int batchComplete(String dateStr) { |
| | | if (StringUtils.isBlank(dateStr)) { |
| | | throw new IllegalArgumentException("日期参数不能为空"); |
| | | } |
| | | java.time.LocalDate date = java.time.LocalDate.parse(dateStr); |
| | | java.time.LocalDateTime startOfDay = date.atStartOfDay(); |
| | | java.time.LocalDateTime endOfDay = date.atTime(java.time.LocalTime.MAX); |
| | | List<InspectionTask> tasks = inspectionTaskMapper.selectList( |
| | | new LambdaQueryWrapper<InspectionTask>() |
| | | .eq(InspectionTask::getStatus, 0) |
| | | .ge(InspectionTask::getCreateTime, startOfDay) |
| | | .le(InspectionTask::getCreateTime, endOfDay)); |
| | | if (tasks.isEmpty()) { |
| | | throw new IllegalArgumentException("该日期下没有待完成的巡检记录"); |
| | | } |
| | | int count = 0; |
| | | for (InspectionTask task : tasks) { |
| | | task.setStatus(1); |
| | | if (task.getInspectionResult() == null) { |
| | | task.setInspectionResult("1"); |
| | | } |
| | | inspectionTaskMapper.updateById(task); |
| | | count++; |
| | | } |
| | | return count; |
| | | } |
| | | |
| | | private void validateInspectionInput(InspectionTaskDto inspectionTaskDto, InspectionTask oldInspectionTask) { |
| | | String inspectionResult = inspectionTaskDto.getInspectionResult(); |
| | | if (StringUtils.isBlank(inspectionResult) && oldInspectionTask != null) { |
| | |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.ruoyi.framework.web.domain.AjaxResult; |
| | | import com.ruoyi.measuringinstrumentledger.dto.SparePartsOutboundDto; |
| | | import com.ruoyi.measuringinstrumentledger.dto.SparePartsRequisitionRecordDto; |
| | | import com.ruoyi.measuringinstrumentledger.service.SparePartsRequisitionRecordService; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import lombok.AllArgsConstructor; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | /** |
| | | * <p> |
| | | * 前端控制器 |
| | | * </p> |
| | | * |
| | | * @author 芯导软件(江苏)有限公司 |
| | | * @since 2026-04-02 03:59:56 |
| | | */ |
| | | @RestController |
| | | @RequestMapping("/sparePartsRequisitionRecord") |
| | | @Tag(name = "备件领用记录接口") |
| | |
| | | private SparePartsRequisitionRecordService sparePartsRequisitionRecordService; |
| | | |
| | | @GetMapping("/listPage") |
| | | @Operation(summary = "备件分类-分页查询") |
| | | @Operation(summary = "备件领用记录-分页查询") |
| | | public AjaxResult listPage(Page page, SparePartsRequisitionRecordDto sparePartsRequisitionRecordDto){ |
| | | IPage<SparePartsRequisitionRecordDto> listPage = sparePartsRequisitionRecordService.listPage(page, sparePartsRequisitionRecordDto); |
| | | return AjaxResult.success(listPage); |
| | | } |
| | | |
| | | @PostMapping("/outbound") |
| | | @Operation(summary = "备件独立出库") |
| | | public AjaxResult outbound(@RequestBody SparePartsOutboundDto dto){ |
| | | sparePartsRequisitionRecordService.outbound(dto); |
| | | return AjaxResult.success(); |
| | | } |
| | | } |
| | |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.ruoyi.measuringinstrumentledger.dto.SparePartsOutboundDto; |
| | | import com.ruoyi.measuringinstrumentledger.dto.SparePartsRequisitionRecordDto; |
| | | import com.ruoyi.measuringinstrumentledger.pojo.SparePartsRequisitionRecord; |
| | | |
| | | /** |
| | | * <p> |
| | | * 服务类 |
| | | * </p> |
| | | * |
| | | * @author 芯导软件(江苏)有限公司 |
| | | * @since 2026-04-02 03:59:56 |
| | | */ |
| | | public interface SparePartsRequisitionRecordService extends IService<SparePartsRequisitionRecord> { |
| | | IPage<SparePartsRequisitionRecordDto> listPage(Page page, SparePartsRequisitionRecordDto sparePartsRequisitionRecordDto); |
| | | |
| | | void outbound(SparePartsOutboundDto dto); |
| | | } |
| | |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ruoyi.common.enums.SparePartsRequisitionRecordSourceTypeEnum; |
| | | import com.ruoyi.measuringinstrumentledger.dto.SparePartsOutboundDto; |
| | | import com.ruoyi.measuringinstrumentledger.dto.SparePartsRequisitionRecordDto; |
| | | import com.ruoyi.measuringinstrumentledger.mapper.SparePartsMapper; |
| | | import com.ruoyi.measuringinstrumentledger.mapper.SparePartsRequisitionRecordMapper; |
| | | import com.ruoyi.measuringinstrumentledger.pojo.SpareParts; |
| | | import com.ruoyi.measuringinstrumentledger.pojo.SparePartsRequisitionRecord; |
| | | import com.ruoyi.measuringinstrumentledger.service.SparePartsRequisitionRecordService; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | /** |
| | | * <p> |
| | | * 服务实现类 |
| | | * </p> |
| | | * |
| | | * @author 芯导软件(江苏)有限公司 |
| | | * @since 2026-04-02 03:59:56 |
| | | */ |
| | | import java.math.BigDecimal; |
| | | |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class SparePartsRequisitionRecordServiceImpl extends ServiceImpl<SparePartsRequisitionRecordMapper, SparePartsRequisitionRecord> implements SparePartsRequisitionRecordService { |
| | | private final SparePartsRequisitionRecordMapper sparePartsRequisitionRecordMapper; |
| | | private final SparePartsMapper sparePartsMapper; |
| | | |
| | | @Override |
| | | public IPage<SparePartsRequisitionRecordDto> listPage(Page page, SparePartsRequisitionRecordDto sparePartsRequisitionRecordDto) { |
| | | IPage<SparePartsRequisitionRecordDto> result = sparePartsRequisitionRecordMapper.listPage(page, sparePartsRequisitionRecordDto); |
| | | // 处理来源类型文本 |
| | | result.getRecords().forEach(record -> { |
| | | if (record.getSourceType() != null) { |
| | | record.setSourceText(SparePartsRequisitionRecordSourceTypeEnum.getByCode(record.getSourceType()).getValue()); |
| | | SparePartsRequisitionRecordSourceTypeEnum typeEnum = SparePartsRequisitionRecordSourceTypeEnum.getByCode(record.getSourceType()); |
| | | if (typeEnum != null) { |
| | | record.setSourceText(typeEnum.getValue()); |
| | | } |
| | | } |
| | | }); |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void outbound(SparePartsOutboundDto dto) { |
| | | SpareParts spareParts = sparePartsMapper.selectById(dto.getSparePartsId()); |
| | | if (spareParts == null) { |
| | | throw new IllegalArgumentException("备件不存在"); |
| | | } |
| | | if (spareParts.getQuantity().compareTo(new BigDecimal(dto.getQuantity())) < 0) { |
| | | throw new IllegalArgumentException("备件 " + spareParts.getName() + " 库存不足"); |
| | | } |
| | | // 扣减库存 |
| | | spareParts.setQuantity(spareParts.getQuantity().subtract(new BigDecimal(dto.getQuantity()))); |
| | | sparePartsMapper.updateById(spareParts); |
| | | // 创建领用记录 |
| | | SparePartsRequisitionRecord record = new SparePartsRequisitionRecord(); |
| | | record.setSourceType(SparePartsRequisitionRecordSourceTypeEnum.SparePartsRequisitionRecordSourceTypeDirectOutbound.getCode()); |
| | | record.setSparePartsId(dto.getSparePartsId()); |
| | | record.setQuantity(dto.getQuantity()); |
| | | record.setDeviceLedgerId(dto.getDeviceLedgerId()); |
| | | this.save(record); |
| | | } |
| | | } |
| | |
| | | import com.ruoyi.procurementrecord.service.ReturnManagementService; |
| | | import com.ruoyi.procurementrecord.service.ReturnSaleProductService; |
| | | import com.ruoyi.procurementrecord.utils.StockUtils; |
| | | import com.ruoyi.sales.mapper.SalesLedgerMapper; |
| | | import com.ruoyi.sales.pojo.SalesLedger; |
| | | import com.ruoyi.sales.pojo.ShippingInfo; |
| | | import com.ruoyi.sales.service.ShippingInfoService; |
| | | import lombok.RequiredArgsConstructor; |
| | |
| | | private final ReturnManagementMapper returnManagementMapper; |
| | | private final ReturnSaleProductService returnSaleProductService; |
| | | private final ShippingInfoService shippingInfoService; |
| | | private final SalesLedgerMapper salesLedgerMapper; |
| | | private final SalesRefundAmountOrderService salesRefundAmountOrderService; |
| | | private final StockUtils stockUtils; |
| | | |
| | |
| | | public boolean handle(Long returnManagementId) { |
| | | ReturnManagement byId = this.getById(returnManagementId); |
| | | List<ReturnSaleProductDto> list = returnSaleProductService.listReturnSaleProduct(returnManagementId); |
| | | |
| | | // 1. 计算正确的退款总额(金额=单价×数量) |
| | | BigDecimal totalRefund = BigDecimal.ZERO; |
| | | byId.setStatus(1); |
| | | byId.setSettler(SecurityUtils.getLoginUser().getNickName()); |
| | | updateById(byId); |
| | | SalesRefundAmountOrderDto salesRefundAmountOrder = new SalesRefundAmountOrderDto(); |
| | | salesRefundAmountOrder.setReturnManagementId(returnManagementId); |
| | | salesRefundAmountOrder.setStatus(0); |
| | | salesRefundAmountOrder.setCreateTime(byId.getCreateTime()); |
| | | salesRefundAmountOrder.setCreateUserId(SecurityUtils.getUserId()); |
| | | BigDecimal bigDecimal = new BigDecimal(0); |
| | | for (ReturnSaleProductDto returnSaleProduct : list) { |
| | | BigDecimal itemAmount = returnSaleProduct.getAmount() != null |
| | | ? returnSaleProduct.getAmount() |
| | | : BigDecimal.ZERO; |
| | | totalRefund = totalRefund.add(itemAmount); |
| | | // 是否有质量问题 |
| | | bigDecimal = bigDecimal.add(returnSaleProduct.getPrice()); |
| | | salesRefundAmountOrder.setRefundedAmount(new BigDecimal(0)); |
| | | if (returnSaleProduct.getIsQuality() == 1) { |
| | | stockUtils.addUnStockWithBatchNo(returnSaleProduct.getProductModelId(), returnSaleProduct.getNum(), StockInQualifiedRecordTypeEnum.RETURN_UNSTOCK_IN.getCode(), returnSaleProduct.getId(), returnSaleProduct.getBatchNo()); |
| | | } else { |
| | | stockUtils.addStockWithBatchNo(returnSaleProduct.getProductModelId(), returnSaleProduct.getNum(), StockInQualifiedRecordTypeEnum.RETURN_HE_IN.getCode(), returnSaleProduct.getId(), returnSaleProduct.getBatchNo()); |
| | | } |
| | | } |
| | | |
| | | // 2. 更新退货单状态和退款总额 |
| | | byId.setStatus(1); |
| | | byId.setSettler(SecurityUtils.getLoginUser().getNickName()); |
| | | byId.setRefundAmount(totalRefund); |
| | | updateById(byId); |
| | | |
| | | // 3. 更新销售台账的实际合同金额 |
| | | if (byId.getShippingId() != null) { |
| | | ShippingInfo shippingInfo = shippingInfoService.getById(byId.getShippingId()); |
| | | if (shippingInfo != null && shippingInfo.getSalesLedgerId() != null) { |
| | | SalesLedger salesLedger = salesLedgerMapper.selectById(shippingInfo.getSalesLedgerId()); |
| | | if (salesLedger != null && salesLedger.getContractAmount() != null) { |
| | | BigDecimal baseAmount = salesLedger.getNetContractAmount() != null |
| | | ? salesLedger.getNetContractAmount() |
| | | : salesLedger.getContractAmount(); |
| | | salesLedger.setNetContractAmount(baseAmount.subtract(totalRefund)); |
| | | salesLedgerMapper.updateById(salesLedger); |
| | | } |
| | | } |
| | | } |
| | | salesRefundAmountOrder.setRefundAmount(bigDecimal); |
| | | salesRefundAmountOrder.setNotRefundedAmount(salesRefundAmountOrder.getRefundedAmount()); |
| | | return true; |
| | | } |
| | | |
| | |
| | | package com.ruoyi.purchase.controller; |
| | | |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.ruoyi.basic.service.ISupplierService; |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Log; |
| | | import com.ruoyi.framework.aspectj.lang.enums.BusinessType; |
| | | import com.ruoyi.framework.web.domain.AjaxResult; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.purchase.dto.VatDto; |
| | | import com.ruoyi.purchase.dto.VatSummaryDto; |
| | | import com.ruoyi.purchase.service.PurchaseReportService; |
| | | import com.ruoyi.purchase.vo.PurchaseReportVo; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | |
| | | private final ISupplierService supplierService; |
| | | private final PurchaseReportService purchaseReportService; |
| | | |
| | | |
| | | @GetMapping("/list") |
| | | @Log(title = "采购报表-项目利润", businessType = BusinessType.OTHER) |
| | | public R list(Page page, String customerName) { |
| | |
| | | List<PurchaseReportVo> list = purchaseReportService.list(new Page(1,-1),customerName).getRecords(); |
| | | ExcelUtil<PurchaseReportVo> util = new ExcelUtil<>(PurchaseReportVo.class); |
| | | util.exportExcel(response, list , "项目利润"); |
| | | |
| | | } |
| | | |
| | | @Log(title = "采购报表-增值税比对", businessType = BusinessType.OTHER) |
| | | @GetMapping("/listVat") |
| | | public R listVat(Page page,String month) { |
| | | return R.ok(purchaseReportService.listVat(page,month)); |
| | | public R listVat(Page page, String month, String type) { |
| | | return R.ok(purchaseReportService.listVat(page, month, type)); |
| | | } |
| | | |
| | | @Log(title = "采购报表-增值税比对", businessType = BusinessType.EXPORT) |
| | | @PostMapping("/exportTwo") |
| | | @Operation(summary = "采购报表-增值税比对") |
| | | @Operation(summary = "采购报表-增值税比对导出") |
| | | public void exportTwo(HttpServletResponse response,String month) { |
| | | List<VatDto> list = purchaseReportService.listVat(new Page(1,-1),month).getRecords(); |
| | | List<VatDto> list = purchaseReportService.listVat(new Page(1, -1), month, null).getRecords(); |
| | | ExcelUtil<VatDto> util = new ExcelUtil<>(VatDto.class); |
| | | util.exportExcel(response, list , "增值税比对"); |
| | | } |
| | | |
| | | @Log(title = "采购报表-增值税图表数据", businessType = BusinessType.OTHER) |
| | | @GetMapping("/vatChart") |
| | | @Operation(summary = "增值税进销项对比图表数据") |
| | | public R vatChart(String year) { |
| | | List<VatSummaryDto> list = purchaseReportService.vatSummary(year); |
| | | return R.ok(list); |
| | | } |
| | | |
| | | @GetMapping("/listVatDetail") |
| | | @Operation(summary = "增值税明细-按发票/订单展示") |
| | | public AjaxResult listVatDetail(Page page, String month) { |
| | | IPage<VatDto> result = purchaseReportService.listVatDetail(page, month); |
| | | return AjaxResult.success(result); |
| | | } |
| | | |
| | | @GetMapping("/supplierTransactions") |
| | | @Log(title = "供应商往来", businessType = BusinessType.OTHER) |
| | | @Operation(summary = "供应商往来") |
| | |
| | | package com.ruoyi.purchase.dto; |
| | | |
| | | import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Excel; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | |
| | | @Data |
| | | @Schema(name = "VatDto", description = "管理驾驶舱--增值税比对参数") |
| | | @Schema(name = "VatDto", description = "增值税比对明细") |
| | | @ExcelIgnoreUnannotated |
| | | public class VatDto { |
| | | |
| | | @Excel(name = "ID") |
| | | @Schema(description = "发票ID") |
| | | private Long id; |
| | | |
| | | @Excel(name = "发票号码") |
| | | @Schema(description = "发票号码") |
| | | private String invoiceNumber; |
| | | |
| | | @Excel(name = "开票日期") |
| | | @Schema(description = "开票日期") |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate issueDate; |
| | | |
| | | @Excel(name = "类型") |
| | | @Schema(description = "类型 sales-销项 purchase-进项") |
| | | private String type; |
| | | |
| | | @Excel(name = "发票类型") |
| | | @Schema(description = "发票类型") |
| | | private String invoiceType; |
| | | |
| | | @Excel(name = "税额") |
| | | @Schema(description = "税额") |
| | | private BigDecimal taxAmount; |
| | | |
| | | @Excel(name = "价税合计") |
| | | @Schema(description = "价税合计") |
| | | private BigDecimal totalAmount; |
| | | |
| | | @Excel(name = "客户名称") |
| | | @Schema(description = "客户名称") |
| | | private String customerName; |
| | | |
| | | @Excel(name = "供应商名称") |
| | | @Schema(description = "供应商名称") |
| | | private String supplierName; |
| | | |
| | | @Excel(name = "月份") |
| | | @Schema(description = "月份") |
| | |
| | | @Schema(description = "进项税额") |
| | | private BigDecimal xTaxAmount; |
| | | |
| | | @Excel(name = "销-进") |
| | | @Schema(description = "销-进") |
| | | private BigDecimal taxAmount; |
| | | // ========== 明细视图字段 ========== |
| | | |
| | | @Excel(name = "发票号") |
| | | @Schema(description = "发票号") |
| | | private String invoiceNo; |
| | | |
| | | @Excel(name = "销售合同号") |
| | | @Schema(description = "销售合同号") |
| | | private String salesContractNo; |
| | | |
| | | @Excel(name = "订单类型") |
| | | @Schema(description = "类型 进项/销项") |
| | | private String orderType; |
| | | |
| | | @Excel(name = "开票日期") |
| | | @Schema(description = "开票日期") |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate invoiceDate; |
| | | |
| | | @Excel(name = "税率") |
| | | @Schema(description = "税率") |
| | | private BigDecimal taxRate; |
| | | |
| | | } |
| | |
| | | * 合同金额(产品含税总价) |
| | | */ |
| | | private BigDecimal contractAmount; |
| | | |
| | | /** |
| | | * 实际合同金额(扣减退货后) |
| | | */ |
| | | @Schema(description = "实际合同金额") |
| | | private BigDecimal netContractAmount; |
| | | // |
| | | // /** |
| | | // * 业务员 |
| | |
| | | package com.ruoyi.purchase.service; |
| | | |
| | | |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.ruoyi.purchase.dto.VatDto; |
| | | import com.ruoyi.purchase.dto.VatSummaryDto; |
| | | import com.ruoyi.purchase.vo.PurchaseReportVo; |
| | | |
| | | import java.util.List; |
| | | |
| | | public interface PurchaseReportService { |
| | | |
| | | IPage<PurchaseReportVo> list(Page page, String customerName); |
| | | |
| | | IPage<VatDto> listVat(Page page, String month); |
| | | IPage<VatDto> listVat(Page page, String month, String type); |
| | | |
| | | List<VatSummaryDto> vatSummary(String year); |
| | | |
| | | IPage<VatDto> listVatDetail(Page page, String month); |
| | | } |
| | |
| | | purchaseLedger.setRecorderId(purchaseLedgerDto.getRecorderId()); |
| | | |
| | | purchaseLedger.setApprovalStatus(1); |
| | | // 新增时初始化实际合同金额 |
| | | if (purchaseLedger.getId() == null) { |
| | | purchaseLedger.setNetContractAmount(purchaseLedger.getContractAmount()); |
| | | } |
| | | // 3. 新增或更新主表 |
| | | if (purchaseLedger.getId() == null) { |
| | | if (!StringUtils.hasText(purchaseLedger.getPurchaseContractNumber())) { |
| | |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.ruoyi.account.mapper.AccountStatementMapper; |
| | | import com.ruoyi.purchase.dto.VatDto; |
| | | import com.ruoyi.purchase.dto.VatSummaryDto; |
| | | import com.ruoyi.purchase.service.PurchaseReportService; |
| | | import com.ruoyi.purchase.vo.PurchaseReportVo; |
| | | import com.ruoyi.sales.mapper.SalesLedgerMapper; |
| | |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.List; |
| | | |
| | | @Service |
| | | @Slf4j |
| | |
| | | } |
| | | |
| | | @Override |
| | | public IPage<VatDto> listVat(Page page, String month) { |
| | | return accountStatementMapper.selectVatDtoPage(page, month); |
| | | public IPage<VatDto> listVat(Page page, String month, String type) { |
| | | return accountStatementMapper.selectVatDtoPage(page, month, type); |
| | | } |
| | | |
| | | @Override |
| | | public List<VatSummaryDto> vatSummary(String year) { |
| | | return accountStatementMapper.selectVatSummary(year); |
| | | } |
| | | |
| | | @Override |
| | | public IPage<VatDto> listVatDetail(Page page, String month) { |
| | | return accountStatementMapper.listVatDetail(page, month); |
| | | } |
| | | } |
| | |
| | | import com.ruoyi.purchase.mapper.PurchaseLedgerMapper; |
| | | import com.ruoyi.purchase.mapper.PurchaseReturnOrderProductsMapper; |
| | | import com.ruoyi.purchase.mapper.PurchaseReturnOrdersMapper; |
| | | import com.ruoyi.purchase.pojo.PurchaseLedger; |
| | | import com.ruoyi.purchase.pojo.PurchaseReturnOrderProducts; |
| | | import com.ruoyi.purchase.pojo.PurchaseReturnOrders; |
| | | import com.ruoyi.purchase.service.PurchaseReturnOrdersService; |
| | |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.List; |
| | | |
| | | /** |
| | |
| | | } |
| | | }else { |
| | | throw new RuntimeException("请选择退货商品"); |
| | | } |
| | | |
| | | // 更新采购台账的实际合同金额 |
| | | if (purchaseReturnOrderDto.getPurchaseLedgerId() != null && purchaseReturnOrderDto.getTotalAmount() != null) { |
| | | PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(purchaseReturnOrderDto.getPurchaseLedgerId()); |
| | | if (purchaseLedger != null) { |
| | | BigDecimal baseAmount = purchaseLedger.getNetContractAmount() != null |
| | | ? purchaseLedger.getNetContractAmount() |
| | | : purchaseLedger.getContractAmount(); |
| | | purchaseLedger.setNetContractAmount(baseAmount.subtract(purchaseReturnOrderDto.getTotalAmount())); |
| | | purchaseLedgerMapper.updateById(purchaseLedger); |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | |
| | | import com.ruoyi.framework.web.controller.BaseController; |
| | | import com.ruoyi.framework.web.domain.AjaxResult; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.procurementrecord.service.ProcurementRecordService; |
| | | import com.ruoyi.procurementrecord.utils.StockUtils; |
| | | import com.ruoyi.purchase.dto.SimpleReturnOrderGroupDto; |
| | | import com.ruoyi.purchase.mapper.PurchaseReturnOrderProductsMapper; |
| | | import com.ruoyi.sales.pojo.SalesLedgerProduct; |
| | | import com.ruoyi.sales.service.ISalesLedgerProductService; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 产品信息Controller |
| | |
| | | public class SalesLedgerProductController extends BaseController |
| | | { |
| | | private final ISalesLedgerProductService salesLedgerProductService; |
| | | private final ProcurementRecordService procurementRecordService; |
| | | private final StockUtils stockUtils; |
| | | private final PurchaseReturnOrderProductsMapper purchaseReturnOrderProductsMapper; |
| | | |
| | | |
| | | /** |
| | |
| | | @GetMapping("/list") |
| | | public AjaxResult list(SalesLedgerProduct salesLedgerProduct) { |
| | | List<SalesLedgerProduct> list = salesLedgerProductService.selectSalesLedgerProductList(salesLedgerProduct); |
| | | if (CollUtil.isNotEmpty(list)) { |
| | | if (CollUtil.isEmpty(list)) { |
| | | return AjaxResult.success(list); |
| | | } |
| | | List<Long> productIds = list.stream().map(SalesLedgerProduct::getProductModelId).collect(Collectors.toList()); |
| | | List<SimpleReturnOrderGroupDto> groupListByProductIds = purchaseReturnOrderProductsMapper.getReturnOrderGroupListByProductIds(productIds); |
| | | Map<Long, BigDecimal> returnOrderGroupDtoMap = groupListByProductIds.stream().collect(Collectors.toMap(SimpleReturnOrderGroupDto::getProductModelId, item -> item.getSumReturnQuantity())); |
| | | |
| | | list.forEach(item -> { |
| | | if (item.getApproveStatus() != 2) { |
| | | if (item.getHasSufficientStock() == 0) { |
| | |
| | | item.setApproveStatus(1); |
| | | } |
| | | } |
| | | java.math.BigDecimal returnQuantity = item.getReturnQuantity() == null |
| | | ? java.math.BigDecimal.ZERO |
| | | : item.getReturnQuantity(); |
| | | java.math.BigDecimal quantity = item.getQuantity() == null |
| | | ? java.math.BigDecimal.ZERO |
| | | : item.getQuantity(); |
| | | item.setReturnQuantity(returnQuantity); |
| | | item.setAvailableQuality(quantity.subtract(returnQuantity)); |
| | | // 统计退货数量 |
| | | BigDecimal returnQuality = returnOrderGroupDtoMap.getOrDefault(item.getProductModelId(), BigDecimal.ZERO); |
| | | item.setReturnQuality(returnQuality); |
| | | item.setAvailableQuality(item.getQuantity().subtract(returnQuality)); |
| | | }); |
| | | } |
| | | return AjaxResult.success(list); |
| | | } |
| | | |
| | |
| | | private String salesContractNo; |
| | | private String customerContractNo; |
| | | private String projectName; |
| | | @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | private Date entryDate; |
| | | |
| | | private String entryDateStart; |
| | |
| | | |
| | | List<Map<String, Object>> selectProductSalesAnalysis(); |
| | | |
| | | List<Map<String, Object>> selectProductSalesAnalysisByDate(@Param("startDate") String startDate, @Param("endDate") String endDate); |
| | | |
| | | List<Map<String, Object>> selectRawMaterialPurchaseAnalysis(); |
| | | |
| | | List<Map<String, Object>> selectRawMaterialPurchaseAnalysisByDate(@Param("startDate") String startDate, @Param("endDate") String endDate); |
| | | |
| | | int selectProductCountByTypeAndDate(@Param("type") Integer type, @Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate); |
| | | |
| | | BigDecimal selectRawMaterialExpense(); |
| | |
| | | /** |
| | | * 录入日期 |
| | | */ |
| | | @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | @Excel(name = "录入日期", width = 30, dateFormat = "yyyy-MM-dd") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd") |
| | | private Date entryDate; |
| | |
| | | |
| | | @Schema(description = "付款方式") |
| | | private String paymentMethod; |
| | | |
| | | @Schema(description = "实际合同金额") |
| | | private BigDecimal netContractAmount; |
| | | |
| | | @TableField(exist = false) |
| | | @Schema(description = "生产状态") |
| | |
| | | @TableField(exist = false) |
| | | private Integer hasSufficientStock; |
| | | |
| | | // 可用数量 quantity - returnQuantity |
| | | // 退货数量 |
| | | @TableField(exist = false) |
| | | private BigDecimal returnQuality; |
| | | |
| | | // 可用数量 quantity - returnQuality |
| | | @TableField(exist = false) |
| | | private BigDecimal availableQuality; |
| | | @Schema(description = "创建用户") |
| | |
| | | @TableField(exist = false) |
| | | @Schema(description = "待发货数量") |
| | | private BigDecimal noQuantity; |
| | | |
| | | @TableField(exist = false) |
| | | @Schema(description = "退货数量") |
| | | private BigDecimal returnQuantity; |
| | | |
| | | @TableField(exist = false) |
| | | @Schema(description = "审批中数量") |
| | |
| | | List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectSalesLedgerProductList(salesLedgerProduct); |
| | | if(!CollectionUtils.isEmpty(salesLedgerProducts)){ |
| | | salesLedgerProducts.forEach(item -> { |
| | | // 发货信息(取最新一条) |
| | | ShippingInfo latestShippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>() |
| | | // 发货信息 |
| | | ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>() |
| | | .eq(ShippingInfo::getSalesLedgerProductId, item.getId()) |
| | | .orderByDesc(ShippingInfo::getCreateTime) |
| | | .last("limit 1")); |
| | | if(latestShippingInfo != null){ |
| | | item.setShippingDate(latestShippingInfo.getShippingDate()); |
| | | item.setExpressCompany(latestShippingInfo.getExpressCompany()); |
| | | item.setExpressNumber(latestShippingInfo.getExpressNumber()); |
| | | } |
| | | // 车牌号:取所有发货记录的车牌号,逗号拼接 |
| | | List<ShippingInfo> allShippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>() |
| | | .eq(ShippingInfo::getSalesLedgerProductId, item.getId()) |
| | | .orderByAsc(ShippingInfo::getCreateTime)); |
| | | if(!CollectionUtils.isEmpty(allShippingInfos)){ |
| | | String carNumbers = allShippingInfos.stream() |
| | | .map(ShippingInfo::getShippingCarNumber) |
| | | .filter(carNo -> carNo != null && !carNo.trim().isEmpty()) |
| | | .distinct() |
| | | .collect(Collectors.joining(",")); |
| | | item.setShippingCarNumber(carNumbers); |
| | | if(shippingInfo != null){ |
| | | item.setShippingDate(shippingInfo.getShippingDate()); |
| | | item.setShippingCarNumber(shippingInfo.getShippingCarNumber()); |
| | | item.setExpressCompany(shippingInfo.getExpressCompany()); |
| | | item.setExpressNumber(shippingInfo.getExpressNumber()); |
| | | } |
| | | }); |
| | | } |
| | |
| | | import com.ruoyi.project.system.domain.SysUser; |
| | | import com.ruoyi.project.system.mapper.SysDeptMapper; |
| | | import com.ruoyi.project.system.mapper.SysUserMapper; |
| | | import com.ruoyi.purchase.dto.SimpleReturnOrderGroupDto; |
| | | import com.ruoyi.purchase.mapper.PurchaseReturnOrderProductsMapper; |
| | | import com.ruoyi.quality.mapper.QualityInspectMapper; |
| | | import com.ruoyi.sales.dto.*; |
| | | import com.ruoyi.sales.mapper.CommonFileMapper; |
| | |
| | | @Autowired |
| | | private ProductionProductMainService productionProductMainService; |
| | | @Autowired |
| | | private PurchaseReturnOrderProductsMapper purchaseReturnOrderProductsMapper; |
| | | ; |
| | | @Autowired |
| | | private SysUserMapper sysUserMapper; |
| | | |
| | | @Override |
| | |
| | | productWrapper.eq(SalesLedgerProduct::getType, type.getCode()); |
| | | List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(productWrapper); |
| | | if (type.equals(SaleEnum.PURCHASE)) { |
| | | // 查询退货信息 |
| | | List<Long> productIds = salesLedgerProducts.stream().map(SalesLedgerProduct::getProductModelId).collect(Collectors.toList()); |
| | | List<SimpleReturnOrderGroupDto> groupListByProductIds = new ArrayList<>(); |
| | | if(CollectionUtils.isNotEmpty(productIds)){ |
| | | groupListByProductIds = purchaseReturnOrderProductsMapper.getReturnOrderGroupListByProductIds(productIds); |
| | | } |
| | | Map<Long, BigDecimal> returnOrderGroupDtoMap = groupListByProductIds.stream().collect(Collectors.toMap(SimpleReturnOrderGroupDto::getProductModelId, SimpleReturnOrderGroupDto::getSumReturnQuantity)); |
| | | salesLedgerProducts.forEach(item -> { |
| | | BigDecimal returnQuantity = item.getReturnQuantity() == null ? BigDecimal.ZERO : item.getReturnQuantity(); |
| | | item.setReturnQuantity(returnQuantity); |
| | | BigDecimal quantity = item.getQuantity() == null ? BigDecimal.ZERO : item.getQuantity(); |
| | | item.setAvailableQuality(quantity.subtract(returnQuantity)); |
| | | BigDecimal returnQuality = returnOrderGroupDtoMap.getOrDefault(item.getProductModelId(), BigDecimal.ZERO); |
| | | item.setReturnQuality(returnQuality); |
| | | item.setAvailableQuality(item.getQuantity().subtract(returnQuality)); |
| | | }); |
| | | } |
| | | return salesLedgerProducts; |
| | |
| | | ); |
| | | } |
| | | |
| | | // 5. 兜底:确保实际合同金额有初始值等于合同金额 |
| | | if (salesLedger.getNetContractAmount() == null) { |
| | | SalesLedger dbLedger = salesLedgerMapper.selectById(salesLedger.getId()); |
| | | if (dbLedger != null && dbLedger.getNetContractAmount() == null && dbLedger.getContractAmount() != null) { |
| | | SalesLedger updateEntity = new SalesLedger(); |
| | | updateEntity.setId(salesLedger.getId()); |
| | | updateEntity.setNetContractAmount(dbLedger.getContractAmount()); |
| | | salesLedgerMapper.updateById(updateEntity); |
| | | } |
| | | } |
| | | |
| | | // 6. 保存销售台账附件 |
| | | // 5. 保存销售台账附件 |
| | | fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.SALES_LEDGER, salesLedger.getId(), salesLedgerDto.getStorageBlobDTOs()); |
| | | |
| | | return 1; |
| | |
| | | Field amountField = mainEntityClass.getDeclaredField("contractAmount"); |
| | | amountField.setAccessible(true); |
| | | amountField.set(entity, totalAmount); |
| | | |
| | | // 实际合同金额初始值等于合同金额 |
| | | try { |
| | | Field netAmountField = mainEntityClass.getDeclaredField("netContractAmount"); |
| | | netAmountField.setAccessible(true); |
| | | netAmountField.set(entity, totalAmount); |
| | | } catch (NoSuchFieldException ignored) { |
| | | // 子类可能没有该字段,忽略 |
| | | } |
| | | |
| | | mainMapper.updateById(entity); |
| | | } catch (Exception e) { |
| | |
| | | druid: |
| | | # 主库数据源 |
| | | master: |
| | | url: jdbc:mysql://localhost:3306/product-inventory-management-bdpro?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 |
| | | url: jdbc:mysql://localhost:3306/product-inventory-management-new-pro?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 |
| | | username: root |
| | | password: 123456 |
| | | # 从库数据源 |
| | |
| | | ORDER BY lj.statement_month DESC |
| | | </select> |
| | | <select id="selectVatDtoPage" resultType="com.ruoyi.purchase.dto.VatDto"> |
| | | SELECT * FROM ( |
| | | SELECT |
| | | asi.id, |
| | | asi.invoice_number AS invoiceNumber, |
| | | asi.issue_date AS issueDate, |
| | | 'sales' AS type, |
| | | asi.invoice_type AS invoiceType, |
| | | asi.tax_price AS taxAmount, |
| | | asi.tax_inclusive_price AS totalAmount, |
| | | c.customer_name AS customerName, |
| | | NULL AS supplierName, |
| | | DATE_FORMAT(asi.issue_date, '%Y-%m') AS month |
| | | FROM account_sales_invoice asi |
| | | LEFT JOIN customer c ON c.id = asi.customer_id |
| | | WHERE (asi.status IS NULL OR asi.status = 0) |
| | | UNION ALL |
| | | SELECT |
| | | api.id, |
| | | api.invoice_number AS invoiceNumber, |
| | | api.issue_date AS issueDate, |
| | | 'purchase' AS type, |
| | | api.invoice_type AS invoiceType, |
| | | api.tax_price AS taxAmount, |
| | | api.tax_inclusive_price AS totalAmount, |
| | | NULL AS customerName, |
| | | s.supplier_name AS supplierName, |
| | | DATE_FORMAT(api.issue_date, '%Y-%m') AS month |
| | | FROM account_purchase_invoice api |
| | | LEFT JOIN supplier_manage s ON s.id = api.supplier_id |
| | | WHERE (api.status IS NULL OR api.status = 0) |
| | | ) AS invoice_detail |
| | | <where> |
| | | <if test="month != null and month != ''"> |
| | | AND month = #{month} |
| | | </if> |
| | | <if test="type != null and type != ''"> |
| | | AND type = #{type} |
| | | </if> |
| | | </where> |
| | | ORDER BY issueDate DESC, type |
| | | </select> |
| | | |
| | | <select id="selectVatSummary" resultType="com.ruoyi.purchase.dto.VatSummaryDto"> |
| | | SELECT |
| | | month, |
| | | jTaxAmount, |
| | | xTaxAmount, |
| | | (jTaxAmount - xTaxAmount) AS taxAmount |
| | | FROM ( |
| | | SELECT |
| | | month, |
| | | SUM(IF(type = 'purchase', tax_price, 0)) AS xTaxAmount, |
| | | SUM(IF(type = 'sales', tax_price, 0)) AS jTaxAmount |
| | | SUM(jTaxAmount) AS jTaxAmount, |
| | | SUM(xTaxAmount) AS xTaxAmount, |
| | | SUM(jTaxAmount) - SUM(xTaxAmount) AS taxAmount |
| | | FROM ( |
| | | SELECT |
| | | DATE_FORMAT(issue_date, '%Y-%m') AS month, |
| | | tax_price, |
| | | 'sales' AS type |
| | | SUM(tax_price) AS jTaxAmount, |
| | | 0 AS xTaxAmount |
| | | FROM account_sales_invoice |
| | | WHERE status != 1 |
| | | WHERE (status IS NULL OR status = 0) |
| | | <if test="year != null and year != ''"> |
| | | AND YEAR(issue_date) = #{year} |
| | | </if> |
| | | GROUP BY DATE_FORMAT(issue_date, '%Y-%m') |
| | | UNION ALL |
| | | SELECT |
| | | DATE_FORMAT(issue_date, '%Y-%m') AS month, |
| | | tax_price, |
| | | 'purchase' AS type |
| | | 0 AS jTaxAmount, |
| | | SUM(tax_price) AS xTaxAmount |
| | | FROM account_purchase_invoice |
| | | WHERE status != 1 |
| | | ) AS all_data |
| | | WHERE (status IS NULL OR status = 0) |
| | | <if test="year != null and year != ''"> |
| | | AND YEAR(issue_date) = #{year} |
| | | </if> |
| | | GROUP BY DATE_FORMAT(issue_date, '%Y-%m') |
| | | ) t |
| | | GROUP BY month |
| | | ) AS TT |
| | | ORDER BY month |
| | | </select> |
| | | |
| | | <select id="listVatDetail" resultType="com.ruoyi.purchase.dto.VatDto"> |
| | | SELECT * |
| | | FROM ( |
| | | -- 进项税明细(采购订单) |
| | | SELECT |
| | | pl.purchase_contract_number AS invoiceNo, |
| | | pl.sales_contract_no AS salesContractNo, |
| | | pl.supplier_name AS supplierName, |
| | | NULL AS customerName, |
| | | '进项' AS orderType, |
| | | pl.entry_date AS invoiceDate, |
| | | slp.tax_rate AS taxRate, |
| | | ROUND(SUM(slp.tax_inclusive_total_price - slp.tax_exclusive_total_price), 2) AS jTaxAmount, |
| | | 0 AS xTaxAmount, |
| | | ROUND(SUM(slp.tax_inclusive_total_price - slp.tax_exclusive_total_price), 2) AS taxAmount |
| | | FROM sales_ledger_product slp |
| | | LEFT JOIN purchase_ledger pl ON pl.id = slp.sales_ledger_id |
| | | WHERE slp.type = 2 |
| | | AND slp.tax_rate IS NOT NULL |
| | | AND slp.tax_rate > 0 |
| | | GROUP BY pl.id |
| | | |
| | | UNION ALL |
| | | |
| | | -- 销项税明细(销售订单) |
| | | SELECT |
| | | sl.sales_contract_no AS invoiceNo, |
| | | sl.sales_contract_no AS salesContractNo, |
| | | NULL AS supplierName, |
| | | sl.customer_name AS customerName, |
| | | '销项' AS orderType, |
| | | sl.entry_date AS invoiceDate, |
| | | slp.tax_rate AS taxRate, |
| | | 0 AS jTaxAmount, |
| | | ROUND(SUM(slp.tax_inclusive_total_price - slp.tax_exclusive_total_price), 2) AS xTaxAmount, |
| | | ROUND(SUM(slp.tax_inclusive_total_price - slp.tax_exclusive_total_price), 2) AS taxAmount |
| | | FROM sales_ledger_product slp |
| | | LEFT JOIN sales_ledger sl ON sl.id = slp.sales_ledger_id |
| | | WHERE slp.type = 1 |
| | | AND slp.tax_rate IS NOT NULL |
| | | AND slp.tax_rate > 0 |
| | | GROUP BY sl.id |
| | | ) a |
| | | <where> |
| | | <if test="month != null"> |
| | | and TT.month = #{month} |
| | | <if test="month != null and month != ''"> |
| | | AND DATE_FORMAT(a.invoiceDate, '%Y-%m') = #{month} |
| | | </if> |
| | | </where> |
| | | ORDER BY TT.month |
| | | ORDER BY a.invoiceDate DESC |
| | | </select> |
| | | </mapper> |
| | |
| | | GROUP BY p.id, p.product_name |
| | | </select> |
| | | |
| | | <select id="productTurnoverDaysByDate" resultType="com.ruoyi.dto.MapDto"> |
| | | SELECT p.product_name AS name, |
| | | DATEDIFF(IFNULL(MAX(sor.create_time), NOW()), MAX(sir.create_time)) AS value |
| | | FROM product p |
| | | JOIN product_model pm ON p.id = pm.product_id |
| | | JOIN stock_in_record sir ON pm.id = sir.product_model_id |
| | | AND sir.create_time >= #{startDate} |
| | | AND sir.create_time <= #{endDate} |
| | | LEFT JOIN stock_out_record sor ON pm.id = sor.product_model_id |
| | | GROUP BY p.id, p.product_name |
| | | </select> |
| | | |
| | | <select id="selectPurchaseCategoryDistribution" resultType="com.ruoyi.dto.MapDto"> |
| | | SELECT p2.product_name AS name, |
| | | COUNT(DISTINCT slp.id) AS value |
| | | FROM sales_ledger_product slp |
| | | LEFT JOIN product p ON p.id = slp.product_category |
| | | LEFT JOIN product p2 ON p2.id = p.parent_id |
| | | WHERE slp.type = 2 |
| | | AND p.parent_id IS NOT NULL |
| | | GROUP BY p2.product_name |
| | | ORDER BY value DESC |
| | | </select> |
| | | |
| | | </mapper> |
| | |
| | | T1.attachment_materials, |
| | | T1.tenant_id, |
| | | T1.contract_amount, |
| | | T1.net_contract_amount, |
| | | T1.contract_amount AS noInvoiceAmountTotal, |
| | | T1.execution_date, |
| | | T2.nick_name AS entry_person_name, |
| | |
| | | ELSE 0 |
| | | END as has_sufficient_stock, |
| | | (IFNULL(T1.quantity, 0) - IFNULL(t3.shipped_quantity, 0) - IFNULL(t5.pending_approval_quantity, 0)) as no_quantity, |
| | | IFNULL(t6.return_quantity, 0) as return_quantity, |
| | | IFNULL(t5.pending_approval_quantity, 0) as pending_approval_quantity, |
| | | CASE |
| | | WHEN IFNULL(t3.shipped_quantity, 0) = 0 AND IFNULL(t5.pending_approval_quantity, 0) = 0 THEN '待发货' |
| | |
| | | )) |
| | | GROUP BY si.sales_ledger_product_id |
| | | ) t5 ON t5.sales_ledger_product_id = T1.id |
| | | LEFT JOIN ( |
| | | SELECT si.sales_ledger_product_id, IFNULL(SUM(rsp.num), 0) AS return_quantity |
| | | FROM return_management rm |
| | | INNER JOIN return_sale_product rsp ON rm.id = rsp.return_management_id |
| | | INNER JOIN shipping_info si ON rm.shipping_id = si.id |
| | | WHERE rm.status = 1 |
| | | GROUP BY si.sales_ledger_product_id |
| | | ) t6 ON t6.sales_ledger_product_id = T1.id |
| | | left join product_model pm ON T1.product_model_id = pm.id |
| | | left join product p ON pm.product_id = p.id |
| | | <where> |
| | |
| | | LIMIT 5 |
| | | </select> |
| | | |
| | | <select id="selectProductSalesAnalysisByDate" resultType="java.util.Map"> |
| | | SELECT |
| | | product_category as name, |
| | | SUM( tax_inclusive_total_price ) AS value |
| | | FROM |
| | | sales_ledger_product |
| | | WHERE |
| | | type = 1 |
| | | AND register_date >= #{startDate} |
| | | AND register_date <= #{endDate} |
| | | GROUP BY |
| | | product_category |
| | | ORDER BY |
| | | value DESC |
| | | LIMIT 5 |
| | | </select> |
| | | |
| | | <select id="selectRawMaterialPurchaseAnalysis" resultType="java.util.Map"> |
| | | WITH RECURSIVE raw_material_tree AS ( |
| | | SELECT id FROM product WHERE product_name = '原材料' AND parent_id IS NULL |
| | | UNION ALL |
| | | SELECT p.id FROM product p INNER JOIN raw_material_tree rmt ON p.parent_id = rmt.id |
| | | ) |
| | | SELECT |
| | | pr.product_name AS name, |
| | | SUM( slp.tax_inclusive_total_price ) AS value |
| | |
| | | JOIN product pr ON slp.product_id = pr.id |
| | | WHERE |
| | | slp.type = 2 |
| | | AND pr.id IN (SELECT id FROM raw_material_tree) |
| | | GROUP BY |
| | | pr.id, |
| | | pr.product_name |
| | | ORDER BY |
| | | value DESC |
| | | LIMIT 5 |
| | | </select> |
| | | |
| | | <select id="selectRawMaterialPurchaseAnalysisByDate" resultType="java.util.Map"> |
| | | SELECT |
| | | pr.product_name AS name, |
| | | SUM( slp.tax_inclusive_total_price ) AS value |
| | | FROM |
| | | sales_ledger_product slp |
| | | JOIN product pr ON slp.product_id = pr.id |
| | | WHERE |
| | | slp.type = 2 |
| | | AND slp.register_date >= #{startDate} |
| | | AND slp.register_date <= #{endDate} |
| | | AND pr.parent_id = ( SELECT id FROM product WHERE product_name = '原材料' ) |
| | | GROUP BY |
| | | pr.id, |
| | |
| | | <select id="selectRawMaterialExpense" resultType="java.math.BigDecimal"> |
| | | WITH RECURSIVE product_tree AS (SELECT id |
| | | FROM product |
| | | WHERE product_name = '原材料' |
| | | WHERE product_name = '原材料' AND parent_id IS NULL |
| | | |
| | | UNION ALL |
| | | |
| | |
| | | order by sor.id |
| | | </select> |
| | | <select id="getShippingInfoByCustomerName" resultType="com.ruoyi.sales.pojo.ShippingInfo"> |
| | | select distinct si.* from shipping_info si |
| | | select * from shipping_info si |
| | | left join sales_ledger sl on si.sales_ledger_id = sl.id |
| | | inner join stock_out_record sor on sor.record_id = si.id and sor.record_type = '13' and sor.approval_status = 1 |
| | | where sl.customer_name = #{customerName} and si.status = '审核通过' |
| | | where sl.customer_name = #{customerName} |
| | | </select> |
| | | </mapper> |