From 799fc0bf9d25d8fc1e087e1bb2a04287b167c91e Mon Sep 17 00:00:00 2001 From: "daniel.w" Date: Sat, 26 Oct 2024 01:17:32 +0800 Subject: [PATCH] add mongo model --- internal/domain/errors.go | 45 +++++ internal/domain/order.go | 22 +++ internal/model/mongo/order_model.go | 210 ++++++++++++++++++++++++ internal/model/mongo/order_model_gen.go | 7 +- 4 files changed, 281 insertions(+), 3 deletions(-) create mode 100644 internal/domain/errors.go create mode 100644 internal/domain/order.go diff --git a/internal/domain/errors.go b/internal/domain/errors.go new file mode 100644 index 0000000..050f912 --- /dev/null +++ b/internal/domain/errors.go @@ -0,0 +1,45 @@ +package domain + +import ( + "strings" + + ers "code.30cm.net/digimon/library-go/errs" + "code.30cm.net/digimon/library-go/errs/code" + "github.com/zeromicro/go-zero/core/logx" +) + +type ErrorCode uint32 + +func (e ErrorCode) ToUint32() uint32 { + return uint32(e) +} + +// Error Code 統一這邊改 +const ( + _ = iota + CreateOrderErrorCode ErrorCode = iota + CancelOrderErrorCode + ModifyOrderErrorCode + TimeoutOrderErrorCode +) + +const ( + _ ErrorCode = 10 + iota + DataNotFoundErrorCode +) + +func CommentError(ec ErrorCode, s ...string) *ers.LibError { + return ers.NewError(code.CloudEPOrder, code.DBError, ec.ToUint32(), strings.Join(s, " ")) +} + +func CommentErrorL(ec ErrorCode, + l logx.Logger, filed []logx.LogField, s ...string) *ers.LibError { + e := CommentError(ec, s...) + l.WithCallerSkip(1).WithFields(filed...).Error(e.Error()) + + return e +} + +func NotFoundError(ec ErrorCode, s ...string) *ers.LibError { + return ers.NewError(code.CloudEPOrder, code.ResourceNotFound, ec.ToUint32(), strings.Join(s, " ")) +} diff --git a/internal/domain/order.go b/internal/domain/order.go new file mode 100644 index 0000000..18233cb --- /dev/null +++ b/internal/domain/order.go @@ -0,0 +1,22 @@ +package domain + +type OrderStatus int64 + +func (o *OrderStatus) ToInt() int { + return int(*o) +} + +const ( + OrderStatusCreated OrderStatus = 0 // 建立訂單 + OrderStatusFailed OrderStatus = 1 // 建單失敗 + OrderStatusReviewing OrderStatus = 2 // 審核中 + OrderStatusPaying OrderStatus = 3 // 付款中 + OrderStatusPaid OrderStatus = 4 // 已付款 + OrderStatusPendingTransfer OrderStatus = 5 // 已付款待轉帳 + OrderStatusDisputing OrderStatus = 6 // 申訴中 + OrderStatusCompleted OrderStatus = 7 // 交易完成 + OrderStatusFailedTrade OrderStatus = 8 // 交易失敗 + OrderStatusCancelled OrderStatus = 9 // 交易取消 + OrderStatusAbnormal OrderStatus = 10 // 交易異常 + OrderStatusTimeout OrderStatus = 11 // 交易超時 +) diff --git a/internal/model/mongo/order_model.go b/internal/model/mongo/order_model.go index c7a7662..b1c95db 100644 --- a/internal/model/mongo/order_model.go +++ b/internal/model/mongo/order_model.go @@ -1,7 +1,14 @@ package model import ( + "app-cloudep-trade-service/internal/domain" + "context" + "errors" "github.com/zeromicro/go-zero/core/stores/mon" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "time" ) var _ OrderModel = (*customOrderModel)(nil) @@ -11,11 +18,49 @@ type ( // and implement the added methods in customOrderModel. OrderModel interface { orderModel + UpdateStatus(ctx context.Context, data UpdateStatusReq) (*mongo.UpdateResult, error) + UpdateTimeoutOrder(ctx context.Context, req UpdateTimeoutReq) (*mongo.UpdateResult, error) + DeleteByBusinessID(ctx context.Context, id string) (*mongo.UpdateResult, error) + FindOneBusinessID(ctx context.Context, id string) (*Order, error) + ListOrder(ctx context.Context, req GetOrderListReq) ([]Order, int64, error) } customOrderModel struct { *defaultOrderModel } + UpdateStatusReq struct { + BusinessID string + Status int64 + } + + UpdateTimeoutReq struct { + CreateTimeBefore int64 + } + + GetOrderListReq struct { + PageIndex int64 `json:"page_index" validate:"required"` + PageSize int64 `json:"page_size" validate:"required"` + + ReferenceID string `json:"reference_id"` + ReferenceUID string `json:"reference_uid"` + BusinessID string `json:"business_id"` + UID string `json:"uid"` + OrderType int `json:"order_type"` + DirectionType []int32 `json:"direction_type"` + OrderStatus []int32 `json:"order_status"` + + StartCreateTime int64 `json:"start_create_time"` + EndCreateTime int64 `json:"end_create_time"` + StartUpdateTime int64 `json:"start_update_time"` + EndUpdateTime int64 `json:"end_update_time"` + StartOrderArrivalTime int64 `json:"start_order_arrival_time"` + EndOrderArrivalTime int64 `json:"end_order_arrival_time"` + StartOrderPaymentTime int64 `json:"start_order_payment_time"` + EndOrderPaymentTime int64 `json:"end_order_payment_time"` + + CryptoType string `json:"crypto_type"` + TxHash string `json:"tx_hash"` + } ) // NewOrderModel returns a model for the mongo. @@ -25,3 +70,168 @@ func NewOrderModel(url, db, collection string, opts ...mon.Option) OrderModel { defaultOrderModel: newDefaultOrderModel(conn), } } + +func (m *customOrderModel) UpdateStatus(ctx context.Context, data UpdateStatusReq) (*mongo.UpdateResult, error) { + // 初始化 updates map + updates := make(map[string]any) + + // 更新 update_time 和 status + updates["update_time"] = time.Now().UTC().UnixNano() + updates["order_status"] = data.Status + + // 使用 updates map 作為 $set 的內容 + res, err := m.conn.UpdateOne(ctx, + bson.M{ + "business_id": data.BusinessID, + "$or": []bson.M{ + {"delete_time": bson.M{"$exists": false}}, + {"delete_time": 0}, + }, + }, + bson.M{"$set": updates}, // 使用 updates 而不是整個 data + ) + + return res, err +} + +func (m *customOrderModel) UpdateTimeoutOrder(ctx context.Context, req UpdateTimeoutReq) (*mongo.UpdateResult, error) { + // 構建過濾條件,選擇創建時間在指定時間之前且狀態為 0 (創建) 的項目 + filter := bson.M{ + "create_time": bson.M{"$lt": req.CreateTimeBefore}, + "status": domain.OrderStatusCreated, + "$or": []bson.M{ + {"delete_time": bson.M{"$exists": false}}, + {"delete_time": 0}, + }, + } + + // 更新內容,將狀態設置為 11,並更新 update_time + updates := bson.M{ + "$set": bson.M{ + "status": domain.OrderStatusTimeout, + "update_time": time.Now().UTC().UnixNano(), + }, + } + + // 執行更新操作 + res, err := m.conn.UpdateOne(ctx, filter, updates) + return res, err +} + +func (m *customOrderModel) DeleteByBusinessID(ctx context.Context, id string) (*mongo.UpdateResult, error) { + filter := bson.M{ + "business_id": id, + "$or": []bson.M{ + {"delete_time": bson.M{"$exists": false}}, + {"delete_time": 0}, + }, + } + + updates := bson.M{ + "$set": bson.M{ + "delete_time": time.Now().UTC().UnixNano(), + "update_time": time.Now().UTC().UnixNano(), + }, + } + // 執行更新操作 + res, err := m.conn.UpdateOne(ctx, filter, updates) + + return res, err +} + +func (m *defaultOrderModel) FindOneBusinessID(ctx context.Context, id string) (*Order, error) { + var data Order + filter := bson.M{"delete_time": bson.M{"$in": []any{0, nil}}} + filter["business_id"] = id + + err := m.conn.FindOne(ctx, &data, filter) + switch { + case err == nil: + return &data, nil + case errors.Is(err, mon.ErrNotFound): + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *customOrderModel) ListOrder(ctx context.Context, req GetOrderListReq) ([]Order, int64, error) { + // 定義查詢過濾器 + filter := bson.M{ + "delete_time": bson.M{"$in": []any{0, nil}}, + } + + // 添加查詢條件 + if req.ReferenceID != "" { + filter["reference_id"] = req.ReferenceID + } + if req.ReferenceUID != "" { + filter["reference_uid"] = req.ReferenceUID + } + if req.BusinessID != "" { + filter["business_id"] = req.BusinessID + } + if req.UID != "" { + filter["order_uid"] = req.UID + } + if req.OrderType != 0 { + filter["order_type"] = req.OrderType + } + if len(req.DirectionType) > 0 { + filter["direction_type"] = bson.M{"$in": req.DirectionType} + } + if len(req.OrderStatus) > 0 { + filter["order_status"] = bson.M{"$in": req.OrderStatus} + } + // 處理時間範圍 + if req.StartCreateTime != 0 { + filter["create_time"] = bson.M{"$gte": req.StartCreateTime} + } + if req.EndCreateTime != 0 { + filter["create_time"] = bson.M{"$lte": req.EndCreateTime} + } + if req.StartUpdateTime != 0 { + filter["update_time"] = bson.M{"$gte": req.StartUpdateTime} + } + if req.EndUpdateTime != 0 { + filter["update_time"] = bson.M{"$lte": req.EndUpdateTime} + } + if req.StartOrderArrivalTime != 0 { + filter["order_arrival_time"] = bson.M{"$gte": req.StartOrderArrivalTime} + } + if req.EndOrderArrivalTime != 0 { + filter["order_arrival_time"] = bson.M{"$lte": req.EndOrderArrivalTime} + } + if req.StartOrderPaymentTime != 0 { + filter["order_payment_time"] = bson.M{"$gte": req.StartOrderPaymentTime} + } + if req.EndOrderPaymentTime != 0 { + filter["order_payment_time"] = bson.M{"$lte": req.EndOrderPaymentTime} + } + if req.CryptoType != "" { + filter["crypto_type"] = req.CryptoType + } + if req.TxHash != "" { + filter["tx_hash"] = req.TxHash + } + + // 計算符合條件的總數量 + totalCount, err := m.conn.CountDocuments(ctx, filter) + if err != nil { + return nil, 0, err + } + + // 設定查詢選項,包含分頁 + findOptions := options.Find() + findOptions.SetSkip((req.PageIndex - 1) * req.PageSize) + findOptions.SetLimit(req.PageSize) + + // 執行查詢 + var orders []Order + err = m.conn.Find(ctx, &orders, filter, findOptions) + if err != nil { + return nil, 0, err + } + + return orders, totalCount, nil +} diff --git a/internal/model/mongo/order_model_gen.go b/internal/model/mongo/order_model_gen.go index 0d9f599..9a082a6 100644 --- a/internal/model/mongo/order_model_gen.go +++ b/internal/model/mongo/order_model_gen.go @@ -28,9 +28,10 @@ func newDefaultOrderModel(conn *mon.Model) *defaultOrderModel { func (m *defaultOrderModel) Insert(ctx context.Context, data *Order) error { if data.ID.IsZero() { + now := time.Now().UTC().UnixNano() data.ID = primitive.NewObjectID() - data.CreateAt = time.Now() - data.UpdateAt = time.Now() + data.CreateTime = now + data.UpdateTime = now } _, err := m.conn.InsertOne(ctx, data) @@ -57,7 +58,7 @@ func (m *defaultOrderModel) FindOne(ctx context.Context, id string) (*Order, err } func (m *defaultOrderModel) Update(ctx context.Context, data *Order) (*mongo.UpdateResult, error) { - data.UpdateAt = time.Now() + data.UpdateTime = time.Now().UTC().UnixNano() res, err := m.conn.UpdateOne(ctx, bson.M{"_id": data.ID}, bson.M{"$set": data}) return res, err