表结构
package model
import "time"
type ShoppingCart struct{
BaseModel
User int32 `gorm:"type:int;index"`
Goods int32 `gorm:"type:int;index"`
Nums int32 `gorm:"type:int"`
Checked bool
}
func (ShoppingCart) TableName() string {
return "shoppingcart"
}
type OrderInfo struct{
BaseModel
User int32 `gorm:"type:int;index"`
OrderSn string `gorm:"type:varchar(30);index"`
PayType string `gorm:"type:varchar(20) comment 'alipay(支付宝), wechat(微信)'"`
//status大家可以考虑使用iota来做
Status string `gorm:"type:varchar(20) comment 'PAYING(待支付), TRADE_SUCCESS(成功), TRADE_SUCCESS(超时关闭), WAIT_BUYER_PAY(交易创建), TRADE_FINISHED(交易结束)'"`
TradeNo string `gorm:"type:varchar(100) comment '交易号'"`
OrderMount float32
PayTime time.Time
Address string `gorm:"type:varchar(100)"`
SignerName string `gorm:"type:varchar(20)"`
SingerMobile string `gorm:"type:varchar(11)"`
Post string `gorm:"type:varchar(20)"`
}
func (OrderInfo) TableName() string {
return "orderinfo"
}
type OrderGoods struct{
BaseModel
Order int32 `gorm:"type:int;index"`
Goods int32 `gorm:"type:int;index"`
GoodsName string `gorm:"type:varchar(100);index"`
GoodsImage string `gorm:"type:varchar(200)"`
GoodsPrice float32
Nums int32 `gorm:"type:int"`
}
func (OrderGoods) TableName() string {
return "ordergoods"
}
proto文件定义
syntax = "proto3";
import "google/protobuf/empty.proto";
option go_package = ".;proto";
service Order {
//购物车
rpc CartItemList(UserInfo) returns(CartItemListResponse); //获取用户的购物车信息
rpc CreateCartItem(CartItemRequest) returns(ShopCartInfoResponse); //添加商品到购物车
rpc UpdateCartItem(CartItemRequest) returns(google.protobuf.Empty); //修改购物车记录
//订单
rpc Create(OrderRequest) returns (OrderInfoResponse); //创建订单
rpc OrderList(OrderFilterRequest) returns (OrderListResponse); // 订单列表
rpc OrderDetail(OrderRequest) returns (OrderInfoDetailResponse); // 订单详情
rpc UpdateOrderStatus(OrderStatus) returns (google.protobuf.Empty); // 修改订单状态
}
message UserInfo {
int32 id = 1;
}
message OrderStatus {
int32 id = 1;
string orderSn = 2;
string status = 3;
}
message CartItemRequest {
int32 id = 1;
int32 userId = 2;
int32 goodsId = 3;
string goodsName = 4;
string goodsImage = 5;
float goodsPrice = 6;
int32 nums = 7;
bool checked = 8;
}
message OrderRequest {
int32 id = 1;
int32 userId = 2;
string address = 3;
string name = 4;
string mobile = 5;
string post = 6;
}
message OrderInfoResponse {
int32 id = 1;
int32 userId = 2;
string orderSn = 3;
string payType = 4;
string status = 5;
string post = 6;
float total = 7;
string address = 8;
string name = 9;
string mobile = 10;
}
message ShopCartInfoResponse {
int32 id = 1;
int32 userId = 2;
int32 goodsId = 3;
int32 nums = 4;
bool checked = 5;
}
message OrderItemResponse {
int32 id = 1;
int32 orderId = 2;
int32 goodsId = 3;
string goodsName = 4;
string goodsImage = 5;
float goodsPrice = 6;
int32 nums = 7;
}
message OrderInfoDetailResponse {
OrderInfoResponse orderInfo = 1;
repeated OrderItemResponse goods = 2;
}
message OrderFilterRequest {
int32 userId = 1;
int32 pages = 2;
int32 pagePerNums = 3;
}
message OrderListResponse {
int32 total = 1;
repeated OrderInfoResponse data = 2;
}
message CartItemListResponse {
int32 total = 1;
repeated ShopCartInfoResponse data = 2;
}
创建订单
func (*OrderServer) CreateOrder(ctx context.Context, req *proto.OrderRequest) (*proto.OrderInfoResponse, error) {
/*
新建订单
1. 从购物车中获取到选中的商品
2. 商品的价格自己查询 - 访问商品服务 (跨微服务)
3. 库存的扣减 - 访问库存服务 (跨微服务)
4. 订单的基本信息表 - 订单的商品信息表
5. 从购物车中删除已购买的记录
*/
//定一个切片用来保存购物车商品数据
var shopCarts []model.ShoppingCart
//定义一个切片存放购物车下的商品id
var goodsIds []int32
//定义商品数据字典
goodsNumsMap := make(map[int32]int32)
if result := global.DB.Where(&model.ShoppingCart{User: req.UserId, Checked: true}).Find(&shopCarts); result.RowsAffected == 0 {
return nil, status.Errorf(codes.Internal, "没有选中任何商品")
}
//得到购物车的所有商品id
for _, shopCart := range shopCarts {
goodsIds = append(goodsIds, shopCart.Goods)
goodsNumsMap[shopCart.Goods] = shopCart.Nums
}
//去商品微服务查询商品价格
goods, err := global.GoodsSrvClient.BatchGetGoods(context.Background(), &proto.BatchGoodsIdInfo{
Id: goodsIds,
})
if err != nil {
return nil, status.Errorf(codes.NotFound, "没有任何商品信息")
}
//订单的总金额 = 所有商品的金额加一起 (商品的价格(goods)*购物车商品的数量(shopCarts.nums))
var orderMount float32
//定义一个切片 保存扣减商品和数量信息
var goodsInvInfo []*proto.GoodsInvInfo
//定义一个切片 保存订单购买的所有商品
var orderGoods []*model.OrderGoods
for _, good := range goods.Data {
orderMount += good.ShopPrice * float32(goodsNumsMap[good.Id])
orderGoods = append(orderGoods, &model.OrderGoods{
Goods: good.Id,
GoodsName: good.Name,
GoodsImage: good.GoodsFrontImage,
GoodsPrice: good.ShopPrice,
Nums: goodsNumsMap[good.Id],
})
goodsInvInfo = append(goodsInvInfo, &proto.GoodsInvInfo{
GoodsId: good.Id,
Num: goodsNumsMap[good.Id],
})
}
//库存的扣减
_, err = global.InventorySrvClient.Sell(context.Background(), &proto.SellInfo{
GoodsInfo: goodsInvInfo,
})
if err != nil {
return nil, status.Errorf(codes.NotFound, "库存扣减失败")
}
tx := global.DB.Begin()
//创建订单基本信息表
OrderInfo := model.OrderInfo{
User: req.UserId,
OrderSn: GenerateOrderSn(req.UserId),
Status: "PAYING",
OrderMount: orderMount,
Address: req.Address,
SignerName: req.Name,
SingerMobile: req.Mobile,
Post: req.Post,
}
if result := tx.Create(&OrderInfo); result.RowsAffected == 0 {
tx.Rollback()
return nil, status.Errorf(codes.Internal, "创建订单失败")
}
//创建订单商品表
for _, orderGood := range orderGoods {
orderGood.Order = OrderInfo.ID
}
//多条数据,最好不要循环入库,来使用批量入库
if result := tx.CreateInBatches(orderGoods, 100); result.RowsAffected == 0 {
tx.Rollback()
return nil, status.Errorf(codes.Internal, "创建订单商品失败")
}
//从购物车中删除已购买的记录
if result := tx.Where(&model.ShoppingCart{User: req.UserId, Checked: true}).Delete(&shopCarts); result.RowsAffected == 0 {
tx.Rollback()
return nil, status.Errorf(codes.Internal, "删除购物车商品失败")
}
//返回结果
OrderInfoResponse := &proto.OrderInfoResponse{
Id: OrderInfo.ID,
UserId: OrderInfo.User,
OrderSn: OrderInfo.OrderSn,
PayType: OrderInfo.PayType,
Status: OrderInfo.Status,
Post: OrderInfo.Post,
Total: OrderInfo.OrderMount,
Address: OrderInfo.Address,
Name: OrderInfo.SignerName,
Mobile: OrderInfo.SingerMobile,
AddTime: OrderInfo.CreatedAt.Format("2006-01-02 15:04:05"),
}
tx.Commit()
return OrderInfoResponse, nil
}