package handler import ( "encoding/json" "net/http" "bj_power_wms/ent" "bj_power_wms/ent/ordermaterialledger" "bj_power_wms/ent/packagebox" "bj_power_wms/ent/semifinished" "bj_power_wms/ent/serialnumber" "bj_power_wms/internal/svc" ) // 半成品 / 包装 / 台账 相关(盘点见 stocktake.go) // semiInboundHandler 半成品入库(携带已完成工序) func semiInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req struct { Sn string `json:"sn"` MaterialCode string `json:"materialCode"` CompletedProcess string `json:"completedProcess"` ZoneCode string `json:"zoneCode"` OrderNo string `json:"orderNo"` Operator string `json:"operator"` } if err := parseJSON(r, &req); err != nil { fail(w, http.StatusBadRequest, "参数错误") return } if req.Sn == "" || req.MaterialCode == "" { fail(w, http.StatusBadRequest, "sn 和 materialCode 必填") return } exists, err := ctx.EntClient.SemiFinished.Query(). Where(semifinished.SnEQ(req.Sn)). Exist(ctx0()) if err != nil { fail(w, http.StatusInternalServerError, err.Error()) return } if exists { fail(w, http.StatusConflict, "半成品已存在: "+req.Sn) return } rec, err := ctx.EntClient.SemiFinished.Create(). SetSn(req.Sn). SetMaterialCode(req.MaterialCode). SetNillableCompletedProcess(strPtr(req.CompletedProcess)). SetNillableZoneCode(strPtr(req.ZoneCode)). SetStatus("在库"). SetNillableOrderNo(strPtr(req.OrderNo)). Save(ctx0()) if err != nil { fail(w, http.StatusInternalServerError, err.Error()) return } // 同时记入 SN 台账(半成品也是精密件) ctx.EntClient.SerialNumber.Create(). SetSnCode(req.Sn). SetMaterialCode(req.MaterialCode). SetStatus("在库"). SetNillableCurrentZone(strPtr(req.ZoneCode)). SaveX(ctx0()) ok(w, rec) } } // semiOutboundHandler 半成品出库(重上线) func semiOutboundHandler(ctx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req struct { Sn string `json:"sn"` ZoneCode string `json:"zoneCode"` Operator string `json:"operator"` } if err := parseJSON(r, &req); err != nil { fail(w, http.StatusBadRequest, "参数错误") return } if req.Sn == "" { fail(w, http.StatusBadRequest, "sn 必填") return } rec, err := ctx.EntClient.SemiFinished.Query(). Where(semifinished.SnEQ(req.Sn)). Only(ctx0()) if err != nil { fail(w, http.StatusNotFound, "半成品不存在: "+req.Sn) return } if rec.Status != "在库" { fail(w, http.StatusConflict, "半成品不在库: "+rec.Status) return } ctx.EntClient.SemiFinished.UpdateOneID(rec.ID). SetStatus("出库"). ExecX(ctx0()) ctx.EntClient.SerialNumber.Update(). Where(serialnumber.SnCodeEQ(req.Sn)). SetStatus("出库"). ExecX(ctx0()) ok(w, map[string]any{"sn": req.Sn, "status": "出库"}) } } // querySemiHandler 半成品查询 func querySemiHandler(ctx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { page := atoi(r.URL.Query().Get("page"), 1) pageSize := atoi(r.URL.Query().Get("pageSize"), 20) materialCode := r.URL.Query().Get("materialCode") status := r.URL.Query().Get("status") q := ctx.EntClient.SemiFinished.Query() if materialCode != "" { q = q.Where(semifinished.MaterialCodeEQ(materialCode)) } if status != "" { q = q.Where(semifinished.StatusEQ(status)) } total, err := q.Count(ctx0()) if err != nil { fail(w, http.StatusInternalServerError, err.Error()) return } list, err := q.Order(ent.Desc("id")). Offset((page - 1) * pageSize).Limit(pageSize).All(ctx0()) if err != nil { fail(w, http.StatusInternalServerError, err.Error()) return } ok(w, map[string]any{ "total": total, "list": list, "page": page, "pageSize": pageSize, }) } } // packageBindHandler 包装绑定(箱号 ↔ SN) func packageBindHandler(ctx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req struct { BoxNo string `json:"boxNo"` SnList []string `json:"snList"` MaterialCode string `json:"materialCode"` Operator string `json:"operator"` } if err := parseJSON(r, &req); err != nil { fail(w, http.StatusBadRequest, "参数错误") return } if req.BoxNo == "" || len(req.SnList) == 0 { fail(w, http.StatusBadRequest, "boxNo 和 snList 必填") return } exists, err := ctx.EntClient.PackageBox.Query(). Where(packagebox.BoxNoEQ(req.BoxNo)). Exist(ctx0()) if err != nil { fail(w, http.StatusInternalServerError, err.Error()) return } if exists { fail(w, http.StatusConflict, "箱号已存在: "+req.BoxNo) return } // SN 列表序列化 snJSON := toJSON(req.SnList) pkg, err := ctx.EntClient.PackageBox.Create(). SetBoxNo(req.BoxNo). SetSnList(snJSON). SetNillableMaterialCode(strPtr(req.MaterialCode)). SetQuantity(len(req.SnList)). SetNillableOperator(strPtr(req.Operator)). Save(ctx0()) if err != nil { fail(w, http.StatusInternalServerError, err.Error()) return } ok(w, pkg) } } // toJSON 序列化任意值为 JSON 字符串 func toJSON(v any) string { b, err := json.Marshal(v) if err != nil { return "[]" } return string(b) } // queryPackageHandler 包装查询 func queryPackageHandler(ctx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { boxNo := r.URL.Query().Get("boxNo") page := atoi(r.URL.Query().Get("page"), 1) pageSize := atoi(r.URL.Query().Get("pageSize"), 20) q := ctx.EntClient.PackageBox.Query() if boxNo != "" { q = q.Where(packagebox.BoxNoContains(boxNo)) } total, err := q.Count(ctx0()) if err != nil { fail(w, http.StatusInternalServerError, err.Error()) return } list, err := q.Order(ent.Desc("id")). Offset((page - 1) * pageSize).Limit(pageSize).All(ctx0()) if err != nil { fail(w, http.StatusInternalServerError, err.Error()) return } ok(w, map[string]any{ "total": total, "list": list, "page": page, "pageSize": pageSize, }) } } // ledger 相关:queryLedgerHandler 工单物料台账查询 func queryLedgerHandler(ctx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orderNo := r.URL.Query().Get("orderNo") materialCode := r.URL.Query().Get("materialCode") page := atoi(r.URL.Query().Get("page"), 1) pageSize := atoi(r.URL.Query().Get("pageSize"), 20) q := ctx.EntClient.OrderMaterialLedger.Query() if orderNo != "" { q = q.Where(ordermaterialledger.OrderNoEQ(orderNo)) } if materialCode != "" { q = q.Where(ordermaterialledger.MaterialCodeEQ(materialCode)) } total, err := q.Count(ctx0()) if err != nil { fail(w, http.StatusInternalServerError, err.Error()) return } list, err := q.Order(ent.Desc("id")). Offset((page - 1) * pageSize).Limit(pageSize).All(ctx0()) if err != nil { fail(w, http.StatusInternalServerError, err.Error()) return } ok(w, map[string]any{ "total": total, "list": list, "page": page, "pageSize": pageSize, }) } }