main-business/src/main/java/com/ruoyi/business/constant/InventoryRecordConstant.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,8 @@ package com.ruoyi.business.constant; public class InventoryRecordConstant { // å¾ å ¥åº public static String PENDING_INVENTORY = "PENDING_INVENTORY"; // æ£å¼åº public static String OFFICIAL_INVENTORY = "OFFICIAL_INVENTORY"; } main-business/src/main/java/com/ruoyi/business/controller/InputInventoryRecordController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,21 @@ package com.ruoyi.business.controller; import org.springframework.web.bind.annotation.RequestMapping; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.RestController; /** * <p> * å ¥åºè®°å½è¡¨ å端æ§å¶å¨ * </p> * * @author chenhj * @since 2025-06-14 */ @RestController @AllArgsConstructor @RequestMapping("/business/inputInventoryRecord") public class InputInventoryRecordController { } main-business/src/main/java/com/ruoyi/business/controller/InventorySummaryController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,21 @@ package com.ruoyi.business.controller; import org.springframework.web.bind.annotation.RequestMapping; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.RestController; /** * <p> * åºåæ±æ»è¡¨ å端æ§å¶å¨ * </p> * * @author chenhj * @since 2025-06-14 */ @RestController @AllArgsConstructor @RequestMapping("/business/inventorySummary") public class InventorySummaryController { } main-business/src/main/java/com/ruoyi/business/controller/OutputInventoryRecordController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,21 @@ package com.ruoyi.business.controller; import org.springframework.web.bind.annotation.RequestMapping; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.RestController; /** * <p> * åºåºè®°å½è¡¨ å端æ§å¶å¨ * </p> * * @author chenhj * @since 2025-06-14 */ @RestController @AllArgsConstructor @RequestMapping("/business/outputInventoryRecord") public class OutputInventoryRecordController { } main-business/src/main/java/com/ruoyi/business/entity/InputInventoryRecord.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,56 @@ package com.ruoyi.business.entity; import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDateTime; /** * å ¥åºè®°å½è¡¨ å®ä½ç±» * * @author chenhj * @date 2025-06-14 */ @Data @TableName("input_inventory_record") public class InputInventoryRecord implements Serializable { private static final long serialVersionUID = 1L; /** * 主é®ID */ @TableId(value = "id", type = IdType.AUTO) private Long id; /** * åºid */ @TableField(value = "inventory_id") private Long inventoryId; /** * åºç±»å */ @TableField(value = "inventory_type") private String inventoryType; /** * è®°å½æ°é */ @TableField(value = "quantity") private BigDecimal quantity; /** é»è¾å é¤å段 */ @TableLogic private Integer deleted; /** å建è */ @TableField(fill = FieldFill.INSERT) private String createBy; /** å建æ¶é´ */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @TableField(fill = FieldFill.INSERT, updateStrategy = FieldStrategy.NEVER) private LocalDateTime createTime; } main-business/src/main/java/com/ruoyi/business/entity/InventorySummary.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,73 @@ package com.ruoyi.business.entity; import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDateTime; /** * åºåæ±æ»è¡¨ å®ä½ç±» * * @author chenhj * @date 2025-06-14 */ @Data @TableName("inventory_summary") public class InventorySummary implements Serializable { private static final long serialVersionUID = 1L; /** * 主é®ID */ @TableId(value = "id", type = IdType.AUTO) private Long id; /** * åºid */ @TableField(value = "inventory_id") private Long inventoryId; /** * åºç±»å */ @TableField(value = "inventory_type") private String inventoryType; /** * åºåæ°é */ @TableField(value = "inventory_quantity") private BigDecimal inventoryQuantity; /** * å ¥åºä¸æ¢æç»è®°å½id */ @TableField(value = "input_end_record_id") private Long inputEndRecordId; /** * åºåºä¸æ¢æç»è®°å½id */ @TableField(value = "output_end_record_id") private Long outputEndRecordId; /** * é»è¾å é¤å段 */ @TableLogic private Integer deleted; /** * å建æ¶é´ */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @TableField(fill = FieldFill.INSERT, updateStrategy = FieldStrategy.NEVER) private LocalDateTime createTime; /** * æ´æ°æ¶é´ */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; } main-business/src/main/java/com/ruoyi/business/entity/OutputInventoryRecord.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,56 @@ package com.ruoyi.business.entity; import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDateTime; /** * åºåºè®°å½è¡¨ å®ä½ç±» * * @author chenhj * @date 2025-06-14 */ @Data @TableName("output_inventory_record") public class OutputInventoryRecord implements Serializable { private static final long serialVersionUID = 1L; /** * 主é®ID */ @TableId(value = "id", type = IdType.AUTO) private Long id; /** * åºid */ @TableField(value = "inventory_id") private Long inventoryId; /** * åºç±»å */ @TableField(value = "inventory_type") private String inventoryType; /** * è®°å½æ°é */ @TableField(value = "quantity") private BigDecimal quantity; /** é»è¾å é¤å段 */ @TableLogic private Integer deleted; /** å建è */ @TableField(fill = FieldFill.INSERT) private String createBy; /** å建æ¶é´ */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @TableField(fill = FieldFill.INSERT, updateStrategy = FieldStrategy.NEVER) private LocalDateTime createTime; } main-business/src/main/java/com/ruoyi/business/mapper/InputInventoryRecordMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.business.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.business.entity.InputInventoryRecord; import org.apache.ibatis.annotations.Mapper; /** * <p> * å ¥åºè®°å½è¡¨ Mapper æ¥å£ * </p> * * @author chenhj * @since 2025-06-14 */ @Mapper public interface InputInventoryRecordMapper extends BaseMapper<InputInventoryRecord> { } main-business/src/main/java/com/ruoyi/business/mapper/InventorySummaryMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,20 @@ package com.ruoyi.business.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.business.entity.InventorySummary; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; /** * <p> * åºåæ±æ»è¡¨ Mapper æ¥å£ * </p> * * @author chenhj * @since 2025-06-14 */ @Mapper public interface InventorySummaryMapper extends BaseMapper<InventorySummary> { InventorySummary getInventorySummaryForUpdateById(@Param("id") Long id); InventorySummary getInventorySummaryForUpdateByInventoryIdAndType(@Param("inventoryId") Long inventoryId, @Param("type") String type); } main-business/src/main/java/com/ruoyi/business/mapper/OfficialInventoryMapper.java
@@ -3,6 +3,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.business.entity.OfficialInventory; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; /** * <p> @@ -14,5 +15,6 @@ */ @Mapper public interface OfficialInventoryMapper extends BaseMapper<OfficialInventory> { // è·åæ£å¼åºè®°å½ OfficialInventory getOfficialInventoryForUpdateById(@Param("id") Long id); } main-business/src/main/java/com/ruoyi/business/mapper/OutputInventoryRecordMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.business.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.business.entity.OutputInventoryRecord; import org.apache.ibatis.annotations.Mapper; /** * <p> * åºåºè®°å½è¡¨ Mapper æ¥å£ * </p> * * @author chenhj * @since 2025-06-14 */ @Mapper public interface OutputInventoryRecordMapper extends BaseMapper<OutputInventoryRecord> { } main-business/src/main/java/com/ruoyi/business/mapper/PendingInventoryMapper.java
@@ -3,6 +3,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.business.entity.PendingInventory; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; /** * <p> @@ -14,5 +15,6 @@ */ @Mapper public interface PendingInventoryMapper extends BaseMapper<PendingInventory> { // è·åå¾ å ¥åºè®°å½ PendingInventory getPendingInventoryForUpdateById(@Param("id") Long id); } main-business/src/main/java/com/ruoyi/business/service/InputInventoryRecordService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,22 @@ package com.ruoyi.business.service; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.business.dto.OfficialInventoryDto; import com.ruoyi.business.dto.PendingInventoryDto; import com.ruoyi.business.entity.InputInventoryRecord; import java.math.BigDecimal; /** * <p> * å ¥åºè®°å½è¡¨ æå¡ç±» * </p> * * @author chenhj * @since 2025-06-14 */ public interface InputInventoryRecordService extends IService<InputInventoryRecord> { // æ·»å å ¥åºè®°å½ int insertInputInventoryRecord(PendingInventoryDto pendingInventoryDto, OfficialInventoryDto officialInventoryDto, BigDecimal quantity); } main-business/src/main/java/com/ruoyi/business/service/InventorySummaryService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,24 @@ package com.ruoyi.business.service; import com.ruoyi.business.dto.OfficialInventoryDto; import com.ruoyi.business.dto.PendingInventoryDto; import com.ruoyi.business.entity.InventorySummary; import com.baomidou.mybatisplus.extension.service.IService; /** * <p> * åºåæ±æ»è¡¨ æå¡ç±» * </p> * * @author chenhj * @since 2025-06-14 */ public interface InventorySummaryService extends IService<InventorySummary> { /** * æ´æ°åºå * @param pendingInventoryDto å¾ å¤çåºå * @param officialInventoryDto æ£å¼åºå */ int updateInventory(PendingInventoryDto pendingInventoryDto, OfficialInventoryDto officialInventoryDto); } main-business/src/main/java/com/ruoyi/business/service/OutputInventoryRecordService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,22 @@ package com.ruoyi.business.service; import com.ruoyi.business.dto.OfficialInventoryDto; import com.ruoyi.business.dto.PendingInventoryDto; import com.ruoyi.business.entity.OutputInventoryRecord; import com.baomidou.mybatisplus.extension.service.IService; import java.math.BigDecimal; /** * <p> * åºåºè®°å½è¡¨ æå¡ç±» * </p> * * @author chenhj * @since 2025-06-14 */ public interface OutputInventoryRecordService extends IService<OutputInventoryRecord> { // æ·»å åºåºè®°å½ int insertOutputInventoryRecord(PendingInventoryDto pendingInventoryDto, OfficialInventoryDto officialInventoryDto, BigDecimal quantity); } main-business/src/main/java/com/ruoyi/business/service/impl/InputInventoryRecordServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,56 @@ package com.ruoyi.business.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.business.dto.OfficialInventoryDto; import com.ruoyi.business.dto.PendingInventoryDto; import com.ruoyi.business.entity.InputInventoryRecord; import com.ruoyi.business.mapper.InputInventoryRecordMapper; import com.ruoyi.business.service.InputInventoryRecordService; import com.ruoyi.business.service.InventorySummaryService; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; import static com.ruoyi.business.constant.InventoryRecordConstant.OFFICIAL_INVENTORY; import static com.ruoyi.business.constant.InventoryRecordConstant.PENDING_INVENTORY; /** * <p> * å ¥åºè®°å½è¡¨ æå¡å®ç°ç±» * </p> * * @author chenhj * @since 2025-06-14 */ @Service @RequiredArgsConstructor public class InputInventoryRecordServiceImpl extends ServiceImpl<InputInventoryRecordMapper, InputInventoryRecord> implements InputInventoryRecordService { @Autowired private InputInventoryRecordMapper inputInventoryRecordMapper; @Autowired private InventorySummaryService inventorySummaryService; @Override public int insertInputInventoryRecord(PendingInventoryDto pendingInventoryDto, OfficialInventoryDto officialInventoryDto, BigDecimal quantity) { if ((pendingInventoryDto != null && officialInventoryDto != null) || (pendingInventoryDto == null && officialInventoryDto == null)) { throw new RuntimeException("åºåè®°å½å¼å¸¸"); } InputInventoryRecord inputInventoryRecord = new InputInventoryRecord(); if (officialInventoryDto != null) { inputInventoryRecord.setInventoryType(OFFICIAL_INVENTORY); inputInventoryRecord.setId(officialInventoryDto.getId()); } else { inputInventoryRecord.setInventoryType(PENDING_INVENTORY); inputInventoryRecord.setId(pendingInventoryDto.getId()); } inputInventoryRecord.setQuantity(quantity); inputInventoryRecordMapper.insert(inputInventoryRecord); // æ´æ°åºå return inventorySummaryService.updateInventory(pendingInventoryDto, officialInventoryDto); } } main-business/src/main/java/com/ruoyi/business/service/impl/InventorySummaryServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,99 @@ package com.ruoyi.business.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.business.dto.OfficialInventoryDto; import com.ruoyi.business.dto.PendingInventoryDto; import com.ruoyi.business.entity.*; import com.ruoyi.business.mapper.InventorySummaryMapper; import com.ruoyi.business.mapper.OfficialInventoryMapper; import com.ruoyi.business.mapper.PendingInventoryMapper; import com.ruoyi.business.service.InputInventoryRecordService; import com.ruoyi.business.service.InventorySummaryService; import com.ruoyi.business.service.OutputInventoryRecordService; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.util.List; import static com.ruoyi.business.constant.InventoryRecordConstant.OFFICIAL_INVENTORY; import static com.ruoyi.business.constant.InventoryRecordConstant.PENDING_INVENTORY; /** * <p> * åºåæ±æ»è¡¨ æå¡å®ç°ç±» * </p> * * @author chenhj * @since 2025-06-14 */ @Service @RequiredArgsConstructor public class InventorySummaryServiceImpl extends ServiceImpl<InventorySummaryMapper, InventorySummary> implements InventorySummaryService { @Autowired private InventorySummaryMapper inventorySummaryMapper; @Autowired private InputInventoryRecordService inputInventoryRecordService; @Autowired private OutputInventoryRecordService outputInventoryRecordService; @Autowired private PendingInventoryMapper pendingInventoryMapper; @Autowired private OfficialInventoryMapper officialInventoryMapper; @Override public int updateInventory(PendingInventoryDto pendingInventoryDto, OfficialInventoryDto officialInventoryDto) { if ((pendingInventoryDto != null && officialInventoryDto != null) || (pendingInventoryDto == null && officialInventoryDto == null)) { throw new RuntimeException("åºåè®°å½å¼å¸¸"); } String inventoryType = pendingInventoryDto != null ? PENDING_INVENTORY : OFFICIAL_INVENTORY; Long inventoryId = pendingInventoryDto != null ? pendingInventoryDto.getId() : officialInventoryDto.getId(); Long inputEndRecordId = 0L; Long outputEndRecordId = 0L; InventorySummary inventorySummary = inventorySummaryMapper.selectOne(new LambdaQueryWrapper<InventorySummary>() .eq(InventorySummary::getInventoryId, inventoryId) .eq(InventorySummary::getInventoryType, inventoryType)); if (inventorySummary != null) { inputEndRecordId = inventorySummary.getInputEndRecordId(); outputEndRecordId = inventorySummary.getOutputEndRecordId(); } // æ¥è¯¢èç¹ä»¥åææå ¥åºè®°å½ List<InputInventoryRecord> inputInventoryRecords = inputInventoryRecordService.list(new LambdaQueryWrapper<InputInventoryRecord>() .eq(InputInventoryRecord::getInventoryId, inventoryId) .eq(InputInventoryRecord::getInventoryType, inventoryType) .gt(InputInventoryRecord::getId, inputEndRecordId)); // æ¥è¯¢èç¹ä»¥åææåºåºè®°å½ List<OutputInventoryRecord> outputInventoryRecords = outputInventoryRecordService.list(new LambdaQueryWrapper<OutputInventoryRecord>() .eq(OutputInventoryRecord::getInventoryId, inventoryId) .eq(OutputInventoryRecord::getInventoryType, inventoryType) .gt(OutputInventoryRecord::getId, outputEndRecordId)); // å¦æå ¥åºæ°é大äºåºåºæ°éï¼ååºåæ°éä¸ºå ¥åºæ°éåå»åºåºæ°éï¼åä¹å为0 BigDecimal quantity = BigDecimal.ZERO; BigDecimal totalInputQuantity = inputInventoryRecords.stream().map(InputInventoryRecord::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal totalOutputQuantity = outputInventoryRecords.stream().map(OutputInventoryRecord::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add); if (totalInputQuantity.compareTo(totalOutputQuantity) > 0) { quantity = totalInputQuantity.subtract(totalOutputQuantity); } if (inventoryType.equals(PENDING_INVENTORY)) { // åæ´å¾ å ¥åºå¼ PendingInventory pendingInventory = pendingInventoryMapper.getPendingInventoryForUpdateById(pendingInventoryDto.getId()); if (pendingInventory == null) { throw new RuntimeException("åºåè®°å½ä¸åå¨"); } pendingInventory.setInventoryQuantity(quantity); return pendingInventoryMapper.updateById(pendingInventory); } else { OfficialInventory officialInventory = officialInventoryMapper.getOfficialInventoryForUpdateById(officialInventoryDto.getId()); if (officialInventory == null) { throw new RuntimeException("åºåè®°å½ä¸åå¨"); } officialInventory.setInventoryQuantity(quantity); return officialInventoryMapper.updateById(officialInventory); } } } main-business/src/main/java/com/ruoyi/business/service/impl/OutputInventoryRecordServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,56 @@ package com.ruoyi.business.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.business.dto.OfficialInventoryDto; import com.ruoyi.business.dto.PendingInventoryDto; import com.ruoyi.business.entity.OutputInventoryRecord; import com.ruoyi.business.mapper.OutputInventoryRecordMapper; import com.ruoyi.business.service.InventorySummaryService; import com.ruoyi.business.service.OutputInventoryRecordService; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; import static com.ruoyi.business.constant.InventoryRecordConstant.OFFICIAL_INVENTORY; import static com.ruoyi.business.constant.InventoryRecordConstant.PENDING_INVENTORY; /** * <p> * åºåºè®°å½è¡¨ æå¡å®ç°ç±» * </p> * * @author chenhj * @since 2025-06-14 */ @Service @RequiredArgsConstructor public class OutputInventoryRecordServiceImpl extends ServiceImpl<OutputInventoryRecordMapper, OutputInventoryRecord> implements OutputInventoryRecordService { @Autowired private OutputInventoryRecordMapper outputInventoryRecordMapper; @Autowired private InventorySummaryService inventorySummaryService; @Override public int insertOutputInventoryRecord(PendingInventoryDto pendingInventoryDto, OfficialInventoryDto officialInventoryDto, BigDecimal quantity) { if ((pendingInventoryDto != null && officialInventoryDto != null) || (pendingInventoryDto == null && officialInventoryDto == null)) { throw new RuntimeException("åºåè®°å½å¼å¸¸"); } OutputInventoryRecord outputInventoryRecord = new OutputInventoryRecord(); if (officialInventoryDto != null) { outputInventoryRecord.setInventoryType(OFFICIAL_INVENTORY); outputInventoryRecord.setId(officialInventoryDto.getId()); } else { outputInventoryRecord.setInventoryType(PENDING_INVENTORY); outputInventoryRecord.setId(pendingInventoryDto.getId()); } outputInventoryRecord.setQuantity(quantity); outputInventoryRecordMapper.insert(outputInventoryRecord); // åæ´ååºåä¿¡æ¯ return inventorySummaryService.updateInventory(pendingInventoryDto, officialInventoryDto); } } main-business/src/main/java/com/ruoyi/business/service/impl/PendingInventoryServiceImpl.java
@@ -136,6 +136,8 @@ pendingInventoryMapper.deleteById(pendingInventoryDto.getPId()); } officialInventoryMapper.delete(new LambdaQueryWrapper<OfficialInventory>().eq(OfficialInventory::getPendingId, pendingInventoryDto.getPId())); OfficialInventory officialInventory = new OfficialInventory(); BeanUtils.copyProperties(pendingInventory, officialInventory); officialInventory.setId(null); main-business/src/main/java/com/ruoyi/business/task/InventorySummaryTask.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,144 @@ package com.ruoyi.business.task; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.ruoyi.business.entity.*; import com.ruoyi.business.mapper.*; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.session.ResultContext; import org.apache.ibatis.session.ResultHandler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import static com.ruoyi.business.constant.InventoryRecordConstant.OFFICIAL_INVENTORY; import static com.ruoyi.business.constant.InventoryRecordConstant.PENDING_INVENTORY; @Slf4j @Component public class InventorySummaryTask { @Autowired private PendingInventoryMapper pendingInventoryMapper; @Autowired private OfficialInventoryMapper officialInventoryMapper; @Autowired private InventorySummaryMapper inventorySummaryMapper; @Autowired private InputInventoryRecordMapper inputInventoryRecordMapper; @Autowired private OutputInventoryRecordMapper outputInventoryRecordMapper; private final ExecutorService executor = Executors.newFixedThreadPool(5); // æ¯é10天ç忍3ç¹æ§è¡ @Scheduled(cron = "0 0 3 1/10 * ?") @Transactional public void updateInventorySummary() { log.info("å¼å§æ§è¡åºåèç¹ç»è®¡å®æ¶ä»»å¡: " + System.currentTimeMillis()); log.info("æ´æ°å¾ å ¥åºåºåèç¹"); updatePendingInventory(); log.info("æ´æ°æ£å¼åºåèç¹"); updateOfficialInventory(); log.info("ç»ææ§è¡åºåèç¹ç»è®¡å®æ¶ä»»å¡: " + System.currentTimeMillis()); } // æ´æ°å¾ å ¥åºåºåèç¹ private void updatePendingInventory() { pendingInventoryMapper.selectList(Wrappers.emptyWrapper(), new ResultHandler<PendingInventory>() { @Override public void handleResult(ResultContext<? extends PendingInventory> resultContext) { PendingInventory pendingInventory = resultContext.getResultObject(); executor.submit(() -> { handleInventorySummary(pendingInventory, null); }); } }); } // æ´æ°æ£å¼åºåèç¹ private void updateOfficialInventory() { officialInventoryMapper.selectList(Wrappers.emptyWrapper(), new ResultHandler<OfficialInventory>() { @Override public void handleResult(ResultContext<? extends OfficialInventory> resultContext) { OfficialInventory officialInventory = resultContext.getResultObject(); executor.submit(() -> { handleInventorySummary(null, officialInventory); }); } }); } // æ´æ°èç¹æ°æ® private void handleInventorySummary(PendingInventory pendingInventory, OfficialInventory officialInventory) { InventorySummary inventorySummary = null; List<InputInventoryRecord> inputInventoryRecordList = new ArrayList<>(); List<OutputInventoryRecord> outputInventoryRecordList = new ArrayList<>(); if (pendingInventory != null) { inventorySummary = inventorySummaryMapper.getInventorySummaryForUpdateByInventoryIdAndType(pendingInventory.getId(), PENDING_INVENTORY); inputInventoryRecordList = inputInventoryRecordMapper.selectList(new LambdaQueryWrapper<InputInventoryRecord>() .eq(InputInventoryRecord::getInventoryId, pendingInventory.getId()) .eq(InputInventoryRecord::getInventoryType, PENDING_INVENTORY) .gt(InputInventoryRecord::getId, inventorySummary == null ? 0 : inventorySummary.getInputEndRecordId())); outputInventoryRecordList = outputInventoryRecordMapper.selectList(new LambdaQueryWrapper<OutputInventoryRecord>() .eq(OutputInventoryRecord::getInventoryId, pendingInventory.getId()) .eq(OutputInventoryRecord::getInventoryType, PENDING_INVENTORY) .gt(OutputInventoryRecord::getId, inventorySummary == null ? 0 : inventorySummary.getOutputEndRecordId())); if (inventorySummary == null) { inventorySummary = new InventorySummary(); inventorySummary.setInventoryQuantity(BigDecimal.ZERO); inventorySummary.setInventoryId(pendingInventory.getId()); inventorySummary.setInventoryType(PENDING_INVENTORY); } } if (officialInventory != null) { inventorySummary = inventorySummaryMapper.getInventorySummaryForUpdateByInventoryIdAndType(officialInventory.getId(), OFFICIAL_INVENTORY); inputInventoryRecordList = inputInventoryRecordMapper.selectList(new LambdaQueryWrapper<InputInventoryRecord>() .eq(InputInventoryRecord::getInventoryId, officialInventory.getId()) .eq(InputInventoryRecord::getInventoryType, OFFICIAL_INVENTORY) .gt(InputInventoryRecord::getId, inventorySummary == null ? 0 : inventorySummary.getInputEndRecordId())); outputInventoryRecordList = outputInventoryRecordMapper.selectList(new LambdaQueryWrapper<OutputInventoryRecord>() .eq(OutputInventoryRecord::getInventoryId, officialInventory.getId()) .eq(OutputInventoryRecord::getInventoryType, OFFICIAL_INVENTORY) .gt(OutputInventoryRecord::getId, inventorySummary == null ? 0 : inventorySummary.getOutputEndRecordId())); if (inventorySummary == null) { inventorySummary = new InventorySummary(); inventorySummary.setInventoryQuantity(BigDecimal.ZERO); inventorySummary.setInventoryId(officialInventory.getId()); inventorySummary.setInventoryType(OFFICIAL_INVENTORY); } } BigDecimal total = inventorySummary.getInventoryQuantity(); BigDecimal inputTotal = BigDecimal.ZERO; if (CollectionUtils.isNotEmpty(inputInventoryRecordList)) { inputTotal = inputInventoryRecordList.stream().map(InputInventoryRecord::getQuantity).reduce(BigDecimal::add).orElse(BigDecimal.ZERO); inventorySummary.setInputEndRecordId(inputInventoryRecordList.get(inputInventoryRecordList.size() - 1).getId()); } BigDecimal outputTotal = BigDecimal.ZERO; if (CollectionUtils.isNotEmpty(outputInventoryRecordList)) { outputTotal = outputInventoryRecordList.stream().map(OutputInventoryRecord::getQuantity).reduce(BigDecimal::add).orElse(BigDecimal.ZERO); inventorySummary.setOutputEndRecordId(outputInventoryRecordList.get(outputInventoryRecordList.size() - 1).getId()); } if (inputTotal.compareTo(outputTotal) > 0) { total = total.add(inputTotal.subtract(outputTotal)); } inventorySummary.setInventoryQuantity(total); inventorySummaryMapper.insertOrUpdate(inventorySummary); } } main-business/src/main/resources/db/migration/postgresql/V20250614110410__create_table_input_inventory_record.sql
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,29 @@ DROP TABLE IF EXISTS input_inventory_record; -- åå»ºå ¥åºè®°å½è¡¨ CREATE TABLE input_inventory_record ( id BIGSERIAL PRIMARY KEY, -- 主é®ID inventory_id bigint not null default 0, inventory_type varchar(10) not null default '', quantity DECIMAL(10, 2) not null default 0, deleted INT NOT NULL DEFAULT 0, -- 软å 餿 å¿ï¼0=æªå é¤ï¼1=å·²å é¤ create_by VARCHAR(255), -- åå»ºäººç¨æ·å create_time TIMESTAMP WITHOUT TIME ZONE -- å建æ¶é´ï¼é»è®¤å½åæ¶é´ ); -- åå»ºç´¢å¼ create index index_inventory_id_and_inventory_type_and_quantity_for_input_inventory_record on input_inventory_record (inventory_id, inventory_type, quantity); -- æ·»å 表注é COMMENT ON TABLE input_inventory_record IS 'å ¥åºè®°å½è¡¨'; -- æ·»å åæ®µæ³¨é COMMENT ON COLUMN input_inventory_record.id IS '主é®ID'; COMMENT ON COLUMN input_inventory_record.inventory_id IS 'åºid'; COMMENT ON COLUMN input_inventory_record.inventory_type IS 'åºç±»å'; COMMENT ON COLUMN input_inventory_record.quantity IS 'è®°å½æ°é'; COMMENT ON COLUMN input_inventory_record.deleted IS '软å 餿 å¿ï¼0=æªå é¤ï¼1=å·²å é¤'; COMMENT ON COLUMN input_inventory_record.create_by IS 'å建该记å½çç¨æ·'; COMMENT ON COLUMN input_inventory_record.create_time IS 'è®°å½å建æ¶é´'; main-business/src/main/resources/db/migration/postgresql/V20250614111500__create_table_output_inventory_record.sql
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,29 @@ DROP TABLE IF EXISTS output_inventory_record; -- å建åºåºè®°å½è¡¨ CREATE TABLE output_inventory_record ( id BIGSERIAL PRIMARY KEY, -- 主é®ID inventory_id bigint not null default 0, inventory_type varchar(10) not null default '', quantity DECIMAL(10, 2) not null default 0, deleted INT NOT NULL DEFAULT 0, -- 软å 餿 å¿ï¼0=æªå é¤ï¼1=å·²å é¤ create_by VARCHAR(255), -- åå»ºäººç¨æ·å create_time TIMESTAMP WITHOUT TIME ZONE -- å建æ¶é´ï¼é»è®¤å½åæ¶é´ ); -- åå»ºç´¢å¼ create index index_inventory_id_and_inventory_type_and_quantity_for_output_inventory_record on output_inventory_record (inventory_id, inventory_type, quantity); -- æ·»å 表注é COMMENT ON TABLE output_inventory_record IS 'åºåºè®°å½è¡¨'; -- æ·»å åæ®µæ³¨é COMMENT ON COLUMN output_inventory_record.id IS '主é®ID'; COMMENT ON COLUMN output_inventory_record.inventory_id IS 'åºid'; COMMENT ON COLUMN output_inventory_record.inventory_type IS 'åºç±»å'; COMMENT ON COLUMN output_inventory_record.quantity IS 'è®°å½æ°é'; COMMENT ON COLUMN output_inventory_record.deleted IS '软å 餿 å¿ï¼0=æªå é¤ï¼1=å·²å é¤'; COMMENT ON COLUMN output_inventory_record.create_by IS 'å建该记å½çç¨æ·'; COMMENT ON COLUMN output_inventory_record.create_time IS 'è®°å½å建æ¶é´'; main-business/src/main/resources/db/migration/postgresql/V20250614111811__create_table_inventory_summary.sql
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,30 @@ DROP TABLE IF EXISTS inventory_summary; -- å建åºåæ±æ»è¡¨ CREATE TABLE inventory_summary ( id BIGSERIAL PRIMARY KEY, -- 主é®ID inventory_id bigint not null default 0, inventory_type varchar(10) not null default '', inventory_quantity DECIMAL(10, 2) not null default 0, input_end_record_id bigint not null default 0, output_end_record_id bigint not null default 0, deleted INT NOT NULL DEFAULT 0, -- 软å 餿 å¿ï¼0=æªå é¤ï¼1=å·²å é¤ create_time TIMESTAMP WITHOUT TIME ZONE, -- å建æ¶é´ï¼é»è®¤å½åæ¶é´ update_time TIMESTAMP WITHOUT TIME ZONE -- æåæ´æ°æ¶é´ï¼é»è®¤å½åæ¶é´ ); -- æ·»å 表注é COMMENT ON TABLE inventory_summary IS 'åºåæ±æ»è¡¨'; -- æ·»å åæ®µæ³¨é COMMENT ON COLUMN inventory_summary.id IS '主é®ID'; COMMENT ON COLUMN inventory_summary.inventory_id IS 'åºid'; COMMENT ON COLUMN inventory_summary.inventory_type IS 'åºç±»å'; COMMENT ON COLUMN inventory_summary.inventory_quantity IS 'åºåæ°é'; COMMENT ON COLUMN inventory_summary.input_end_record_id IS 'å ¥åºä¸æ¢æç»è®°å½id'; COMMENT ON COLUMN inventory_summary.output_end_record_id IS 'åºåºä¸æ¢æç»è®°å½id'; COMMENT ON COLUMN inventory_summary.deleted IS '软å 餿 å¿ï¼0=æªå é¤ï¼1=å·²å é¤'; COMMENT ON COLUMN inventory_summary.create_time IS 'è®°å½å建æ¶é´'; COMMENT ON COLUMN inventory_summary.update_time IS 'è®°å½æåæ´æ°æ¶é´'; main-business/src/main/resources/mapper/InputInventoryRecordMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,24 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ruoyi.business.mapper.InputInventoryRecordMapper"> <!-- éç¨æ¥è¯¢æ å°ç»æ --> <resultMap id="BaseResultMap" type="com.ruoyi.business.entity.InputInventoryRecord"> <id column="id" property="id" /> <result column="deleted" property="deleted" /> <result column="create_by" property="createBy" /> <result column="create_time" property="createTime" /> <result column="inventory_id" property="inventoryId" /> <result column="inventory_type" property="inventoryType" /> <result column="quantity" property="quantity" /> </resultMap> <!-- éç¨æ¥è¯¢ç»æå --> <sql id="Base_Column_List"> deleted, create_by, create_time, id, inventory_id, inventory_type, quantity </sql> </mapper> main-business/src/main/resources/mapper/InventorySummaryMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,38 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ruoyi.business.mapper.InventorySummaryMapper"> <!-- éç¨æ¥è¯¢æ å°ç»æ --> <resultMap id="BaseResultMap" type="com.ruoyi.business.entity.InventorySummary"> <id column="id" property="id"/> <result column="deleted" property="deleted"/> <result column="create_time" property="createTime"/> <result column="update_time" property="updateTime"/> <result column="inventory_id" property="inventoryId"/> <result column="inventory_type" property="inventoryType"/> <result column="inventory_quantity" property="inventoryQuantity"/> <result column="input_end_record_id" property="inputEndRecordId"/> <result column="output_end_record_id" property="outputEndRecordId"/> </resultMap> <!-- éç¨æ¥è¯¢ç»æå --> <sql id="Base_Column_List"> deleted, create_time, update_time, id, inventory_id, inventory_type, inventory_quantity, input_end_record_id, output_end_record_id </sql> <select id="getInventorySummaryForUpdateById" resultType="com.ruoyi.business.entity.InventorySummary"> select * from inventory_summary where id = #{id} for update </select> <select id="getInventorySummaryForUpdateByInventoryIdAndType" resultType="com.ruoyi.business.entity.InventorySummary"> select * from inventory_summary where inventory_id = #{inventoryId} and inventory_type = #{type} for update </select> </mapper> main-business/src/main/resources/mapper/OfficialInventoryMapper.xml
@@ -30,5 +30,11 @@ update_time, id, supplier_name, coal, unit, inventory_quantity, price_including_tax, total_price_including_tax, pending_replenishment, registrant_id, registration_date </sql> <select id="getOfficialInventoryForUpdateById" resultType="com.ruoyi.business.entity.OfficialInventory"> select * from official_inventory where id = #{id} for update </select> </mapper> main-business/src/main/resources/mapper/OutputInventoryRecordMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,24 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ruoyi.business.mapper.OutputInventoryRecordMapper"> <!-- éç¨æ¥è¯¢æ å°ç»æ --> <resultMap id="BaseResultMap" type="com.ruoyi.business.entity.OutputInventoryRecord"> <id column="id" property="id" /> <result column="deleted" property="deleted" /> <result column="create_by" property="createBy" /> <result column="create_time" property="createTime" /> <result column="inventory_id" property="inventoryId" /> <result column="inventory_type" property="inventoryType" /> <result column="quantity" property="quantity" /> </resultMap> <!-- éç¨æ¥è¯¢ç»æå --> <sql id="Base_Column_List"> deleted, create_by, create_time, id, inventory_id, inventory_type, quantity </sql> </mapper> main-business/src/main/resources/mapper/PendingInventoryMapper.xml
@@ -29,5 +29,11 @@ update_time, id, supplier_name, coal, unit, inventory_quantity, price_including_tax, total_price_including_tax, registrant, registration_time </sql> <select id="getPendingInventoryForUpdateById" resultType="com.ruoyi.business.entity.PendingInventory"> select * from pending_inventory where id = #{id} for update </select> </mapper> ruoyi-admin/src/main/java/com/ruoyi/PlusCodeGenerator.java
@@ -28,18 +28,18 @@ public class PlusCodeGenerator { // æ°æ®åºé ç½® private static final String DB_URL = "jdbc:postgresql://localhost:5432/ruoyi-zd"; private static final String DB_URL = "jdbc:postgresql://192.168.1.35:5432/ruoyi-zd"; private static final String DB_USERNAME = "postgres"; private static final String DB_PASSWORD = "123456"; // 项ç®åºç¡é ç½® private static final String BASE_PACKAGE = "com.ruoyi"; private static final String MODULE_NAME = "basic"; // 模åå private static final String MODULE_NAME = "business"; // 模åå public static void main(String[] args) { String projectPath = System.getProperty("user.dir"); // è·åé¡¹ç®æ ¹è·¯å¾ String path = "basic-server"; // 模ååç§° String table = "coal_info"; // 表åï¼å¤ä¸ªè¡¨éå·éå¼ String path = "main-business"; // 模ååç§° String table = "input_inventory_record,output_inventory_record,inventory_summary"; // 表åï¼å¤ä¸ªè¡¨éå·éå¼ // 代ç è¾åºè·¯å¾é ç½® String outputBasePath = Paths.get(projectPath, path, "src", "main", "java").toString(); @@ -48,7 +48,7 @@ // 代ç çææ ¸å¿é ç½® FastAutoGenerator.create(DB_URL, DB_USERNAME, DB_PASSWORD) .globalConfig(builder -> { builder.author("ld") // ä½è ä¿¡æ¯ builder.author("chenhj") // ä½è ä¿¡æ¯ .outputDir(outputBasePath) // 代ç è¾åºç®å½ .dateType(DateType.ONLY_DATE) // æ¥æç±»å .commentDate("yyyy-MM-dd") // æ³¨éæ¥ææ ¼å¼ @@ -128,7 +128,7 @@ )); // åºç±»å段 customMap.put("idType", "AUTO"); // 主é®ç±»å customMap.put("superEntityClass", "com.ruoyi.common.core.domain.MyBaseEntity"); // åºç±»å ¨è·¯å¾ customMap.put("author", "ruoyi"); // ä½è ä¿¡æ¯ customMap.put("author", "chenhj"); // ä½è ä¿¡æ¯ customMap.put("packageName", BASE_PACKAGE + "." + MODULE_NAME); // å å customMap.put("tableName", table); // 表å ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
@@ -3,6 +3,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.scheduling.annotation.EnableScheduling; /** * å¯å¨ç¨åº @@ -10,6 +11,7 @@ * @author ruoyi */ @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) @EnableScheduling public class RuoYiApplication { public static void main(String[] args)