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 }