diff --git a/Makefile b/Makefile index fbbfdf5..80e5221 100644 --- a/Makefile +++ b/Makefile @@ -61,4 +61,4 @@ mock-gen: # 建立 mock 資料 .PHONY: migrate-database migrate-database: - migrate -source file://generate/database/migrations/mongodb -database 'mongodb://127.0.0.1:27017/digimon_order' up + migrate -source file://generate/database/mongodb -database 'mongodb://127.0.0.1:27017/digimon_order' up diff --git a/generate/database/mongodb/20241006000001_order.up.mongo b/generate/database/mongodb/20241006000001_order.up.mongo new file mode 100644 index 0000000..fb82665 --- /dev/null +++ b/generate/database/mongodb/20241006000001_order.up.mongo @@ -0,0 +1,19 @@ +use digimon_order; + +db.order.createIndex({ + "uid": 1, + "order_type": 1, + "order_status": 1, + "create_time": 1, +}) + +db.order.createIndex({ + "business_id": 1, +}) + +// 查詢時全部要 1&2 有幾個類用幾個累才會中索引 +db.order.createIndex({ + "uid": 1, + "direction_type": 1, + "crypto_type": 1 +}) \ No newline at end of file diff --git a/generate/protobuf/order.proto b/generate/protobuf/order.proto index 7372d20..c4a9792 100644 --- a/generate/protobuf/order.proto +++ b/generate/protobuf/order.proto @@ -9,46 +9,159 @@ message OKResp {} message NoneReq {} // 分頁信息 -message Pager -{ - int64 total = 1; // 總數量 - int64 size = 2; // 每頁數量 - int64 index = 3; // 當前頁碼 +message Pager { + int64 total = 1; // 總數量 + int64 size = 2; // 每頁數量 + int64 index = 3; // 當前頁碼 } -message CreateOrderReq{} -message CreateOrderResp{} +message CreateOrderReq { + string business_id = 1; // 訂單業務流水號 + int32 order_type = 2; // 訂單類型 + int32 order_status = 3; // 訂單狀態 + string brand = 4; // 下單平台 + string order_uid = 5; // 下單用戶 UID + string reference_id = 6; // 訂單來源 + string count = 7; // 訂單數量 (decimal to string) + string order_fee = 8; // 訂單手續費 (decimal to string) + string amount = 9; // 單價 (decimal to string) -message CancelOrderReq{} -message ModifyOrderReq{} -message ModifyOrderStatusReq{} -message DeleteOrderReq{} + // 以下是可選字段(擴充用) + optional string reference_brand = 10; // 訂單來源平台 + optional string reference_uid = 11; // 訂單來源用戶 UID + optional int64 wallet_status = 12; // 交易金額狀態 + optional int64 three_party_status = 13; // 三方請求狀態 + optional int64 direction_type = 14; // 交易方向 + optional string crypto_type = 15; // 交易幣種 + optional string third_party_fee = 16; // 第三方手續費 (decimal to string) + optional string crypto_to_usdt_rate = 17; // 交易幣種對 USDT 匯率 (decimal to string) + optional string fiat_to_usd_rate = 18; // 法幣對 USD 匯率 (decimal to string) + optional string fee_crypto_to_usdt_rate = 19; // 手續費幣種對 USDT 匯率 (decimal to string) + optional string usdt_to_crypto_type_rate = 20; // USDT 對交易幣種匯率 (decimal to string) + optional string payment_fiat = 21; // 支付法幣 + optional string payment_unit_price = 22; // crypto 單價 (decimal to string) + optional string payment_template_id = 23; // 支付方式配置 ID + optional int64 order_arrival_time = 24; // 訂單到帳時間 + optional int64 order_payment_time = 25; // 訂單付款時間 + optional int64 unpaid_timeout_second = 26; // 支付期限秒數 + optional string chain_type = 27; // 主網類型 + optional string tx_hash = 28; // 交易哈希 + optional string from_address = 29; // 來源地址 + optional string to_address = 30; // 目標地址 + optional string chain_fee = 31; // 鏈上交易手續費 (decimal to string) + optional string chain_fee_crypto = 32; // 鏈上手續費使用幣別 + optional string memo = 33; // 鏈上備註 + optional string order_note = 34; // 訂單交易備註 +} -message GetOrderReq{} -message GetOrderResp{} +message CancelOrderReq { + string business_id = 1; + int64 status = 2; +} -message ListOrderReq{} -message ListOrderResp{} +message ModifyOrderStatusReq { + string business_id = 1; + int64 status = 2; +} +message DeleteOrderReq { + string business_id = 1; +} -message OrderStatusTimeoutReq{} +message OrderStatusTimeoutReq {} + +message GetOrderReq { + string business_id = 1; // 訂單業務流水號 +} +message GetOrderResp { + string business_id = 1; // 訂單業務流水號 + int32 order_type = 2; // 訂單類型 + int32 order_status = 3; // 訂單狀態 + string brand = 4; // 下單平台 + string order_uid = 5; // 下單用戶 UID + string reference_id = 6; // 訂單來源 + string count = 7; // 訂單數量 (decimal to string) + string order_fee = 8; // 訂單手續費 (decimal to string) + string amount = 9; // 單價 (decimal to string) + + // 以下是可選字段(擴充用) + optional string reference_brand = 10; // 訂單來源平台 + optional string reference_uid = 11; // 訂單來源用戶 UID + optional int64 wallet_status = 12; // 交易金額狀態 + optional int64 three_party_status = 13; // 三方請求狀態 + optional int64 direction_type = 14; // 交易方向 + optional string crypto_type = 15; // 交易幣種 + optional string third_party_fee = 16; // 第三方手續費 (decimal to string) + optional string crypto_to_usdt_rate = 17; // 交易幣種對 USDT 匯率 (decimal to string) + optional string fiat_to_usd_rate = 18; // 法幣對 USD 匯率 (decimal to string) + optional string fee_crypto_to_usdt_rate = 19; // 手續費幣種對 USDT 匯率 (decimal to string) + optional string usdt_to_crypto_type_rate = 20; // USDT 對交易幣種匯率 (decimal to string) + optional string payment_fiat = 21; // 支付法幣 + optional string payment_unit_price = 22; // crypto 單價 (decimal to string) + optional string payment_template_id = 23; // 支付方式配置 ID + optional int64 order_arrival_time = 24; // 訂單到帳時間 + optional int64 order_payment_time = 25; // 訂單付款時間 + optional int64 unpaid_timeout_second = 26; // 支付期限秒數 + optional string chain_type = 27; // 主網類型 + optional string tx_hash = 28; // 交易哈希 + optional string from_address = 29; // 來源地址 + optional string to_address = 30; // 目標地址 + optional string chain_fee = 31; // 鏈上交易手續費 (decimal to string) + optional string chain_fee_crypto = 32; // 鏈上手續費使用幣別 + optional string memo = 33; // 鏈上備註 + optional string order_note = 34; // 訂單交易備註 + int64 create_time = 35; // 建立時間 + int64 update_time = 36; // 更新時間 +} + +message ModifyOrderReq {} + +message ListOrderReq { + int64 page_index = 1; // required + int64 page_size = 2; // required + + string reference_id = 3; + string reference_uid = 4; + string business_id = 5; + string uid = 6; + int32 order_type = 7; + repeated int32 direction_type = 8; + repeated int32 order_status = 9; + + int64 start_create_time = 10; + int64 end_create_time = 11; + int64 start_update_time = 12; + int64 end_update_time = 13; + int64 start_order_arrival_time = 14; + int64 end_order_arrival_time = 15; + int64 start_order_payment_time = 16; + int64 end_order_payment_time = 17; + + string crypto_type = 18; + string tx_hash = 19; +} + +message ListOrderResp { + repeated GetOrderResp data = 1; // 訂單列表 + Pager page = 2; +} // OrderService 訂單服務(業務邏輯在外面組合) -service OrderService{ +service OrderService { // CreateOrder 建立訂單 - rpc CreateOrder(CreateOrderReq)returns(CreateOrderResp); + rpc CreateOrder(CreateOrderReq) returns (OKResp); // CancelOrder 取消訂單 - rpc CancelOrder(CancelOrderReq)returns(OKResp); + rpc CancelOrder(CancelOrderReq) returns (OKResp); // ModifyOrder 修改訂單 - rpc ModifyOrder(ModifyOrderReq)returns(OKResp); + rpc ModifyOrder(ModifyOrderReq) returns (OKResp); // ModifyOrderStatus 修改訂單狀態 - rpc ModifyOrderStatus(ModifyOrderStatusReq)returns(OKResp); + rpc ModifyOrderStatus(ModifyOrderStatusReq) returns (OKResp); // DeleteOrder 刪除訂單(軟刪除) - rpc DeleteOrder(DeleteOrderReq)returns(OKResp); + rpc DeleteOrder(DeleteOrderReq) returns (OKResp); // GetOrder 取得訂單詳情 - rpc GetOrder(GetOrderReq)returns(GetOrderResp); + rpc GetOrder(GetOrderReq) returns (GetOrderResp); // ListOrder 取得訂單列表 - rpc ListOrder(ListOrderReq)returns(ListOrderResp); + rpc ListOrder(ListOrderReq) returns (ListOrderResp); // OrderStatusTimeout 訂單超時任務/cron/order-status/timeout - rpc OrderStatusTimeout(OrderStatusTimeoutReq)returns(OKResp); + rpc OrderStatusTimeout(OrderStatusTimeoutReq) returns (OKResp); } diff --git a/go.mod b/go.mod index 0a5d0f1..72694e2 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,12 @@ module app-cloudep-order-server go 1.22.3 require ( + code.30cm.net/digimon/library-go/errs v1.2.5 + code.30cm.net/digimon/library-go/validator v1.0.0 + github.com/shopspring/decimal v1.4.0 github.com/zeromicro/go-zero v1.7.2 + go.mongodb.org/mongo-driver v1.16.1 + go.uber.org/mock v0.4.0 google.golang.org/grpc v1.67.1 google.golang.org/protobuf v1.34.2 ) @@ -18,14 +23,19 @@ require ( github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/fatih/color v1.17.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.4 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.22.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect @@ -34,11 +44,13 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.9 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/montanaflynn/stats v0.7.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.3 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect @@ -48,6 +60,10 @@ require ( github.com/prometheus/procfs v0.15.1 // indirect github.com/redis/go-redis/v9 v9.6.1 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect go.etcd.io/etcd/api/v3 v3.5.15 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect go.etcd.io/etcd/client/v3 v3.5.15 // indirect @@ -66,8 +82,10 @@ require ( go.uber.org/automaxprocs v1.5.3 // indirect go.uber.org/multierr v1.9.0 // indirect go.uber.org/zap v1.24.0 // indirect + golang.org/x/crypto v0.26.0 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/oauth2 v0.22.0 // indirect + golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.24.0 // indirect golang.org/x/term v0.23.0 // indirect golang.org/x/text v0.17.0 // indirect diff --git a/internal/config/config.go b/internal/config/config.go index c1f85b9..85679b2 100755 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -4,4 +4,13 @@ import "github.com/zeromicro/go-zero/zrpc" type Config struct { zrpc.RpcServerConf + + Mongo struct { + Schema string + User string + Password string + Host string + Port string + Database string + } } diff --git a/internal/domain/errors.go b/internal/domain/errors.go new file mode 100644 index 0000000..15bfbf5 --- /dev/null +++ b/internal/domain/errors.go @@ -0,0 +1,36 @@ +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 +) + +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 +} 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/logic/orderservice/cancel_order_logic.go b/internal/logic/orderservice/cancel_order_logic.go index 053b579..80b242e 100644 --- a/internal/logic/orderservice/cancel_order_logic.go +++ b/internal/logic/orderservice/cancel_order_logic.go @@ -1,8 +1,12 @@ package orderservicelogic import ( + "app-cloudep-order-server/internal/domain" + model "app-cloudep-order-server/internal/model/mongo" "context" + ers "code.30cm.net/digimon/library-go/errs" + "app-cloudep-order-server/gen_result/pb/tweeting" "app-cloudep-order-server/internal/svc" @@ -23,9 +27,42 @@ func NewCancelOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Cance } } +// CancelOrderQuery 1.建單失敗 9.交易取消 10.交易異常 +type CancelOrderQuery struct { + BusinessID string `json:"business_id" validate:"required"` + Status int64 `json:"status" validate:"required,oneof=1 9 10"` +} + // CancelOrder 取消訂單 func (l *CancelOrderLogic) CancelOrder(in *tweeting.CancelOrderReq) (*tweeting.OKResp, error) { - // todo: add your logic here and delete this line + // 驗證資料 + if err := l.svcCtx.Validate.ValidateAll(&CancelOrderQuery{ + BusinessID: in.GetBusinessId(), + Status: in.GetStatus(), + }); err != nil { + // 錯誤代碼 06-011-00 + return nil, ers.InvalidFormat(err.Error()) + } + + _, err := l.svcCtx.OrderModel.UpdateStatus(l.ctx, + model.UpdateStatusReq{ + BusinessID: in.GetBusinessId(), + Status: in.GetStatus(), + }) + if err != nil { + // 錯誤代碼 06-021-02 + e := domain.CommentErrorL( + domain.CancelOrderErrorCode, + logx.WithContext(l.ctx), + []logx.LogField{ + {Key: "req", Value: in}, + {Key: "func", Value: "OrderModel.UpdateStatus"}, + {Key: "err", Value: err}, + }, + "failed to update order status:").Wrap(err) + + return nil, e + } return &tweeting.OKResp{}, nil } diff --git a/internal/logic/orderservice/create_order_logic.go b/internal/logic/orderservice/create_order_logic.go index 9ae8e56..151fbe4 100644 --- a/internal/logic/orderservice/create_order_logic.go +++ b/internal/logic/orderservice/create_order_logic.go @@ -1,7 +1,13 @@ package orderservicelogic import ( + "app-cloudep-order-server/internal/domain" + model "app-cloudep-order-server/internal/model/mongo" "context" + "time" + + ers "code.30cm.net/digimon/library-go/errs" + "github.com/shopspring/decimal" "app-cloudep-order-server/gen_result/pb/tweeting" "app-cloudep-order-server/internal/svc" @@ -23,9 +29,237 @@ func NewCreateOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Creat } } -// CreateOrder 建立訂單 -func (l *CreateOrderLogic) CreateOrder(in *tweeting.CreateOrderReq) (*tweeting.CreateOrderResp, error) { - // todo: add your logic here and delete this line - - return &tweeting.CreateOrderResp{}, nil +type createOrderReq struct { // 訂單ID + BusinessID string `json:"business_id" validate:"required"` // 訂單業務流水號 + OrderType int8 `json:"order_type" validate:"required"` // 訂單類型 + OrderStatus int8 `json:"order_status" validate:"required,oneof=0 1 2 3 4 5 6 7 8 9 10 11"` // 訂單狀態 + Brand string `json:"brand" validate:"required"` // 下單平台 + OrderUID string `json:"order_uid" validate:"required"` // 下單用戶 UID + ReferenceID string `json:"reference_id" validate:"required"` // 訂單來源 + Count decimal.Decimal `json:"count" validate:"required,gt=0"` // 訂單數量 + OrderFee decimal.Decimal `json:"order_fee" validate:"required,gte=0"` // 訂單手續費 + Amount decimal.Decimal `json:"amount" validate:"required,gte=0"` // 單價 + ReferenceBrand *string `json:"reference_brand,omitempty" validate:"omitempty"` // 訂單來源平台 + ReferenceUID *string `json:"reference_uid,omitempty" validate:"omitempty"` // 訂單來源用戶 UID + WalletStatus *int64 `json:"wallet_status,omitempty" validate:"omitempty,oneof=1 2 3 4 5 6 7"` // 交易金額狀態 + ThreePartyStatus *int64 `json:"three_party_status,omitempty" validate:"omitempty,oneof=1 2 3"` // 三方請求狀態 + DirectionType *int64 `json:"direction_type,omitempty" validate:"omitempty,oneof=1 2"` // 交易方向 + CryptoType *string `json:"crypto_type,omitempty" validate:"omitempty"` // 交易幣種 + ThirdPartyFee *decimal.Decimal `json:"third_party_fee,omitempty" validate:"omitempty,gte=0"` // 第三方手續費 + CryptoToUSDTRate *decimal.Decimal `json:"crypto_to_usdt_rate,omitempty" validate:"omitempty,gte=0"` // 交易幣種對 USDT 匯率 + FiatToUSDRate *decimal.Decimal `json:"fiat_to_usd_rate,omitempty" validate:"omitempty,gte=0"` // 法幣對 USD 匯率 + FeeCryptoToUSDTRate *decimal.Decimal `json:"fee_crypto_to_usdt_rate,omitempty" validate:"omitempty,gte=0"` // 手續費幣種對 USDT 匯率 + USDTToCryptoTypeRate *decimal.Decimal `json:"usdt_to_crypto_type_rate,omitempty" validate:"omitempty,gte=0"` // USDT 對交易幣種匯率 + PaymentFiat *string `json:"payment_fiat,omitempty" validate:"omitempty"` // 支付法幣 + PaymentUnitPrice *decimal.Decimal `json:"payment_unit_price,omitempty" validate:"omitempty,gte=0"` // crypto 單價 + PaymentTemplateID *string `json:"payment_template_id,omitempty" validate:"omitempty"` // 支付方式配置 ID + OrderArrivalTime *int64 `json:"order_arrival_time,omitempty" validate:"omitempty"` // 訂單到帳時間 + OrderPaymentTime *int64 `json:"order_payment_time,omitempty" validate:"omitempty"` // 訂單付款時間 + UnpaidTimeoutSecond *int64 `json:"unpaid_timeout_second,omitempty" validate:"omitempty,gte=0"` // 支付期限秒數 + ChainType *string `json:"chain_type,omitempty" validate:"omitempty"` // 主網類型 + TxHash *string `json:"tx_hash,omitempty" validate:"omitempty"` // 交易哈希 + FromAddress *string `json:"from_address,omitempty" validate:"omitempty"` // 來源地址 + ToAddress *string `json:"to_address,omitempty" validate:"omitempty"` // 目標地址 + ChainFee *decimal.Decimal `json:"chain_fee,omitempty" validate:"omitempty,gte=0"` // 鏈上交易手續費 + ChainFeeCrypto *string `json:"chain_fee_crypto,omitempty" validate:"omitempty"` // 鏈上手續費使用幣別 + Memo *string `json:"memo,omitempty" validate:"omitempty"` // 鏈上備註 + OrderNote *string `json:"order_note,omitempty" validate:"omitempty"` +} + +// CreateOrder 建立訂單 +func (l *CreateOrderLogic) CreateOrder(in *tweeting.CreateOrderReq) (*tweeting.OKResp, error) { + req, err := buildCreateOrderReq(in) + if err != nil { + // 錯誤代碼 06-011-00 + return nil, ers.InvalidFormat(err.Error()) + } + // 驗證資料 + if err := l.svcCtx.Validate.ValidateAll(&req); err != nil { + // 錯誤代碼 06-011-00 + return nil, ers.InvalidFormat(err.Error()) + } + + now := time.Now().UTC().UnixNano() + // 插入資料庫 + o := &model.Order{ + UpdateTime: now, + CreateTime: now, + BusinessID: req.BusinessID, + OrderType: req.OrderType, + OrderStatus: req.OrderStatus, + Brand: req.Brand, + OrderUID: req.OrderUID, + ReferenceID: req.ReferenceID, + Count: req.Count, + OrderFee: req.OrderFee, + Amount: req.Amount, + // 下面的是未來擴充用,加密貨幣用,或者幣別轉換用,普通訂單用不到 + ReferenceBrand: req.ReferenceBrand, + ReferenceUID: req.ReferenceUID, + WalletStatus: req.WalletStatus, + ThreePartyStatus: req.ThreePartyStatus, + DirectionType: req.DirectionType, + CryptoType: req.CryptoType, + ThirdPartyFee: req.ThirdPartyFee, + CryptoToUSDTRate: req.CryptoToUSDTRate, + FiatToUSDRate: req.FiatToUSDRate, + FeeCryptoToUSDTRate: req.FeeCryptoToUSDTRate, + USDTToCryptoTypeRate: req.USDTToCryptoTypeRate, + PaymentFiat: req.PaymentFiat, + PaymentUnitPrice: req.PaymentUnitPrice, + PaymentTemplateID: req.PaymentTemplateID, + OrderArrivalTime: req.OrderArrivalTime, + OrderPaymentTime: req.OrderPaymentTime, + UnpaidTimeoutSecond: req.UnpaidTimeoutSecond, + ChainType: req.ChainType, + TxHash: req.TxHash, + FromAddress: req.FromAddress, + ToAddress: req.ToAddress, + ChainFee: req.ChainFee, + ChainFeeCrypto: req.ChainFeeCrypto, + Memo: req.Memo, + OrderNote: req.OrderNote, + } + err = l.svcCtx.OrderModel.Insert(l.ctx, o) + + if err != nil { + // 錯誤代碼 06-021-01 + e := domain.CommentErrorL( + domain.CreateOrderErrorCode, + logx.WithContext(l.ctx), + []logx.LogField{ + {Key: "req", Value: in}, + {Key: "func", Value: "OrderModel.Insert"}, + {Key: "err", Value: err}, + }, + "failed to insert order into mongo:").Wrap(err) + + return nil, e + } + + return &tweeting.OKResp{}, nil +} + +func buildCreateOrderReq(in *tweeting.CreateOrderReq) (*createOrderReq, error) { + createOrderReq := &createOrderReq{ + BusinessID: in.BusinessId, + OrderType: int8(in.OrderType), + OrderStatus: int8(in.OrderStatus), + Brand: in.Brand, + OrderUID: in.OrderUid, + ReferenceID: in.ReferenceId, + } + + var err error + // 只有當 Count, OrderFee, Amount 不為空時才進行轉換和設置 + if in.Count != "" { + createOrderReq.Count, err = decimal.NewFromString(in.Count) + if err != nil { + return nil, err + } + } + if in.OrderFee != "" { + createOrderReq.OrderFee, err = decimal.NewFromString(in.OrderFee) + if err != nil { + return nil, err + } + } + if in.Amount != "" { + createOrderReq.Amount, err = decimal.NewFromString(in.Amount) + if err != nil { + return nil, err + } + } + + // 判斷可選字段,只有不為 nil 才設置 + if in.ReferenceBrand != nil { + createOrderReq.ReferenceBrand = in.ReferenceBrand + } + if in.ReferenceUid != nil { + createOrderReq.ReferenceUID = in.ReferenceUid + } + if in.WalletStatus != nil { + createOrderReq.WalletStatus = in.WalletStatus + } + if in.ThreePartyStatus != nil { + createOrderReq.ThreePartyStatus = in.ThreePartyStatus + } + if in.DirectionType != nil { + createOrderReq.DirectionType = in.DirectionType + } + if in.CryptoType != nil { + createOrderReq.CryptoType = in.CryptoType + } + if in.ThirdPartyFee != nil && *in.ThirdPartyFee != "" { + createOrderReq.ThirdPartyFee = decimalPtrFromString(*in.ThirdPartyFee) + } + if in.CryptoToUsdtRate != nil && *in.CryptoToUsdtRate != "" { + createOrderReq.CryptoToUSDTRate = decimalPtrFromString(*in.CryptoToUsdtRate) + } + if in.FiatToUsdRate != nil && *in.FiatToUsdRate != "" { + createOrderReq.FiatToUSDRate = decimalPtrFromString(*in.FiatToUsdRate) + } + if in.FeeCryptoToUsdtRate != nil && *in.FeeCryptoToUsdtRate != "" { + createOrderReq.FeeCryptoToUSDTRate = decimalPtrFromString(*in.FeeCryptoToUsdtRate) + } + if in.UsdtToCryptoTypeRate != nil && *in.UsdtToCryptoTypeRate != "" { + createOrderReq.USDTToCryptoTypeRate = decimalPtrFromString(*in.UsdtToCryptoTypeRate) + } + if in.PaymentFiat != nil { + createOrderReq.PaymentFiat = in.PaymentFiat + } + if in.PaymentUnitPrice != nil && *in.PaymentUnitPrice != "" { + createOrderReq.PaymentUnitPrice = decimalPtrFromString(*in.PaymentUnitPrice) + } + if in.PaymentTemplateId != nil { + createOrderReq.PaymentTemplateID = in.PaymentTemplateId + } + if in.OrderArrivalTime != nil { + createOrderReq.OrderArrivalTime = in.OrderArrivalTime + } + if in.OrderPaymentTime != nil { + createOrderReq.OrderPaymentTime = in.OrderPaymentTime + } + if in.UnpaidTimeoutSecond != nil { + createOrderReq.UnpaidTimeoutSecond = in.UnpaidTimeoutSecond + } + if in.ChainType != nil { + createOrderReq.ChainType = in.ChainType + } + if in.TxHash != nil { + createOrderReq.TxHash = in.TxHash + } + if in.FromAddress != nil { + createOrderReq.FromAddress = in.FromAddress + } + if in.ToAddress != nil { + createOrderReq.ToAddress = in.ToAddress + } + if in.ChainFee != nil && *in.ChainFee != "" { + createOrderReq.ChainFee = decimalPtrFromString(*in.ChainFee) + } + if in.ChainFeeCrypto != nil { + createOrderReq.ChainFeeCrypto = in.ChainFeeCrypto + } + if in.Memo != nil { + createOrderReq.Memo = in.Memo + } + if in.OrderNote != nil { + createOrderReq.OrderNote = in.OrderNote + } + + return createOrderReq, nil +} + +// Helper function for decimal conversion with nil support +func decimalPtrFromString(val string) *decimal.Decimal { + if val == "" { + return nil + } + dec, err := decimal.NewFromString(val) + if err != nil { + return nil + } + + return &dec } diff --git a/internal/logic/orderservice/delete_order_logic.go b/internal/logic/orderservice/delete_order_logic.go index f66b6cb..fccce01 100644 --- a/internal/logic/orderservice/delete_order_logic.go +++ b/internal/logic/orderservice/delete_order_logic.go @@ -1,6 +1,7 @@ package orderservicelogic import ( + ers "code.30cm.net/digimon/library-go/errs" "context" "app-cloudep-order-server/gen_result/pb/tweeting" @@ -23,9 +24,25 @@ func NewDeleteOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Delet } } +// DeleteOrderQuery 刪除訂單(軟刪除) +type DeleteOrderQuery struct { + BusinessID string `json:"business_id" validate:"required"` +} + // DeleteOrder 刪除訂單(軟刪除) func (l *DeleteOrderLogic) DeleteOrder(in *tweeting.DeleteOrderReq) (*tweeting.OKResp, error) { - // todo: add your logic here and delete this line + // 驗證資料 + if err := l.svcCtx.Validate.ValidateAll(&DeleteOrderQuery{ + BusinessID: in.GetBusinessId(), + }); err != nil { + // 錯誤代碼 06-011-00 + return nil, ers.InvalidFormat(err.Error()) + } + + _, err := l.svcCtx.OrderModel.DeleteByBusinessID(l.ctx, in.GetBusinessId()) + if err != nil { + return nil, err + } return &tweeting.OKResp{}, nil } diff --git a/internal/logic/orderservice/get_order_logic.go b/internal/logic/orderservice/get_order_logic.go index 9260f0f..f236f28 100644 --- a/internal/logic/orderservice/get_order_logic.go +++ b/internal/logic/orderservice/get_order_logic.go @@ -1,7 +1,9 @@ package orderservicelogic import ( + ers "code.30cm.net/digimon/library-go/errs" "context" + "github.com/shopspring/decimal" "app-cloudep-order-server/gen_result/pb/tweeting" "app-cloudep-order-server/internal/svc" @@ -23,9 +25,68 @@ func NewGetOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetOrder } } +// GetOrderQuery 取得訂單 +type GetOrderQuery struct { + BusinessID string `json:"business_id" validate:"required"` +} + // GetOrder 取得訂單詳情 func (l *GetOrderLogic) GetOrder(in *tweeting.GetOrderReq) (*tweeting.GetOrderResp, error) { - // todo: add your logic here and delete this line + // 驗證資料 + if err := l.svcCtx.Validate.ValidateAll(&GetOrderQuery{ + BusinessID: in.GetBusinessId(), + }); err != nil { + // 錯誤代碼 06-011-00 + return nil, ers.InvalidFormat(err.Error()) + } - return &tweeting.GetOrderResp{}, nil + order, err := l.svcCtx.OrderModel.FindOneBusinessID(l.ctx, in.GetBusinessId()) + if err != nil { + return nil, err + } + + return &tweeting.GetOrderResp{ + UpdateTime: order.UpdateTime, + CreateTime: order.CreateTime, + BusinessId: order.BusinessID, + OrderType: int32(order.OrderType), + OrderStatus: int32(order.OrderStatus), + Brand: order.Brand, + OrderUid: order.OrderUID, + ReferenceId: order.ReferenceID, + Count: order.Count.String(), + OrderFee: order.OrderFee.String(), + Amount: order.Amount.String(), + // 下面的是未來擴充用,加密貨幣用,或者幣別轉換用,普通訂單用不到 + ReferenceBrand: order.ReferenceBrand, + ReferenceUid: order.ReferenceUID, + WalletStatus: order.WalletStatus, + ThreePartyStatus: order.ThreePartyStatus, + DirectionType: order.DirectionType, + CryptoType: order.CryptoType, + ThirdPartyFee: decimalToString(*order.ThirdPartyFee), + CryptoToUsdtRate: decimalToString(*order.CryptoToUSDTRate), + FiatToUsdRate: decimalToString(*order.FiatToUSDRate), + FeeCryptoToUsdtRate: decimalToString(*order.FeeCryptoToUSDTRate), + UsdtToCryptoTypeRate: decimalToString(*order.USDTToCryptoTypeRate), + PaymentFiat: order.PaymentFiat, + PaymentUnitPrice: decimalToString(*order.PaymentUnitPrice), + PaymentTemplateId: order.PaymentTemplateID, + OrderArrivalTime: order.OrderArrivalTime, + OrderPaymentTime: order.OrderPaymentTime, + UnpaidTimeoutSecond: order.UnpaidTimeoutSecond, + ChainType: order.ChainType, + TxHash: order.TxHash, + FromAddress: order.FromAddress, + ToAddress: order.ToAddress, + ChainFee: decimalToString(*order.ChainFee), + ChainFeeCrypto: order.ChainFeeCrypto, + Memo: order.Memo, + OrderNote: order.OrderNote, + }, nil +} + +func decimalToString(amount decimal.Decimal) *string { + a := amount.String() + return &a } diff --git a/internal/logic/orderservice/list_order_logic.go b/internal/logic/orderservice/list_order_logic.go index 67e4cdb..dc55359 100644 --- a/internal/logic/orderservice/list_order_logic.go +++ b/internal/logic/orderservice/list_order_logic.go @@ -1,7 +1,10 @@ package orderservicelogic import ( + model "app-cloudep-order-server/internal/model/mongo" + ers "code.30cm.net/digimon/library-go/errs" "context" + "fmt" "app-cloudep-order-server/gen_result/pb/tweeting" "app-cloudep-order-server/internal/svc" @@ -23,9 +26,47 @@ func NewListOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListOrd } } +type 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 []int64 `json:"direction_type"` + OrderStatus []int64 `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"` +} + // ListOrder 取得訂單列表 func (l *ListOrderLogic) ListOrder(in *tweeting.ListOrderReq) (*tweeting.ListOrderResp, error) { - // todo: add your logic here and delete this line + // 驗證資料,目前只有 Page 必帶,其他要驗證在驗證 + if err := l.svcCtx.Validate.ValidateAll(&GetOrderListReq{ + PageIndex: in.GetPageIndex(), + PageSize: in.GetPageSize(), + }); err != nil { + // 錯誤代碼 06-011-00 + return nil, ers.InvalidFormat(err.Error()) + } + orders, total, err := l.svcCtx.OrderModel.ListOrder(l.ctx, model.GetOrderListReq{}) + if err != nil { + return nil, err + } + + fmt.Println(orders, total) return &tweeting.ListOrderResp{}, nil } diff --git a/internal/logic/orderservice/modify_order_status_logic.go b/internal/logic/orderservice/modify_order_status_logic.go index 4a2581b..02a204c 100644 --- a/internal/logic/orderservice/modify_order_status_logic.go +++ b/internal/logic/orderservice/modify_order_status_logic.go @@ -1,8 +1,12 @@ package orderservicelogic import ( + "app-cloudep-order-server/internal/domain" + model "app-cloudep-order-server/internal/model/mongo" "context" + ers "code.30cm.net/digimon/library-go/errs" + "app-cloudep-order-server/gen_result/pb/tweeting" "app-cloudep-order-server/internal/svc" @@ -23,9 +27,46 @@ func NewModifyOrderStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) } } +// ModifyOrderQuery +// 0.建立訂單 1.建單失敗 2.審核中 3.付款中 4.已付款 +// 5.已付款待轉帳 6.申訴中 7.交易完成 +// 8.交易失敗 9.交易取消 10.交易異常 11.交易超時 + +type ModifyOrderQuery struct { + BusinessID string `json:"business_id" validate:"required"` + Status int64 `json:"status" validate:"required,oneof=2 3 4 5 6 7 8 11"` +} + // ModifyOrderStatus 修改訂單狀態 func (l *ModifyOrderStatusLogic) ModifyOrderStatus(in *tweeting.ModifyOrderStatusReq) (*tweeting.OKResp, error) { - // todo: add your logic here and delete this line + // 驗證資料 + if err := l.svcCtx.Validate.ValidateAll(&ModifyOrderQuery{ + BusinessID: in.GetBusinessId(), + Status: in.GetStatus(), + }); err != nil { + // 錯誤代碼 06-011-00 + return nil, ers.InvalidFormat(err.Error()) + } + + _, err := l.svcCtx.OrderModel.UpdateStatus(l.ctx, + model.UpdateStatusReq{ + BusinessID: in.GetBusinessId(), + Status: in.GetStatus(), + }) + if err != nil { + // 錯誤代碼 06-021-02 + e := domain.CommentErrorL( + domain.ModifyOrderErrorCode, + logx.WithContext(l.ctx), + []logx.LogField{ + {Key: "req", Value: in}, + {Key: "func", Value: "OrderModel.UpdateStatus"}, + {Key: "err", Value: err}, + }, + "failed to update order status:").Wrap(err) + + return nil, e + } return &tweeting.OKResp{}, nil } diff --git a/internal/logic/orderservice/order_status_timeout_logic.go b/internal/logic/orderservice/order_status_timeout_logic.go index 67ce9c6..4a3096c 100644 --- a/internal/logic/orderservice/order_status_timeout_logic.go +++ b/internal/logic/orderservice/order_status_timeout_logic.go @@ -1,7 +1,10 @@ package orderservicelogic import ( + "app-cloudep-order-server/internal/domain" + model "app-cloudep-order-server/internal/model/mongo" "context" + "time" "app-cloudep-order-server/gen_result/pb/tweeting" "app-cloudep-order-server/internal/svc" @@ -25,7 +28,24 @@ func NewOrderStatusTimeoutLogic(ctx context.Context, svcCtx *svc.ServiceContext) // OrderStatusTimeout 訂單超時任務/cron/order-status/timeout func (l *OrderStatusTimeoutLogic) OrderStatusTimeout(in *tweeting.OrderStatusTimeoutReq) (*tweeting.OKResp, error) { - // todo: add your logic here and delete this line + now := time.Now().UTC().UnixNano() + _, err := l.svcCtx.OrderModel.UpdateTimeoutOrder(l.ctx, model.UpdateTimeoutReq{ + CreateTimeBefore: now, + }) + if err != nil { + // 錯誤代碼 06-021-02 + e := domain.CommentErrorL( + domain.TimeoutOrderErrorCode, + logx.WithContext(l.ctx), + []logx.LogField{ + {Key: "now", Value: now}, + {Key: "func", Value: "OrderModel.UpdateTimeoutOrder"}, + {Key: "err", Value: err}, + }, + "failed to update timeout order").Wrap(err) + + return nil, e + } return &tweeting.OKResp{}, nil } diff --git a/internal/model/mongo/order_model.go b/internal/model/mongo/order_model.go index 73a14ba..47f5b25 100644 --- a/internal/model/mongo/order_model.go +++ b/internal/model/mongo/order_model.go @@ -1,6 +1,16 @@ package model -import "github.com/zeromicro/go-zero/core/stores/mon" +import ( + "app-cloudep-order-server/internal/domain" + "context" + "errors" + "go.mongodb.org/mongo-driver/mongo/options" + "time" + + "github.com/zeromicro/go-zero/core/stores/mon" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) var _ OrderModel = (*customOrderModel)(nil) @@ -9,11 +19,50 @@ 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 []int64 `json:"direction_type"` + OrderStatus []int64 `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. @@ -23,3 +72,163 @@ func NewOrderModel(url, db, collection string) 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["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 + + err := m.conn.FindOne(ctx, &data, bson.M{"business_id": id}) + 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{} + + // 添加查詢條件 + 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..ecd3914 100644 --- a/internal/model/mongo/order_model_gen.go +++ b/internal/model/mongo/order_model_gen.go @@ -29,8 +29,8 @@ func newDefaultOrderModel(conn *mon.Model) *defaultOrderModel { func (m *defaultOrderModel) Insert(ctx context.Context, data *Order) error { if data.ID.IsZero() { data.ID = primitive.NewObjectID() - data.CreateAt = time.Now() - data.UpdateAt = time.Now() + data.CreateTime = time.Now().UTC().UnixNano() + data.UpdateTime = time.Now().UTC().UnixNano() } _, err := m.conn.InsertOne(ctx, data) @@ -57,7 +57,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 diff --git a/internal/model/mongo/order_types.go b/internal/model/mongo/order_types.go index 30198e9..fa50eb0 100644 --- a/internal/model/mongo/order_types.go +++ b/internal/model/mongo/order_types.go @@ -1,14 +1,51 @@ package model import ( - "time" - + "github.com/shopspring/decimal" "go.mongodb.org/mongo-driver/bson/primitive" ) type Order struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - // TODO: Fill your own fields - UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` - CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + UpdateTime int64 `bson:"update_time"` + CreateTime int64 `bson:"create_time"` + BusinessID string `bson:"business_id"` // 訂單業務流水號 + OrderType int8 `bson:"order_type"` // 訂單類型 + OrderStatus int8 `bson:"order_status"` // 訂單狀態 0.建立訂單 1.建單失敗 2.審核中 3.付款中 4.已付款 5.已付款待轉帳 6.申訴中 7.交易完成 8.交易失敗 9.交易取消 10.交易異常 11.交易超時 + Brand string `bson:"brand"` // 下單平台(混合也可用) + OrderUID string `bson:"order_uid"` // 下單用戶 UID + ReferenceID string `bson:"reference_id"` // 訂單來源(用) + Count decimal.Decimal `bson:"count"` // 訂單數量 + OrderFee decimal.Decimal `bson:"order_fee"` // 訂單手續費 + Amount decimal.Decimal `bson:"amount"` // 單價 + // 下面的是未來擴充用,加密貨幣用,或者幣別轉換用,普通訂單用不到 + ReferenceBrand *string `bson:"reference_brand"` // 訂單來源平台 + ReferenceUID *string `bson:"reference_uid"` // 訂單來源用戶 UID + WalletStatus *int64 `bson:"wallet_status,omitempty"` // 交易金額狀態 1.未凍結 2.已凍結 3.解凍(扣錢) 4.未增加資產 5.已增加資產 6.解凍還原 7.限制(將凍結餘額轉至限制餘額) + ThreePartyStatus *int64 `bson:"three_party_status,omitempty"` // 三方請求狀態 1.已發送 2.通知處理中 3.通知已完成 + DirectionType *int64 `bson:"direction_type,omitempty"` // 交易方向 1.買入 2.賣出 + CryptoType *string `bson:"crypto_type,omitempty"` // 交易幣種 + ThirdPartyFee *decimal.Decimal `bson:"third_party_fee,omitempty"` // 第三方手續費 + CryptoToUSDTRate *decimal.Decimal `bson:"crypto_to_usdt_rate,omitempty"` // 交易幣種 對 USDT 匯率 + FiatToUSDRate *decimal.Decimal `bson:"fiat_to_usd_rate,omitempty"` // 法幣 對 USD 匯率 + FeeCryptoToUSDTRate *decimal.Decimal `bson:"fee_crypto_to_usdt_rate,omitempty"` // 手續費幣種 對 USDT 匯率 + USDTToCryptoTypeRate *decimal.Decimal `bson:"usdt_to_crypto_type_rate,omitempty"` // USDT 對 交易幣種 匯率 + PaymentFiat *string `bson:"payment_fiat,omitempty"` // 支付法幣 + PaymentUnitPrice *decimal.Decimal `bson:"payment_unit_price,omitempty"` // crypto 單價 + PaymentTemplateID *string `bson:"payment_template_id,omitempty"` // 支付方式配置 ID + OrderArrivalTime *int64 `bson:"order_arrival_time,omitempty"` // 訂單到帳時間/充值到帳時間 + OrderPaymentTime *int64 `bson:"order_payment_time,omitempty"` // 訂單付款時間/鏈上成功或失敗時間 + UnpaidTimeoutSecond *int64 `bson:"unpaid_timeout_second,omitempty"` // 支付期限秒數 + ChainType *string `bson:"chain_type,omitempty"` // 主網類型 + TxHash *string `bson:"tx_hash,omitempty"` // 交易哈希 + FromAddress *string `bson:"from_address,omitempty"` // 來源地址 + ToAddress *string `bson:"to_address,omitempty"` // 目標地址 + ChainFee *decimal.Decimal `bson:"chain_fee,omitempty"` // 鏈上交易手續費 + ChainFeeCrypto *string `bson:"chain_fee_crypto,omitempty"` // 鏈上手續費使用幣別 + Memo *string `bson:"memo,omitempty"` // 鏈上備註 + OrderNote *string `bson:"order_note,omitempty"` // 訂單交易備註 +} + +func (p *Order) CollectionName() string { + return "order" } diff --git a/internal/server/orderservice/order_service_server.go b/internal/server/orderservice/order_service_server.go index 7014e9d..0438b47 100644 --- a/internal/server/orderservice/order_service_server.go +++ b/internal/server/orderservice/order_service_server.go @@ -23,7 +23,7 @@ func NewOrderServiceServer(svcCtx *svc.ServiceContext) *OrderServiceServer { } // CreateOrder 建立訂單 -func (s *OrderServiceServer) CreateOrder(ctx context.Context, in *tweeting.CreateOrderReq) (*tweeting.CreateOrderResp, error) { +func (s *OrderServiceServer) CreateOrder(ctx context.Context, in *tweeting.CreateOrderReq) (*tweeting.OKResp, error) { l := orderservicelogic.NewCreateOrderLogic(ctx, s.svcCtx) return l.CreateOrder(in) } diff --git a/internal/svc/init_mongo.go b/internal/svc/init_mongo.go new file mode 100644 index 0000000..ef417ad --- /dev/null +++ b/internal/svc/init_mongo.go @@ -0,0 +1,23 @@ +package svc + +import ( + "app-cloudep-order-server/internal/config" + model "app-cloudep-order-server/internal/model/mongo" + "fmt" +) + +func mustMongoConnectURL(c config.Config) string { + return fmt.Sprintf("%s://%s:%s", + c.Mongo.Schema, + c.Mongo.Host, + c.Mongo.Port, + ) +} + +// TODO 思考快取做在那邊 + +func MustOrderModel(c config.Config) model.OrderModel { + orderCollection := model.Order{} + + return model.NewOrderModel(mustMongoConnectURL(c), c.Mongo.Database, orderCollection.CollectionName()) +} diff --git a/internal/svc/service_context.go b/internal/svc/service_context.go index 53b091b..1c91e31 100644 --- a/internal/svc/service_context.go +++ b/internal/svc/service_context.go @@ -1,13 +1,27 @@ package svc -import "app-cloudep-order-server/internal/config" +import ( + "app-cloudep-order-server/internal/config" + model "app-cloudep-order-server/internal/model/mongo" + + ers "code.30cm.net/digimon/library-go/errs" + "code.30cm.net/digimon/library-go/errs/code" + vi "code.30cm.net/digimon/library-go/validator" +) type ServiceContext struct { - Config config.Config + Config config.Config + Validate vi.Validate + + OrderModel model.OrderModel } func NewServiceContext(c config.Config) *ServiceContext { + ers.Scope = code.CloudEPOrder + return &ServiceContext{ - Config: c, + Config: c, + Validate: vi.MustValidator(), + OrderModel: MustOrderModel(c), } }