package jnpf.limsService.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import jnpf.audit.sdk.annotation.AuditLog; import jnpf.base.ActionResult; import jnpf.base.BillRuleApi; import jnpf.base.UserInfo; import jnpf.base.service.SuperServiceImpl; import jnpf.exception.DataException; import jnpf.limsEntity.*; import jnpf.limsMapper.LimsQingyandanMapper; import jnpf.limsService.*; import jnpf.util.JsonUtil; import jnpf.util.RandomUtil; import jnpf.util.StringUtil; import jnpf.util.UserProvider; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; @Service public class LimsQingyandanServiceImpl extends SuperServiceImpl implements LimsQingyandanService { /** * 留样接收编号规则 enCode */ private static final String LIUYANG_JIESHOU_BIANHAO_RULE = "liuyangJieshouBianhaoGuize"; private static final String JIANYAN_LIUSHUIHAO_RULE = "jianyan_liushuihao"; @Autowired private BillRuleApi billRuleApi; @Autowired private ZhiliangBiaozhunGuanliService zhiliangBiaozhunGuanliService; @Autowired private ZhiliangBiaozhunGuanliZixiangService zhiliangBiaozhunGuanliZixiangService; @Autowired private LimsJianyanXiangService limsJianyanXiangService; @Autowired private LimsLiuyangJiluService limsLiuyangJiluService; @Autowired private LimsSxtRenwuQingyandanZhuangtaiTongbuService renwuQingyandanZhuangtaiTongbuService; @Autowired private LimsOperationalMessagePublisher operationalMessagePublisher; @Override public LimsQingyandanEntity findByFormData(LimsQingyandanEntity formData) { if (formData.getId() != null && !formData.getId().isEmpty()) { return this.getById(formData.getId()); } // JNPF 在线表单保存后不返回记录ID,通过业务字段匹配 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("chanpin_id", formData.getChanpinId()); if (formData.getPihao() != null) { wrapper.eq("pihao", formData.getPihao()); } wrapper.orderByDesc("f_id"); wrapper.last("LIMIT 1"); return this.getOne(wrapper); } @Override public LimsQingyandanEntity findByLiushuihao(String liushuihao) { QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("jianyan_liushuihao", liushuihao); return this.getOne(wrapper); } @Override @AuditLog( action = "SUBMIT", label = "请验单 提交", bizType = "QINGYANDAN", bizCodeExpr = "#qingyandan.jianyanLiushuihao", targetTable = "lims_qingyandan", targetIdExpr = "#qingyandan.id", diff = true, entityClass = LimsQingyandanEntity.class ) @Transactional(rollbackFor = Exception.class) public void submit(LimsQingyandanEntity qingyandan) { String expectedBizStatus = qingyandan.getBizStatus(); ZhiliangBiaozhunGuanliEntity standard = findReadyQualityStandardOrThrow(qingyandan); copyStandardLiangFields(qingyandan, standard); qingyandan.setBizStatus(BizStatus.CONFIRMED.getCode()); // 请验单提交后进入取样阶段:取样状态初始化为待取样 qingyandan.setQuyangStatus(BizStatus.PENDING_FETCH.getCode()); backfillCreatorTimeIfMissing(qingyandan); UpdateWrapper submitUpdate = activeRowUpdate(qingyandan.getId()); submitUpdate.eq("biz_status", expectedBizStatus); if (!this.update(qingyandan, submitUpdate)) { throw new DataException("请验单状态已变更,提交未生效"); } createJianyanXiang(qingyandan, standard); tongbuRenwuQingyandanZhuangtai(qingyandan); } @Override public void wendingxingSubmit(LimsQingyandanEntity qingyandan) { ZhiliangBiaozhunGuanliEntity standard = findReadyQualityStandardOrThrow(qingyandan); createJianyanXiang(qingyandan, standard); } @Override @Transactional(rollbackFor = Exception.class) public LimsQingyandanEntity sxtAutoSubmit(LimsQingyandanEntity qingyandan) { ZhiliangBiaozhunGuanliEntity standard = findReadyQualityStandardOrThrow(qingyandan); String plannedJianyanLiang = qingyandan.getJianyanLiang(); String plannedQuyangDanwei = qingyandan.getQuyangDanwei(); copyStandardLiangFields(qingyandan, standard); if (StringUtil.isNotEmpty(plannedJianyanLiang)) { qingyandan.setJianyanLiang(plannedJianyanLiang); } if (StringUtil.isNotEmpty(plannedQuyangDanwei)) { qingyandan.setQuyangDanwei(plannedQuyangDanwei); } qingyandan.setBizStatus(BizStatus.CONFIRMED.getCode()); // 请验单提交后进入取样阶段:取样状态初始化为待取样 qingyandan.setQuyangStatus(BizStatus.PENDING_FETCH.getCode()); qingyandan.setJianyanLiushuihao(nextJianyanBianhao()); backfillCreatorTimeIfMissing(qingyandan); this.saveOrUpdate(qingyandan); createJianyanXiang(qingyandan, standard); tongbuRenwuQingyandanZhuangtai(qingyandan); return qingyandan; } @Override @Transactional(rollbackFor = Exception.class) public LimsQingyandanEntity sxtRenwuKuaizhaoAutoSubmit( LimsQingyandanEntity qingyandan, List jianyanKuaizhaoList) { if (jianyanKuaizhaoList == null || jianyanKuaizhaoList.isEmpty()) { throw new DataException("任务检验项快照不能为空"); } if (StringUtil.isEmpty(qingyandan.getLaiyuanRenwuId())) { throw new DataException("请验单来源任务不能为空"); } if (StringUtil.isEmpty(qingyandan.getId())) { qingyandan.setId(RandomUtil.uuId()); } qingyandan.setBizStatus(BizStatus.CONFIRMED.getCode()); qingyandan.setQuyangStatus(BizStatus.PENDING_FETCH.getCode()); qingyandan.setJianyanLiushuihao(nextJianyanBianhao()); backfillCreatorTimeIfMissing(qingyandan); this.save(qingyandan); List records = new ArrayList<>(jianyanKuaizhaoList.size()); for (LimsSxtQuyangJihuaRenwuJianyanXiangKuaizhaoEntity kuaizhao : jianyanKuaizhaoList) { records.add(buildXiangFromRenwuKuaizhao(qingyandan, kuaizhao)); } limsJianyanXiangService.saveBatch(records); return qingyandan; } @Override @AuditLog( action = "UPDATE", label = "请验单 编辑", bizType = "QINGYANDAN", bizCodeExpr = "#qingyandan.jianyanLiushuihao", targetTable = "lims_qingyandan", targetIdExpr = "#qingyandan.id", diff = true, entityClass = LimsQingyandanEntity.class ) @Transactional(rollbackFor = Exception.class) public void edit(LimsQingyandanEntity qingyandan, LimsQingyandanEntity formData) { String expectedBizStatus = qingyandan.getBizStatus(); String originalId = qingyandan.getId(); // 排除后端管理的状态字段:前端 formData 不带这些字段,BeanUtils 会用 null 覆盖。 // 尤其 quyangStatus 加了 updateStrategy=ALWAYS,被覆盖成 null 会撞 NOT NULL 约束。 BeanUtils.copyProperties(formData, qingyandan, "id", "tenantId", "bizStatus", "quyangStatus", "jieyangStatus", "laiyuanRenwuId", "renwuKuaizhaoHaxi", "deleteMark", "deleteTime", "deleteUserId", "flowId", "version", "flowTaskId", "flowState", "jianyanLiushuihao", "creatorUserId", "creatorTime", "lastModifyUserId", "lastModifyTime"); qingyandan.setId(originalId); ZhiliangBiaozhunGuanliEntity standard = findReadyQualityStandardOrThrow(qingyandan); copyStandardLiangFields(qingyandan, standard); qingyandan.setBizStatus(BizStatus.CONFIRMED.getCode()); // 退回后修正重新提交:取样状态重新回到待取样(与 submit 一致) qingyandan.setQuyangStatus(BizStatus.PENDING_FETCH.getCode()); backfillCreatorTimeIfMissing(qingyandan); UpdateWrapper editUpdate = activeRowUpdate(qingyandan.getId()); editUpdate.eq("biz_status", expectedBizStatus); if (!this.update(qingyandan, editUpdate)) { throw new DataException("请验单状态已变更,重新提交未生效"); } // 编辑后重新提交:重建检验项(先软删旧的,避免重复) softDeleteJianyanXiangRecords(qingyandan.getId()); createJianyanXiang(qingyandan, standard); tongbuRenwuQingyandanZhuangtai(qingyandan); } @Override @Transactional(rollbackFor = Exception.class) @AuditLog( action = "FETCH", label = "取样", bizType = "QUYANG", bizCodeExpr = "#qingyandan.jianyanLiushuihao", targetTable = "lims_qingyandan", targetIdExpr = "#qingyandan.id", diff = true, entityClass = LimsQingyandanEntity.class ) public void fetch(LimsQingyandanEntity qingyandan, LimsQingyandanEntity formData) { String expectedQuyangStatus = qingyandan.getQuyangStatus(); // 只写取样阶段录入字段,不用 BeanUtils 全量复制,避免覆盖 submit 时从质量标准 // 复制的量/单位字段(jianyan_liang / quyang_danwei / jiance_liuyang_liang / // liuyang_liang / liuyang_danwei / shifou_shixiaoxing_yaoqiu)。 qingyandan.setJianyanLiangShiji(formData.getJianyanLiangShiji()); qingyandan.setJianceLiuyangLiangShiji(formData.getJianceLiuyangLiangShiji()); qingyandan.setLiuyangLiangShiji(formData.getLiuyangLiangShiji()); qingyandan.setQuyangren(formData.getQuyangren()); qingyandan.setQuyangRiqi(formData.getQuyangRiqi()); qingyandan.setQuyangDidian(formData.getQuyangDidian()); qingyandan.setQuyangBeizhu(formData.getQuyangBeizhu()); qingyandan.setBizSign(formData.getBizSign()); // 取样完成:取样状态 → 已取样,接样状态 → 待接样;biz_status 主状态保持不变 qingyandan.setQuyangStatus(BizStatus.FETCHED.getCode()); qingyandan.setJieyangStatus(BizStatus.PENDING_RECEIVE.getCode()); LimsLiuyangJiluEntity liuyangJilu = null; if (isPositiveNumber(qingyandan.getLiuyangLiangShiji())) { liuyangJilu = buildLiuyangJiluFromQingyandan(qingyandan); limsLiuyangJiluService.save(liuyangJilu); qingyandan.setLiuyangJiluId(liuyangJilu.getId()); } UpdateWrapper fetchUpdate = activeRowUpdate(qingyandan.getId()); fetchUpdate.eq("quyang_status", expectedQuyangStatus); if (!this.update(qingyandan, fetchUpdate)) { throw new DataException("请验单状态已变更,取样未生效"); } tongbuRenwuQingyandanZhuangtai(qingyandan); if (liuyangJilu != null) { operationalMessagePublisher.retainSamplePendingReceive( liuyangJilu, qingyandan, UserProvider.getUser()); } } private boolean isPositiveNumber(String value) { if (value == null || value.trim().isEmpty()) { return false; } try { return new BigDecimal(value.trim()).compareTo(BigDecimal.ZERO) > 0; } catch (NumberFormatException e) { return false; } } private LimsLiuyangJiluEntity buildLiuyangJiluFromQingyandan(LimsQingyandanEntity qingyandan) { LimsLiuyangJiluEntity record = new LimsLiuyangJiluEntity(); record.setId(RandomUtil.uuId()); record.setJieshouBianhao(nextLiuyangJieshouBianhao()); record.setYangpinMingcheng(qingyandan.getChanpinMingcheng()); record.setYangpinBianma(qingyandan.getChanpinBianma()); record.setQingyandanId(qingyandan.getId()); record.setBizType(qingyandan.getBizType()); record.setGuige(qingyandan.getGuige()); record.setBaozhuangGuige(qingyandan.getBaozhuangGuige()); record.setPihao(qingyandan.getPihao()); record.setLaiyuanBianma(qingyandan.getLaiyuanBianma()); record.setShengchanRiqi(qingyandan.getShengchanRiqi()); record.setYouxiaoqi(qingyandan.getYouxiaoqi()); record.setChucunTiaojian(qingyandan.getChucunTiaojian()); record.setSongjianRen(qingyandan.getQingyanRen()); record.setSongjianRiqi(qingyandan.getQingyanRiqi()); record.setBizSign(qingyandan.getBizSign()); record.setBizStatus(LiuyangStatus.PENDING_RECEIVE.getCode()); record.setLiuyangLiangShiji(qingyandan.getLiuyangLiangShiji()); record.setLiuyangDanwei(qingyandan.getLiuyangDanwei()); return record; } /** * 留样接收编号取号失败时立即中断,避免生成空编号的留样记录。 */ private String nextLiuyangJieshouBianhao() throws DataException { ActionResult result = billRuleApi.getBillNumber(LIUYANG_JIESHOU_BIANHAO_RULE); String bianhao = result == null ? null : result.getData(); if (StringUtil.isEmpty(bianhao)) { throw new DataException("留样接收编号取号失败:单据规则[" + LIUYANG_JIESHOU_BIANHAO_RULE + "]不可用,请确认规则已配置且系统服务在线"); } return bianhao; } /** * 生成新的检验流水号 */ private String nextJianyanBianhao() throws DataException { ActionResult result = billRuleApi.getBillNumber(JIANYAN_LIUSHUIHAO_RULE); String bianhao = result == null ? null : result.getData(); if (StringUtil.isEmpty(bianhao)) { throw new DataException("检验流水号取号失败:单据规则[" + JIANYAN_LIUSHUIHAO_RULE + "]不可用,请确认规则已配置且系统服务在线"); } return bianhao; } @Override @Transactional(rollbackFor = Exception.class) @AuditLog( action = "RECEIVE", label = "接样", bizType = "JIEYANG", bizCodeExpr = "#qingyandan.jianyanLiushuihao", targetTable = "lims_qingyandan", targetIdExpr = "#qingyandan.id", diff = true, entityClass = LimsQingyandanEntity.class ) public void jieyangReceive(LimsQingyandanEntity qingyandan, LimsQingyandanEntity formData) { String expectedJieyangStatus = qingyandan.getJieyangStatus(); // 只写接样阶段录入字段;检验项 submit 时已创建(created + wei_fenjian), // 本步不创建、不推进检验项状态(由后续单独的"分检"动作处理)。 qingyandan.setJieshouren(formData.getJieshouren()); qingyandan.setJieshouRiqi(formData.getJieshouRiqi()); qingyandan.setJieshouShuliang(formData.getJieshouShuliang()); qingyandan.setJieshouShuliangDanwei(formData.getJieshouShuliangDanwei()); qingyandan.setCunfangWeizhi(formData.getCunfangWeizhi()); qingyandan.setShixiaoxingJianceyuan(formData.getShixiaoxingJianceyuan()); qingyandan.setJieyangBeizhu(formData.getJieyangBeizhu()); qingyandan.setBizSign(formData.getBizSign()); // 接样完成 qingyandan.setJieyangStatus(BizStatus.RECEIVED.getCode()); UpdateWrapper receiveUpdate = activeRowUpdate(qingyandan.getId()); receiveUpdate.eq("jieyang_status", expectedJieyangStatus); if (!this.update(qingyandan, receiveUpdate)) { throw new DataException("请验单状态已变更,接样未生效"); } tongbuRenwuQingyandanZhuangtai(qingyandan); } private UpdateWrapper activeRowUpdate(String id) { UpdateWrapper update = new UpdateWrapper<>(); update.eq("f_id", id); update.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1)); return update; } /** * 请验单创建 / 编辑提交时,从质量标准主表复制量与单位配置到请验单本行: * 取样单位、检验量(← jiance_liang)、检测留样量、留样量、留样单位(← liuyang_kaocha_danwei)。 * 对应的 _shiji 实际值字段留空,由后续取样 / 接样阶段录入。 */ private void copyStandardLiangFields(LimsQingyandanEntity qingyandan, ZhiliangBiaozhunGuanliEntity standard) { qingyandan.setQuyangDanwei(standard.getQuyangDanwei()); qingyandan.setJianyanLiang(standard.getJianceLiang()); qingyandan.setJianceLiuyangLiang(standard.getJianceLiuyangLiang()); qingyandan.setLiuyangLiang(standard.getLiuyangLiang()); qingyandan.setLiuyangDanwei(standard.getLiuyangKaochaDanwei()); qingyandan.setShifouShixiaoxingYaoqiu(standard.getShifouShixiaoxingYaoqiu()); } /** * lims_qingyandan 由 JNPF 在线表单 INSERT,绕开 MyBatis-Plus, * MetaObjectHandler 的 insertFill 不触发,导致 f_creator_time 永远为 null。 * 在我们业务代码首次接管这条记录时(submit / edit),如果还没值就补填当前时间。 */ private void backfillCreatorTimeIfMissing(LimsQingyandanEntity qingyandan) { if (qingyandan.getCreatorTime() == null) { qingyandan.setCreatorTime(new Date()); } } @Override @Transactional(rollbackFor = Exception.class) @AuditLog( action = "CANCEL", label = "请验单 撤回", bizType = "QINGYANDAN", bizCodeExpr = "#result ? #qingyandan.jianyanLiushuihao : null", targetTable = "lims_qingyandan", targetIdExpr = "#qingyandan.id", diff = true, entityClass = LimsQingyandanEntity.class ) public boolean cancel(LimsQingyandanEntity qingyandan) { UpdateWrapper update = activeRowUpdate(qingyandan.getId()); update.eq("biz_status", BizStatus.CONFIRMED.getCode()); update.set("biz_status", BizStatus.CANCELLED.getCode()); if (!this.update(update)) { return false; } softDeleteJianyanXiangRecords(qingyandan.getId()); qingyandan.setBizStatus(BizStatus.CANCELLED.getCode()); tongbuRenwuQingyandanZhuangtai(qingyandan); return true; } @Override @Transactional(rollbackFor = Exception.class) @AuditLog( action = "RETURN", label = "取样 退回", bizType = "QINGYANDAN", bizCodeExpr = "#qingyandan.jianyanLiushuihao", extraExpr = "{'reason': #tuihuiyuanyin}", targetTable = "lims_qingyandan", targetIdExpr = "#qingyandan.id", diff = true, entityClass = LimsQingyandanEntity.class ) public boolean reject(LimsQingyandanEntity qingyandan, String tuihuiyuanyin, String bizSign) { UserInfo userInfo = UserProvider.getUser(); Date now = new Date(); UpdateWrapper update = new UpdateWrapper<>(); update.eq("f_id", qingyandan.getId()); update.in("biz_status", BizStatus.PENDING_FETCH.getCode(), BizStatus.CONFIRMED.getCode()); update.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1)); update.set("biz_status", BizStatus.REJECTED.getCode()); update.set("quyang_status", ""); update.set("quyang_tuihui_ren", userInfo.getUserId()); update.set("quyang_tuihui_yuanyin", tuihuiyuanyin); update.set("quyang_tuihui_riqi", now); if (!this.update(update)) { return false; } softDeleteJianyanXiangRecords(qingyandan.getId()); qingyandan.setBizStatus(BizStatus.REJECTED.getCode()); qingyandan.setQuyangStatus(""); qingyandan.setQuyangTuihuiRen(userInfo.getUserId()); qingyandan.setQuyangTuihuiYuanyin(tuihuiyuanyin); qingyandan.setQuyangTuihuiRiqi(now); tongbuRenwuQingyandanZhuangtai(qingyandan); return true; } @Override @Transactional(rollbackFor = Exception.class) @AuditLog( action = "RETURN", label = "接样 退回", bizType = "JIEYANG", bizCodeExpr = "#qingyandan.jianyanLiushuihao", extraExpr = "{'reason': #tuihuiyuanyin}", targetTable = "lims_qingyandan", targetIdExpr = "#qingyandan.id", diff = true, entityClass = LimsQingyandanEntity.class ) public boolean jieyangReject(LimsQingyandanEntity qingyandan, String tuihuiyuanyin, String bizSign) { UserInfo userInfo = UserProvider.getUser(); Date now = new Date(); UpdateWrapper update = new UpdateWrapper<>(); update.eq("f_id", qingyandan.getId()); update.eq("jieyang_status", BizStatus.PENDING_RECEIVE.getCode()); update.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1)); update.set("quyang_status", BizStatus.PENDING_FETCH.getCode()); update.set("jieyang_status", ""); update.set("jieyang_tuihui_yuanyin", tuihuiyuanyin); update.set("jieyang_tuihui_ren", userInfo.getUserId()); update.set("jieyang_tuihui_riqi", now); if (!this.update(update)) { return false; } // 接样退回 → 退回取样阶段重新取样:取样状态回到待取样、接样状态清空, // biz_status 主状态不变;检验项仍在流程中,不软删。 qingyandan.setQuyangStatus(BizStatus.PENDING_FETCH.getCode()); qingyandan.setJieyangStatus(""); qingyandan.setJieyangTuihuiYuanyin(tuihuiyuanyin); qingyandan.setJieyangTuihuiRen(userInfo.getUserId()); qingyandan.setJieyangTuihuiRiqi(now); tongbuRenwuQingyandanZhuangtai(qingyandan); return true; } @Override @Transactional(rollbackFor = Exception.class) @AuditLog( action = "DELETE", label = "请验单 废弃", bizType = "QINGYANDAN", bizCodeExpr = "#qingyandan.jianyanLiushuihao", targetTable = "lims_qingyandan", targetIdExpr = "#qingyandan.id", diff = true, entityClass = LimsQingyandanEntity.class ) public void delete(LimsQingyandanEntity qingyandan) { softDeleteJianyanXiangRecords(qingyandan.getId()); qingyandan.setBizStatus(BizStatus.DELETED.getCode()); this.updateById(qingyandan); tongbuRenwuQingyandanZhuangtai(qingyandan); } private void tongbuRenwuQingyandanZhuangtai(LimsQingyandanEntity qingyandan) { renwuQingyandanZhuangtaiTongbuService.tongbu(qingyandan, "qingyandan_zhuangtai_tongbu"); } /** * 批量软删除该请验单下所有未软删的检验项(lims_jianyan_xiang)。 * 撤回 / 退回 / 废弃时调用,撤掉本次提交生成的检验任务项。 */ private void softDeleteJianyanXiangRecords(String qingyandanId) { UserInfo userInfo = UserProvider.getUser(); QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("qingyandan_id", qingyandanId); wrapper.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1)); List list = limsJianyanXiangService.list(wrapper); for (LimsJianyanXiangEntity item : list) { item.setDeleteMark(1); item.setDeleteTime(new Date()); item.setDeleteUserId(userInfo.getUserId()); limsJianyanXiangService.updateById(item); } } /** * 提交请验单时,按质量标准子表(zhiliang_biaozhun_guanli_zixiang)逐条直写 lims_jianyan_xiang。 * 替代旧的"写 lims_qingyandan_jiancexiang 中间表"链路:检验项初始 jianyan_zhuangtai = created、 * fenjian_zhuangtai = wei_fenjian,等后续"分检"动作推进到 pending_assign 进入分配/录入/审核流程。 * *

只生成请验单 jiance_xiangmu 选中的子项:该字段存前端勾选的 zixiang.f_id 数组 * (全检会传全部 id,部分检传子集)。jiance_xiangmu 为空时兜底取全部子项,避免异常情况漏生成。 */ private void createJianyanXiang(LimsQingyandanEntity qingyandan, ZhiliangBiaozhunGuanliEntity standard) { List zixiangList = zhiliangBiaozhunGuanliZixiangService.listByForeignId(standard.getId()); if (zixiangList == null || zixiangList.isEmpty()) { return; } // 仅保留前端选中的检验子项(jiance_xiangmu 存选中的 zixiang.f_id) Set selectedIds = parseSelectedXiangmuIds(qingyandan.getJianceXiangmu()); if (!selectedIds.isEmpty()) { zixiangList = zixiangList.stream() .filter(z -> selectedIds.contains(z.getId())) .collect(Collectors.toList()); } if (zixiangList.isEmpty()) { return; } List records = new ArrayList<>(zixiangList.size()); for (ZhiliangBiaozhunGuanliZixiangEntity zixiang : zixiangList) { records.add(buildXiangFromQingyandan(qingyandan, zixiang, standard)); } limsJianyanXiangService.saveBatch(records); } /** * 解析请验单 jiance_xiangmu(前端勾选的检验子项 zixiang.f_id,JSON 数组字符串如 ["id1","id2"]) * 为 id 集合。空 / null / 解析失败返回空集,调用方据此兜底取全部子项。 */ private Set parseSelectedXiangmuIds(String jianceXiangmu) { if (jianceXiangmu == null || jianceXiangmu.trim().isEmpty()) { return Collections.emptySet(); } try { List ids = JsonUtil.getJsonToList(jianceXiangmu, String.class); if (ids == null) { return Collections.emptySet(); } return ids.stream() .filter(s -> s != null && !s.isEmpty()) .collect(Collectors.toCollection(LinkedHashSet::new)); } catch (Exception e) { // 容错:格式异常时返回空集,兜底走全部子项,避免漏生成 return Collections.emptySet(); } } /** * 从请验单 + 质量标准子项构造一行 lims_jianyan_xiang。 * 头信息(产品 / 批号 / 规格 / 流水号 / 储存条件)从请验单取,检验项配置从子项取。 */ private LimsJianyanXiangEntity buildXiangFromQingyandan(LimsQingyandanEntity qingyandan, ZhiliangBiaozhunGuanliZixiangEntity zixiang, ZhiliangBiaozhunGuanliEntity standard) { LimsJianyanXiangEntity record = new LimsJianyanXiangEntity(); record.setTenantId(qingyandan.getTenantId()); record.setForeignId(zixiang.getId()); record.setQingyandanId(qingyandan.getId()); record.setBizType(qingyandan.getBizType()); record.setJianyanLiushuihao(qingyandan.getJianyanLiushuihao()); record.setChanpinId(qingyandan.getChanpinId()); record.setChanpinBianma(qingyandan.getChanpinBianma()); record.setChanpinMingcheng(qingyandan.getChanpinMingcheng()); record.setPihao(qingyandan.getPihao()); record.setGuige(qingyandan.getGuige()); record.setJianyanXiangmuBianma(zixiang.getJianyanXiangmuBianma()); record.setJianyanXiangmuMingcheng(zixiang.getJianyanXiangmuMingcheng()); record.setFenxiLeixing(zixiang.getFenxiLeixing()); record.setShifouWaijian(zixiang.getShifouWaijian()); record.setShifouChujuBaogao(zixiang.getShifouChujuBaogao()); record.setBiaozhunGuiding(zixiang.getBiaozhunGuiding()); record.setBiaozhunShangxian(zixiang.getBiaozhunShangxian()); record.setBiaozhunXiaxian(zixiang.getBiaozhunXiaxian()); record.setShujuLeixing(zixiang.getShujuLeixing()); record.setJianchaBanzu(zixiang.getJianchaBanzu()); record.setJianyanZhuangtai(JianyanStatus.CREATED.getCode()); record.setFenjianZhuangtai(FenjianZhuangtai.WEI_FENJIAN.getCode()); record.setFenjianLiang(zixiang.getFenjianLiang()); record.setFenjianDanwei(zixiang.getFenjianDanwei()); record.setFenjianFenzhuangRongqi(zixiang.getFenjianFenzhuangRongqi()); record.setFenjianBaocunTiaojian(zixiang.getFenjianBaocunTiaojian()); record.setFenjianHuanjing(zixiang.getFenjianHuanjing()); // 是否组合分拣:样品级配置,从质量标准主表复制 record.setShifouZuheFenjian(standard.getShifouZuheFenjian()); return record; } private LimsJianyanXiangEntity buildXiangFromRenwuKuaizhao( LimsQingyandanEntity qingyandan, LimsSxtQuyangJihuaRenwuJianyanXiangKuaizhaoEntity kuaizhao) { LimsJianyanXiangEntity record = new LimsJianyanXiangEntity(); record.setId(RandomUtil.uuId()); record.setTenantId(qingyandan.getTenantId()); record.setForeignId(kuaizhao.getLaiyuanZhiliangBiaozhunZixiangId()); record.setQingyandanId(qingyandan.getId()); record.setLaiyuanRenwuId(qingyandan.getLaiyuanRenwuId()); record.setRenwuJianyanXiangKuaizhaoId(kuaizhao.getId()); record.setBizType(qingyandan.getBizType()); record.setJianyanLiushuihao(qingyandan.getJianyanLiushuihao()); record.setChanpinId(qingyandan.getChanpinId()); record.setChanpinBianma(qingyandan.getChanpinBianma()); record.setChanpinMingcheng(qingyandan.getChanpinMingcheng()); record.setPihao(qingyandan.getPihao()); record.setGuige(qingyandan.getGuige()); record.setJianyanXiangmuBianma(kuaizhao.getJianyanXiangmuBianma()); record.setJianyanXiangmuMingcheng(kuaizhao.getJianyanXiangmuMingcheng()); record.setFenxiLeixing(kuaizhao.getFenxiLeixing()); record.setBiaozhunGuiding(kuaizhao.getBiaozhunGuiding()); record.setBiaozhunShangxian(kuaizhao.getBiaozhunShangxian()); record.setBiaozhunXiaxian(kuaizhao.getBiaozhunXiaxian()); record.setShujuLeixing(kuaizhao.getShujuLeixing()); record.setJianchaBanzu(kuaizhao.getJianchaBanzu()); record.setJianyanZhuangtai(JianyanStatus.CREATED.getCode()); record.setFenjianZhuangtai(FenjianZhuangtai.WEI_FENJIAN.getCode()); return record; } /** * jiance_fangshi 字典里"免检"对应的 enCode */ private static final String JIANCE_FANGSHI_MIANJIAN = "mianjian"; /** * 校验请验单选中的质量标准是否齐备: * - qingyandan.jianyan_biaozhun 直接存 zhiliang_biaozhun_guanli.f_id * - 主表必须存在 / 未软删 / biz_enabled=enabled * - 且其 yangpin_id 必须与 qingyandan.chanpin_id 一致 * - 非免检场景再校验子项至少 1 条 * 任一条件不满足则抛 DataException。 */ private ZhiliangBiaozhunGuanliEntity findReadyQualityStandardOrThrow(LimsQingyandanEntity qingyandan) { String chanpinId = qingyandan.getChanpinId(); String chanpinMingcheng = qingyandan.getChanpinMingcheng(); String label = (chanpinMingcheng != null && !chanpinMingcheng.isEmpty()) ? chanpinMingcheng : chanpinId; if (chanpinId == null || chanpinId.isEmpty()) { throw new DataException("请验单未关联样品ID,无法校验质量标准"); } // 请验单上选中的质量标准主键 String biaozhunId = qingyandan.getJianyanBiaozhun(); if (biaozhunId == null || biaozhunId.isEmpty()) { throw new DataException("请验单未指定检验标准,无法定位质量标准"); } ZhiliangBiaozhunGuanliEntity standard = zhiliangBiaozhunGuanliService.getById(biaozhunId); if (standard == null || (standard.getDeleteMark() != null && standard.getDeleteMark() == 1)) { throw new DataException("样品【" + label + "】的质量标准不存在或已被删除,请先在【质量标准管理】中维护后再提交"); } if (!BizEnabledEnum.ENABLED.getCode().equals(standard.getBizEnabled())) { throw new DataException("样品【" + label + "】所选的质量标准已停用,请重新选择有效的质量标准"); } if (!chanpinId.equals(standard.getYangpinId())) { throw new DataException("样品【" + label + "】与所选质量标准不匹配,请重新选择"); } // 免检时跳过"检验项目至少 1 条"的校验;其他检测方式仍要求至少配置 1 项 if (!JIANCE_FANGSHI_MIANJIAN.equals(qingyandan.getJianceFangshi())) { long itemCount = zhiliangBiaozhunGuanliZixiangService.countByForeignId(standard.getId()); if (itemCount <= 0) { throw new DataException("样品【" + label + "】的质量标准未配置检验项目,请先补充检验项目后再提交"); } } return standard; } }