feat: 完成附件存储重构与磁盘监控功能,同步物料档案与入库单规则更新

1.  新增跨平台磁盘空间监控能力,每日7点自动检测附件目录剩余空间,触发阈值告警
2.  重构附件存储方案为年/月/日/文件类型分层结构,统一MES与WMS的附件管理逻辑
3.  对齐物料档案与入库单的质量状态校验规则,仅合格品计入库存与出库
4.  实现入库单作废功能与区域库位的多级父子结构管理
5.  删除物料简称字段,补充规格型号与单位必填项,统一系统数据口径
6.  新增附件中心与磁盘状态查询接口,完善权限控制与操作日志
This commit is contained in:
SunYF
2026-09-19 10:54:15 +08:00
parent 9002d9a642
commit 62e45b7379
95 changed files with 10467 additions and 2677 deletions
+15 -14
View File
@@ -127,9 +127,9 @@ func deductStockHandler(ctx *svc.ServiceContext) http.HandlerFunc {
fail(w, http.StatusConflict, "批次库存不足: "+req.BatchNo+" 可用 "+itoa(avail))
return
}
// 质量门禁(P0-2):不合格/待退 批次禁止上线领料(客户诉求 L135:不合格不上产线)
if b.QualityStatus == "不合格" || b.QualityStatus == "待退" {
fail(w, http.StatusConflict, "批次 "+req.BatchNo+" 质量状态为「"+b.QualityStatus+"」,禁止领料上线(请先完成不合格处置")
// 质量门禁(P0-2,客户口径):仅「合格」批次可领料上线;未检(待检)/不合格/待退 一律拦截
if b.QualityStatus != QStatusPass {
fail(w, http.StatusConflict, "批次 "+req.BatchNo+" 质量状态为「"+qualityLabel(b.QualityStatus)+"」,仅合格品可领料上线(请先完成质量检验")
return
}
aff, err := tx.Inventory.Update().
@@ -155,12 +155,12 @@ func deductStockHandler(ctx *svc.ServiceContext) http.HandlerFunc {
}
// 4. 扣减 SN(原子:仅 在库/锁定 的 SN 可出库 → 置出库)
// 质量门禁(P0-2):不合格/待退 的 SN 禁止领料上线(请走「通用出库」办理退货/报废
// 质量门禁(P0-2,客户口径):仅「合格」SN 可出库(未检/不合格/待退 拦截;退货/报废走「通用出库」
if len(req.SnList) > 0 {
for _, sn := range req.SnList {
aff, err := tx.Inventory.Update().
Where(inventory.ManageModeEQ(2), inventory.SnCodeEQ(sn), inventory.StatusIn("在库", "锁定"),
inventory.QualityStatusNotIn("不合格", "待退")).
inventory.QualityStatusEQ(QStatusPass)).
SetStatus("出库").
SetNillableZoneCode(strPtr(req.ZoneCode)).
Save(ctx0())
@@ -169,7 +169,7 @@ func deductStockHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return
}
if aff == 0 {
fail(w, http.StatusBadRequest, "SN 不可出库(不存在、非在库/锁定,或质量状态为不合格/待退): "+sn)
fail(w, http.StatusBadRequest, "SN 不可出库(不存在、非在库/锁定,或质量状态非「合格」): "+sn)
return
}
if _, err = tx.OutboundDetail.Create().
@@ -444,9 +444,10 @@ func generalOutboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
fail(w, http.StatusBadRequest, "批次不存在: "+req.BatchNo)
return
}
// 质量门禁(U5,客户口径):发货/样品/其他类出库禁止不合格/待退品流向下游;退货/报废/退料类豁免(本身即处置不合格品)。
if outboundBlocksUnqualified(req.OutboundCategory) && (b.QualityStatus == "不合格" || b.QualityStatus == "待退") {
fail(w, http.StatusConflict, "批次 "+req.BatchNo+" 质量状态为「"+b.QualityStatus+"」,"+outboundCategoryLabel(req.OutboundCategory)+"出库禁止发出(请走退货/报废处置)")
// 质量门禁(U5,客户口径):发货/样品/其他类出库仅允许「合格」品流向下游;
// 退货/报废/退料类豁免(本身即处置不合格品)。
if outboundBlocksUnqualified(req.OutboundCategory) && b.QualityStatus != QStatusPass {
fail(w, http.StatusConflict, "批次 "+req.BatchNo+" 质量状态为「"+qualityLabel(b.QualityStatus)+"」,"+outboundCategoryLabel(req.OutboundCategory)+"出库仅允许合格品(请先完成质量检验/处置)")
return
}
avail := b.Quantity - b.LockedQty
@@ -476,13 +477,13 @@ func generalOutboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
// SN 扣减(电气件):仅在库/锁定的 SN 可出库
if len(req.SnList) > 0 {
// 质量门禁(U5,客户口径):发货/样品/其他类出库禁止不合格/待退 SN 流出;退货/报废/退料类豁免。
// 质量门禁(U5,客户口径):发货/样品/其他类出库仅允许「合格」SN;退货/报废/退料类豁免。
if outboundBlocksUnqualified(req.OutboundCategory) {
bad, _ := tx.Inventory.Query().
Where(inventory.ManageModeEQ(2), inventory.SnCodeIn(req.SnList...), inventory.QualityStatusIn("不合格", "待退")).
passCnt, _ := tx.Inventory.Query().
Where(inventory.ManageModeEQ(2), inventory.SnCodeIn(req.SnList...), inventory.QualityStatusEQ(QStatusPass)).
Count(ctx0())
if bad > 0 {
fail(w, http.StatusConflict, "所选 SN 含不合格/待退"+outboundCategoryLabel(req.OutboundCategory)+"出库禁止发出(请走退货/报废处置)")
if passCnt < len(req.SnList) {
fail(w, http.StatusConflict, "所选 SN 含非合格品(未检/不合格/待退"+outboundCategoryLabel(req.OutboundCategory)+"出库仅允许合格品(请先完成质量检验/处置)")
return
}
}