feat(mes): 添加定时同步可生产数量到WMS及BOM项相关标准字段
- 在main.go中添加定时任务每10分钟同步可生产数量到WMS系统 - 为BomItem实体添加relatedStandard字段及相关CRUD方法 - 为InspectionRecord实体添加reportNo、materialCode、materialName等字段 - 更新ent schema确保新字段的验证和默认值设置 - 添加必要的数据库迁移和字段映射逻辑
This commit is contained in:
@@ -64,6 +64,9 @@ func createInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
Quantity int `json:"quantity"`
|
||||
SnList []string `json:"snList"`
|
||||
ZoneCode string `json:"zoneCode"`
|
||||
ShelfNo string `json:"shelfNo"`
|
||||
LayerNo string `json:"layerNo"`
|
||||
PositionNo string `json:"positionNo"`
|
||||
Operator string `json:"operator"`
|
||||
ProductionDate string `json:"productionDate"`
|
||||
Supplier string `json:"supplier"`
|
||||
@@ -77,7 +80,7 @@ func createInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
if req.MaterialCode == "" {
|
||||
fail(w, http.StatusBadRequest, "物料编码必填")
|
||||
fail(w, http.StatusBadRequest, "图号必填")
|
||||
return
|
||||
}
|
||||
if req.ZoneCode == "" {
|
||||
@@ -116,6 +119,21 @@ func createInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
|
||||
inboundNo := "IB" + uuid.NewString()[:12]
|
||||
|
||||
// 质量状态自动带出(客户诉求 问题记录 L129:入库记录增加 合格/不合格 列)
|
||||
// 按检测单号查最近一次检验结论:合格→合格;不合格且部分入库→部分;不合格→不合格;无记录→空(未关联)
|
||||
qualityStatus := ""
|
||||
if req.InspectionNo != "" {
|
||||
if rec, qerr := ctx.EntClient.InspectionRecord.Query().
|
||||
Where(inspectionrecord.InspectionNoEQ(req.InspectionNo)).
|
||||
Order(ent.Desc("created_at"), ent.Desc("id")).
|
||||
First(ctx0()); qerr == nil && rec != nil {
|
||||
qualityStatus = rec.Status
|
||||
if rec.Status == "不合格" && rec.DisposalType == "PARTIAL" {
|
||||
qualityStatus = "部分"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 开启事务:入库单 + 库存行 + 明细 原子提交
|
||||
tx, err := ctx.EntClient.Tx(ctx0())
|
||||
if err != nil {
|
||||
@@ -136,12 +154,16 @@ func createInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
SetNillableMaterialName(strPtr(m.Name)).
|
||||
SetManageMode(m.ManageMode).
|
||||
SetNillableZoneCode(strPtr(req.ZoneCode)).
|
||||
SetNillableShelfNo(strPtr(req.ShelfNo)).
|
||||
SetNillableLayerNo(strPtr(req.LayerNo)).
|
||||
SetNillablePositionNo(strPtr(req.PositionNo)).
|
||||
SetQuantity(0).
|
||||
SetNillableOperator(strPtr(req.Operator)).
|
||||
SetNillableRemark(strPtr(req.Remark)).
|
||||
SetInspectionNo(req.InspectionNo).
|
||||
SetOwnershipType(ownershipTypeOrNone(req.OwnershipType)).
|
||||
SetNillableOwnershipNo(strPtr(req.OwnershipNo)).
|
||||
SetNillableQualityStatus(strPtr(qualityStatus)).
|
||||
Save(ctx0())
|
||||
if err != nil {
|
||||
fail(w, http.StatusInternalServerError, "创建入库单失败: "+err.Error())
|
||||
@@ -159,7 +181,7 @@ func createInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
}
|
||||
batchNo := req.BatchNo
|
||||
if batchNo == "" {
|
||||
batchNo = genBatchNo(req.MaterialCode)
|
||||
batchNo = genBatchNo(ctx, req.MaterialCode)
|
||||
}
|
||||
qty := req.Quantity
|
||||
if qty <= 0 {
|
||||
@@ -189,6 +211,9 @@ func createInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
SetNillableSupplier(strPtr(req.Supplier)).
|
||||
SetQualityStatus("未检").
|
||||
SetNillableZoneCode(strPtr(req.ZoneCode)).
|
||||
SetNillableShelfNo(strPtr(req.ShelfNo)).
|
||||
SetNillableLayerNo(strPtr(req.LayerNo)).
|
||||
SetNillablePositionNo(strPtr(req.PositionNo)).
|
||||
SetStatus("在库").
|
||||
SetInboundNo(inboundNo).
|
||||
Save(ctx0()); err != nil {
|
||||
@@ -217,9 +242,10 @@ func createInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
for _, sn := range req.SnList {
|
||||
// 查重
|
||||
// 查重(P2-2):SN 全局唯一(一物一码)——不再按 manage_mode 分区隔离,
|
||||
// 避免同一 SN 在不同管理模式/物料下共存;DB 侧另有部分唯一索引 ux_inventories_sn_code 兜底。
|
||||
exists, _ := tx.Inventory.Query().
|
||||
Where(inventory.ManageModeEQ(2), inventory.SnCodeEQ(sn)).
|
||||
Where(inventory.SnCodeEQ(sn)).
|
||||
Exist(ctx0())
|
||||
if exists {
|
||||
fail(w, http.StatusConflict, "SN 已存在: "+sn)
|
||||
@@ -233,6 +259,9 @@ func createInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
SetQuantity(1).SetLockedQty(0).
|
||||
SetQualityStatus("未检").
|
||||
SetNillableZoneCode(strPtr(req.ZoneCode)).
|
||||
SetNillableShelfNo(strPtr(req.ShelfNo)).
|
||||
SetNillableLayerNo(strPtr(req.LayerNo)).
|
||||
SetNillablePositionNo(strPtr(req.PositionNo)).
|
||||
SetStatus("在库").
|
||||
SetInboundNo(inboundNo).
|
||||
Save(ctx0()); err != nil {
|
||||
@@ -428,15 +457,15 @@ func exportInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
rows := buildInboundRows(ctx, list)
|
||||
// xlsx 导出:格式化 = xlsx → 直接生成二进制文件;否则保持 JSON 兼容
|
||||
if r.URL.Query().Get("format") == "xlsx" {
|
||||
headers := []string{"入库单号", "物料编码", "物料名称", "类型", "数量", "区域", "操作人", "备注", "检测单号", "明细条数", "入库时间"}
|
||||
headers := []string{"入库单号", "图号", "物料名称", "类型", "数量", "区域", "库位", "归属单号", "检测单号", "质量状态", "操作人", "备注", "明细条数", "入库时间"}
|
||||
matrix := make([][]any, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
ib := row.InboundOrder
|
||||
matrix = append(matrix, []any{
|
||||
ib.InboundNo, ib.MaterialCode, ib.MaterialName,
|
||||
manageModeLabel(ib.ManageMode), ib.Quantity, ib.ZoneCode,
|
||||
manageModeLabel(ib.ManageMode), ib.Quantity, ib.ZoneCode, locLabel(ib.ZoneCode, ib.ShelfNo, ib.LayerNo, ib.PositionNo),
|
||||
ib.OwnershipNo, ib.InspectionNo, ib.QualityStatus,
|
||||
ib.Operator, ib.Remark, row.DetailCount,
|
||||
ib.InspectionNo,
|
||||
unixFmt(ib.CreatedAt),
|
||||
})
|
||||
}
|
||||
@@ -457,23 +486,24 @@ func ownershipTypeOrNone(v string) string {
|
||||
}
|
||||
}
|
||||
|
||||
// genBatchNo 生成批次号:日期 + 自增
|
||||
func genBatchNo(materialCode string) string {
|
||||
// TODO: 使用数据库序列或 Redis INCR 保证自增唯一
|
||||
// 暂用时间戳 + 随机后缀
|
||||
now := nowStr()
|
||||
return "B" + now + materialCodeSuffix(materialCode)
|
||||
}
|
||||
|
||||
func nowStr() string {
|
||||
// YYYYMMDDHHMMSS
|
||||
const layout = "20060102150405"
|
||||
return timeNow().Format(layout)
|
||||
}
|
||||
|
||||
func materialCodeSuffix(code string) string {
|
||||
if len(code) > 4 {
|
||||
code = code[len(code)-4:]
|
||||
// genBatchNo 生成批次号:物料编码-日期-流水号(客户诉求 问题记录 L88-92)。
|
||||
// 格式 {materialCode}-YYYYMMDD-{3位流水},流水号按"当日该物料已有最大流水+1"取,
|
||||
// 保证同物料同日不重号(跨物料因前缀不同天然不冲突)。可手填覆盖,非强制系统生成。
|
||||
func genBatchNo(ctx *svc.ServiceContext, materialCode string) string {
|
||||
day := timeNow().Format("20060102")
|
||||
prefix := materialCode + "-" + day + "-"
|
||||
// 查当日该物料已有批次中最大流水号
|
||||
maxSeq := 0
|
||||
rows, err := ctx.EntClient.Inventory.Query().
|
||||
Where(inventory.ManageModeEQ(1), inventory.BatchNoHasPrefix(prefix)).
|
||||
All(ctx0())
|
||||
if err == nil {
|
||||
for _, r := range rows {
|
||||
suffix := strings.TrimPrefix(r.BatchNo, prefix)
|
||||
if n, e := strconv.Atoi(suffix); e == nil && n > maxSeq {
|
||||
maxSeq = n
|
||||
}
|
||||
}
|
||||
}
|
||||
return code
|
||||
return fmt.Sprintf("%s%03d", prefix, maxSeq+1)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user