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<LimsQingyandanMapper, LimsQingyandanEntity>
|
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<LimsQingyandanEntity> 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<LimsQingyandanEntity> 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<LimsQingyandanEntity> 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<LimsSxtQuyangJihuaRenwuJianyanXiangKuaizhaoEntity> 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<LimsJianyanXiangEntity> 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<LimsQingyandanEntity> 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<LimsQingyandanEntity> 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<String> 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<String> 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<LimsQingyandanEntity> receiveUpdate = activeRowUpdate(qingyandan.getId());
|
receiveUpdate.eq("jieyang_status", expectedJieyangStatus);
|
if (!this.update(qingyandan, receiveUpdate)) {
|
throw new DataException("请验单状态已变更,接样未生效");
|
}
|
tongbuRenwuQingyandanZhuangtai(qingyandan);
|
}
|
|
private UpdateWrapper<LimsQingyandanEntity> activeRowUpdate(String id) {
|
UpdateWrapper<LimsQingyandanEntity> 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<LimsQingyandanEntity> 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<LimsQingyandanEntity> 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<LimsQingyandanEntity> 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<LimsJianyanXiangEntity> wrapper = new QueryWrapper<>();
|
wrapper.eq("qingyandan_id", qingyandanId);
|
wrapper.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1));
|
List<LimsJianyanXiangEntity> 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 进入分配/录入/审核流程。
|
*
|
* <p>只生成请验单 jiance_xiangmu 选中的子项:该字段存前端勾选的 zixiang.f_id 数组
|
* (全检会传全部 id,部分检传子集)。jiance_xiangmu 为空时兜底取全部子项,避免异常情况漏生成。
|
*/
|
private void createJianyanXiang(LimsQingyandanEntity qingyandan, ZhiliangBiaozhunGuanliEntity standard) {
|
List<ZhiliangBiaozhunGuanliZixiangEntity> zixiangList =
|
zhiliangBiaozhunGuanliZixiangService.listByForeignId(standard.getId());
|
if (zixiangList == null || zixiangList.isEmpty()) {
|
return;
|
}
|
|
// 仅保留前端选中的检验子项(jiance_xiangmu 存选中的 zixiang.f_id)
|
Set<String> selectedIds = parseSelectedXiangmuIds(qingyandan.getJianceXiangmu());
|
if (!selectedIds.isEmpty()) {
|
zixiangList = zixiangList.stream()
|
.filter(z -> selectedIds.contains(z.getId()))
|
.collect(Collectors.toList());
|
}
|
if (zixiangList.isEmpty()) {
|
return;
|
}
|
|
List<LimsJianyanXiangEntity> 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<String> parseSelectedXiangmuIds(String jianceXiangmu) {
|
if (jianceXiangmu == null || jianceXiangmu.trim().isEmpty()) {
|
return Collections.emptySet();
|
}
|
try {
|
List<String> 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;
|
}
|
}
|