feat:反审核操作。可以对已审核的订单进行反审核,反审核的时候可以选择作废还是重新生成一条,并记录反审核描述。选择作废的话则不生成新增订单。选择重新生成的话则跳转到新增台账页面对反审核的销售产品进行编辑保存重新生成一条新增的订单。反审核的订单即使是发货了还是可以反审核,并且需要将对应的入库、出库、发货进行作废。
已添加2个文件
已修改6个文件
149 ■■■■■ 文件已修改
doc/sales_ledger_add_counter_review_fields.sql 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/CounterReviewDto.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/SalesLedgerDto.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesLedger.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/SalesLedgerMapper.xml 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/sales_ledger_add_counter_review_fields.sql
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,3 @@
-- é”€å”®å°è´¦æ–°å¢žåå®¡æ ¸ç±»åž‹å’Œåå®¡æ ¸æè¿°å­—段
ALTER TABLE sales_ledger ADD COLUMN counter_review_type INT DEFAULT NULL COMMENT '反审核类型:1=作废,2=重新生成';
ALTER TABLE sales_ledger ADD COLUMN counter_review_desc VARCHAR(500) DEFAULT NULL COMMENT '反审核描述';
src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java
@@ -194,6 +194,21 @@
    }
    /**
     * åå®¡æ ¸æ“ä½œ
     */
    @Log(title = "销售台账反审核", businessType = BusinessType.UPDATE)
    @PostMapping("/counterReview")
    @ApiOperation("反审核操作:作废或重新生成")
    public AjaxResult counterReview(@RequestBody CounterReviewDto dto) {
        List<Long> newLedgerIds = salesLedgerService.counterReview(dto);
        AjaxResult result = AjaxResult.success("反审核成功");
        if (newLedgerIds != null && !newLedgerIds.isEmpty()) {
            result.put("newLedgerIds", newLedgerIds);
        }
        return result;
    }
    /**
     * åˆ é™¤é”€å”®å°è´¦
     */
    @Log(title = "销售台账", businessType = BusinessType.DELETE)
