package logic import ( "context" "errors" "strconv" "muyu-apiserver/model" "muyu-apiserver/pkg/metrics" "muyu-apiserver/pkg/tenantctx" "muyu-apiserver/pkg/uid" "muyu-apiserver/rpc/inventory/internal/svc" "muyu-apiserver/rpc/inventory/pb" "github.com/zeromicro/go-zero/core/logx" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) type SavePansLogic struct { ctx context.Context svcCtx *svc.ServiceContext logx.Logger } func NewSavePansLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SavePansLogic { return &SavePansLogic{ ctx: ctx, svcCtx: svcCtx, Logger: logx.WithContext(ctx), } } func (l *SavePansLogic) SavePans(in *pb.SavePansReq) (*pb.Empty, error) { tenantId := tenantctx.ExtractTenantId(l.ctx) product, err := l.svcCtx.ProductModel.FindOneByProductId(l.ctx, in.ProductId) if err != nil || product.TenantId != tenantId { return nil, status.Error(codes.NotFound, "product not found") } defaultBatch, err := l.svcCtx.ProductBatchModel.FindLatestByProductId(l.ctx, tenantId, in.ProductId) if err != nil { if !errors.Is(err, model.ErrNotFound) { return nil, status.Error(codes.Internal, err.Error()) } defaultBatch = &model.InvProductBatch{ BatchId: uid.Generate(), TenantId: tenantId, ProductId: in.ProductId, BatchNo: product.ProductCode + "-B001", Status: 1, } if err := batchInputToModelFields(nil, defaultBatch); err != nil { return nil, status.Error(codes.InvalidArgument, err.Error()) } if _, err := l.svcCtx.ProductBatchModel.Insert(l.ctx, defaultBatch); err != nil { return nil, status.Error(codes.Internal, err.Error()) } } var totalLengthM float64 var totalBolts int type panBoltSet struct { panId string bolts []*model.InvProductBolt } boltsByPan := make([]panBoltSet, 0, len(in.Pans)) pans := make([]*model.InvProductPan, 0, len(in.Pans)) for i, panInput := range in.Pans { panId := uid.Generate() batchId := panInput.BatchId if batchId == "" { batchId = defaultBatch.BatchId } if _, err := l.svcCtx.ProductBatchModel.FindOneByProductAndBatchId(l.ctx, tenantId, in.ProductId, batchId); err != nil { return nil, status.Error(codes.InvalidArgument, "批次不存在或不属于该产品") } pans = append(pans, &model.InvProductPan{ PanId: panId, ProductId: in.ProductId, BatchId: batchId, Name: panInput.Name, Position: panInput.Position, SortOrder: int64(i + 1), TenantId: tenantId, }) if len(panInput.BoltLengths) > 0 { bolts := make([]*model.InvProductBolt, 0, len(panInput.BoltLengths)) for j, lengthStr := range panInput.BoltLengths { lengthM, _ := strconv.ParseFloat(lengthStr, 64) totalLengthM += lengthM bolts = append(bolts, &model.InvProductBolt{ BoltId: uid.Generate(), PanId: panId, LengthM: lengthM, Color: product.Color, SortOrder: int64(j + 1), TenantId: tenantId, }) } totalBolts += len(panInput.BoltLengths) boltsByPan = append(boltsByPan, panBoltSet{panId: panId, bolts: bolts}) } } if err := l.svcCtx.BoltModel.DeleteByProductId(l.ctx, in.ProductId); err != nil { return nil, status.Error(codes.Internal, err.Error()) } if err := l.svcCtx.PanModel.BulkReplace(l.ctx, in.ProductId, tenantId, pans); err != nil { return nil, status.Error(codes.Internal, err.Error()) } for _, item := range boltsByPan { if err := l.svcCtx.BoltModel.BulkReplace(l.ctx, item.panId, tenantId, item.bolts); err != nil { return nil, status.Error(codes.Internal, err.Error()) } } metrics.PansSavedTotal.WithLabelValues(tenantId, in.ProductId).Inc() if totalLengthM > 0 { productName := l.resolveProductName(in.ProductId) color := l.resolveProductColor(in.ProductId) metrics.InboundLengthMetersTotal.WithLabelValues(tenantId, productName, color, "save_pans").Add(totalLengthM) } if totalBolts > 0 { metrics.InboundBoltsTotal.WithLabelValues(tenantId, "save_pans").Add(float64(totalBolts)) } return &pb.Empty{}, nil } func (l *SavePansLogic) resolveProductName(productId string) string { p, err := l.svcCtx.ProductModel.FindOneByProductId(l.ctx, productId) if err != nil { return "unknown" } return p.ProductName } func (l *SavePansLogic) resolveProductColor(productId string) string { p, err := l.svcCtx.ProductModel.FindOneByProductId(l.ctx, productId) if err != nil { return "unknown" } return p.Color }