3 天以前 ffb7c59cadfb8a043a41849fd6d093f7967ea4cb
feat(quality): 增加不合格品拒收处理功能

- 在QualityUnqualifiedServiceImpl中新增拒收处理逻辑
- 新增createRejectPurchaseReturn方法处理采购退货单创建
- 添加相关依赖注入包括PurchaseReturnOrdersMapper等
- 在deal方法上添加@Transactional注解确保事务性
- 新增resetAllUserPwd接口用于重置所有用户密码
- 在SysUserController中添加resetAllPwd端点
- 更新QualityInspectHelper等多处设置检验公司名称
- 新增原料检验不合格拒收处理文档说明
已修改10个文件
已添加1个文件
169 ■■■■■ 文件已修改
docs/quality_unqualified_reject.md 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/controller/SysUserController.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/mapper/SysUserMapper.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/service/ISysUserService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/service/impl/SysUserServiceImpl.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/utils/QualityInspectHelper.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/system/SysUserMapper.xml 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/quality_unqualified_reject.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,63 @@
# åŽŸæ–™æ£€éªŒä¸åˆæ ¼å¤„ç†-拒收
## æ¶‰åŠé¡µé¢
- ä¸åˆæ ¼ç®¡ç†å¤„理弹窗(原料检验)
## API
| æ–¹æ³• | è·¯å¾„ | è¯´æ˜Ž |
|------|------|------|
| POST | /quality/qualityUnqualified/deal | ä¸åˆæ ¼ç®¡ç†å¤„理(新增"拒收"选项) |
**请求参数:**
| å‚æ•° | ç±»åž‹ | å¿…å¡« | è¯´æ˜Ž |
|------|------|------|------|
| id | Long | æ˜¯ | ä¸åˆæ ¼è®°å½•ID |
| dealResult | String | æ˜¯ | å¤„理结果,新增"拒收"选项 |
| dealName | String | å¦ | å¤„理人 |
| dealTime | Date | å¦ | å¤„理日期 |
**响应:** `{ "code": 200, "msg": "操作成功" }`
## å‰ç«¯ä¿®æ”¹ç‚¹
### 1. ä¸åˆæ ¼å¤„理弹窗 - å¤„理结果下拉框
在原料检验(inspectType=0)的不合格处理弹窗中,处理结果下拉框新增"拒收"选项:
```html
<el-select v-model="form.dealResult" placeholder="请选择处理结果">
  <el-option label="报废" value="报废" />
  <el-option label="让步放行" value="让步放行" />
  <el-option label="拒收" value="拒收" />  <!-- æ–°å¢ž -->
</el-select>
```
### 2. åˆ—表/详情 - å¤„理结果展示
列表页和详情页的 `dealResult` å­—段需支持显示"拒收"状态:
```html
<el-table-column prop="dealResult" label="处理结果">
  <template slot-scope="scope">
    <el-tag v-if="scope.row.dealResult === '拒收'" type="danger">拒收</el-tag>
    <span v-else>{{ scope.row.dealResult }}</span>
  </template>
</el-table-column>
```
### 3. å¤„理逻辑
前端调用 `/quality/qualityUnqualified/deal` æŽ¥å£æ—¶ï¼Œ`dealResult` ä¼ å€¼ `"拒收"` å³å¯ï¼ŒåŽç«¯ä¼šè‡ªåŠ¨ï¼š
- åˆ›å»ºé‡‡è´­é€€è´§å•(`purchase_return_orders`),退货方式=拒收(returnType=1)
- åˆ›å»ºé‡‡è´­é€€è´§äº§å“æ˜Žç»†ï¼ˆ`purchase_return_order_products`)
- ä¸å…¥åº“(不产生入库/出库记录)
- æ›´æ–°ä¸åˆæ ¼è®°å½•状态为"已处理"
## æ³¨æ„äº‹é¡¹
- "拒收"选项仅对原料检验(inspectType=0)的不合格记录有效
- æ‹’收后会自动生成采购退货单号(CGTL前缀),可在采购退货页面查看
- æ‹’收不会产生任何库存变动,物品直接退回供应商
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -332,6 +332,7 @@
                qualityInspect.setInspectState(0);
                qualityInspect.setInspectType(inspectType);
                qualityInspect.setProductMainId(productionProductMain.getId());
                qualityInspect.setCheckCompany("新疆大罗素马铃薯制品有限公司");
                qualityInspect.setProductModelId(productModel.getId());
                qualityInspectMapper.insert(qualityInspect);
                List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(product.getId(), inspectType, process);
