feat: product number

This commit is contained in:
zzw
2026-08-25 18:11:28 +08:00
parent 13ea690874
commit 0ca3f6d84f
13 changed files with 481 additions and 52 deletions
+11
View File
@@ -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"`
@@ -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)
}
@@ -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
}
@@ -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
}
@@ -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)
}
+31
View File
@@ -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",
}
}