From 0ca3f6d84fa656fdba01cd0667d1ce269f1d11da Mon Sep 17 00:00:00 2001 From: zzw <1464003642@qq.com> Date: Tue, 25 Aug 2026 18:11:28 +0800 Subject: [PATCH] feat: product number --- pkg/utils/status.go | 1 + rpc/product/pb/product.pb.go | 227 ++++++++++++++---- rpc/product/pb/product_grpc.pb.go | 84 ++++++- rpc/product/product.pb | Bin 18390 -> 19011 bytes rpc/product/product.proto | 24 ++ services/chore/internal/logic/policyLogic.go | 2 +- services/chore/run.toml | 4 +- services/product/internal/dao/product.go | 11 + .../product/internal/logic/numberAddLogic.go | 41 ++++ .../product/internal/logic/numberLogic.go | 80 ++++++ .../product/internal/model/product_model.go | 18 ++ .../product/internal/server/productserver.go | 10 + services/product/validator/validator.go | 31 +++ 13 files changed, 481 insertions(+), 52 deletions(-) create mode 100644 services/product/internal/logic/numberAddLogic.go create mode 100644 services/product/internal/logic/numberLogic.go diff --git a/pkg/utils/status.go b/pkg/utils/status.go index a53ec20..a3049f6 100644 --- a/pkg/utils/status.go +++ b/pkg/utils/status.go @@ -106,6 +106,7 @@ var ( // ErrorNotFund 数据类 ErrorFormatDataError = Status{Code: 11010, Msg: "格式化数据出错"} + ErrorStockNotEnough = Status{Code: 11014, Msg: "库存不足"} // —————————————————————————————————————————————————————————————————————————————————————— diff --git a/rpc/product/pb/product.pb.go b/rpc/product/pb/product.pb.go index f01256a..c80636c 100644 --- a/rpc/product/pb/product.pb.go +++ b/rpc/product/pb/product.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v4.25.8 +// protoc v3.19.4 // source: product/product.proto package product @@ -1069,6 +1069,119 @@ func (x *EditSusceptibleReq) GetType() uint32 { return 0 } +// type: 1 增加, 2 减少;number 为变更数量 +type NumberReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Type uint32 `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"` + Number uint32 `protobuf:"varint,3,opt,name=number,proto3" json:"number,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NumberReq) Reset() { + *x = NumberReq{} + mi := &file_product_product_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NumberReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NumberReq) ProtoMessage() {} + +func (x *NumberReq) ProtoReflect() protoreflect.Message { + mi := &file_product_product_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NumberReq.ProtoReflect.Descriptor instead. +func (*NumberReq) Descriptor() ([]byte, []int) { + return file_product_product_proto_rawDescGZIP(), []int{13} +} + +func (x *NumberReq) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *NumberReq) GetType() uint32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *NumberReq) GetNumber() uint32 { + if x != nil { + return x.Number + } + return 0 +} + +type NumberAddReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Number uint32 `protobuf:"varint,2,opt,name=number,proto3" json:"number,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NumberAddReq) Reset() { + *x = NumberAddReq{} + mi := &file_product_product_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NumberAddReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NumberAddReq) ProtoMessage() {} + +func (x *NumberAddReq) ProtoReflect() protoreflect.Message { + mi := &file_product_product_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NumberAddReq.ProtoReflect.Descriptor instead. +func (*NumberAddReq) Descriptor() ([]byte, []int) { + return file_product_product_proto_rawDescGZIP(), []int{14} +} + +func (x *NumberAddReq) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *NumberAddReq) GetNumber() uint32 { + if x != nil { + return x.Number + } + return 0 +} + type ItemsData struct { state protoimpl.MessageState `protogen:"open.v1"` Count int64 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"` @@ -1079,7 +1192,7 @@ type ItemsData struct { func (x *ItemsData) Reset() { *x = ItemsData{} - mi := &file_product_product_proto_msgTypes[13] + mi := &file_product_product_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1091,7 +1204,7 @@ func (x *ItemsData) String() string { func (*ItemsData) ProtoMessage() {} func (x *ItemsData) ProtoReflect() protoreflect.Message { - mi := &file_product_product_proto_msgTypes[13] + mi := &file_product_product_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1104,7 +1217,7 @@ func (x *ItemsData) ProtoReflect() protoreflect.Message { // Deprecated: Use ItemsData.ProtoReflect.Descriptor instead. func (*ItemsData) Descriptor() ([]byte, []int) { - return file_product_product_proto_rawDescGZIP(), []int{13} + return file_product_product_proto_rawDescGZIP(), []int{15} } func (x *ItemsData) GetCount() int64 { @@ -1131,7 +1244,7 @@ type VerifyItemsData struct { func (x *VerifyItemsData) Reset() { *x = VerifyItemsData{} - mi := &file_product_product_proto_msgTypes[14] + mi := &file_product_product_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1143,7 +1256,7 @@ func (x *VerifyItemsData) String() string { func (*VerifyItemsData) ProtoMessage() {} func (x *VerifyItemsData) ProtoReflect() protoreflect.Message { - mi := &file_product_product_proto_msgTypes[14] + mi := &file_product_product_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1156,7 +1269,7 @@ func (x *VerifyItemsData) ProtoReflect() protoreflect.Message { // Deprecated: Use VerifyItemsData.ProtoReflect.Descriptor instead. func (*VerifyItemsData) Descriptor() ([]byte, []int) { - return file_product_product_proto_rawDescGZIP(), []int{14} + return file_product_product_proto_rawDescGZIP(), []int{16} } func (x *VerifyItemsData) GetCount() int64 { @@ -1193,7 +1306,7 @@ type VerifyParams struct { func (x *VerifyParams) Reset() { *x = VerifyParams{} - mi := &file_product_product_proto_msgTypes[15] + mi := &file_product_product_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1205,7 +1318,7 @@ func (x *VerifyParams) String() string { func (*VerifyParams) ProtoMessage() {} func (x *VerifyParams) ProtoReflect() protoreflect.Message { - mi := &file_product_product_proto_msgTypes[15] + mi := &file_product_product_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1218,7 +1331,7 @@ func (x *VerifyParams) ProtoReflect() protoreflect.Message { // Deprecated: Use VerifyParams.ProtoReflect.Descriptor instead. func (*VerifyParams) Descriptor() ([]byte, []int) { - return file_product_product_proto_rawDescGZIP(), []int{15} + return file_product_product_proto_rawDescGZIP(), []int{17} } func (x *VerifyParams) GetId() int64 { @@ -1317,7 +1430,7 @@ type VerifyItem struct { func (x *VerifyItem) Reset() { *x = VerifyItem{} - mi := &file_product_product_proto_msgTypes[16] + mi := &file_product_product_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1329,7 +1442,7 @@ func (x *VerifyItem) String() string { func (*VerifyItem) ProtoMessage() {} func (x *VerifyItem) ProtoReflect() protoreflect.Message { - mi := &file_product_product_proto_msgTypes[16] + mi := &file_product_product_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1342,7 +1455,7 @@ func (x *VerifyItem) ProtoReflect() protoreflect.Message { // Deprecated: Use VerifyItem.ProtoReflect.Descriptor instead. func (*VerifyItem) Descriptor() ([]byte, []int) { - return file_product_product_proto_rawDescGZIP(), []int{16} + return file_product_product_proto_rawDescGZIP(), []int{18} } func (x *VerifyItem) GetName() string { @@ -1383,7 +1496,7 @@ type NameItem struct { func (x *NameItem) Reset() { *x = NameItem{} - mi := &file_product_product_proto_msgTypes[17] + mi := &file_product_product_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1395,7 +1508,7 @@ func (x *NameItem) String() string { func (*NameItem) ProtoMessage() {} func (x *NameItem) ProtoReflect() protoreflect.Message { - mi := &file_product_product_proto_msgTypes[17] + mi := &file_product_product_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1408,7 +1521,7 @@ func (x *NameItem) ProtoReflect() protoreflect.Message { // Deprecated: Use NameItem.ProtoReflect.Descriptor instead. func (*NameItem) Descriptor() ([]byte, []int) { - return file_product_product_proto_rawDescGZIP(), []int{17} + return file_product_product_proto_rawDescGZIP(), []int{19} } func (x *NameItem) GetId() int64 { @@ -1469,7 +1582,7 @@ type Item struct { func (x *Item) Reset() { *x = Item{} - mi := &file_product_product_proto_msgTypes[18] + mi := &file_product_product_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1481,7 +1594,7 @@ func (x *Item) String() string { func (*Item) ProtoMessage() {} func (x *Item) ProtoReflect() protoreflect.Message { - mi := &file_product_product_proto_msgTypes[18] + mi := &file_product_product_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1494,7 +1607,7 @@ func (x *Item) ProtoReflect() protoreflect.Message { // Deprecated: Use Item.ProtoReflect.Descriptor instead. func (*Item) Descriptor() ([]byte, []int) { - return file_product_product_proto_rawDescGZIP(), []int{18} + return file_product_product_proto_rawDescGZIP(), []int{20} } func (x *Item) GetId() int64 { @@ -1860,7 +1973,14 @@ const file_product_product_proto_rawDesc = "" + "\n" + "box_number\x18\n" + " \x01(\x01R\tboxNumber\x12\x12\n" + - "\x04type\x18\v \x01(\rR\x04type\"F\n" + + "\x04type\x18\v \x01(\rR\x04type\"G\n" + + "\tNumberReq\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x12\n" + + "\x04type\x18\x02 \x01(\rR\x04type\x12\x16\n" + + "\x06number\x18\x03 \x01(\rR\x06number\"6\n" + + "\fNumberAddReq\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x16\n" + + "\x06number\x18\x02 \x01(\rR\x06number\"F\n" + "\tItemsData\x12\x14\n" + "\x05count\x18\x01 \x01(\x03R\x05count\x12#\n" + "\x05items\x18\x02 \x03(\v2\r.product.ItemR\x05items\"R\n" + @@ -1946,7 +2066,8 @@ const file_product_product_proto_rawDesc = "" + "\x06reason\x18\" \x01(\tR\x06reason\x12\x1d\n" + "\n" + "admin_name\x18# \x01(\tR\tadminName\x12\x12\n" + - "\x04edit\x18$ \x01(\rR\x04edit2\xa6\t\n" + + "\x04edit\x18$ \x01(\rR\x04edit2\xb3\n" + + "\n" + "\aProduct\x12M\n" + "\x06Create\x12\x12.product.CreateReq\x1a\x11.product.Response\"\x1c\x82\xd3\xe4\x93\x02\x16:\x01*\"\x11/admin/v3/product\x12N\n" + "\x04Info\x12\x10.product.InfoReq\x1a\x11.product.Response\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\x12\x16/admin/v3/product/info\x12K\n" + @@ -1960,7 +2081,9 @@ const file_product_product_proto_rawDesc = "" + "\tEditApply\x12\x15.product.EditApplyReq\x1a\x11.product.Response\"'\x82\xd3\xe4\x93\x02!:\x01*\"\x1c/admin/v3/product/edit/apply\x12V\n" + "\bEditBase\x12\x14.product.EditBaseReq\x1a\x11.product.Response\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\x1a\x16/admin/v3/product/base\x12k\n" + "\x0fEditSusceptible\x12\x1b.product.EditSusceptibleReq\x1a\x11.product.Response\"(\x82\xd3\xe4\x93\x02\":\x01*\x1a\x1d/admin/v3/product/susceptible\x12k\n" + - "\rEditApplyPass\x12\x19.product.EditApplyPassReq\x1a\x11.product.Response\",\x82\xd3\xe4\x93\x02&:\x01*\x1a!/admin/v3/product/edit/apply/passB\x1bZ\x19lone-services/rpc/productb\x06proto3" + "\rEditApplyPass\x12\x19.product.EditApplyPassReq\x1a\x11.product.Response\",\x82\xd3\xe4\x93\x02&:\x01*\x1a!/admin/v3/product/edit/apply/pass\x12/\n" + + "\x06Number\x12\x12.product.NumberReq\x1a\x11.product.Response\x12Z\n" + + "\tNumberAdd\x12\x15.product.NumberAddReq\x1a\x11.product.Response\"#\x82\xd3\xe4\x93\x02\x1d:\x01*\x1a\x18/admin/v3/product/numberB\x1bZ\x19lone-services/rpc/productb\x06proto3" var ( file_product_product_proto_rawDescOnce sync.Once @@ -1974,7 +2097,7 @@ func file_product_product_proto_rawDescGZIP() []byte { return file_product_product_proto_rawDescData } -var file_product_product_proto_msgTypes = make([]protoimpl.MessageInfo, 19) +var file_product_product_proto_msgTypes = make([]protoimpl.MessageInfo, 21) var file_product_product_proto_goTypes = []any{ (*Response)(nil), // 0: product.Response (*CreateReq)(nil), // 1: product.CreateReq @@ -1989,18 +2112,20 @@ var file_product_product_proto_goTypes = []any{ (*EditApplyPassReq)(nil), // 10: product.EditApplyPassReq (*EditBaseReq)(nil), // 11: product.EditBaseReq (*EditSusceptibleReq)(nil), // 12: product.EditSusceptibleReq - (*ItemsData)(nil), // 13: product.ItemsData - (*VerifyItemsData)(nil), // 14: product.VerifyItemsData - (*VerifyParams)(nil), // 15: product.VerifyParams - (*VerifyItem)(nil), // 16: product.VerifyItem - (*NameItem)(nil), // 17: product.NameItem - (*Item)(nil), // 18: product.Item + (*NumberReq)(nil), // 13: product.NumberReq + (*NumberAddReq)(nil), // 14: product.NumberAddReq + (*ItemsData)(nil), // 15: product.ItemsData + (*VerifyItemsData)(nil), // 16: product.VerifyItemsData + (*VerifyParams)(nil), // 17: product.VerifyParams + (*VerifyItem)(nil), // 18: product.VerifyItem + (*NameItem)(nil), // 19: product.NameItem + (*Item)(nil), // 20: product.Item } var file_product_product_proto_depIdxs = []int32{ - 18, // 0: product.ItemsData.items:type_name -> product.Item - 16, // 1: product.VerifyItemsData.items:type_name -> product.VerifyItem - 15, // 2: product.VerifyItem.new:type_name -> product.VerifyParams - 15, // 3: product.VerifyItem.old:type_name -> product.VerifyParams + 20, // 0: product.ItemsData.items:type_name -> product.Item + 18, // 1: product.VerifyItemsData.items:type_name -> product.VerifyItem + 17, // 2: product.VerifyItem.new:type_name -> product.VerifyParams + 17, // 3: product.VerifyItem.old:type_name -> product.VerifyParams 1, // 4: product.Product.Create:input_type -> product.CreateReq 2, // 5: product.Product.Info:input_type -> product.InfoReq 3, // 6: product.Product.Items:input_type -> product.ItemsReq @@ -2014,21 +2139,25 @@ var file_product_product_proto_depIdxs = []int32{ 11, // 14: product.Product.EditBase:input_type -> product.EditBaseReq 12, // 15: product.Product.EditSusceptible:input_type -> product.EditSusceptibleReq 10, // 16: product.Product.EditApplyPass:input_type -> product.EditApplyPassReq - 0, // 17: product.Product.Create:output_type -> product.Response - 0, // 18: product.Product.Info:output_type -> product.Response - 0, // 19: product.Product.Items:output_type -> product.Response - 0, // 20: product.Product.Names:output_type -> product.Response - 0, // 21: product.Product.Status:output_type -> product.Response - 0, // 22: product.Product.Sort:output_type -> product.Response - 0, // 23: product.Product.Verify:output_type -> product.Response - 0, // 24: product.Product.VerifyFirst:output_type -> product.Response - 0, // 25: product.Product.VerifySecond:output_type -> product.Response - 0, // 26: product.Product.EditApply:output_type -> product.Response - 0, // 27: product.Product.EditBase:output_type -> product.Response - 0, // 28: product.Product.EditSusceptible:output_type -> product.Response - 0, // 29: product.Product.EditApplyPass:output_type -> product.Response - 17, // [17:30] is the sub-list for method output_type - 4, // [4:17] is the sub-list for method input_type + 13, // 17: product.Product.Number:input_type -> product.NumberReq + 14, // 18: product.Product.NumberAdd:input_type -> product.NumberAddReq + 0, // 19: product.Product.Create:output_type -> product.Response + 0, // 20: product.Product.Info:output_type -> product.Response + 0, // 21: product.Product.Items:output_type -> product.Response + 0, // 22: product.Product.Names:output_type -> product.Response + 0, // 23: product.Product.Status:output_type -> product.Response + 0, // 24: product.Product.Sort:output_type -> product.Response + 0, // 25: product.Product.Verify:output_type -> product.Response + 0, // 26: product.Product.VerifyFirst:output_type -> product.Response + 0, // 27: product.Product.VerifySecond:output_type -> product.Response + 0, // 28: product.Product.EditApply:output_type -> product.Response + 0, // 29: product.Product.EditBase:output_type -> product.Response + 0, // 30: product.Product.EditSusceptible:output_type -> product.Response + 0, // 31: product.Product.EditApplyPass:output_type -> product.Response + 0, // 32: product.Product.Number:output_type -> product.Response + 0, // 33: product.Product.NumberAdd:output_type -> product.Response + 19, // [19:34] is the sub-list for method output_type + 4, // [4:19] is the sub-list for method input_type 4, // [4:4] is the sub-list for extension type_name 4, // [4:4] is the sub-list for extension extendee 0, // [0:4] is the sub-list for field type_name @@ -2045,7 +2174,7 @@ func file_product_product_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_product_product_proto_rawDesc), len(file_product_product_proto_rawDesc)), NumEnums: 0, - NumMessages: 19, + NumMessages: 21, NumExtensions: 0, NumServices: 1, }, diff --git a/rpc/product/pb/product_grpc.pb.go b/rpc/product/pb/product_grpc.pb.go index 0599a4c..17d192c 100644 --- a/rpc/product/pb/product_grpc.pb.go +++ b/rpc/product/pb/product_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.6.2 -// - protoc v4.25.8 +// - protoc v3.19.4 // source: product/product.proto package product @@ -32,6 +32,8 @@ const ( Product_EditBase_FullMethodName = "/product.Product/EditBase" Product_EditSusceptible_FullMethodName = "/product.Product/EditSusceptible" Product_EditApplyPass_FullMethodName = "/product.Product/EditApplyPass" + Product_Number_FullMethodName = "/product.Product/Number" + Product_NumberAdd_FullMethodName = "/product.Product/NumberAdd" ) // ProductClient is the client API for Product service. @@ -58,6 +60,11 @@ type ProductClient interface { EditSusceptible(ctx context.Context, in *EditSusceptibleReq, opts ...grpc.CallOption) (*Response, error) // TODO: 临时接口,企微编辑申请审批对接后删除 EditApplyPass(ctx context.Context, in *EditApplyPassReq, opts ...grpc.CallOption) (*Response, error) + // 增减库存 + // type: 1 增加, 2 减少 + Number(ctx context.Context, in *NumberReq, opts ...grpc.CallOption) (*Response, error) + // 增加库存 + NumberAdd(ctx context.Context, in *NumberAddReq, opts ...grpc.CallOption) (*Response, error) } type productClient struct { @@ -198,6 +205,26 @@ func (c *productClient) EditApplyPass(ctx context.Context, in *EditApplyPassReq, return out, nil } +func (c *productClient) Number(ctx context.Context, in *NumberReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Product_Number_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *productClient) NumberAdd(ctx context.Context, in *NumberAddReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Product_NumberAdd_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // ProductServer is the server API for Product service. // All implementations must embed UnimplementedProductServer // for forward compatibility. @@ -222,6 +249,11 @@ type ProductServer interface { EditSusceptible(context.Context, *EditSusceptibleReq) (*Response, error) // TODO: 临时接口,企微编辑申请审批对接后删除 EditApplyPass(context.Context, *EditApplyPassReq) (*Response, error) + // 增减库存 + // type: 1 增加, 2 减少 + Number(context.Context, *NumberReq) (*Response, error) + // 增加库存 + NumberAdd(context.Context, *NumberAddReq) (*Response, error) mustEmbedUnimplementedProductServer() } @@ -271,6 +303,12 @@ func (UnimplementedProductServer) EditSusceptible(context.Context, *EditSuscepti func (UnimplementedProductServer) EditApplyPass(context.Context, *EditApplyPassReq) (*Response, error) { return nil, status.Error(codes.Unimplemented, "method EditApplyPass not implemented") } +func (UnimplementedProductServer) Number(context.Context, *NumberReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method Number not implemented") +} +func (UnimplementedProductServer) NumberAdd(context.Context, *NumberAddReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method NumberAdd not implemented") +} func (UnimplementedProductServer) mustEmbedUnimplementedProductServer() {} func (UnimplementedProductServer) testEmbeddedByValue() {} @@ -526,6 +564,42 @@ func _Product_EditApplyPass_Handler(srv interface{}, ctx context.Context, dec fu return interceptor(ctx, in, info, handler) } +func _Product_Number_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(NumberReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProductServer).Number(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Product_Number_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProductServer).Number(ctx, req.(*NumberReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Product_NumberAdd_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(NumberAddReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProductServer).NumberAdd(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Product_NumberAdd_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProductServer).NumberAdd(ctx, req.(*NumberAddReq)) + } + return interceptor(ctx, in, info, handler) +} + // Product_ServiceDesc is the grpc.ServiceDesc for Product service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -585,6 +659,14 @@ var Product_ServiceDesc = grpc.ServiceDesc{ MethodName: "EditApplyPass", Handler: _Product_EditApplyPass_Handler, }, + { + MethodName: "Number", + Handler: _Product_Number_Handler, + }, + { + MethodName: "NumberAdd", + Handler: _Product_NumberAdd_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "product/product.proto", diff --git a/rpc/product/product.pb b/rpc/product/product.pb index 04602bce9a79cd1c7f95ce0b2fd0ddcc5c2ac520..b223d3f9f3d0ac9da1c6d6bd3193d819d140a135 100644 GIT binary patch delta 766 zcmccC&vk8o36o!aHAlmnQ~wzS8bPE~u243FFJz*ZRGOxj zl3JWxlvz-cU!+%N2oi};%gjlQM+nCkrN$FzI(~@-OvZ7}r-rYI3ed7L0pcLvHeKjdXd4 z;zf*{LM(p%ey$QN?28z=h1kMegFM|LC7w@i)J&FvsSy$4_i^=e5Alc(2y%7vjBs_4 zXqluH2QxBGOMP><)-%TXZbqQ}0^NR6O^iaaK&BA8UO|#xazTL;ODqM0l{*7fdjb_BqUZt>m!NxUUh3w<`U)&e|1~#1HFo9Tap&UnE6q(x zEec94oMbP;R#I7zD#0|l-%M1BS%Fc5H;63{EUje5#RF03n36L2p1HUPL|lRiS=DAu zn+I%6o4Gb~J1=9A7SiWpgXj?ghDuR>N@;S59zW0bd+%*7MTLoqS delta 260 zcmX>+h4ETH#B+9#k{6TjXk<_J)s$m} z@Uk>BfI5I`{QUh~!Rmp!!(4+r-6G*SK58b*EMgQ9;`ed&a}V)|4+wH~^Nau+4>6=b zD{k@?Ep>>In}2CNXJlvNc)>2v?YB8kmz#-cE7Rs`eGNu5A4nQ%vM_yA-|S-Q%CVWt U?mipSGS1DfU6!#-mh(~t08z_S!vFvP diff --git a/rpc/product/product.proto b/rpc/product/product.proto index 82766d9..379d348 100644 --- a/rpc/product/product.proto +++ b/rpc/product/product.proto @@ -92,6 +92,18 @@ service Product { body: "*" }; } + + // 增减库存 + // type: 1 增加, 2 减少 + rpc Number(NumberReq) returns (Response); + + // 增加库存 + rpc NumberAdd(NumberAddReq) returns (Response) { + option (google.api.http) = { + put: "/admin/v3/product/number" + body: "*" + }; + } } message Response { @@ -207,6 +219,18 @@ message EditSusceptibleReq { uint32 type = 11; } +// type: 1 增加, 2 减少;number 为变更数量 +message NumberReq { + int64 id = 1; + uint32 type = 2; + uint32 number = 3; +} + +message NumberAddReq { + int64 id = 1; + uint32 number = 2; +} + message ItemsData { int64 count = 1; repeated Item items = 2; diff --git a/services/chore/internal/logic/policyLogic.go b/services/chore/internal/logic/policyLogic.go index 2268f83..b880765 100644 --- a/services/chore/internal/logic/policyLogic.go +++ b/services/chore/internal/logic/policyLogic.go @@ -101,7 +101,7 @@ func (l *PolicyLogic) Policy(in *chore.PolicyReq) (*chore.Response, error) { region = "oss-cn-hangzhou" } if endpoint == utils.StringEmpty { - endpoint = "https://lone-images.oss-accelerate.aliyuncs.com" + endpoint = "https://oss-accelerate.aliyuncs.com" } if host == utils.StringEmpty { host = "https://images.ailuowan.com" diff --git a/services/chore/run.toml b/services/chore/run.toml index b9f2988..b6bc01d 100644 --- a/services/chore/run.toml +++ b/services/chore/run.toml @@ -22,7 +22,9 @@ roleSessionName = "oss-upload" region = "oss-cn-hangzhou" bucketName = "lone-images" - endpoint = "https://lone-images.oss-accelerate.aliyuncs.com" + # SDK 会拼成 {bucket}.{endpoint},这里不要再带 bucket 名 + # 错误示例: lone-images.oss-accelerate... → 实际请求 lone-images.lone-images.oss-accelerate... + endpoint = "https://oss-accelerate.aliyuncs.com" host = "https://images.ailuowan.com" dir = "upload/" expireSeconds = 3600 diff --git a/services/product/internal/dao/product.go b/services/product/internal/dao/product.go index ac63779..75d64fc 100644 --- a/services/product/internal/dao/product.go +++ b/services/product/internal/dao/product.go @@ -11,6 +11,12 @@ const ( ProductTryName = "多次试用" ) +// 库存变更类型(服务间 Number 接口) +const ( + NumberTypeAdd uint32 = 1 // 增加 + NumberTypeSub uint32 = 2 // 减少 +) + // 销售模式 const ( ProductSalesModelOffline = 1 // 线下 @@ -109,6 +115,11 @@ type ProductCheckExist struct { Status uint8 `gorm:"column:status"` } +type ProductNumberInfo struct { + Id int `gorm:"column:id"` + Number uint `gorm:"column:number"` +} + type ProductVerify struct { Id int `json:"id"` Name string `json:"name,omitempty"` diff --git a/services/product/internal/logic/numberAddLogic.go b/services/product/internal/logic/numberAddLogic.go new file mode 100644 index 0000000..0824f27 --- /dev/null +++ b/services/product/internal/logic/numberAddLogic.go @@ -0,0 +1,41 @@ +package logic + +import ( + "context" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + product "lone-services/rpc/product/pb" + "lone-services/services/product/internal/dao" + "lone-services/services/product/internal/svc" + "lone-services/services/product/validator" + + "github.com/zeromicro/go-zero/core/logx" +) + +type NumberAddLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewNumberAddLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NumberAddLogic { + return &NumberAddLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *NumberAddLogic) NumberAdd(in *product.NumberAddReq) (*product.Response, error) { + var req validator.ProductNumberAddValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + + return changeProductNumber(l.Logger, req.Id, dao.NumberTypeAdd, req.Number) +} diff --git a/services/product/internal/logic/numberLogic.go b/services/product/internal/logic/numberLogic.go new file mode 100644 index 0000000..12eb893 --- /dev/null +++ b/services/product/internal/logic/numberLogic.go @@ -0,0 +1,80 @@ +package logic + +import ( + "context" + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + product "lone-services/rpc/product/pb" + "lone-services/services/product/internal/dao" + "lone-services/services/product/internal/model" + "lone-services/services/product/internal/svc" + "lone-services/services/product/validator" + "strconv" + + "github.com/zeromicro/go-zero/core/logx" +) + +type NumberLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewNumberLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NumberLogic { + return &NumberLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// Number 服务间增减库存:type=1 增加,type=2 减少 +func (l *NumberLogic) Number(in *product.NumberReq) (*product.Response, error) { + var req validator.ProductNumberValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + return changeProductNumber(l.Logger, req.Id, req.Type, req.Number) +} + +func changeProductNumber(logger logx.Logger, id int64, typ uint32, number uint32) (*product.Response, error) { + var info dao.ProductNumberInfo + w := modelbase.Params{ + Eq: map[string]string{"id": strconv.FormatInt(id, 10)}, + } + m := model.ProductModel{}.Init() + if err := m.GetOne(w, &info); err != nil { + logger.Errorf("product number get: %v", err) + return failResponse(utils.Fail), nil + } + if info.Id < 1 { + return failResponse(utils.ErrorNotFund), nil + } + + var ( + rows int64 + err error + ) + switch typ { + case dao.NumberTypeAdd: + rows, err = m.IncrNumber(id, number) + case dao.NumberTypeSub: + rows, err = m.DecrNumber(id, number) + default: + return failResponse(utils.ErrorParams), nil + } + if err != nil { + logger.Errorf("product number change: %v", err) + return failResponse(utils.Fail), nil + } + if rows < 1 { + if typ == dao.NumberTypeSub { + return failResponse(utils.ErrorStockNotEnough), nil + } + return failResponse(utils.Fail), nil + } + + return okResponse(utils.StringEmpty), nil +} diff --git a/services/product/internal/model/product_model.go b/services/product/internal/model/product_model.go index 8c31198..ee735e2 100644 --- a/services/product/internal/model/product_model.go +++ b/services/product/internal/model/product_model.go @@ -3,6 +3,8 @@ package model import ( "lone-services/pkg/modelbase" "lone-services/services/product/internal/dao" + + "gorm.io/gorm" ) type ProductModel struct { @@ -21,3 +23,19 @@ func (m ProductModel) Init() ProductModel { func (m ProductModel) Create(data *dao.ProductCreate) error { return m.Base.Create(data) } + +// IncrNumber 原子增加库存 +func (m ProductModel) IncrNumber(id int64, n uint32) (int64, error) { + ret := modelbase.DB().Table(m.TableName()). + Where("id = ?", id). + Update("number", gorm.Expr("number + ?", n)) + return ret.RowsAffected, ret.Error +} + +// DecrNumber 原子减少库存(库存不足时 RowsAffected=0) +func (m ProductModel) DecrNumber(id int64, n uint32) (int64, error) { + ret := modelbase.DB().Table(m.TableName()). + Where("id = ? AND number >= ?", id, n). + Update("number", gorm.Expr("number - ?", n)) + return ret.RowsAffected, ret.Error +} diff --git a/services/product/internal/server/productserver.go b/services/product/internal/server/productserver.go index f93ca51..bdd145a 100644 --- a/services/product/internal/server/productserver.go +++ b/services/product/internal/server/productserver.go @@ -85,3 +85,13 @@ func (s *ProductServer) EditSusceptible(ctx context.Context, in *product.EditSus l := logic.NewEditSusceptibleLogic(ctx, s.svcCtx) return l.EditSusceptible(in) } + +func (s *ProductServer) Number(ctx context.Context, in *product.NumberReq) (*product.Response, error) { + l := logic.NewNumberLogic(ctx, s.svcCtx) + return l.Number(in) +} + +func (s *ProductServer) NumberAdd(ctx context.Context, in *product.NumberAddReq) (*product.Response, error) { + l := logic.NewNumberAddLogic(ctx, s.svcCtx) + return l.NumberAdd(in) +} diff --git a/services/product/validator/validator.go b/services/product/validator/validator.go index 4975930..ef15af4 100644 --- a/services/product/validator/validator.go +++ b/services/product/validator/validator.go @@ -218,3 +218,34 @@ func (p ProductEditSusceptibleValidator) GetMessage() validate.ValidatorMessages "Type.oneof": "类型不对", } } + +type ProductNumberValidator struct { + Id int64 `validate:"required,gt=0"` + Type uint32 `validate:"required,oneof=1 2"` + Number uint32 `validate:"required,gt=0"` +} + +func (p ProductNumberValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Id.required": "ID不能为空", + "Id.gt": "ID必须大于0", + "Type.required": "类型不能为空", + "Type.oneof": "类型不对", + "Number.required": "数量不能为空", + "Number.gt": "数量必须大于0", + } +} + +type ProductNumberAddValidator struct { + Id int64 `validate:"required,gt=0"` + Number uint32 `validate:"required,gt=0"` +} + +func (p ProductNumberAddValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Id.required": "ID不能为空", + "Id.gt": "ID必须大于0", + "Number.required": "数量不能为空", + "Number.gt": "数量必须大于0", + } +}