src/main/java/com/ruoyi/project/system/controller/SysUserController.java
@@ -210,6 +210,23 @@
    }
    /**
     * ä¸€é”®é‡ç½®æ‰€æœ‰ç”¨æˆ·å¯†ç ï¼ˆä»…超级管理员)
     */
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PostMapping("/resetAllPwd")
    public AjaxResult resetAllPwd()
    {
        if (!SysUser.isAdmin(getUserId()))
        {
            return error("仅超级管理员可执行此操作");
        }
        String defaultPassword = "12345";
        String encryptedPwd = SecurityUtils.encryptPassword(defaultPassword);
        int rows = userService.resetAllUserPwd(encryptedPwd);
        return success("已重置 " + rows + " ä¸ªç”¨æˆ·çš„密码为 " + defaultPassword);
    }
    /**
     * çŠ¶æ€ä¿®æ”¹
     */
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
src/main/java/com/ruoyi/project/system/mapper/SysUserMapper.java
@@ -110,6 +110,14 @@
    public int resetUserPwd(@Param("userName") String userName, @Param("password") String password);
    /**
     * é‡ç½®æ‰€æœ‰æœªåˆ é™¤ç”¨æˆ·çš„密码
     *
     * @param password å¯†ç 
     * @return ç»“æžœ
     */
    public int resetAllUserPwd(@Param("password") String password);
    /**
     * é€šè¿‡ç”¨æˆ·ID删除用户
     *
     * @param userId ç”¨æˆ·ID
src/main/java/com/ruoyi/project/system/service/ISysUserService.java
@@ -179,6 +179,14 @@
    public int resetUserPwd(String userName, String password);
    /**
     * é‡ç½®æ‰€æœ‰ç”¨æˆ·å¯†ç ä¸ºé»˜è®¤å€¼
     *
     * @param password é»˜è®¤å¯†ç ï¼ˆæ˜Žæ–‡ï¼‰
     * @return ç»“æžœ
     */
    public int resetAllUserPwd(String password);
    /**
     * é€šè¿‡ç”¨æˆ·ID删除用户
     * 
     * @param userId ç”¨æˆ·ID
src/main/java/com/ruoyi/project/system/service/impl/SysUserServiceImpl.java
@@ -360,6 +360,12 @@
        return userMapper.resetUserPwd(userName, password);
    }
    @Override
    public int resetAllUserPwd(String password)
    {
        return userMapper.resetAllUserPwd(password);
    }
    /**
     * æ–°å¢žç”¨æˆ·è§’色信息
     * 
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -425,6 +425,7 @@
        qualityInspect.setUnit(saleProduct.getUnit());
        qualityInspect.setQuantity(saleProduct.getQuantity());
        qualityInspect.setWarehouse(saleProduct.getStorageLocation());
        qualityInspect.setCheckCompany("新疆大罗素马铃薯制品有限公司");
        qualityInspectMapper.insert(qualityInspect);
        List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(saleProduct.getProductId(), 0,null);
        if (qualityTestStandard.size()>0){
src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java
@@ -7,9 +7,16 @@
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.procurementrecord.utils.StockUtils;
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.production.mapper.ProductionOperationTaskMapper;
import com.ruoyi.production.mapper.ProductionOrderMapper;
import com.ruoyi.production.mapper.ProductionOrderRoutingMapper;
@@ -30,10 +37,12 @@
import com.ruoyi.stock.service.StockUninventoryService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import jakarta.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
@@ -54,6 +63,9 @@
    private final ProductionOperationTaskMapper productionOperationTaskMapper;
    private final StockUninventoryService stockUninventoryService;
    private final StockInRecordService stockInRecordService;
    private final PurchaseReturnOrdersMapper purchaseReturnOrdersMapper;
    private final PurchaseReturnOrderProductsMapper purchaseReturnOrderProductsMapper;
    private final PurchaseLedgerMapper purchaseLedgerMapper;
    @Override
    public IPage<QualityUnqualified> qualityUnqualifiedListPage(Page page, QualityUnqualified qualityUnqualified) {
@@ -68,6 +80,7 @@
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deal(QualityUnqualified qualityUnqualified) {
        QualityUnqualified unqualified = qualityUnqualifiedMapper.selectById(qualityUnqualified.getId());
        QualityInspect qualityInspect = qualityInspectService.getById(unqualified.getInspectId());
@@ -106,6 +119,9 @@
                case "让步放行":
                    stockUtils.addStock(modelId, unqualified.getQuantity(),
                            StockInQualifiedRecordTypeEnum.DEFECTIVE_PASS.getCode(), unqualified.getId());
                    break;
                case "拒收":
                    createRejectPurchaseReturn(qualityInspect, qualityUnqualified);
                    break;
                default:
                    break;
@@ -226,6 +242,34 @@
        return value == null ? BigDecimal.ZERO : value;
    }
    private void createRejectPurchaseReturn(QualityInspect qualityInspect, QualityUnqualified qualityUnqualified) {
        if (qualityInspect == null) {
            throw new ServiceException("手动新增的不合格记录不支持拒收处理,请选择报废或让步放行");
        }
        Long supplierId = null;
        Long purchaseLedgerId = qualityInspect.getPurchaseLedgerId();
        if (purchaseLedgerId != null) {
            PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(purchaseLedgerId);
            if (purchaseLedger != null) {
                supplierId = purchaseLedger.getSupplierId();
            }
        }
        PurchaseReturnOrders returnOrder = new PurchaseReturnOrders();
        returnOrder.setReturnType(1);
        returnOrder.setSupplierId(supplierId);
        returnOrder.setPurchaseLedgerId(purchaseLedgerId);
        returnOrder.setPreparedAt(LocalDate.now());
        returnOrder.setReturnUserName(qualityUnqualified.getDealName());
        returnOrder.setRemark("原料检验不合格-拒收");
        returnOrder.setNo(OrderUtils.countTodayByCreateTime(purchaseReturnOrdersMapper, "CGTL", "no", LocalDateTime.now()));
        purchaseReturnOrdersMapper.insert(returnOrder);
        PurchaseReturnOrderProducts product = new PurchaseReturnOrderProducts();
        product.setPurchaseReturnOrderId(returnOrder.getId());
        product.setReturnQuantity(qualityUnqualified.getQuantity());
        product.setStockInRecordId(0L);
        purchaseReturnOrderProductsMapper.insert(product);
    }
    private String resolveProductionBatchNo(Long productionProductMainId,
                                            Long qualityInspectId,
                                            Long productModelId) {
src/main/java/com/ruoyi/quality/utils/QualityInspectHelper.java
@@ -48,6 +48,7 @@
        qualityInspect.setProductModelId(saleProduct.getProductModelId());
        qualityInspect.setUnit(saleProduct.getUnit());
        qualityInspect.setQuantity(saleProduct.getQuantity());
        qualityInspect.setCheckCompany("新疆大罗素马铃薯制品有限公司");
        qualityInspectMapper.insert(qualityInspect);
        List<QualityTestStandard> qualityTestStandardList = qualityTestStandardMapper
src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
@@ -181,6 +181,7 @@
        }
        qualityInspectDto.setModel(productModel.getModel());
        qualityInspectDto.setUnit(productModel.getUnit());
        qualityInspectDto.setCheckCompany("新疆大罗素马铃薯制品有限公司");
        // åˆå§‹åŒ–空的检验参数列表
        qualityInspectDto.setQualityInspectParams(new ArrayList<>());
src/main/resources/mapper/system/SysUserMapper.xml
@@ -97,7 +97,7 @@
        </if>
        <!-- æ•°æ®èŒƒå›´è¿‡æ»¤ -->
        ${params.dataScope}
        ORDER BY u.create_time DESC
        ORDER BY u.create_time DESC, u.user_id DESC
    </select>
    <select id="selectAllocatedList" parameterType="com.ruoyi.project.system.domain.SysUser" resultMap="SysUserResult">
@@ -131,20 +131,20 @@
        </if>
        <!-- æ•°æ®èŒƒå›´è¿‡æ»¤ -->
        ${params.dataScope}
        ORDER BY u.create_time DESC
        ORDER BY u.create_time DESC, u.user_id DESC
    </select>
    <select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult">
        <include refid="selectUserVo"/>
        where u.user_name = #{userName} and u.del_flag = '0'
        ORDER BY u.create_time DESC
        ORDER BY u.create_time DESC, u.user_id DESC
    </select>
    <select id="selectUserById" parameterType="Long" resultMap="SysUserResult">
        <include refid="selectUserVo"/>
        where u.user_id = #{userId}
        and u.del_flag = '0'
        ORDER BY u.create_time DESC
        ORDER BY u.create_time DESC, u.user_id DESC
    </select>
    <select id="checkUserNameUnique" parameterType="String" resultMap="SysUserResult">
@@ -169,7 +169,7 @@
            </if>
            and u.del_flag = '0'
        </where>
        ORDER BY u.create_time DESC
        ORDER BY u.create_time DESC, u.user_id DESC
    </select>
    <select id="selectRegistrantIds" resultType="com.ruoyi.project.system.domain.SysUser">
        SELECT user_id, nick_name FROM sys_user
@@ -184,7 +184,7 @@
                1=0  <!-- ç©ºåˆ—表时返回空结果 -->
            </if>
        </where>
        ORDER BY sys_user.create_time DESC
        ORDER BY sys_user.create_time DESC, sys_user.user_id DESC
    </select>
    <select id="selectUsersByIds" resultType="com.ruoyi.project.system.domain.SysUser">
        SELECT user_id, nick_name
@@ -194,7 +194,7 @@
            #{id}
        </foreach>
        and del_flag = '0'
        ORDER BY sys_user.create_time DESC
        ORDER BY sys_user.create_time DESC, sys_user.user_id DESC
    </select>
    <select id="selectUserByNickName" resultType="com.ruoyi.project.system.domain.SysUser"
            parameterType="java.lang.String">
@@ -266,6 +266,9 @@
    <update id="resetUserPwd" parameterType="com.ruoyi.project.system.domain.SysUser">
         update sys_user set password = #{password} where user_name = #{userName}
    </update>
        <update id="resetAllUserPwd">
            update sys_user set password = #{password} where del_flag = '0'
        </update>
    <delete id="deleteUserById" parameterType="Long">
         update sys_user set del_flag = '2' where user_id = #{userId}
@@ -288,7 +291,7 @@
          and sr.status = '0'
          and su.status = '0'
          and su.del_flag = '0'
        ORDER BY su.create_time DESC
        ORDER BY su.create_time DESC, su.user_id DESC
    </select>
    <select id="getUserByPerms" resultType="java.lang.Long">
        select distinct t5.user_id