本次重构删除原有BOM物料清单表,改用工单工艺组合×工艺物料清单作为唯一用料来源;新增系统基础设置表支持WMS地址、日志保留天数等配置,新增虚拟工位作业管理后台接口与前端页签控制功能,同时优化工位号校验逻辑、事件日志自动清理与工单用料查询能力。
99 lines
2.9 KiB
Go
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
|
|
}
|