feat: 完成多模块迭代更新

- 新增过程巡检按步骤上报、数量不符上报、工位退料功能
- 增加工单工程编号三级归属字段
- 新增物料安全库存与缺货预警
- 新增附件管理、退库单管理模块
- 优化生产看板展示逻辑与前端页面文案
- 清理冗余的工艺路线相关代码与备份文件
This commit is contained in:
SunYF
2026-09-15 16:37:39 +08:00
parent 951f3dfecd
commit 4a5e2d7bac
494 changed files with 24702 additions and 139223 deletions
+67 -3
View File
@@ -1,13 +1,16 @@
package handler
import (
"fmt"
"net/http"
"strconv"
"strings"
"time"
"bj_power_wms/ent"
"bj_power_wms/ent/inbounddetail"
"bj_power_wms/ent/inboundorder"
"bj_power_wms/ent/inspectionrecord"
"bj_power_wms/ent/inventory"
"bj_power_wms/ent/material"
"bj_power_wms/internal/svc"
@@ -16,6 +19,37 @@ import (
"github.com/zeromicro/go-zero/core/logx"
)
// 物料品类:4=其他(辅料/工装/试验设备),与 schema/material.go 的 item_type 保持一致
const invItemOther = 4
// validateInboundQuality 入库质量门禁:该物料/批次/SN 若已被判定"不合格",拒绝入库。
// 依据客户诉求《问题记录》L135:「不合格不入库、不上产线,仅合格品入库存数量」。
func validateInboundQuality(ctx *svc.ServiceContext, materialCode, batchNo string, snList []string) error {
if batchNo != "" {
n, err := ctx.EntClient.InspectionRecord.Query().
Where(
inspectionrecord.MaterialCodeEQ(materialCode),
inspectionrecord.TargetIDEQ(batchNo),
inspectionrecord.StatusEQ("不合格"),
).Count(ctx0())
if err == nil && n > 0 {
return fmt.Errorf("批次 %s 已被判定不合格,禁止入库(请走退货/报废处置)", batchNo)
}
}
if len(snList) > 0 {
recs, err := ctx.EntClient.InspectionRecord.Query().
Where(
inspectionrecord.MaterialCodeEQ(materialCode),
inspectionrecord.TargetIDIn(snList...),
inspectionrecord.StatusEQ("不合格"),
).Limit(1).All(ctx0())
if err == nil && len(recs) > 0 {
return fmt.Errorf("SN %s 已被判定不合格,禁止入库", recs[0].TargetID)
}
}
return nil
}
// createInboundHandler 入库
// 结构件: { inboundType, materialCode, batchNo, quantity, zoneCode, operator }
// 电气件: { inboundType, materialCode, snList: [sn...], zoneCode, operator }
@@ -24,7 +58,7 @@ import (
func createInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req struct {
InboundType string `json:"inboundType"` // purchase/semi/finished/return
InboundType string `json:"inboundType"` // purchase/semi/finished/return/other
MaterialCode string `json:"materialCode"`
BatchNo string `json:"batchNo"`
Quantity int `json:"quantity"`
@@ -34,7 +68,9 @@ func createInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
ProductionDate string `json:"productionDate"`
Supplier string `json:"supplier"`
Remark string `json:"remark"`
InspectionNo string `json:"inspectionNo"`
InspectionNo string `json:"inspectionNo"`
OwnershipType string `json:"ownershipType"` // workorder/project/none
OwnershipNo string `json:"ownershipNo"`
}
if err := parseJSON(r, &req); err != nil {
fail(w, http.StatusBadRequest, "参数错误: "+err.Error())
@@ -62,6 +98,22 @@ func createInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return
}
// 其他类物料(item_type=4:辅料/工装/试验设备):规格强制必填(客户诉求 问题记录 L50)
if m.ItemType == invItemOther {
if strings.TrimSpace(m.Spec) == "" {
fail(w, http.StatusBadRequest, "其他类物料必须填写规格型号,请先在物料档案补全")
return
}
req.InboundType = "other"
}
// 质量门禁(P0-2):已被判定不合格的批次/SN 禁止再入库——
// 客户诉求 L135「不合格不入库、不上产线,仅合格品计入库存数量」。
if qerr := validateInboundQuality(ctx, req.MaterialCode, req.BatchNo, req.SnList); qerr != nil {
fail(w, http.StatusConflict, qerr.Error())
return
}
inboundNo := "IB" + uuid.NewString()[:12]
// 开启事务:入库单 + 库存行 + 明细 原子提交
@@ -87,7 +139,9 @@ func createInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
SetQuantity(0).
SetNillableOperator(strPtr(req.Operator)).
SetNillableRemark(strPtr(req.Remark)).
SetInspectionNo(req.InspectionNo).
SetInspectionNo(req.InspectionNo).
SetOwnershipType(ownershipTypeOrNone(req.OwnershipType)).
SetNillableOwnershipNo(strPtr(req.OwnershipNo)).
Save(ctx0())
if err != nil {
fail(w, http.StatusInternalServerError, "创建入库单失败: "+err.Error())
@@ -393,6 +447,16 @@ func exportInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
}
}
// ownershipTypeOrNone 归属类型归一化(工单号/科技项目号/无)
func ownershipTypeOrNone(v string) string {
switch v {
case "workorder", "project":
return v
default:
return "none"
}
}
// genBatchNo 生成批次号:日期 + 自增
func genBatchNo(materialCode string) string {
// TODO: 使用数据库序列或 Redis INCR 保证自增唯一