Files
bj_power/bj_power_mes/internal/logic/usage.go
T
SunYF f274da044c feat: 重构BOM架构,新增基础设置与虚拟工位管理功能
本次重构删除原有BOM物料清单表,改用工单工艺组合×工艺物料清单作为唯一用料来源;新增系统基础设置表支持WMS地址、日志保留天数等配置,新增虚拟工位作业管理后台接口与前端页签控制功能,同时优化工位号校验逻辑、事件日志自动清理与工单用料查询能力。
2026-09-23 11:41:28 +08:00

99 lines
2.9 KiB
Go

package logic
import (
"context"
"errors"
"sort"
"bj_power_mes/ent"
"bj_power_mes/ent/flowmaterial"
"bj_power_mes/ent/workorder"
)
// UsageRow 工单的单台用料行(BOM 已删除:用料唯一来源 = 工单工艺组合条目 × 工艺物料清单)。
// 同一物料出现在组合中多个工艺时合并累加;同一成品不同工单可用不同工艺,物料跟着工单走。
type UsageRow struct {
MaterialCode string `json:"materialCode"`
MaterialName string `json:"materialName"`
Spec string `json:"spec"`
Unit string `json:"unit"`
ManageMode string `json:"manageMode"`
UnitQty float64 `json:"unitQty"` // 单台净用量(跨工艺累加)
LossRate float64 `json:"lossRate"` // 综合损耗率%(按各行损耗加权折算,仅供展示)
EffQty float64 `json:"effQty"` // 单台含损耗用量 = Σ 行单台用量×(1+损耗率/100),参与计算
}
// GetOrderUsage 按工单号查询单台用料(工位终端上线位领料确认 / 管理后台展示用)
func (s *Service) GetOrderUsage(ctx context.Context, orderNo string) ([]UsageRow, error) {
if orderNo == "" {
return []UsageRow{}, nil
}
wo, err := s.ctx.EntClient.WorkOrder.Query().
Where(workorder.WorkOrderNo(orderNo)).First(ctx)
if err != nil {
return nil, errors.New("工单不存在: " + orderNo)
}
return s.WorkOrderUnitUsage(ctx, wo), nil
}
// WorkOrderUnitUsage 汇总工单的单台用料:工艺组合条目×flow_material,同物料合并。
// 组合为空或工艺均无物料时返回空切片。
func (s *Service) WorkOrderUnitUsage(ctx context.Context, wo *ent.WorkOrder) []UsageRow {
if wo == nil {
return nil
}
items, _ := RouteStationsFromWO(ctx, s.ctx.EntClient, wo)
if len(items) == 0 {
return nil
}
idSet := map[int]bool{}
for _, it := range items {
idSet[it.FlowId] = true
}
ids := make([]int, 0, len(idSet))
for id := range idSet {
ids = append(ids, id)
}
fms, err := s.ctx.EntClient.FlowMaterial.Query().
Where(flowmaterial.FlowIdIn(ids...)).All(ctx)
if err != nil {
return nil
}
byCode := map[string]*UsageRow{}
for _, fm := range fms {
if fm.MaterialCode == "" {
continue
}
r, ok := byCode[fm.MaterialCode]
if !ok {
r = &UsageRow{
MaterialCode: fm.MaterialCode, MaterialName: fm.MaterialName,
Spec: fm.Spec, Unit: fm.Unit, ManageMode: fm.ManageMode,
}
byCode[fm.MaterialCode] = r
}
if r.MaterialName == "" {
r.MaterialName = fm.MaterialName
}
if r.Unit == "" {
r.Unit = fm.Unit
}
r.UnitQty += fm.UnitQty
r.EffQty += fm.UnitQty * (1 + fm.LossRate/100)
}
codes := make([]string, 0, len(byCode))
for c := range byCode {
codes = append(codes, c)
}
sort.Strings(codes)
out := make([]UsageRow, 0, len(codes))
for _, c := range codes {
r := byCode[c]
if r.UnitQty > 0 {
r.LossRate = (r.EffQty/r.UnitQty - 1) * 100
}
out = append(out, *r)
}
return out
}