Files
bj_power/bj_power_wms/internal/handler/misc.go
T

342 lines
9.7 KiB
Go
Raw Normal View History

2026-08-28 15:06:01 +08:00
package handler
import (
"encoding/json"
"net/http"
"strconv"
"strings"
2026-08-28 15:06:01 +08:00
"bj_power_wms/ent"
"bj_power_wms/ent/ordermaterialledger"
"bj_power_wms/ent/packagebox"
"bj_power_wms/ent/semifinished"
"bj_power_wms/internal/svc"
)
// 半成品 / 包装 / 台账 相关(盘点见 stocktake.go
// semiInboundHandler 半成品入库(携带已完成工序)
// 与 MES 闭环:MES 工位报工暂存退库时调用本接口,把半成品 SN 入 WMS 库。
// 为保持两系统解耦,materialCode 不强制要求——优先用请求传入,
// 其次按 SN 反查 WMS 序列号台账,都没有则留空(SN 本身即追溯锚点)。
2026-08-28 15:06:01 +08:00
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"`
DoneProcessCodes []int `json:"doneProcessCodes"`
2026-08-28 15:06:01 +08:00
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 == "" {
fail(w, http.StatusBadRequest, "sn 必填")
2026-08-28 15:06:01 +08:00
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
}
// 已完成工序:MES 传 doneProcessCodes([]int) 优先,否则用 completedProcess 字符串
completed := req.CompletedProcess
if len(req.DoneProcessCodes) > 0 {
parts := make([]string, 0, len(req.DoneProcessCodes))
for _, c := range req.DoneProcessCodes {
parts = append(parts, strconv.Itoa(c))
}
completed = strings.Join(parts, ",")
}
// 物料编码:以请求传入为准(半成品是独立固定业务类型,不依赖统一库存表)
materialCode := req.MaterialCode
2026-08-28 15:06:01 +08:00
rec, err := ctx.EntClient.SemiFinished.Create().
SetSn(req.Sn).
SetNillableMaterialCode(strPtr(materialCode)).
SetNillableCompletedProcess(strPtr(completed)).
2026-08-28 15:06:01 +08:00
SetNillableZoneCode(strPtr(req.ZoneCode)).
SetStatus("在库").
SetNillableOrderNo(strPtr(req.OrderNo)).
Save(ctx0())
if err != nil {
fail(w, http.StatusInternalServerError, err.Error())
return
}
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())
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),支持合同号
2026-08-28 15:06:01 +08:00
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"`
ContractNo string `json:"contractNo"`
2026-08-28 15:06:01 +08:00
Operator string `json:"operator"`
Remark string `json:"remark"`
2026-08-28 15:06:01 +08:00
}
if err := parseJSON(r, &req); err != nil {
fail(w, http.StatusBadRequest, "参数错误")
return
}
if req.BoxNo == "" || len(req.SnList) == 0 {
fail(w, http.StatusBadRequest, "箱号和 SN 清单必填")
2026-08-28 15:06:01 +08:00
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)).
SetNillableContractNo(strPtr(req.ContractNo)).
2026-08-28 15:06:01 +08:00
SetNillableOperator(strPtr(req.Operator)).
SetNillableRemark(strPtr(req.Remark)).
2026-08-28 15:06:01 +08:00
Save(ctx0())
if err != nil {
fail(w, http.StatusInternalServerError, err.Error())
return
}
ok(w, pkg)
}
}
// packageUpdateHandler 编辑装箱(重新装箱 SN / 修改合同号等)
func packageUpdateHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req struct {
ID int `json:"id"`
SnList []string `json:"snList"`
MaterialCode string `json:"materialCode"`
ContractNo string `json:"contractNo"`
Operator string `json:"operator"`
Remark string `json:"remark"`
}
if err := parseJSON(r, &req); err != nil || req.ID <= 0 {
fail(w, http.StatusBadRequest, "参数错误")
return
}
upd := ctx.EntClient.PackageBox.UpdateOneID(req.ID)
if len(req.SnList) > 0 {
upd.SetSnList(toJSON(req.SnList)).SetQuantity(len(req.SnList))
}
upd.SetNillableMaterialCode(strPtr(req.MaterialCode)).
SetNillableContractNo(strPtr(req.ContractNo)).
SetNillableOperator(strPtr(req.Operator)).
SetNillableRemark(strPtr(req.Remark))
pkg, err := upd.Save(ctx0())
if err != nil {
fail(w, http.StatusInternalServerError, "更新装箱失败: "+err.Error())
return
}
ok(w, pkg)
}
}
2026-08-28 15:06:01 +08:00
// toJSON 序列化任意值为 JSON 字符串
func toJSON(v any) string {
b, err := json.Marshal(v)
if err != nil {
return "[]"
}
return string(b)
}
// queryPackageHandler 装箱查询(多条件:箱号/合同号/操作人/物料/时间范围)
2026-08-28 15:06:01 +08:00
func queryPackageHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
boxNo := r.URL.Query().Get("boxNo")
contractNo := r.URL.Query().Get("contractNo")
operator := r.URL.Query().Get("operator")
materialCode := r.URL.Query().Get("materialCode")
startAt := r.URL.Query().Get("startAt")
endAt := r.URL.Query().Get("endAt")
2026-08-28 15:06:01 +08:00
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))
}
if contractNo != "" {
q = q.Where(packagebox.ContractNoContains(contractNo))
}
if operator != "" {
q = q.Where(packagebox.OperatorContains(operator))
}
if materialCode != "" {
q = q.Where(packagebox.MaterialCodeEQ(materialCode))
}
if startAt != "" {
start := atoi64(startAt, 0)
if start > 0 {
q = q.Where(packagebox.CreatedAtGTE(start))
}
}
if endAt != "" {
end := atoi64(endAt, 0)
if end > 0 {
q = q.Where(packagebox.CreatedAtLTE(end))
}
}
2026-08-28 15:06:01 +08:00
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,
})
}
}