Commit 63a3b3de37eb0889a951df506902af853f203941
1 parent
58f525c9
增加自有机械折旧定时任务及派单超时处理定时任务
Showing
7 changed files
with
251 additions
and
3 deletions
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/mechanicaldepreciation/MechanicalDepreciationController.java
| @@ -100,5 +100,9 @@ public class MechanicalDepreciationController { | @@ -100,5 +100,9 @@ public class MechanicalDepreciationController { | ||
| 100 | ExcelUtils.write(response, "自有机械折旧子.xls", "数据", MechanicalDepreciationRespVO.class, | 100 | ExcelUtils.write(response, "自有机械折旧子.xls", "数据", MechanicalDepreciationRespVO.class, |
| 101 | BeanUtils.toBean(list, MechanicalDepreciationRespVO.class)); | 101 | BeanUtils.toBean(list, MechanicalDepreciationRespVO.class)); |
| 102 | } | 102 | } |
| 103 | + @GetMapping(value = "/batchSaveMechDepr") | ||
| 104 | + public void batchSaveMechDepr(@RequestParam String depreciationMethod) { | ||
| 105 | + mechanicalDepreciationService.batchSaveMechDepr(depreciationMethod); | ||
| 106 | + } | ||
| 103 | 107 | ||
| 104 | -} | ||
| 105 | \ No newline at end of file | 108 | \ No newline at end of file |
| 109 | +} |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/mechanicalcost/MechanicalCostDO.java
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/job/costfee/CostFeeMachDepr.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.job.costfee; | ||
| 2 | + | ||
| 3 | +import com.zteits.urbanops.framework.quartz.core.handler.JobHandler; | ||
| 4 | +import com.zteits.urbanops.module.garden.service.mechanicaldepreciation.MechanicalDepreciationService; | ||
| 5 | +import jakarta.annotation.Resource; | ||
| 6 | +import lombok.extern.slf4j.Slf4j; | ||
| 7 | +import org.springframework.stereotype.Component; | ||
| 8 | + | ||
| 9 | +import java.time.LocalDate; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * @Classname CostFeeMachDepr | ||
| 13 | + * @Description 人机材自有机械折旧处理 | ||
| 14 | + * @Date 2025/12/25 10:43 | ||
| 15 | + * @Created by wangqian | ||
| 16 | + */ | ||
| 17 | +@Component | ||
| 18 | +@Slf4j | ||
| 19 | +public class CostFeeMachDepr implements JobHandler { | ||
| 20 | + @Resource | ||
| 21 | + private MechanicalDepreciationService mechanicalDepreciationService; | ||
| 22 | + @Override | ||
| 23 | + public String execute(String param) throws Exception { | ||
| 24 | + log.info("自有机械折旧定时任务,开始========"+ LocalDate.now()); | ||
| 25 | + int count = mechanicalDepreciationService.batchSaveMechDepr(param); | ||
| 26 | + log.info("自有机械折,mechanicalCostList.size=" + count); | ||
| 27 | + log.info("自有机械折旧定时任务,结束========"+ LocalDate.now()); | ||
| 28 | + return "Successfully"; | ||
| 29 | + } | ||
| 30 | +} |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/job/task/AssignTaskJob.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.job.task; | ||
| 2 | + | ||
| 3 | +import com.zteits.urbanops.framework.quartz.core.handler.JobHandler; | ||
| 4 | +import com.zteits.urbanops.module.garden.service.assigntasks.AssignTasksService; | ||
| 5 | +import jakarta.annotation.Resource; | ||
| 6 | +import lombok.extern.slf4j.Slf4j; | ||
| 7 | +import org.springframework.stereotype.Component; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * @Classname AssignTaskJob | ||
| 11 | + * @Description 派单超时处理 | ||
| 12 | + * @Date 2025/12/25 10:37 | ||
| 13 | + * @Created by wangqian | ||
| 14 | + */ | ||
| 15 | +@Component | ||
| 16 | +@Slf4j | ||
| 17 | +public class AssignTaskJob implements JobHandler { | ||
| 18 | + | ||
| 19 | + @Resource | ||
| 20 | + private AssignTasksService assignTasksService; | ||
| 21 | + | ||
| 22 | + @Override | ||
| 23 | + public String execute(String param) throws Exception { | ||
| 24 | + assignTasksService.tasksOutTimeAuto(); | ||
| 25 | + return "Successfully"; | ||
| 26 | + } | ||
| 27 | +} |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/assigntasks/AssignTasksServiceImpl.java
| @@ -219,7 +219,7 @@ public class AssignTasksServiceImpl implements AssignTasksService { | @@ -219,7 +219,7 @@ public class AssignTasksServiceImpl implements AssignTasksService { | ||
| 219 | List<AssignTasksInfoDO> taskInfoList = assiAssignTasksInfoMapper.selectList(queryWrapper); | 219 | List<AssignTasksInfoDO> taskInfoList = assiAssignTasksInfoMapper.selectList(queryWrapper); |
| 220 | if (CollectionUtils.isEmpty(taskInfoList)) { | 220 | if (CollectionUtils.isEmpty(taskInfoList)) { |
| 221 | log.info("未找到未完成的派单详情,无需处理"); | 221 | log.info("未找到未完成的派单详情,无需处理"); |
| 222 | - return 0; | 222 | + continue; |
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | // 4. 筛选“已超时”的派单详情(截止时间 < 当前时间) | 225 | // 4. 筛选“已超时”的派单详情(截止时间 < 当前时间) |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/mechanicaldepreciation/MechanicalDepreciationService.java
| @@ -67,4 +67,6 @@ public interface MechanicalDepreciationService { | @@ -67,4 +67,6 @@ public interface MechanicalDepreciationService { | ||
| 67 | */ | 67 | */ |
| 68 | void deleteMechanicalDepreciationByMechId(Long mechId); | 68 | void deleteMechanicalDepreciationByMechId(Long mechId); |
| 69 | 69 | ||
| 70 | + public int batchSaveMechDepr(String depreciationMethod); | ||
| 71 | + | ||
| 70 | } | 72 | } |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/mechanicaldepreciation/MechanicalDepreciationServiceImpl.java
| @@ -6,13 +6,27 @@ import com.zteits.urbanops.framework.common.pojo.PageResult; | @@ -6,13 +6,27 @@ import com.zteits.urbanops.framework.common.pojo.PageResult; | ||
| 6 | import com.zteits.urbanops.framework.common.util.object.BeanUtils; | 6 | import com.zteits.urbanops.framework.common.util.object.BeanUtils; |
| 7 | import com.zteits.urbanops.module.garden.controller.admin.mechanicaldepreciation.vo.MechanicalDepreciationPageReqVO; | 7 | import com.zteits.urbanops.module.garden.controller.admin.mechanicaldepreciation.vo.MechanicalDepreciationPageReqVO; |
| 8 | import com.zteits.urbanops.module.garden.controller.admin.mechanicaldepreciation.vo.MechanicalDepreciationSaveReqVO; | 8 | import com.zteits.urbanops.module.garden.controller.admin.mechanicaldepreciation.vo.MechanicalDepreciationSaveReqVO; |
| 9 | +import com.zteits.urbanops.module.garden.dal.dataobject.mechanicalcost.MechanicalCostDO; | ||
| 9 | import com.zteits.urbanops.module.garden.dal.dataobject.mechanicaldepreciation.MechanicalDepreciationDO; | 10 | import com.zteits.urbanops.module.garden.dal.dataobject.mechanicaldepreciation.MechanicalDepreciationDO; |
| 11 | +import com.zteits.urbanops.module.garden.dal.mysql.mechanicalcost.MechanicalCostMapper; | ||
| 10 | import com.zteits.urbanops.module.garden.dal.mysql.mechanicaldepreciation.MechanicalDepreciationMapper; | 12 | import com.zteits.urbanops.module.garden.dal.mysql.mechanicaldepreciation.MechanicalDepreciationMapper; |
| 11 | import jakarta.annotation.Resource; | 13 | import jakarta.annotation.Resource; |
| 14 | +import lombok.extern.slf4j.Slf4j; | ||
| 12 | import org.springframework.stereotype.Service; | 15 | import org.springframework.stereotype.Service; |
| 16 | +import org.springframework.util.CollectionUtils; | ||
| 13 | import org.springframework.validation.annotation.Validated; | 17 | import org.springframework.validation.annotation.Validated; |
| 14 | 18 | ||
| 19 | +import java.math.BigDecimal; | ||
| 20 | +import java.time.LocalDate; | ||
| 21 | +import java.time.LocalDateTime; | ||
| 22 | +import java.time.YearMonth; | ||
| 23 | +import java.time.ZoneId; | ||
| 24 | +import java.time.format.DateTimeFormatter; | ||
| 25 | +import java.util.ArrayList; | ||
| 26 | +import java.util.Date; | ||
| 15 | import java.util.List; | 27 | import java.util.List; |
| 28 | +import java.util.Set; | ||
| 29 | +import java.util.stream.Collectors; | ||
| 16 | 30 | ||
| 17 | import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception; | 31 | import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 18 | import static com.zteits.urbanops.module.garden.enums.ErrorCodeConstants.MECHANICAL_DEPRECIATION_NOT_EXISTS; | 32 | import static com.zteits.urbanops.module.garden.enums.ErrorCodeConstants.MECHANICAL_DEPRECIATION_NOT_EXISTS; |
| @@ -25,10 +39,13 @@ import static com.zteits.urbanops.module.garden.enums.ErrorCodeConstants.MECHANI | @@ -25,10 +39,13 @@ import static com.zteits.urbanops.module.garden.enums.ErrorCodeConstants.MECHANI | ||
| 25 | */ | 39 | */ |
| 26 | @Service | 40 | @Service |
| 27 | @Validated | 41 | @Validated |
| 42 | +@Slf4j | ||
| 28 | public class MechanicalDepreciationServiceImpl implements MechanicalDepreciationService { | 43 | public class MechanicalDepreciationServiceImpl implements MechanicalDepreciationService { |
| 29 | 44 | ||
| 30 | @Resource | 45 | @Resource |
| 31 | private MechanicalDepreciationMapper mechanicalDepreciationMapper; | 46 | private MechanicalDepreciationMapper mechanicalDepreciationMapper; |
| 47 | + @Resource | ||
| 48 | + private MechanicalCostMapper mechanicalCostMapper; | ||
| 32 | 49 | ||
| 33 | @Override | 50 | @Override |
| 34 | public Long createMechanicalDepreciation(MechanicalDepreciationSaveReqVO createReqVO) { | 51 | public Long createMechanicalDepreciation(MechanicalDepreciationSaveReqVO createReqVO) { |
| @@ -90,4 +107,172 @@ public class MechanicalDepreciationServiceImpl implements MechanicalDepreciation | @@ -90,4 +107,172 @@ public class MechanicalDepreciationServiceImpl implements MechanicalDepreciation | ||
| 90 | mechanicalDepreciationMapper.delete(queryWrapper); | 107 | mechanicalDepreciationMapper.delete(queryWrapper); |
| 91 | } | 108 | } |
| 92 | 109 | ||
| 110 | + @Override | ||
| 111 | + public int batchSaveMechDepr(String depreciationMethod) { | ||
| 112 | + log.info("自有机械折旧业务处理,start"); | ||
| 113 | + List<MechanicalCostDO> mechanicalCostList = mechanicalCostMapper.selectList(MechanicalCostDO::getStatus, 0); | ||
| 114 | + if (!CollectionUtils.isEmpty(mechanicalCostList)) { | ||
| 115 | + straightLineMethod(mechanicalCostList); | ||
| 116 | + } | ||
| 117 | + log.info("自有机械折旧业务处理,end"); | ||
| 118 | + return mechanicalCostList.size(); | ||
| 119 | + } | ||
| 120 | + /** | ||
| 121 | + * @Author wangqian | ||
| 122 | + * @Description 直线法 | ||
| 123 | + * @Date 2025/8/3 10:47 | ||
| 124 | + * @Param mechanicalCostList | ||
| 125 | + * @Return int | ||
| 126 | + */ | ||
| 127 | + public void straightLineMethod(List<MechanicalCostDO> mechanicalCostList) { | ||
| 128 | + if (CollectionUtils.isEmpty(mechanicalCostList)) { | ||
| 129 | + return; // 空集合直接返回,避免无效处理 | ||
| 130 | + } | ||
| 131 | + | ||
| 132 | + // 1. 批量查询已有折旧记录 | ||
| 133 | + Set<Long> mechIdSet = mechanicalCostList.stream() | ||
| 134 | + .map(MechanicalCostDO::getId) | ||
| 135 | + .collect(Collectors.toSet()); | ||
| 136 | + LambdaQueryWrapper<MechanicalDepreciationDO> queryWrapper = new LambdaQueryWrapper<>(); | ||
| 137 | + queryWrapper.in(MechanicalDepreciationDO::getMechId, mechIdSet); | ||
| 138 | + List<MechanicalDepreciationDO> existingDepreciations = mechanicalDepreciationMapper.selectList(queryWrapper); | ||
| 139 | + Set<Long> existingMechIdSet = existingDepreciations.stream() | ||
| 140 | + .map(MechanicalDepreciationDO::getMechId) | ||
| 141 | + .collect(Collectors.toSet()); | ||
| 142 | + | ||
| 143 | + // 2. 统一获取当前时间 | ||
| 144 | + | ||
| 145 | + for (MechanicalCostDO cost : mechanicalCostList) { | ||
| 146 | + Long mechId = cost.getId(); | ||
| 147 | + // 跳过已存在折旧记录的资产 | ||
| 148 | + if (existingMechIdSet.contains(mechId)) { | ||
| 149 | + continue; | ||
| 150 | + } | ||
| 151 | + // 3. 单价 | ||
| 152 | + BigDecimal originalValue = cost.getUnitPrice(); | ||
| 153 | + Integer serviceLifeYears = cost.getServiceLife(); | ||
| 154 | + if (originalValue == null || originalValue.compareTo(BigDecimal.ZERO) <= 0 | ||
| 155 | + || serviceLifeYears == null || serviceLifeYears <= 0) { | ||
| 156 | + log.warn("资产ID:{} 折旧参数异常,原值:{}, 使用年限:{}", | ||
| 157 | + mechId, originalValue, serviceLifeYears); | ||
| 158 | + continue; | ||
| 159 | + } | ||
| 160 | + List<MechanicalDepreciationDO> toSaveList = new ArrayList<>(); // 收集待保存对象,批量插入 | ||
| 161 | + | ||
| 162 | + // 4. 计算固定参数 | ||
| 163 | + Integer totalMonths = serviceLifeYears * 12; | ||
| 164 | + BigDecimal residualRate = BigDecimal.ZERO; // 默认残值率0 | ||
| 165 | + BigDecimal netValue = originalValue.multiply(BigDecimal.ONE.subtract(residualRate)); | ||
| 166 | + | ||
| 167 | + // 优化尾差计算:基础月折旧额 + 最后一个月调整 | ||
| 168 | + // 先计算未四舍五入的精确月折旧额 | ||
| 169 | + BigDecimal exactMonthlyDepreciation = netValue.divide(new BigDecimal(totalMonths), 10, BigDecimal.ROUND_HALF_UP); | ||
| 170 | + // 计算四舍五入到分的基础月折旧额 | ||
| 171 | + BigDecimal baseMonthlyDepreciation = exactMonthlyDepreciation.setScale(2, BigDecimal.ROUND_HALF_UP); | ||
| 172 | + // 计算总折旧额(基础月折旧 × 总月数) | ||
| 173 | + BigDecimal totalDepreciation = baseMonthlyDepreciation.multiply(new BigDecimal(totalMonths)); | ||
| 174 | + // 计算尾差(需要调整的金额) | ||
| 175 | + BigDecimal tailDifference = netValue.subtract(totalDepreciation); | ||
| 176 | + | ||
| 177 | + // 5. 生成折旧期间列表(如YYYY-MM) | ||
| 178 | + List<String> depreciationPeriods = generateMonths(cost.getStartUseTime(), serviceLifeYears); | ||
| 179 | + if (depreciationPeriods.size() != totalMonths) { | ||
| 180 | + log.warn("资产ID:{} 折旧期间数量不匹配,计算月数:{}, 实际生成:{}", | ||
| 181 | + mechId, totalMonths, depreciationPeriods.size()); | ||
| 182 | + continue; // 期间数量异常时跳过,避免数据错误 | ||
| 183 | + } | ||
| 184 | + | ||
| 185 | + // 6. 循环生成每月折旧记录 | ||
| 186 | + BigDecimal accumulatedDepreciation = BigDecimal.ZERO; // 累计折旧初始化为0 | ||
| 187 | + for (int i = 0; i < depreciationPeriods.size(); i++) { | ||
| 188 | + MechanicalDepreciationDO depreciation = new MechanicalDepreciationDO(); | ||
| 189 | + | ||
| 190 | + // 固定属性(一次设置) | ||
| 191 | + depreciation.setMechId(mechId); | ||
| 192 | + depreciation.setOriginalValue(originalValue); | ||
| 193 | + depreciation.setDepreciationMethod("直线法"); | ||
| 194 | + depreciation.setResidualRate(residualRate); | ||
| 195 | + depreciation.setServiceLife(serviceLifeYears); | ||
| 196 | + depreciation.setNetValue(netValue); | ||
| 197 | + | ||
| 198 | + // 月度变化属性 - 处理尾差 | ||
| 199 | + BigDecimal monthlyDepreciation; | ||
| 200 | + // 如果是最后一个月,加上尾差调整 | ||
| 201 | + if (i == depreciationPeriods.size() - 1) { | ||
| 202 | + monthlyDepreciation = baseMonthlyDepreciation.add(tailDifference); | ||
| 203 | + // 确保最后调整后没有因精度问题产生的微小偏差 | ||
| 204 | + monthlyDepreciation = monthlyDepreciation.setScale(2, BigDecimal.ROUND_HALF_UP); | ||
| 205 | + } else { | ||
| 206 | + monthlyDepreciation = baseMonthlyDepreciation; | ||
| 207 | + } | ||
| 208 | + | ||
| 209 | + accumulatedDepreciation = accumulatedDepreciation.add(monthlyDepreciation); | ||
| 210 | + depreciation.setDepreciationAmount(monthlyDepreciation); | ||
| 211 | + depreciation.setAccumulatedDepreciation(accumulatedDepreciation); | ||
| 212 | + depreciation.setRemainingPeriods(totalMonths - (i + 1)); // 剩余期数=总月数-已计提月数 | ||
| 213 | + depreciation.setDepreciationPeriod(depreciationPeriods.get(i)); | ||
| 214 | + | ||
| 215 | + toSaveList.add(depreciation); | ||
| 216 | + } | ||
| 217 | + | ||
| 218 | + // 额外校验:确保累计折旧等于净残值,避免计算错误 | ||
| 219 | + if (accumulatedDepreciation.compareTo(netValue) != 0) { | ||
| 220 | + log.error("资产ID:{} 折旧总和校验失败,应有:{}, 实际计算:{}", | ||
| 221 | + mechId, netValue, accumulatedDepreciation); | ||
| 222 | + continue; | ||
| 223 | + } | ||
| 224 | + | ||
| 225 | + // 7. 批量插入,减少数据库交互 | ||
| 226 | + if (!toSaveList.isEmpty()) { | ||
| 227 | + mechanicalDepreciationMapper.insertBatch(toSaveList); // 假设新增批量插入方法 | ||
| 228 | + } | ||
| 229 | + } | ||
| 230 | + } | ||
| 231 | + | ||
| 232 | + | ||
| 233 | + | ||
| 234 | + /** | ||
| 235 | + * 生成从开始日期起指定年限内的所有月份(格式:yyyy-MM) | ||
| 236 | + * | ||
| 237 | + * @param localStartDate 开始日期(不能为null) | ||
| 238 | + * @param years 年限(必须大于等于0) | ||
| 239 | + * @return 月份字符串集合,若输入参数无效则返回空集合 | ||
| 240 | + */ | ||
| 241 | + public static List<String> generateMonths(LocalDate localStartDate, Integer years) { | ||
| 242 | + // 初始化返回集合 | ||
| 243 | + List<String> months = new ArrayList<>(); | ||
| 244 | + | ||
| 245 | + // 参数校验 | ||
| 246 | + if (localStartDate == null || years == null || years < 0) { | ||
| 247 | + return months; | ||
| 248 | + } | ||
| 249 | + | ||
| 250 | + try { | ||
| 251 | + // 转换为年月对象,从开始日期的当月开始 | ||
| 252 | + YearMonth current = YearMonth.from(localStartDate); | ||
| 253 | + | ||
| 254 | + // 计算结束年月(开始日期加上指定年数) | ||
| 255 | + YearMonth end = current.plusYears(years).minusMonths(1); | ||
| 256 | + | ||
| 257 | + // 定义日期格式化器(线程安全) | ||
| 258 | + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM"); | ||
| 259 | + | ||
| 260 | + // 循环添加每个月 | ||
| 261 | + while (!current.isAfter(end)) { | ||
| 262 | + months.add(current.format(formatter)); | ||
| 263 | + current = current.plusMonths(1); | ||
| 264 | + } | ||
| 265 | + } catch (Exception e) { | ||
| 266 | + // 捕获所有异常,避免方法抛出异常影响调用方 | ||
| 267 | + // 实际应用中可根据需要记录日志 | ||
| 268 | + e.printStackTrace(); | ||
| 269 | + } | ||
| 270 | + | ||
| 271 | + return months; | ||
| 272 | + } | ||
| 273 | + | ||
| 274 | + public static void main(String[] args) { | ||
| 275 | + LocalDate localDate = LocalDate.of(2024, 5, 6); | ||
| 276 | + System.out.println(generateMonths(localDate, 1)); | ||
| 277 | + } | ||
| 93 | } | 278 | } |