feat: 完成客户第12条需求+多系统改造
1. 新增预警表添加工单号字段,支持按工单号检索预警 2. 添加工单过滤在制品/绩效报表/预警中心查询 3. 补全WMS台账字段口径与权限配置 4. 修复备料单与数量不符处理流程 5. 新增配送进度/库位联动/自动出库功能 6. 修复AGV配送状态更新逻辑 7. 优化退料与库存管理细节
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"bj_power_wms/ent"
|
||||
"bj_power_wms/ent/inventory"
|
||||
"bj_power_wms/ent/zone"
|
||||
"bj_power_wms/internal/svc"
|
||||
)
|
||||
@@ -299,6 +300,59 @@ func updateZoneNodeHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
// listZonesForPicker 库位下拉(兼容 + 层级两用):
|
||||
// - 不带 level:返回所有启用位置号(level4)扁平结构(兼容 Outbound/Stocktake/Inventory 旧调用)
|
||||
// - 带 level:返回该层级节点(用于入库页区域→货架→层→位置 级联下拉)
|
||||
// locKey 四级货位比较键:区域/货架忽略大小写(存量数据存在 z01/Z01 混用),层/位置原样。
|
||||
func locKey(zoneCode, shelfNo, layerNo, positionNo string) string {
|
||||
return strings.ToLower(strings.TrimSpace(zoneCode)) + "|" +
|
||||
strings.ToLower(strings.TrimSpace(shelfNo)) + "|" +
|
||||
strings.TrimSpace(layerNo) + "|" + strings.TrimSpace(positionNo)
|
||||
}
|
||||
|
||||
// vacantZoneHandler 同区空位推荐:返回指定区域(不传 zoneCode 则不限区域)内「未被库存占用」的位置节点(level=4)。
|
||||
// 用途:入库选中物料后,若该物料无历史库位(新物料),自动推荐同区空位,替代人工逐个挑选货架/层/位置。
|
||||
// 占用判定:inventories 中 quantity>0 且 status 非「出库/报废」的记录,其四级货位视为已占用。
|
||||
func vacantZoneHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
wantZone := strings.ToLower(strings.TrimSpace(r.URL.Query().Get("zoneCode")))
|
||||
limit := atoi(r.URL.Query().Get("limit"), 20)
|
||||
if limit <= 0 || limit > 200 {
|
||||
limit = 20
|
||||
}
|
||||
rows, err := ctx.EntClient.Zone.Query().
|
||||
Where(zone.LevelEQ(zoneLevelPos), zone.StatusEQ("启用")).
|
||||
Order(ent.Asc("zone_code"), ent.Asc("shelf_no"), ent.Asc("layer_no"), ent.Asc("code")).
|
||||
All(ctx0())
|
||||
if err != nil {
|
||||
fail(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
occupied := map[string]bool{}
|
||||
if invs, ierr := ctx.EntClient.Inventory.Query().
|
||||
Where(inventory.QuantityGT(0), inventory.StatusNotIn("出库", "报废")).
|
||||
All(ctx0()); ierr == nil {
|
||||
for _, iv := range invs {
|
||||
occupied[locKey(iv.ZoneCode, iv.ShelfNo, iv.LayerNo, iv.PositionNo)] = true
|
||||
}
|
||||
}
|
||||
list := make([]map[string]any, 0, limit)
|
||||
for _, z := range rows {
|
||||
if wantZone != "" && strings.ToLower(z.ZoneCode) != wantZone {
|
||||
continue
|
||||
}
|
||||
if occupied[locKey(z.ZoneCode, z.ShelfNo, z.LayerNo, z.PositionNo)] {
|
||||
continue
|
||||
}
|
||||
list = append(list, map[string]any{
|
||||
"zoneCode": z.ZoneCode, "zoneName": z.ZoneName, "shelfNo": z.ShelfNo,
|
||||
"layerNo": z.LayerNo, "positionNo": z.PositionNo, "name": z.Name, "code": z.Code,
|
||||
})
|
||||
if len(list) >= limit {
|
||||
break
|
||||
}
|
||||
}
|
||||
ok(w, list)
|
||||
}
|
||||
}
|
||||
|
||||
func listZonesForPicker(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
level := atoi(r.URL.Query().Get("level"), 0)
|
||||
|
||||
Reference in New Issue
Block a user