src/main/java/com/ruoyi/sales/dto/CounterReviewDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,19 @@
package com.ruoyi.sales.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
public class CounterReviewDto {
    @ApiModelProperty("要反审核的订单ID列表")
    private List<Long> ids;
    @ApiModelProperty("反审核类型:1=作废,2=重新生成")
    private Integer counterReviewType;
    @ApiModelProperty("反审核描述")
    private String counterReviewDesc;
}
src/main/java/com/ruoyi/sales/dto/SalesLedgerDto.java
@@ -87,4 +87,10 @@
    @ApiModelProperty("反审人")
    private String counterReviewPerson;
    @ApiModelProperty("反审核类型:1=作废,2=重新生成")
    private Integer counterReviewType;
    @ApiModelProperty("反审核描述")
    private String counterReviewDesc;
}
src/main/java/com/ruoyi/sales/pojo/SalesLedger.java
@@ -194,4 +194,10 @@
    @ApiModelProperty("反审人Id")
    private Long counterReviewPersonId;
    @ApiModelProperty("反审核类型:1=作废,2=重新生成")
    private Integer counterReviewType;
    @ApiModelProperty("反审核描述")
    private String counterReviewDesc;
}
src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java
@@ -101,4 +101,9 @@
    void shippingImport(MultipartFile file);
    void notShippingImport(MultipartFile file);
    /**
     * åå®¡æ ¸æ“ä½œï¼šä½œåºŸæˆ–重新生成
     */
    List<Long> counterReview(CounterReviewDto dto);
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -3357,6 +3357,97 @@
     * 2. å¤åˆ¶åŽŸé”€å”®å°è´¦åŠäº§å“æ•°æ®ï¼Œç”Ÿæˆæ–°çš„å°è´¦
     * 3. å¯¹åŽŸå°è´¦çš„åº“å­˜æ•°æ®è¿›è¡Œåå‘æ“ä½œ
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Long> counterReview(CounterReviewDto dto) {
        if (dto == null || CollectionUtils.isEmpty(dto.getIds())) {
            throw new ServiceException("请选择要反审核的订单");
        }
        if (dto.getCounterReviewType() == null || (dto.getCounterReviewType() != 1 && dto.getCounterReviewType() != 2)) {
            throw new ServiceException("请选择反审核类型:作废或重新生成");
        }
        if (dto.getCounterReviewDesc() == null || dto.getCounterReviewDesc().trim().isEmpty()) {
            throw new ServiceException("请输入反审核描述");
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        List<Long> newLedgerIds = new ArrayList<>();
        for (Long id : dto.getIds()) {
            SalesLedger originalLedger = salesLedgerMapper.selectById(id);
            if (originalLedger == null) {
                throw new ServiceException("订单不存在,无法反审核");
            }
            if (originalLedger.getReviewStatus() == null || originalLedger.getReviewStatus() != 1) {
                throw new ServiceException("订单" + originalLedger.getSalesContractNo() + "不是已审核状态,无法反审核");
            }
            // 1. æ ‡è®°åŽŸè®¢å•ä¸ºå·²åå®¡
            originalLedger.setReviewStatus(2);
            originalLedger.setCounterReviewTime(LocalDateTime.now());
            originalLedger.setCounterReviewPerson(loginUser.getUser().getNickName());
            originalLedger.setCounterReviewPersonId(loginUser.getUserId());
            originalLedger.setCounterReviewType(dto.getCounterReviewType());
            originalLedger.setCounterReviewDesc(dto.getCounterReviewDesc());
            salesLedgerMapper.updateById(originalLedger);
            // 2. ä½œåºŸåº“存:入库扣减、出库增加、删除记录
            processOriginalOrderStock(id);
            // 3. æ¸…除质检记录
            clearQualityInspectRecords(id);
            // 4. æ¸…除发货信息和发货审批记录
            clearShippingAndApprovalRecords(id);
            // 5. å–消审批流程
            cancelApproveProcesses(id, originalLedger.getSalesContractNo());
            // 6. é‡æ–°ç”Ÿæˆï¼šåˆ›å»ºæ–°å°è´¦å‰¯æœ¬
            if (dto.getCounterReviewType() == 2) {
                SalesLedger newLedger = new SalesLedger();
                BeanUtils.copyProperties(originalLedger, newLedger);
                newLedger.setId(null);
                newLedger.setSalesContractNo(generateSalesContractNo());
                newLedger.setDeliveryStatus(1);
                newLedger.setStockStatus(0);
                newLedger.setReviewStatus(0);
                newLedger.setCounterReviewTime(null);
                newLedger.setCounterReviewPerson(null);
                newLedger.setCounterReviewPersonId(null);
                newLedger.setCounterReviewType(null);
                newLedger.setCounterReviewDesc(null);
                salesLedgerMapper.insert(newLedger);
                // å¤åˆ¶äº§å“åˆ°æ–°å°è´¦
                List<SalesLedgerProduct> originalProducts = salesLedgerProductMapper.selectList(
                    Wrappers.<SalesLedgerProduct>lambdaQuery()
                        .eq(SalesLedgerProduct::getSalesLedgerId, id)
                );
                for (SalesLedgerProduct originalProduct : originalProducts) {
                    SalesLedgerProduct newProduct = new SalesLedgerProduct();
                    BeanUtils.copyProperties(originalProduct, newProduct);
                    newProduct.setId(null);
                    newProduct.setSalesLedgerId(newLedger.getId());
                    newProduct.setStockedQuantity(BigDecimal.ZERO);
                    newProduct.setShippedQuantity(BigDecimal.ZERO);
                    newProduct.setUnqualifiedStockedQuantity(BigDecimal.ZERO);
                    newProduct.setUnqualifiedShippedQuantity(BigDecimal.ZERO);
                    newProduct.setReturnQuality(BigDecimal.ZERO);
                    newProduct.setAvailableQuality(newProduct.getQuantity().subtract(newProduct.getReturnQuality()));
                    newProduct.setProductStockStatus(0);
                    newProduct.fillRemainingQuantity();
                    salesLedgerProductMapper.insert(newProduct);
                }
                newLedgerIds.add(newLedger.getId());
            }
        }
        return newLedgerIds;
    }
    /**
     * æ—§ç‰ˆåå®¡å¤„理(兼容 addOrUpdateSalesLedger ä¸­ reviewStatus=2 çš„调用)
     */
    private void handleCounterReview(SalesLedger salesLedger) {
        // 1. è®¾ç½®åå®¡ç›¸å…³ä¿¡æ¯
        LoginUser loginUser = SecurityUtils.getLoginUser();
src/main/resources/mapper/sales/SalesLedgerMapper.xml
@@ -70,7 +70,9 @@
        T1.review_status AS reviewStatus,
        T1.counter_review_time AS counterReviewTime,
        T1.counter_review_person AS counterReviewPerson,
        T1.counter_review_person_id AS counterReviewPersonId
        T1.counter_review_person_id AS counterReviewPersonId,
        T1.counter_review_type AS counterReviewType,
        T1.counter_review_desc AS counterReviewDesc
        FROM sales_ledger T1
        LEFT JOIN sys_user T2 ON T1.entry_person = T2.user_id
        <where>