package jnpf.limsController; import jnpf.audit.sdk.annotation.AuditLog; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jnpf.limsEntity.LimsLiuyangBiangengShenqingEntity; import jnpf.limsEntity.LimsLiuyangJihuaBiangengShenqingEntity; import jnpf.limsEntity.LimsLiuyangJihuaBiangengShenqingZixiangEntity; import jnpf.limsEntity.LimsLiuyangJihuaCalculateParam; import jnpf.limsEntity.LimsLiuyangJihuaCalculateResult; import jnpf.limsEntity.LimsLiuyangJihuaBiangengCalculateParam; import jnpf.limsEntity.LimsLiuyangJihuaEntity; import jnpf.limsEntity.LimsLiuyangJihuaZixiangEntity; import jnpf.limsEntity.LimsLiuyangJiluEntity; import jnpf.limsEntity.LiuyangStatus; import jnpf.limsEntity.LiuyangWendingxingZhouqiZixiangEntity; import jnpf.limsEntity.LimsQingyandanEntity; import jnpf.limsService.LiuyangWendingxingZhouqiZixiangService; import jnpf.limsService.LimsLiuyangJihuaService; import jnpf.limsService.LimsLiuyangJihuaZixiangService; import jnpf.limsService.LimsLiuyangBiangengShenqingService; import jnpf.limsService.LimsLiuyangJihuaBiangengShenqingService; import jnpf.limsService.LimsLiuyangJihuaBiangengShenqingZixiangService; import jnpf.limsService.LimsLiuyangJiluService; import jnpf.limsService.LimsQingyandanService; import jnpf.util.R; import jnpf.util.RandomUtil; import jnpf.util.UserProvider; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.sql.DataSource; import java.math.BigDecimal; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @Slf4j @Tag(name = "lims留样接口", description = "留样记录流程操作") @RestController @RequestMapping("/lims/biz") public class LimsLiuyangController { private static final String BIANGENG_ZIXIANG_TABLE = "lims_liuyang_jihua_biangeng_shenqing_zixiang"; private static final String LIUYANG_CHUKU_SHENQING_TABLE = "lims_liuyang_chuku_shenqing"; private static final String LIUYANG_CHUKU_SHENQING_ZIXIANG_TABLE = "lims_liuyang_chuku_shenqing_zixiang"; private static final String LIUYANG_CHUKU_TABLE = "lims_liuyang_chuku"; private static final String LIUYANG_XIAOHUI_SHENQING_TABLE = "lims_liuyang_xiaohui_shenqing"; private static final String LIUYANG_XIAOHUI_SHENQING_ZIXIANG_TABLE = "lims_liuyang_xiaohui_shenqing_zixiang"; private static final String BIZ_STATUS_DESTROYED = "destroyed"; private static final String BIZ_STATUS_DISABLED = "disabled"; private static final List DEFAULT_BIANGENG_ZIXIANG_FIELDS = Arrays.asList( "zhouqi", "zhouqi_danwei", "jihua_riqi", "shifou_yiguancha", "guancha_riqi", "guancha_ren", "guancha_shuliang", "guancha_qingkuang", "guancha_jieguo", "beizhu" ); @Autowired private LimsLiuyangJiluService limsLiuyangJiluService; @Autowired private LimsQingyandanService limsQingyandanService; @Autowired private LiuyangWendingxingZhouqiZixiangService liuyangWendingxingZhouqiZixiangService; @Autowired private LimsLiuyangJihuaService limsLiuyangJihuaService; @Autowired private LimsLiuyangJihuaZixiangService limsLiuyangJihuaZixiangService; @Autowired private LimsLiuyangBiangengShenqingService limsLiuyangBiangengShenqingService; @Autowired private LimsLiuyangJihuaBiangengShenqingService limsLiuyangJihuaBiangengShenqingService; @Autowired private LimsLiuyangJihuaBiangengShenqingZixiangService limsLiuyangJihuaBiangengShenqingZixiangService; @Autowired private DataSource dataSource; @Autowired private JdbcTemplate jdbcTemplate; /** * 留样操作: * submit -> 待审核,并把请验单 liuyang_jilu_id 关联到当前留样记录; * reject -> 已退回,并清空请验单 liuyang_jilu_id; * accept -> 已接收,并同步入库数量/单位为留样现存量; * delete -> 按 JNPF 表单规范软删除留样记录。 */ @Transactional(rollbackFor = Exception.class) @Operation(summary = "留样操作(提交/拒绝/同意)") @PostMapping("/liuyang/action") @AuditLog(action = "LIUYANG_ACTION", label = "留样操作", bizType = "LIUYANG", bizCodeExpr = "#result.success ? (#params['id'] ?: 'LIUYANG_ACTION') : ''", targetTable = "lims_liuyang_jilu", targetIdExpr = "#params['id']", extraExpr = "{'action': #params['action']}", diff = true, entityClass = LimsLiuyangJiluEntity.class) public R liuyangAction(@RequestBody Map params) { String action = params.get("action"); String id = params.get("id"); String flowId = firstNotBlank(params.get("flow_id"), params.get("flowId")); String taskId = firstNotBlank(params.get("task_id"), params.get("taskId")); String bizSign = params.get("biz_sign"); if (action == null || action.isEmpty()) { return R.error("缺少 action"); } if ((id == null || id.isEmpty()) && (flowId == null || flowId.isEmpty())) { return R.error("缺少 flow_id"); } LimsLiuyangJiluEntity liuyangJilu = findLiuyangJilu(id, flowId, taskId); if (liuyangJilu == null) { return R.error("留样记录数据不存在"); } switch (action) { case "submit": updateLiuyangStatus(liuyangJilu, LiuyangStatus.PENDING_AUDIT, bizSign); updateQingyandanLiuyangJiluId(liuyangJilu, liuyangJilu.getId()); return R.success("提交成功"); case "reject": updateLiuyangStatus(liuyangJilu, LiuyangStatus.REJECTED, bizSign); updateQingyandanLiuyangJiluId(liuyangJilu, null); return R.success("拒绝成功"); case "accept": receiveLiuyangJilu(liuyangJilu, bizSign); return R.success("同意成功"); case "delete": softDeleteLiuyangJilu(liuyangJilu, bizSign); updateQingyandanLiuyangJiluId(liuyangJilu, null); return R.success("删除成功"); default: return R.error("不支持的操作: " + action); } } /** * 留样销毁流程操作: * submit -> 销毁单号回写到留样记录; * reject -> 清空留样记录销毁单号; * accept -> shifou_pizhun=yes 时置为已销毁并禁用关联观察计划及子项,shifou_pizhun=no 时清空销毁单号。 */ @Transactional(rollbackFor = Exception.class) @Operation(summary = "留样销毁操作(提交/拒绝/同意)") @PostMapping("/liuyang/xiaohui/action") @AuditLog(action = "DESTROY_ACTION", label = "留样销毁操作", bizType = "LIUYANG", bizCodeExpr = "#result.success ? (#params['id'] ?: 'LIUYANG_DESTROY') : ''", targetTable = "lims_liuyang_jilu", targetIdExpr = "#params['id']", extraExpr = "{'action': #params['action']}", diff = true, entityClass = LimsLiuyangJiluEntity.class) public R liuyangXiaohuiAction(@RequestBody Map params) { if (params == null) { return R.error("请求参数不能为空"); } String flowId = firstNotBlank(params.get("flow_id"), params.get("flowId")); String taskId = firstNotBlank(params.get("task_id"), params.get("taskId")); String action = params.get("action"); String shifouPizhun = firstNotBlank(params.get("shifou_pizhun"), params.get("shifouPizhun")); if (isBlank(flowId)) { return R.error("流程id(flow_id)不能为空"); } if (isBlank(taskId)) { return R.error("流程任务id(task_id)不能为空"); } if (isBlank(action)) { return R.error("缺少 action"); } Map shenqing = findLiuyangXiaohuiShenqing(flowId, taskId); if (shenqing == null || shenqing.isEmpty()) { return R.error("留样销毁申请数据不存在"); } String shenqingId = getString(shenqing, "f_id"); String xiaohuiDanhao = getString(shenqing, "xiaohui_danhao"); List liuyangJiluIds = listLiuyangXiaohuiJiluIds(shenqingId); if (liuyangJiluIds.isEmpty()) { return R.error("留样销毁申请子项不能为空"); } switch (action) { case "submit": if (isBlank(xiaohuiDanhao)) { return R.error("销毁单号不能为空"); } updateLiuyangXiaohuiDanhao(liuyangJiluIds, xiaohuiDanhao); return R.success("提交成功"); case "reject": updateLiuyangXiaohuiDanhao(liuyangJiluIds, null); return R.success("拒绝成功"); case "accept": if ("yes".equals(shifouPizhun)) { acceptLiuyangXiaohui(liuyangJiluIds); return R.success("同意成功"); } if ("no".equals(shifouPizhun)) { updateLiuyangXiaohuiDanhao(liuyangJiluIds, null); return R.success("拒绝成功"); } return R.error("是否批准(shifou_pizhun)不能为空,且必须为 yes 或 no"); default: return R.error("不支持的操作: " + action); } } /** * 计算留样计划子项周期列表。 */ @Operation(summary = "计算留样计划周期") @PostMapping("/liuyang/jihua/calculate") public R> calculateLiuyangJihua(@RequestBody LimsLiuyangJihuaCalculateParam param) { if (param == null || isBlank(param.getLiuyangJiluId())) { return R.error("留样记录主键不能为空"); } if (isBlank(param.getLiuyangZhouqiId())) { return R.error("留样周期主键不能为空"); } LimsLiuyangJiluEntity liuyangJilu = limsLiuyangJiluService.getById(param.getLiuyangJiluId()); if (liuyangJilu == null || Integer.valueOf(1).equals(liuyangJilu.getDeleteMark())) { return R.error("留样记录数据不存在"); } if (liuyangJilu.getShouyangRiqi() == null) { return R.error("留样记录收样日期不能为空"); } List zhouqiList = listWendingxingZhouqiZixiang(param.getLiuyangZhouqiId()); if (zhouqiList.isEmpty()) { return R.error("稳定性周期子项不能为空"); } try { List jihuaList = zhouqiList.stream() .map(row -> buildJihuaZixiang(row, liuyangJilu.getShouyangRiqi())) .collect(Collectors.toList()); return R.success("计算成功", jihuaList); } catch (IllegalArgumentException e) { return R.error(e.getMessage()); } } /** * 计划变更时,按新的留样日期重新计算未观察计划,并保留已观察的原计划。 */ @Operation(summary = "计算留样计划变更子项") @PostMapping("/liuyang/jihua/biangeng/calculate") public R>> calculateLiuyangJihuaBiangeng(@RequestBody LimsLiuyangJihuaBiangengCalculateParam param) { if (param == null || isBlank(param.getLiuyangJihuaId())) { return R.error("留样观察计划主键不能为空"); } if (isBlank(param.getLiuyangZhouqiId())) { return R.error("留样周期主键不能为空"); } if (param.getLiuyangRiqi() == null) { return R.error("留样日期不能为空"); } List zhouqiList = listWendingxingZhouqiZixiang(param.getLiuyangZhouqiId()); if (zhouqiList.isEmpty()) { return R.error("稳定性周期子项不能为空"); } try { List responseFields = getBiangengZixiangBusinessFields(); List> result = new ArrayList<>(); List observedList = listObservedJihuaZixiang(param.getLiuyangJihuaId()); Set observedZhouqiKeys = observedList.stream() .map(row -> buildZhouqiKey(row.getZhouqi(), row.getZhouqiDanwei())) .collect(Collectors.toSet()); observedList.stream() .map(row -> buildBiangengRow(row, responseFields)) .forEach(result::add); zhouqiList.stream() .filter(row -> !observedZhouqiKeys.contains(buildZhouqiKey(row.getZhouqi(), row.getZhouqiDanwei()))) .map(row -> buildBiangengRow(row, param.getLiuyangRiqi(), responseFields)) .forEach(result::add); return R.success("计算成功", result); } catch (IllegalArgumentException e) { return R.error(e.getMessage()); } } /** * 提交留样观察计划:启用计划,并关联回留样记录。 */ @Transactional(rollbackFor = Exception.class) @Operation(summary = "提交留样观察计划") @PostMapping("/liuyang/jihua/submit") @AuditLog(action = "PLAN_SUBMIT", label = "提交留样观察计划", bizType = "LIUYANG", bizCodeExpr = "#result.success ? 'LIUYANG_PLAN' : ''", targetTable = "lims_liuyang_jihua", targetIdExpr = "#formData['id'] ?: #formData['f_id']", diff = true, entityClass = LimsLiuyangJihuaEntity.class) public R submitLiuyangJihua(@RequestBody Map formData) { String jihuaId = getFormId(formData); if (isBlank(jihuaId)) { return R.error("留样观察计划主键不能为空"); } LimsLiuyangJihuaEntity jihua = limsLiuyangJihuaService.getById(jihuaId); if (jihua == null || Integer.valueOf(1).equals(jihua.getDeleteMark())) { return R.error("留样观察计划数据不存在"); } if (isBlank(jihua.getLiuyangJiluId())) { return R.error("留样观察计划未关联留样记录"); } LimsLiuyangJihuaEntity jihuaUpdate = new LimsLiuyangJihuaEntity(); jihuaUpdate.setId(jihua.getId()); jihuaUpdate.setBizStatus("enabled"); limsLiuyangJihuaService.updateById(jihuaUpdate); jihua.setBizStatus("enabled"); syncJihuaInfoToZixiang(jihua); LimsLiuyangJiluEntity jiluUpdate = new LimsLiuyangJiluEntity(); jiluUpdate.setId(jihua.getLiuyangJiluId()); jiluUpdate.setLiuyangJihuaId(jihua.getId()); limsLiuyangJiluService.updateById(jiluUpdate); return R.success("提交成功"); } /** * 留样观察计划变更:将变更申请同步到实际留样观察计划。 */ @Transactional(rollbackFor = Exception.class) @Operation(summary = "留样观察计划变更") @PostMapping("/liuyang/jihua/biangeng/action") @AuditLog(action = "PLAN_CHANGE", label = "留样观察计划变更", bizType = "LIUYANG", bizCodeExpr = "#result.success ? (#params['id'] ?: 'LIUYANG_PLAN_CHANGE') : ''", targetTable = "lims_liuyang_jihua", targetIdExpr = "T(jnpf.limsService.support.LimsAuditTargetIds).liuyangJihuaByChangeFlow(" + "#params['flow_id'] ?: #params['flowId'], #params['task_id'] ?: #params['taskId'])", extraExpr = "{'action': #params['action']}", diff = true, entityClass = LimsLiuyangJihuaEntity.class) public R liuyangJihuaBiangengAction(@RequestBody Map params) { if (params == null) { return R.error("请求参数不能为空"); } String flowId = firstNotBlank(params.get("flow_id"), params.get("flowId")); String taskId = firstNotBlank(params.get("task_id"), params.get("taskId")); if (isBlank(flowId)) { return R.error("流程id(flow_id)不能为空"); } if (isBlank(taskId)) { return R.error("流程任务id(task_id)不能为空"); } LimsLiuyangJihuaBiangengShenqingEntity shenqing = findJihuaBiangengShenqing(flowId, taskId); if (shenqing == null) { return R.error("留样观察计划变更申请数据不存在"); } if (isBlank(shenqing.getLiuyangJihuaId())) { return R.error("变更申请未关联留样观察计划"); } LimsLiuyangJihuaEntity jihua = limsLiuyangJihuaService.getById(shenqing.getLiuyangJihuaId()); if (jihua == null || Integer.valueOf(1).equals(jihua.getDeleteMark())) { return R.error("留样观察计划数据不存在"); } updateJihuaByBiangeng(shenqing); softDeleteUnobservedJihuaZixiang(shenqing.getLiuyangJihuaId()); syncBiangengZixiangToJihuaZixiang(jihua, shenqing); return R.success("变更成功"); } /** * 留样数量变更:将变更申请的入库数量/单位同步到留样记录。 * 仅当留样记录未出库(入库数量 == 留样现存量)时允许变更。 */ @Transactional(rollbackFor = Exception.class) @Operation(summary = "留样数量变更") @PostMapping("/liuyang/biangeng/action") @AuditLog(action = "QUANTITY_CHANGE", label = "留样数量变更", bizType = "LIUYANG", bizCodeExpr = "#result.success ? #params['liuyang_jilu_id'] : ''", targetTable = "lims_liuyang_jilu", targetIdExpr = "#params['liuyang_jilu_id']", diff = true, entityClass = LimsLiuyangJiluEntity.class) public R liuyangBiangengAction(@RequestBody Map params) { String liuyangJiluId = params.get("liuyang_jilu_id"); String biangengShenqingId = params.get("biangeng_shenqing_id"); if (isBlank(liuyangJiluId)) { return R.error("留样记录主键不能为空"); } if (isBlank(biangengShenqingId)) { return R.error("变更申请主键不能为空"); } LimsLiuyangJiluEntity jilu = findById(liuyangJiluId); if (jilu == null) { return R.error("留样记录数据不存在"); } LimsLiuyangBiangengShenqingEntity shenqing = findBiangengShenqing(biangengShenqingId); if (shenqing == null) { return R.error("变更申请数据不存在"); } if (!equalsNullable(jilu.getRukuShuliang(), jilu.getLiuyangXiancunliang())) { return R.error("该留样样品已出库,无法变更数量"); } LimsLiuyangJiluEntity jiluUpdate = new LimsLiuyangJiluEntity(); jiluUpdate.setId(jilu.getId()); jiluUpdate.setRukuShuliang(shenqing.getRukuShuliang()); jiluUpdate.setLiuyangXiancunliang(shenqing.getRukuShuliang()); jiluUpdate.setDanwei(shenqing.getDanwei()); jiluUpdate.setLiuyangXiancunliangDanwei(shenqing.getDanwei()); limsLiuyangJiluService.updateById(jiluUpdate); syncBiangengToJihua(liuyangJiluId, shenqing); return R.success("变更成功"); } /** * 留样出库验证:审批前校验申请出库数量不能大于留样现存量。 */ @Operation(summary = "留样出库验证") @PostMapping("/liuyang/chuku/validate") public R validateLiuyangChuku(@RequestBody Map params) { if (params == null) { return R.error("请求参数不能为空"); } String flowId = params.get("flow_id"); String taskId = params.get("task_id"); if (isBlank(flowId)) { return R.error("流程id(flow_id)不能为空"); } if (isBlank(taskId)) { return R.error("流程任务id(task_id)不能为空"); } try { String shenqingId = findLiuyangChukuShenqingId(flowId, taskId); if (isBlank(shenqingId)) { return R.error("留样出库申请数据不存在"); } List> zixiangList = listLiuyangChukuShenqingZixiang(shenqingId); for (Map zixiang : zixiangList) { String liuyangJiluId = zixiang.get("liuyang_jilu_id"); LimsLiuyangJiluEntity jilu = isBlank(liuyangJiluId) ? null : findById(liuyangJiluId); if (jilu == null) { return R.error(buildChukuStockErrorMessage(zixiang)); } BigDecimal chukuShuliang = parseDecimal(zixiang.get("chuku_shuliang")); BigDecimal xiancunliang = parseDecimal(jilu.getLiuyangXiancunliang()); if (chukuShuliang == null || xiancunliang == null || chukuShuliang.compareTo(xiancunliang) > 0) { return R.error(buildChukuStockErrorMessage(zixiang, jilu)); } } return R.success("验证通过"); } catch (SQLException e) { log.error("留样出库验证失败:flowId={}, taskId={}", flowId, taskId, e); return R.error("留样出库验证失败"); } } /** * 留样出库:按申请子项扣减留样现存量,同步观察计划现存量,并写出库记录。 */ @Transactional(rollbackFor = Exception.class) @Operation(summary = "留样出库") @PostMapping("/liuyang/chuku/action") @AuditLog(action = "OUTBOUND", label = "留样出库", bizType = "LIUYANG", bizCodeExpr = "#result.success ? #params['liuyang_jilu_id'] : ''", targetTable = "lims_liuyang_jilu", targetIdExpr = "#params['liuyang_jilu_id']", diff = true, entityClass = LimsLiuyangJiluEntity.class) public R liuyangChukuAction(@RequestBody Map params) { if (params == null) { return R.error("请求参数不能为空"); } String flowId = params.get("flow_id"); String taskId = params.get("task_id"); if (isBlank(flowId)) { return R.error("流程id(flow_id)不能为空"); } if (isBlank(taskId)) { return R.error("流程任务id(task_id)不能为空"); } Map shenqing = findLiuyangChukuShenqing(flowId, taskId); if (shenqing == null || shenqing.isEmpty()) { return R.error("留样出库申请数据不存在"); } String shenqingId = getString(shenqing, "f_id"); List> zixiangList = listLiuyangChukuShenqingZixiangRows(shenqingId); if (zixiangList.isEmpty()) { return R.error("留样出库申请子项不能为空"); } for (Map zixiang : zixiangList) { String liuyangJiluId = getString(zixiang, "liuyang_jilu_id"); LimsLiuyangJiluEntity jilu = isBlank(liuyangJiluId) ? null : findById(liuyangJiluId); if (jilu == null) { return R.error(buildChukuStockErrorMessage(zixiang)); } BigDecimal chukuShuliang = parseDecimal(getString(zixiang, "chuku_shuliang")); BigDecimal oldXiancunliang = parseDecimal(jilu.getLiuyangXiancunliang()); if (chukuShuliang == null || oldXiancunliang == null || chukuShuliang.compareTo(oldXiancunliang) > 0) { return R.error(buildChukuStockErrorMessage(zixiang, jilu)); } BigDecimal newXiancunliang = oldXiancunliang.subtract(chukuShuliang); String newXiancunliangText = toPlainString(newXiancunliang); LimsLiuyangJiluEntity jiluUpdate = new LimsLiuyangJiluEntity(); jiluUpdate.setId(jilu.getId()); jiluUpdate.setLiuyangXiancunliang(newXiancunliangText); limsLiuyangJiluService.updateById(jiluUpdate); syncChukuLiuyangXiancunliangToJihua(jilu.getId(), newXiancunliangText); insertLiuyangChukuRecord(shenqing, zixiang, jilu, oldXiancunliang); } return R.success("出库成功"); } private Map findLiuyangChukuShenqing(String flowId, String taskId) { String sql = "select * from " + LIUYANG_CHUKU_SHENQING_TABLE + " where f_flow_id = ? and f_flow_task_id = ?" + " and (f_delete_mark is null or f_delete_mark <> 1)" + " limit 1"; List> list = jdbcTemplate.queryForList(sql, flowId, taskId); return list.isEmpty() ? null : list.get(0); } private List> listLiuyangChukuShenqingZixiangRows(String shenqingId) { String sql = "select * from " + LIUYANG_CHUKU_SHENQING_ZIXIANG_TABLE + " where f_foreign_id = ?" + " and (f_delete_mark is null or f_delete_mark <> 1)"; return jdbcTemplate.queryForList(sql, shenqingId); } private void syncChukuLiuyangXiancunliangToJihua(String liuyangJiluId, String liuyangXiancunliang) { LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); wrapper.eq(LimsLiuyangJihuaEntity::getLiuyangJiluId, liuyangJiluId) .and(w -> w.isNull(LimsLiuyangJihuaEntity::getDeleteMark) .or() .ne(LimsLiuyangJihuaEntity::getDeleteMark, 1)) .set(LimsLiuyangJihuaEntity::getLiuyangXiancunliang, liuyangXiancunliang); limsLiuyangJihuaService.update(wrapper); } private void insertLiuyangChukuRecord(Map shenqing, Map zixiang, LimsLiuyangJiluEntity jilu, BigDecimal oldXiancunliang) { String sql = "insert into " + LIUYANG_CHUKU_TABLE + " (f_id, f_foreign_id, f_tenant_id, chuku_shenqing_id," + " yangpin_mingcheng, yangpin_bianma, guige, pihao," + " liuyang_xiancunliang, chuku_shuliang, danwei, yongtu," + " shenqing_ren, shenqing_riqi, fafang_ren, shenhe_ren, shenhe_riqi, fafang_riqi)" + " values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; String shenqingId = getString(shenqing, "f_id"); jdbcTemplate.update(sql, RandomUtil.uuId(), jilu.getId(), firstNotBlank(getString(zixiang, "f_tenant_id"), getString(shenqing, "f_tenant_id")), shenqingId, firstNotBlank(getString(zixiang, "yangpin_mingcheng"), jilu.getYangpinMingcheng()), firstNotBlank(getString(zixiang, "yangpin_bianma"), jilu.getYangpinBianma()), firstNotBlank(getString(zixiang, "guige"), jilu.getGuige()), firstNotBlank(getString(zixiang, "pihao"), jilu.getPihao()), toPlainString(oldXiancunliang), parseDecimal(getString(zixiang, "chuku_shuliang")), firstNotBlank(getString(zixiang, "danwei"), jilu.getDanwei()), firstNotBlank(getString(zixiang, "yongtu"), getString(shenqing, "yongtu")), getObject(shenqing, "shenqing_ren"), getObject(shenqing, "shenqing_riqi"), getObject(shenqing, "fafang_ren"), getObject(shenqing, "shenhe_ren"), getObject(shenqing, "shenhe_riqi"), getObject(shenqing, "fafang_riqi")); } private Map findLiuyangXiaohuiShenqing(String flowId, String taskId) { String sql = "select * from " + LIUYANG_XIAOHUI_SHENQING_TABLE + " where f_flow_id = ? and f_flow_task_id = ?" + " and (f_delete_mark is null or f_delete_mark <> 1)" + " limit 1"; List> list = jdbcTemplate.queryForList(sql, flowId, taskId); return list.isEmpty() ? null : list.get(0); } private List listLiuyangXiaohuiJiluIds(String shenqingId) { String sql = "select distinct liuyang_jilu_id from " + LIUYANG_XIAOHUI_SHENQING_ZIXIANG_TABLE + " where f_foreign_id = ?" + " and liuyang_jilu_id is not null and liuyang_jilu_id <> ''" + " and (f_delete_mark is null or f_delete_mark <> 1)"; return jdbcTemplate.queryForList(sql, shenqingId).stream() .map(row -> getString(row, "liuyang_jilu_id")) .filter(value -> !isBlank(value)) .distinct() .collect(Collectors.toList()); } private void updateLiuyangXiaohuiDanhao(List liuyangJiluIds, String xiaohuiDanhao) { LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); wrapper.in(LimsLiuyangJiluEntity::getId, liuyangJiluIds) .and(w -> w.isNull(LimsLiuyangJiluEntity::getDeleteMark) .or() .ne(LimsLiuyangJiluEntity::getDeleteMark, 1)) .set(LimsLiuyangJiluEntity::getXiaohuiDanhao, xiaohuiDanhao); limsLiuyangJiluService.update(wrapper); } private void acceptLiuyangXiaohui(List liuyangJiluIds) { LambdaUpdateWrapper jiluUpdate = new LambdaUpdateWrapper<>(); jiluUpdate.in(LimsLiuyangJiluEntity::getId, liuyangJiluIds) .and(w -> w.isNull(LimsLiuyangJiluEntity::getDeleteMark) .or() .ne(LimsLiuyangJiluEntity::getDeleteMark, 1)) .set(LimsLiuyangJiluEntity::getBizStatus, BIZ_STATUS_DESTROYED); limsLiuyangJiluService.update(jiluUpdate); List jihuaIds = listLiuyangJihuaIdsByJiluIds(liuyangJiluIds); LambdaUpdateWrapper jihuaUpdate = new LambdaUpdateWrapper<>(); jihuaUpdate.in(LimsLiuyangJihuaEntity::getLiuyangJiluId, liuyangJiluIds) .and(w -> w.isNull(LimsLiuyangJihuaEntity::getDeleteMark) .or() .ne(LimsLiuyangJihuaEntity::getDeleteMark, 1)) .set(LimsLiuyangJihuaEntity::getBizStatus, BIZ_STATUS_DISABLED); limsLiuyangJihuaService.update(jihuaUpdate); if (!jihuaIds.isEmpty()) { LambdaUpdateWrapper zixiangUpdate = new LambdaUpdateWrapper<>(); zixiangUpdate.in(LimsLiuyangJihuaZixiangEntity::getForeignId, jihuaIds) .and(w -> w.isNull(LimsLiuyangJihuaZixiangEntity::getDeleteMark) .or() .ne(LimsLiuyangJihuaZixiangEntity::getDeleteMark, 1)) .set(LimsLiuyangJihuaZixiangEntity::getBizStatus, BIZ_STATUS_DISABLED); limsLiuyangJihuaZixiangService.update(zixiangUpdate); } } private List listLiuyangJihuaIdsByJiluIds(List liuyangJiluIds) { LambdaQueryWrapper query = new LambdaQueryWrapper<>(); query.in(LimsLiuyangJihuaEntity::getLiuyangJiluId, liuyangJiluIds) .and(w -> w.isNull(LimsLiuyangJihuaEntity::getDeleteMark) .or() .ne(LimsLiuyangJihuaEntity::getDeleteMark, 1)); return limsLiuyangJihuaService.list(query).stream() .map(LimsLiuyangJihuaEntity::getId) .filter(value -> !isBlank(value)) .distinct() .collect(Collectors.toList()); } private String findLiuyangChukuShenqingId(String flowId, String taskId) throws SQLException { String sql = "select f_id from " + LIUYANG_CHUKU_SHENQING_TABLE + " where f_flow_id = ? and f_flow_task_id = ?" + " and (f_delete_mark is null or f_delete_mark <> 1)" + " limit 1"; try (Connection connection = dataSource.getConnection(); PreparedStatement statement = connection.prepareStatement(sql)) { statement.setString(1, flowId); statement.setString(2, taskId); try (ResultSet resultSet = statement.executeQuery()) { return resultSet.next() ? resultSet.getString("f_id") : null; } } } private List> listLiuyangChukuShenqingZixiang(String shenqingId) throws SQLException { String sql = "select liuyang_jilu_id, chuku_shuliang, yangpin_mingcheng, pihao from " + LIUYANG_CHUKU_SHENQING_ZIXIANG_TABLE + " where f_foreign_id = ?" + " and (f_delete_mark is null or f_delete_mark <> 1)"; List> list = new ArrayList<>(); try (Connection connection = dataSource.getConnection(); PreparedStatement statement = connection.prepareStatement(sql)) { statement.setString(1, shenqingId); try (ResultSet resultSet = statement.executeQuery()) { while (resultSet.next()) { Map row = new LinkedHashMap<>(); row.put("liuyang_jilu_id", resultSet.getString("liuyang_jilu_id")); row.put("chuku_shuliang", resultSet.getString("chuku_shuliang")); row.put("yangpin_mingcheng", resultSet.getString("yangpin_mingcheng")); row.put("pihao", resultSet.getString("pihao")); list.add(row); } } } return list; } private String buildChukuStockErrorMessage(Map zixiang) { return buildChukuStockErrorMessage(zixiang, null); } private String buildChukuStockErrorMessage(Map zixiang, LimsLiuyangJiluEntity jilu) { String yangpinMingcheng = firstNotBlank(getString(zixiang, "yangpin_mingcheng"), jilu == null ? null : jilu.getYangpinMingcheng()); String pihao = firstNotBlank(getString(zixiang, "pihao"), jilu == null ? null : jilu.getPihao()); return trimToEmpty(yangpinMingcheng) + "批次" + trimToEmpty(pihao) + "库存不足,不满足出库条件"; } private BigDecimal parseDecimal(String value) { if (isBlank(value)) { return null; } try { return new BigDecimal(value.trim()); } catch (NumberFormatException e) { return null; } } private String firstNotBlank(String first, String second) { return isBlank(first) ? second : first; } private String trimToEmpty(String value) { return value == null ? "" : value.trim(); } private String getString(Map row, String key) { if (row == null || key == null) { return null; } Object value = row.get(key); return value == null ? null : String.valueOf(value); } private Object getObject(Map row, String key) { if (row == null || key == null) { return null; } return row.get(key); } private String toPlainString(BigDecimal value) { return value == null ? null : value.stripTrailingZeros().toPlainString(); } private void syncBiangengToJihua(String liuyangJiluId, LimsLiuyangBiangengShenqingEntity shenqing) { LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); wrapper.eq(LimsLiuyangJihuaEntity::getLiuyangJiluId, liuyangJiluId) .and(w -> w.isNull(LimsLiuyangJihuaEntity::getDeleteMark) .or() .ne(LimsLiuyangJihuaEntity::getDeleteMark, 1)) .set(LimsLiuyangJihuaEntity::getRukuShuliang, shenqing.getRukuShuliang()) .set(LimsLiuyangJihuaEntity::getLiuyangXiancunliang, shenqing.getRukuShuliang()) .set(LimsLiuyangJihuaEntity::getDanwei, shenqing.getDanwei()) .set(LimsLiuyangJihuaEntity::getLiuyangXiancunliangDanwei, shenqing.getDanwei()); limsLiuyangJihuaService.update(wrapper); } private LimsLiuyangBiangengShenqingEntity findBiangengShenqing(String id) { LambdaQueryWrapper query = new LambdaQueryWrapper<>(); query.eq(LimsLiuyangBiangengShenqingEntity::getId, id) .and(w -> w.isNull(LimsLiuyangBiangengShenqingEntity::getDeleteMark) .or() .ne(LimsLiuyangBiangengShenqingEntity::getDeleteMark, 1)); query.last("limit 1"); return limsLiuyangBiangengShenqingService.getOne(query, false); } private LimsLiuyangJihuaBiangengShenqingEntity findJihuaBiangengShenqing(String flowId, String taskId) { LambdaQueryWrapper query = new LambdaQueryWrapper<>(); query.eq(LimsLiuyangJihuaBiangengShenqingEntity::getFlowId, flowId) .eq(LimsLiuyangJihuaBiangengShenqingEntity::getFlowTaskId, taskId) .and(w -> w.isNull(LimsLiuyangJihuaBiangengShenqingEntity::getDeleteMark) .or() .ne(LimsLiuyangJihuaBiangengShenqingEntity::getDeleteMark, 1)); query.last("limit 1"); return limsLiuyangJihuaBiangengShenqingService.getOne(query, false); } private void updateJihuaByBiangeng(LimsLiuyangJihuaBiangengShenqingEntity shenqing) { LimsLiuyangJihuaEntity update = new LimsLiuyangJihuaEntity(); update.setId(shenqing.getLiuyangJihuaId()); update.setLiuyangRiqi(shenqing.getLiuyangRiqi()); update.setLiuyangZhouqiId(shenqing.getLiuyangZhouqiId()); limsLiuyangJihuaService.updateById(update); } private void softDeleteUnobservedJihuaZixiang(String jihuaId) { LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); wrapper.eq(LimsLiuyangJihuaZixiangEntity::getForeignId, jihuaId) .and(w -> w.isNull(LimsLiuyangJihuaZixiangEntity::getShifouYiguancha) .or() .ne(LimsLiuyangJihuaZixiangEntity::getShifouYiguancha, "yes")) .and(w -> w.isNull(LimsLiuyangJihuaZixiangEntity::getDeleteMark) .or() .ne(LimsLiuyangJihuaZixiangEntity::getDeleteMark, 1)) .set(LimsLiuyangJihuaZixiangEntity::getDeleteMark, 1) .set(LimsLiuyangJihuaZixiangEntity::getDeleteTime, new Date()) .set(LimsLiuyangJihuaZixiangEntity::getDeleteUserId, UserProvider.getUser().getUserId()); limsLiuyangJihuaZixiangService.update(wrapper); } private void syncBiangengZixiangToJihuaZixiang(LimsLiuyangJihuaEntity jihua, LimsLiuyangJihuaBiangengShenqingEntity shenqing) { List shenqingZixiangList = listUnobservedJihuaBiangengZixiang(shenqing.getId()); if (shenqingZixiangList.isEmpty()) { return; } List jihuaZixiangList = shenqingZixiangList.stream() .map(row -> buildJihuaZixiangFromBiangeng(jihua, shenqing, row)) .collect(Collectors.toList()); limsLiuyangJihuaZixiangService.saveBatch(jihuaZixiangList); } private List listUnobservedJihuaBiangengZixiang(String shenqingId) { LambdaQueryWrapper query = new LambdaQueryWrapper<>(); query.eq(LimsLiuyangJihuaBiangengShenqingZixiangEntity::getForeignId, shenqingId) .and(w -> w.isNull(LimsLiuyangJihuaBiangengShenqingZixiangEntity::getShifouYiguancha) .or() .ne(LimsLiuyangJihuaBiangengShenqingZixiangEntity::getShifouYiguancha, "yes")) .and(w -> w.isNull(LimsLiuyangJihuaBiangengShenqingZixiangEntity::getDeleteMark) .or() .ne(LimsLiuyangJihuaBiangengShenqingZixiangEntity::getDeleteMark, 1)) .orderByAsc(LimsLiuyangJihuaBiangengShenqingZixiangEntity::getJihuaRiqi); return limsLiuyangJihuaBiangengShenqingZixiangService.list(query); } private LimsLiuyangJihuaZixiangEntity buildJihuaZixiangFromBiangeng( LimsLiuyangJihuaEntity jihua, LimsLiuyangJihuaBiangengShenqingEntity shenqing, LimsLiuyangJihuaBiangengShenqingZixiangEntity shenqingZixiang) { LimsLiuyangJihuaZixiangEntity zixiang = new LimsLiuyangJihuaZixiangEntity(); zixiang.setId(RandomUtil.uuId()); zixiang.setForeignId(jihua.getId()); zixiang.setZhouqi(shenqingZixiang.getZhouqi()); zixiang.setZhouqiDanwei(shenqingZixiang.getZhouqiDanwei()); zixiang.setJihuaRiqi(shenqingZixiang.getJihuaRiqi()); zixiang.setGuanchaRiqi(shenqingZixiang.getGuanchaRiqi()); zixiang.setGuanchaRen(shenqingZixiang.getGuanchaRen()); zixiang.setGuanchaShuliang(shenqingZixiang.getGuanchaShuliang()); zixiang.setGuanchaQingkuang(shenqingZixiang.getGuanchaQingkuang()); zixiang.setGuanchaJieguo(shenqingZixiang.getGuanchaJieguo()); zixiang.setShifouYiguancha(shenqingZixiang.getShifouYiguancha()); zixiang.setBeizhu(shenqingZixiang.getBeizhu()); zixiang.setBizType(jihua.getBizType()); zixiang.setYangpinMingcheng(jihua.getYangpinMingcheng()); zixiang.setYangpinBianma(jihua.getYangpinBianma()); zixiang.setGuige(jihua.getGuige()); zixiang.setPihao(jihua.getPihao()); zixiang.setShengchanRiqi(jihua.getShengchanRiqi()); zixiang.setYouxiaoqi(jihua.getYouxiaoqi()); zixiang.setLiuyangRiqi(shenqing.getLiuyangRiqi()); zixiang.setGuanchaShuliangDanwei(jihua.getDanwei()); zixiang.setBizStatus(jihua.getBizStatus()); return zixiang; } private boolean equalsNullable(String a, String b) { if (a == null && b == null) { return true; } if (a == null || b == null) { return false; } return a.trim().equals(b.trim()); } private String getFormId(Map formData) { if (formData == null) { return null; } Object id = formData.get("f_id"); if (id == null) { id = formData.get("id"); } return id == null ? null : String.valueOf(id); } private void syncJihuaInfoToZixiang(LimsLiuyangJihuaEntity jihua) { LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); wrapper.eq(LimsLiuyangJihuaZixiangEntity::getForeignId, jihua.getId()) .and(w -> w.isNull(LimsLiuyangJihuaZixiangEntity::getDeleteMark) .or() .ne(LimsLiuyangJihuaZixiangEntity::getDeleteMark, 1)) // 提交计划时,将主表样品信息冗余到周期子项,便于后续观察列表独立展示。 .set(LimsLiuyangJihuaZixiangEntity::getBizType, jihua.getBizType()) .set(LimsLiuyangJihuaZixiangEntity::getYangpinMingcheng, jihua.getYangpinMingcheng()) .set(LimsLiuyangJihuaZixiangEntity::getYangpinBianma, jihua.getYangpinBianma()) .set(LimsLiuyangJihuaZixiangEntity::getGuige, jihua.getGuige()) .set(LimsLiuyangJihuaZixiangEntity::getPihao, jihua.getPihao()) .set(LimsLiuyangJihuaZixiangEntity::getShengchanRiqi, jihua.getShengchanRiqi()) .set(LimsLiuyangJihuaZixiangEntity::getYouxiaoqi, jihua.getYouxiaoqi()) .set(LimsLiuyangJihuaZixiangEntity::getLiuyangRiqi, jihua.getLiuyangRiqi()) .set(LimsLiuyangJihuaZixiangEntity::getGuanchaShuliangDanwei, jihua.getDanwei()) .set(LimsLiuyangJihuaZixiangEntity::getBizStatus, jihua.getBizStatus()); limsLiuyangJihuaZixiangService.update(wrapper); } private LimsLiuyangJiluEntity findLiuyangJilu(String id, String flowId, String taskId) { if (id != null && !id.isEmpty()) { return findById(id); } return findByFlow(flowId, taskId); } private LimsLiuyangJiluEntity findById(String id) { LambdaQueryWrapper query = new LambdaQueryWrapper<>(); query.eq(LimsLiuyangJiluEntity::getId, id) .and(w -> w.isNull(LimsLiuyangJiluEntity::getDeleteMark) .or() .ne(LimsLiuyangJiluEntity::getDeleteMark, 1)); query.last("limit 1"); return limsLiuyangJiluService.getOne(query, false); } private LimsLiuyangJiluEntity findByFlow(String flowId, String taskId) { LambdaQueryWrapper query = new LambdaQueryWrapper<>(); query.eq(LimsLiuyangJiluEntity::getFlowId, flowId) .and(w -> w.isNull(LimsLiuyangJiluEntity::getDeleteMark) .or() .ne(LimsLiuyangJiluEntity::getDeleteMark, 1)); if (taskId != null && !taskId.isEmpty()) { query.eq(LimsLiuyangJiluEntity::getFlowTaskId, taskId); } query.last("limit 1"); return limsLiuyangJiluService.getOne(query, false); } private List listWendingxingZhouqiZixiang(String zhouqiId) { LambdaQueryWrapper query = new LambdaQueryWrapper<>(); query.eq(LiuyangWendingxingZhouqiZixiangEntity::getForeignId, zhouqiId) .and(w -> w.isNull(LiuyangWendingxingZhouqiZixiangEntity::getDeleteMark) .or() .ne(LiuyangWendingxingZhouqiZixiangEntity::getDeleteMark, 1)) .orderByAsc(LiuyangWendingxingZhouqiZixiangEntity::getZhouqi); return liuyangWendingxingZhouqiZixiangService.list(query); } private List listObservedJihuaZixiang(String jihuaId) { LambdaQueryWrapper query = new LambdaQueryWrapper<>(); query.eq(LimsLiuyangJihuaZixiangEntity::getForeignId, jihuaId) .eq(LimsLiuyangJihuaZixiangEntity::getShifouYiguancha, "yes") .and(w -> w.isNull(LimsLiuyangJihuaZixiangEntity::getDeleteMark) .or() .ne(LimsLiuyangJihuaZixiangEntity::getDeleteMark, 1)) .orderByAsc(LimsLiuyangJihuaZixiangEntity::getJihuaRiqi); return limsLiuyangJihuaZixiangService.list(query); } private LimsLiuyangJihuaCalculateResult buildJihuaZixiang(LiuyangWendingxingZhouqiZixiangEntity zhouqi, Date shouyangRiqi) { if (zhouqi.getZhouqi() == null) { throw new IllegalArgumentException("周期不能为空"); } if (isBlank(zhouqi.getZhouqiDanwei())) { throw new IllegalArgumentException("周期单位不能为空"); } LimsLiuyangJihuaCalculateResult item = new LimsLiuyangJihuaCalculateResult(); item.setZhouqi(zhouqi.getZhouqi()); item.setZhouqiDanwei(zhouqi.getZhouqiDanwei()); item.setJihuaRiqi(calculateJihuaRiqi(shouyangRiqi, zhouqi.getZhouqi(), zhouqi.getZhouqiDanwei())); item.setGuanchaRiqi(null); item.setShifouYiguancha("no"); return item; } private Map buildBiangengRow(LimsLiuyangJihuaZixiangEntity jihuaZixiang, List responseFields) { Map row = newEmptyBiangengRow(responseFields); putIfPresent(row, "zhouqi", jihuaZixiang.getZhouqi()); putIfPresent(row, "zhouqi_danwei", jihuaZixiang.getZhouqiDanwei()); putIfPresent(row, "jihua_riqi", jihuaZixiang.getJihuaRiqi()); putIfPresent(row, "shifou_yiguancha", jihuaZixiang.getShifouYiguancha()); putIfPresent(row, "guancha_riqi", jihuaZixiang.getGuanchaRiqi()); putIfPresent(row, "guancha_ren", jihuaZixiang.getGuanchaRen()); putIfPresent(row, "guancha_shuliang", jihuaZixiang.getGuanchaShuliang()); putIfPresent(row, "guancha_qingkuang", jihuaZixiang.getGuanchaQingkuang()); putIfPresent(row, "guancha_jieguo", jihuaZixiang.getGuanchaJieguo()); putIfPresent(row, "beizhu", jihuaZixiang.getBeizhu()); return row; } private Map buildBiangengRow(LiuyangWendingxingZhouqiZixiangEntity zhouqi, Date liuyangRiqi, List responseFields) { if (zhouqi.getZhouqi() == null) { throw new IllegalArgumentException("周期不能为空"); } if (isBlank(zhouqi.getZhouqiDanwei())) { throw new IllegalArgumentException("周期单位不能为空"); } Map row = newEmptyBiangengRow(responseFields); putIfPresent(row, "zhouqi", zhouqi.getZhouqi()); putIfPresent(row, "zhouqi_danwei", zhouqi.getZhouqiDanwei()); putIfPresent(row, "jihua_riqi", calculateJihuaRiqi(liuyangRiqi, zhouqi.getZhouqi(), zhouqi.getZhouqiDanwei())); putIfPresent(row, "shifou_yiguancha", "no"); return row; } private Map newEmptyBiangengRow(List responseFields) { Map row = new LinkedHashMap<>(); for (String field : responseFields) { row.put(field, null); } return row; } private void putIfPresent(Map row, String field, Object value) { if (row.containsKey(field)) { row.put(field, value); } } private String buildZhouqiKey(BigDecimal zhouqi, String zhouqiDanwei) { if (zhouqi == null || isBlank(zhouqiDanwei)) { return ""; } return zhouqi.stripTrailingZeros().toPlainString() + "|" + zhouqiDanwei.trim(); } private List getBiangengZixiangBusinessFields() { Set fields = new LinkedHashSet<>(); try (Connection connection = dataSource.getConnection()) { DatabaseMetaData metaData = connection.getMetaData(); readBusinessColumns(fields, metaData, connection.getCatalog(), connection.getSchema(), BIANGENG_ZIXIANG_TABLE); if (fields.isEmpty()) { readBusinessColumns(fields, metaData, connection.getCatalog(), connection.getSchema(), BIANGENG_ZIXIANG_TABLE.toUpperCase()); } } catch (Exception e) { log.warn("读取{}字段失败,使用默认字段", BIANGENG_ZIXIANG_TABLE, e); } if (fields.isEmpty()) { fields.addAll(DEFAULT_BIANGENG_ZIXIANG_FIELDS); } return new ArrayList<>(fields); } private void readBusinessColumns(Set fields, DatabaseMetaData metaData, String catalog, String schema, String tableName) throws SQLException { try (ResultSet columns = metaData.getColumns(catalog, schema, tableName, null)) { while (columns.next()) { String columnName = columns.getString("COLUMN_NAME"); if (!isBlank(columnName) && !columnName.toLowerCase().startsWith("f_")) { fields.add(columnName); } } } } private Date calculateJihuaRiqi(Date shouyangRiqi, BigDecimal zhouqi, String zhouqiDanwei) { int amount = toIntegerZhouqi(zhouqi); LocalDateTime baseTime = LocalDateTime.ofInstant(shouyangRiqi.toInstant(), ZoneId.systemDefault()); LocalDateTime jihuaTime; switch (zhouqiDanwei.trim()) { case "day": case "天": jihuaTime = baseTime.plusDays(amount); break; case "week": case "周": jihuaTime = baseTime.plusWeeks(amount); break; case "month": case "月": jihuaTime = baseTime.plusMonths(amount); break; case "quarter": case "季": jihuaTime = baseTime.plusMonths(amount * 3L); break; case "year": case "年": jihuaTime = baseTime.plusYears(amount); break; default: throw new IllegalArgumentException("不支持的周期单位:" + zhouqiDanwei); } return Date.from(jihuaTime.atZone(ZoneId.systemDefault()).toInstant()); } private int toIntegerZhouqi(BigDecimal zhouqi) { try { return zhouqi.stripTrailingZeros().intValueExact(); } catch (ArithmeticException e) { throw new IllegalArgumentException("周期必须为整数:" + zhouqi); } } private void updateLiuyangStatus(LimsLiuyangJiluEntity liuyangJilu, LiuyangStatus status, String bizSign) { LimsLiuyangJiluEntity update = new LimsLiuyangJiluEntity(); update.setId(liuyangJilu.getId()); update.setBizStatus(status.getCode()); if (bizSign != null && !bizSign.isEmpty()) { update.setBizSign(bizSign); } limsLiuyangJiluService.updateById(update); } private void receiveLiuyangJilu(LimsLiuyangJiluEntity liuyangJilu, String bizSign) { LimsLiuyangJiluEntity update = new LimsLiuyangJiluEntity(); update.setId(liuyangJilu.getId()); update.setBizStatus(LiuyangStatus.RECEIVED.getCode()); update.setLiuyangXiancunliang(liuyangJilu.getRukuShuliang()); update.setLiuyangXiancunliangDanwei(liuyangJilu.getDanwei()); if (bizSign != null && !bizSign.isEmpty()) { update.setBizSign(bizSign); } limsLiuyangJiluService.updateById(update); } private void softDeleteLiuyangJilu(LimsLiuyangJiluEntity liuyangJilu, String bizSign) { LimsLiuyangJiluEntity update = new LimsLiuyangJiluEntity(); update.setId(liuyangJilu.getId()); update.setDeleteMark(1); update.setDeleteTime(new Date()); update.setDeleteUserId(UserProvider.getUser().getUserId()); if (bizSign != null && !bizSign.isEmpty()) { update.setBizSign(bizSign); } limsLiuyangJiluService.updateById(update); } private void updateQingyandanLiuyangJiluId(LimsLiuyangJiluEntity liuyangJilu, String liuyangJiluId) { String qingyandanId = liuyangJilu.getQingyandanId(); if (qingyandanId == null || qingyandanId.isEmpty()) { return; } LimsQingyandanEntity qingyandan = limsQingyandanService.getById(qingyandanId); if (qingyandan == null) { return; } LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); updateWrapper.eq(LimsQingyandanEntity::getId, qingyandan.getId()) .set(LimsQingyandanEntity::getLiuyangJiluId, liuyangJiluId); limsQingyandanService.update(updateWrapper); } private boolean isBlank(String value) { return value == null || value.trim().isEmpty(); } }