diff --git a/model/gmodel/fs_cart_logic.go b/model/gmodel/fs_cart_logic.go index 618a8d9b..34824d94 100755 --- a/model/gmodel/fs_cart_logic.go +++ b/model/gmodel/fs_cart_logic.go @@ -79,3 +79,11 @@ func (c *FsCartModel) GetAllByUserId(ctx context.Context, userId int64, sort str } return } + +func (c *FsCartModel) GetUserCartsByIds(ctx context.Context, userId int64, ids []int64) (resp []FsCart, err error) { + if userId <= 0 || len(ids) == 0 { + return + } + err = c.db.WithContext(ctx).Model(&FsCart{}).Where("`id` in (?) and `user_id` = ?", ids, userId).Find(&resp).Error + return resp, err +} diff --git a/model/gmodel/fs_product_price_logic.go b/model/gmodel/fs_product_price_logic.go index 88cf1530..b9e204cf 100755 --- a/model/gmodel/fs_product_price_logic.go +++ b/model/gmodel/fs_product_price_logic.go @@ -102,3 +102,14 @@ func (c *FsProductPriceModel) GetAllSelectBySizeId(ctx context.Context, sizeIds } return prices, err } +func (p *FsProductPriceModel) GetPriceListByIds(ctx context.Context, Ids []int64) (resp []FsProductPrice, err error) { + if len(Ids) == 0 { + return nil, nil + } + db := p.db.WithContext(ctx).Model(&FsProductPrice{}). + Where("`id` in (?)", Ids) + if err = db.Find(&resp).Error; err != nil { + return nil, err + } + return +} diff --git a/server/inventory/internal/logic/supplementlogic.go b/server/inventory/internal/logic/supplementlogic.go index ae981c8e..c7cb0df0 100644 --- a/server/inventory/internal/logic/supplementlogic.go +++ b/server/inventory/internal/logic/supplementlogic.go @@ -105,7 +105,7 @@ func (l *SupplementLogic) Supplement(req *types.SupplementReq, userinfo *auth.Us minByNum := math.Ceil(float64(req.Num) / float64(*productPriceInfo.EachBoxNum)) amount := step_price.GetCentStepPrice(int(minByNum), stepNum, stepPrice) + optionalPrice totalAmount := amount * req.Num - newOrderSn := id_generator.GenPickUpTrackNum() + newOrderSn := id_generator.GenSnNum() now := time.Now().Unix() deliveryMethod := int64(constants.DELIVERY_METHOD_CLOUD) isSup := int64(1) diff --git a/server/inventory/internal/logic/takelogic.go b/server/inventory/internal/logic/takelogic.go index c623c717..74faeea7 100644 --- a/server/inventory/internal/logic/takelogic.go +++ b/server/inventory/internal/logic/takelogic.go @@ -58,7 +58,7 @@ func (l *TakeLogic) Take(req *types.TakeReq, userinfo *auth.UserInfo) (resp *bas //提货单总单 addressInfoBytes, _ := json.Marshal(addressInfo) addressInfoJson := string(addressInfoBytes) - trackNum := id_generator.GenPickUpTrackNum() + trackNum := id_generator.GenSnNum() status := int64(constants.STATUS_ORDERD) now := time.Now().Unix() pickUpData := gmodel.FsCloudPickUp{ diff --git a/server/shopping-cart-confirmation/internal/handler/createorderhandler.go b/server/shopping-cart-confirmation/internal/handler/createorderhandler.go new file mode 100644 index 00000000..e06afabb --- /dev/null +++ b/server/shopping-cart-confirmation/internal/handler/createorderhandler.go @@ -0,0 +1,78 @@ +package handler + +import ( + "errors" + "net/http" + + "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/rest/httpx" + + "fusenapi/utils/auth" + "fusenapi/utils/basic" + + "fusenapi/server/shopping-cart-confirmation/internal/logic" + "fusenapi/server/shopping-cart-confirmation/internal/svc" + "fusenapi/server/shopping-cart-confirmation/internal/types" +) + +func CreateOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + + var ( + // 定义错误变量 + err error + // 定义用户信息变量 + userinfo *auth.UserInfo + ) + // 解析JWT token,并对空用户进行判断 + claims, err := svcCtx.ParseJwtToken(r) + // 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, // 返回401状态码,表示未授权 + Message: "unauthorized", // 返回未授权信息 + }) + logx.Info("unauthorized:", err.Error()) // 记录错误日志 + return + } + + if claims != nil { + // 从token中获取对应的用户信息 + userinfo, err = auth.GetUserInfoFormMapClaims(claims) + // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, + Message: "unauthorized", + }) + logx.Info("unauthorized:", err.Error()) + return + } + } else { + // 如果claims为nil,则认为用户身份为白板用户 + userinfo = &auth.UserInfo{UserId: 0, GuestId: 0} + } + + var req types.CreateOrderReq + // 如果端点有请求结构体,则使用httpx.Parse方法从HTTP请求体中解析请求数据 + if err := httpx.Parse(r, &req); err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 510, + Message: "parameter error", + }) + logx.Info(err) + return + } + // 创建一个业务逻辑层实例 + l := logic.NewCreateOrderLogic(r.Context(), svcCtx) + resp := l.CreateOrder(&req, userinfo) + // 如果响应不为nil,则使用httpx.OkJsonCtx方法返回JSON响应; + if resp != nil { + httpx.OkJsonCtx(r.Context(), w, resp) + } else { + err := errors.New("server logic is error, resp must not be nil") + httpx.ErrorCtx(r.Context(), w, err) + logx.Error(err) + } + } +} diff --git a/server/shopping-cart-confirmation/internal/handler/routes.go b/server/shopping-cart-confirmation/internal/handler/routes.go index c69baeaf..12b9e809 100644 --- a/server/shopping-cart-confirmation/internal/handler/routes.go +++ b/server/shopping-cart-confirmation/internal/handler/routes.go @@ -42,6 +42,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/cart/chang-order-method", Handler: ChangeOrderMethodHandler(serverCtx), }, + { + Method: http.MethodPost, + Path: "/cart/create-order", + Handler: CreateOrderHandler(serverCtx), + }, }, ) } diff --git a/server/shopping-cart-confirmation/internal/logic/createorderlogic.go b/server/shopping-cart-confirmation/internal/logic/createorderlogic.go new file mode 100644 index 00000000..74047060 --- /dev/null +++ b/server/shopping-cart-confirmation/internal/logic/createorderlogic.go @@ -0,0 +1,190 @@ +package logic + +import ( + "errors" + "fmt" + "fusenapi/model/gmodel" + "fusenapi/utils/auth" + "fusenapi/utils/basic" + "fusenapi/utils/format" + "fusenapi/utils/id_generator" + "fusenapi/utils/step_price" + "gorm.io/gorm" + "math" + "strings" + "time" + + "context" + + "fusenapi/server/shopping-cart-confirmation/internal/svc" + "fusenapi/server/shopping-cart-confirmation/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type CreateOrderLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewCreateOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateOrderLogic { + return &CreateOrderLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *CreateOrderLogic) CreateOrder(req *types.CreateOrderReq, userinfo *auth.UserInfo) (resp *basic.Response) { + if userinfo.GetIdType() != auth.IDTYPE_User { + return resp.SetStatusWithMessage(basic.CodeUnAuth, "please login first") + } + if len(req.Form) == 0 { + return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "err param form:can`t be empty") + } + cartIds := make([]int64, 0, len(req.Form)) + mapForm := make(map[int64]int) + for k, v := range req.Form { + cartIds = append(cartIds, v.Id) + mapForm[v.Id] = k + } + //获取购物车列表 + cartList, err := l.svcCtx.AllModels.FsCart.GetUserCartsByIds(l.ctx, userinfo.UserId, cartIds) + if err != nil { + logx.Error(err) + return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get cart list") + } + if len(cartList) != len(req.Form) { + return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "sorry,may be some one not belong to you") + } + priceIds := make([]int64, 0, len(cartList)) + optionalIds := make([]int64, 0, len(cartList)) + for _, v := range cartList { + priceIds = append(priceIds, *v.PriceId) + optionalIds = append(optionalIds, *v.OptionalId) + } + //获取价格 + priceList, err := l.svcCtx.AllModels.FsProductPrice.GetPriceListByIds(l.ctx, priceIds) + if err != nil { + logx.Error(err) + return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product price list") + } + mapPrice := make(map[int64]int) + for k, v := range priceList { + mapPrice[v.Id] = k + } + //获取附加项 + model3dList, err := l.svcCtx.AllModels.FsProductModel3d.GetAllByIdsWithoutStatus(l.ctx, optionalIds) + if err != nil { + logx.Error(err) + return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get 3d model list") + } + mapModel3d := make(map[int64]int) + for k, v := range model3dList { + mapModel3d[v.Id] = k + } + var ( + now = time.Now().Unix() + total int64 //总价 + ) + orderSn := id_generator.GenSnNum() + //开启事务 + err = l.svcCtx.MysqlConn.Transaction(func(tx *gorm.DB) error { + orderDetailTemplateModel := gmodel.NewFsOrderDetailTemplateModel(tx) + orderDetailModel := gmodel.NewFsOrderDetailModel(tx) + orderModel := gmodel.NewFsOrderModel(tx) + //订单数据 + deliveryMethod := int64(1) + orderCreateData := gmodel.FsOrder{ + Sn: &orderSn, + UserId: &userinfo.UserId, + Ctime: &now, + Utime: &now, + DeliveryMethod: &deliveryMethod, + } + if err = orderModel.Create(l.ctx, &orderCreateData); err != nil { + return err + } + for _, cart := range cartList { + priceIndex, ok := mapPrice[*cart.PriceId] + if !ok { + return errors.New(fmt.Sprintf("price info is not exists,id = %d", *cart.PriceId)) + } + //订单详情模板数据 + orderDetailTemplateSn, err := id_generator.GenSnowFlakeId() + if err != nil { + return err + } + orderDetailTemplateCreateData := gmodel.FsOrderDetailTemplate{ + Sn: &orderDetailTemplateSn, + ProductId: cart.ProductId, + ModelId: cart.OptionalId, + TemplateId: cart.TemplateId, + MaterialId: cart.MaterialId, + SizeId: cart.SizeId, + EachBoxNum: priceList[priceIndex].EachBoxNum, + EachBoxWeight: priceList[priceIndex].EachBoxWeight, + DesignId: cart.DesignId, + Ctime: &now, + } + if err = orderDetailTemplateModel.Create(l.ctx, &orderDetailTemplateCreateData); err != nil { + return err + } + //获取阶梯价格和数量 + stepNumSlice, err := format.StrSlicToIntSlice(strings.Split(*priceList[priceIndex].StepNum, ",")) + if err != nil { + return err + } + stepPriceSlice, err := format.StrSlicToIntSlice(strings.Split(*priceList[priceIndex].StepPrice, ",")) + if err != nil { + return err + } + formIndex, _ := mapForm[cart.Id] //一定会有不用判断 + //订单详情数据 + orderDetailSn, err := id_generator.GenSnowFlakeId() + if err != nil { + return err + } + optionalPrice := int64(0) + optionalTitle := "" + if model3dIndex, ok := mapModel3d[*cart.OptionalId]; ok { + optionalPrice = *model3dList[model3dIndex].Price + optionalTitle = *model3dList[model3dIndex].Title + } + fn := int(math.Ceil(float64(req.Form[formIndex].Num) / float64(*priceList[priceIndex].EachBoxNum))) + amount := step_price.GetCentStepPrice(fn, stepNumSlice, stepPriceSlice) + orderDetailCreateData := gmodel.FsOrderDetail{ + OrderId: &orderCreateData.Id, + Sn: &orderDetailSn, + UserId: &userinfo.UserId, + OrderDetailTemplateId: &orderDetailTemplateCreateData.Id, + ProductId: cart.ProductId, + BuyNum: &req.Form[formIndex].Num, //以提交数量为准 + Amount: &amount, + Cover: cart.Cover, + Ctime: &now, + OptionalId: cart.OptionalId, + OptionalTitle: &optionalTitle, + OptionPrice: &optionalPrice, + CartId: &cart.Id, + } + if err = orderDetailModel.Create(l.ctx, &orderDetailCreateData); err != nil { + return err + } + total += amount * (*orderDetailCreateData.BuyNum) + } + //更新订单总价 + return orderModel.Update(l.ctx, &gmodel.FsOrder{ + Id: orderCreateData.Id, + TotalAmount: &total, + }) + }) + if err != nil { + logx.Error(err) + return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to create order") + } + return resp.SetStatusWithMessage(basic.CodeOK, "success", types.CreateOrderRsp{ + Sn: orderSn, + }) +} diff --git a/server/shopping-cart-confirmation/internal/types/types.go b/server/shopping-cart-confirmation/internal/types/types.go index b976d735..9dbf1774 100644 --- a/server/shopping-cart-confirmation/internal/types/types.go +++ b/server/shopping-cart-confirmation/internal/types/types.go @@ -104,26 +104,41 @@ type ChangeOrderMethodReq struct { PayMethod int64 `json:"pay_method"` } +type CreateOrderReq struct { + Form []OrderFormItem `json:"form"` +} + +type OrderFormItem struct { + Id int64 `json:"id"` + Num int64 `json:"num"` +} + +type CreateOrderRsp struct { + Sn string `json:"sn"` +} + +type Request struct { +} + type Response struct { Code int `json:"code"` Message string `json:"msg"` Data interface{} `json:"data"` } -type ResponseJwt struct { - Code int `json:"code"` - Message string `json:"msg"` - Data interface{} `json:"data"` - AccessSecret string `json:"accessSecret"` - AccessExpire int64 `json:"accessExpire"` -} - type Auth struct { AccessSecret string `json:"accessSecret"` AccessExpire int64 `json:"accessExpire"` RefreshAfter int64 `json:"refreshAfter"` } +type Meta struct { + TotalCount int64 `json:"totalCount"` + PageCount int64 `json:"pageCount"` + CurrentPage int `json:"currentPage"` + PerPage int `json:"perPage"` +} + // Set 设置Response的Code和Message值 func (resp *Response) Set(Code int, Message string) *Response { return &Response{ diff --git a/server_api/shopping-cart-confirmation.api b/server_api/shopping-cart-confirmation.api index d8de6a39..15060f17 100644 --- a/server_api/shopping-cart-confirmation.api +++ b/server_api/shopping-cart-confirmation.api @@ -28,6 +28,9 @@ service shopping-cart-confirmation { //变更发货方式和地址 @handler ChangeOrderMethodHandler post /cart/chang-order-method (ChangeOrderMethodReq) returns (response); + //创建购物车订单 + @handler CreateOrderHandler + post /cart/create-order (CreateOrderReq) returns (response); } //添加入购物车 @@ -122,4 +125,15 @@ type ChangeOrderMethodReq { DeliveryMethod int64 `json:"delivery_method , options=1|2"` AddressId int64 `json:"address_id"` PayMethod int64 `json:"pay_method"` +} +//创建购物车订单 +type CreateOrderReq { + Form []OrderFormItem `json:"form"` +} +type OrderFormItem { + Id int64 `json:"id"` + Num int64 `json:"num"` +} +type CreateOrderRsp { + Sn string `json:"sn"` } \ No newline at end of file diff --git a/utils/id_generator/pickup_track_num.go b/utils/id_generator/pickup_track_num.go index 0e7d3037..59edda26 100644 --- a/utils/id_generator/pickup_track_num.go +++ b/utils/id_generator/pickup_track_num.go @@ -7,7 +7,7 @@ import ( "time" ) -func GenPickUpTrackNum() string { +func GenSnNum() string { a := fmt.Sprintf("%s%.8d", time.Now().Format("20060102150405.000"), rand.Intn(1000000)) return strings.ReplaceAll(a, ".", "") }